From 9a2592f8d2177f1480758e94faf9b986c7bba681 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 12 Jan 2026 19:41:21 +0000 Subject: [PATCH 001/328] 8374953: Add note on about implicit state when comparing TypeMirrors Reviewed-by: attila, vromero, jlahoda --- .../classes/javax/lang/model/type/TypeMirror.java | 11 ++++++++++- .../share/classes/javax/lang/model/util/Types.java | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/java.compiler/share/classes/javax/lang/model/type/TypeMirror.java b/src/java.compiler/share/classes/javax/lang/model/type/TypeMirror.java index 5bd205a6c4b..facdbe405dd 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/TypeMirror.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/TypeMirror.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,6 +120,15 @@ public interface TypeMirror extends AnnotatedConstruct { * The results of {@code t1.equals(t2)} and * {@code Types.isSameType(t1, t2)} may differ. * + * @apiNote The identity of a {@code TypeMirror} involves implicit + * state not directly accessible from its methods, including state + * about the presence of unrelated types. {@code TypeMirror} + * objects created by different implementations of these + * interfaces should not be expected to compare as equal + * even if "the same" type is being modeled; this is + * analogous to the inequality of {@code Class} objects for the + * same class file loaded through different class loaders. + * * @param obj the object to be compared with this type * @return {@code true} if the specified object is equal to this one */ diff --git a/src/java.compiler/share/classes/javax/lang/model/util/Types.java b/src/java.compiler/share/classes/javax/lang/model/util/Types.java index 951b56ed214..e7212a7e0be 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/Types.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/Types.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, 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 @@ -106,6 +106,15 @@ public interface Types { * {@code TypeMirror} objects can have different annotations and * still be considered the same. * + * @apiNote The identity of a {@code TypeMirror} involves implicit + * state not directly accessible from its methods, including state + * about the presence of unrelated types. {@code TypeMirror} + * objects created by different implementations of these + * interfaces should not be expected to compare as equal + * even if "the same" type is being modeled; this is + * analogous to the inequality of {@code Class} objects for the + * same class file loaded through different class loaders. + * * @param t1 the first type * @param t2 the second type * @return {@code true} if and only if the two types are the same From 15b7a4252b8d3595b7bc409e20d4c617e89240e8 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Mon, 12 Jan 2026 23:36:26 +0000 Subject: [PATCH 002/328] 8373819: Genshen: Control thread can miss allocation failure notification (redux) Reviewed-by: kdnilsen, ysr --- .../shenandoahGenerationalControlThread.cpp | 106 +++++++++++------- .../shenandoahGenerationalControlThread.hpp | 11 +- .../shenandoah/shenandoahGenerationalHeap.hpp | 4 +- .../shenandoah/shenandoahRegulatorThread.cpp | 7 ++ 4 files changed, 78 insertions(+), 50 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index ece4150f577..018b4898a19 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -61,7 +61,12 @@ ShenandoahGenerationalControlThread::ShenandoahGenerationalControlThread() : void ShenandoahGenerationalControlThread::run_service() { + // This is the only instance of request. It is important that request.generation + // does not change between a concurrent cycle failure and the start of a degenerated + // cycle. We initialize it with the young generation to handle the pathological case + // where the very first cycle is degenerated (some tests exercise this path). ShenandoahGCRequest request; + request.generation = _heap->young_generation(); while (!should_terminate()) { // Figure out if we have pending requests. @@ -77,12 +82,10 @@ void ShenandoahGenerationalControlThread::run_service() { // If the cycle was cancelled, continue the next iteration to deal with it. Otherwise, // if there was no other cycle requested, cleanup and wait for the next request. - if (!_heap->cancelled_gc()) { - MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); - if (_requested_gc_cause == GCCause::_no_gc) { - set_gc_mode(ml, none); - ml.wait(); - } + MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); + if (_requested_gc_cause == GCCause::_no_gc) { + set_gc_mode(ml, none); + ml.wait(); } } @@ -96,8 +99,7 @@ void ShenandoahGenerationalControlThread::stop_service() { log_debug(gc, thread)("Stopping control thread"); MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); _heap->cancel_gc(GCCause::_shenandoah_stop_vm); - _requested_gc_cause = GCCause::_shenandoah_stop_vm; - notify_cancellation(ml, GCCause::_shenandoah_stop_vm); + notify_control_thread(ml, GCCause::_shenandoah_stop_vm); // We can't wait here because it may interfere with the active cycle's ability // to reach a safepoint (this runs on a java thread). } @@ -105,29 +107,39 @@ void ShenandoahGenerationalControlThread::stop_service() { void ShenandoahGenerationalControlThread::check_for_request(ShenandoahGCRequest& request) { // Hold the lock while we read request cause and generation MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); - if (_heap->cancelled_gc()) { - // The previous request was cancelled. Either it was cancelled for an allocation - // failure (degenerated cycle), or old marking was cancelled to run a young collection. - // In either case, the correct generation for the next cycle can be determined by - // the cancellation cause. - request.cause = _heap->clear_cancellation(GCCause::_shenandoah_concurrent_gc); - if (request.cause == GCCause::_shenandoah_concurrent_gc) { + + log_debug(gc, thread)("cancelled cause: %s, requested cause: %s", + GCCause::to_string(_heap->cancelled_cause()), GCCause::to_string(_requested_gc_cause)); + + request.cause = _requested_gc_cause; + if (ShenandoahCollectorPolicy::is_allocation_failure(request.cause)) { + if (_degen_point == ShenandoahGC::_degenerated_unset) { request.generation = _heap->young_generation(); + _degen_point = ShenandoahGC::_degenerated_outside_cycle; + } else { + assert(request.generation != nullptr, "Must know which generation to use for degenerated cycle"); } } else { - request.cause = _requested_gc_cause; + if (request.cause == GCCause::_shenandoah_concurrent_gc) { + // This is a regulator request. It is also possible that the regulator "canceled" an old mark, + // so we can clear that here. This clear operation will only clear the cancellation if it is + // a regulator request. + _heap->clear_cancellation(GCCause::_shenandoah_concurrent_gc); + } request.generation = _requested_generation; - - // Only clear these if we made a request from them. In the case of a cancelled gc, - // we do not want to inadvertently lose this pending request. - _requested_gc_cause = GCCause::_no_gc; - _requested_generation = nullptr; } + log_debug(gc, thread)("request.cause: %s, request.generation: %s", + GCCause::to_string(request.cause), request.generation == nullptr ? "None" : request.generation->name()); + + _requested_gc_cause = GCCause::_no_gc; + _requested_generation = nullptr; + if (request.cause == GCCause::_no_gc || request.cause == GCCause::_shenandoah_stop_vm) { return; } + assert(request.generation != nullptr, "request.generation cannot be null, cause is: %s", GCCause::to_string(request.cause)); GCMode mode; if (ShenandoahCollectorPolicy::is_allocation_failure(request.cause)) { mode = prepare_for_allocation_failure_gc(request); @@ -140,11 +152,9 @@ void ShenandoahGenerationalControlThread::check_for_request(ShenandoahGCRequest& } ShenandoahGenerationalControlThread::GCMode ShenandoahGenerationalControlThread::prepare_for_allocation_failure_gc(ShenandoahGCRequest &request) { - - if (_degen_point == ShenandoahGC::_degenerated_unset) { - _degen_point = ShenandoahGC::_degenerated_outside_cycle; - request.generation = _heap->young_generation(); - } else if (request.generation->is_old()) { + // Important: not all paths update the request.generation. This is intentional. + // A degenerated cycle must use the same generation carried over from the previous request. + if (request.generation->is_old()) { // This means we degenerated during the young bootstrap for the old generation // cycle. The following degenerated cycle should therefore also be young. request.generation = _heap->young_generation(); @@ -588,6 +598,8 @@ bool ShenandoahGenerationalControlThread::check_cancellation_or_degen(Shenandoah if (ShenandoahCollectorPolicy::is_allocation_failure(_heap->cancelled_cause())) { assert(_degen_point == ShenandoahGC::_degenerated_unset, "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point)); + MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); + _requested_gc_cause = _heap->cancelled_cause(); _degen_point = point; log_debug(gc, thread)("Cancellation detected:, reason: %s, degen point: %s", GCCause::to_string(_heap->cancelled_cause()), @@ -633,9 +645,7 @@ void ShenandoahGenerationalControlThread::service_stw_degenerated_cycle(const Sh void ShenandoahGenerationalControlThread::request_gc(GCCause::Cause cause) { if (ShenandoahCollectorPolicy::is_allocation_failure(cause)) { - // GC should already be cancelled. Here we are just notifying the control thread to - // wake up and handle the cancellation request, so we don't need to set _requested_gc_cause. - notify_cancellation(cause); + notify_control_thread(cause); } else if (ShenandoahCollectorPolicy::should_handle_requested_gc(cause)) { handle_requested_gc(cause); } @@ -653,7 +663,8 @@ bool ShenandoahGenerationalControlThread::request_concurrent_gc(ShenandoahGenera MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); if (gc_mode() == servicing_old) { if (!preempt_old_marking(generation)) { - log_debug(gc, thread)("Cannot start young, old collection is not preemptible"); + // Global should be able to cause old collection to be abandoned + log_debug(gc, thread)("Cannot start %s, old collection is not preemptible", generation->name()); return false; } @@ -661,7 +672,7 @@ bool ShenandoahGenerationalControlThread::request_concurrent_gc(ShenandoahGenera log_info(gc)("Preempting old generation mark to allow %s GC", generation->name()); while (gc_mode() == servicing_old) { ShenandoahHeap::heap()->cancel_gc(GCCause::_shenandoah_concurrent_gc); - notify_cancellation(ml, GCCause::_shenandoah_concurrent_gc); + notify_control_thread(ml, GCCause::_shenandoah_concurrent_gc, generation); ml.wait(); } return true; @@ -695,21 +706,34 @@ void ShenandoahGenerationalControlThread::notify_control_thread(GCCause::Cause c void ShenandoahGenerationalControlThread::notify_control_thread(MonitorLocker& ml, GCCause::Cause cause, ShenandoahGeneration* generation) { assert(_control_lock.is_locked(), "Request lock must be held here"); - log_debug(gc, thread)("Notify control (%s): %s, %s", gc_mode_name(gc_mode()), GCCause::to_string(cause), generation->name()); - _requested_gc_cause = cause; - _requested_generation = generation; - ml.notify(); + if (ShenandoahCollectorPolicy::is_allocation_failure(_requested_gc_cause)) { + // We have already observed a request to handle an allocation failure. We cannot allow + // another request (System.gc or regulator) to subvert the degenerated cycle. + log_debug(gc, thread)("Not overwriting gc cause %s with %s", GCCause::to_string(_requested_gc_cause), GCCause::to_string(cause)); + } else { + log_debug(gc, thread)("Notify control (%s): %s, %s", gc_mode_name(gc_mode()), GCCause::to_string(cause), generation->name()); + _requested_gc_cause = cause; + _requested_generation = generation; + ml.notify(); + } } -void ShenandoahGenerationalControlThread::notify_cancellation(GCCause::Cause cause) { +void ShenandoahGenerationalControlThread::notify_control_thread(GCCause::Cause cause) { MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); - notify_cancellation(ml, cause); + notify_control_thread(ml, cause); } -void ShenandoahGenerationalControlThread::notify_cancellation(MonitorLocker& ml, GCCause::Cause cause) { - assert(_heap->cancelled_gc(), "GC should already be cancelled"); - log_debug(gc,thread)("Notify control (%s): %s", gc_mode_name(gc_mode()), GCCause::to_string(cause)); - ml.notify(); +void ShenandoahGenerationalControlThread::notify_control_thread(MonitorLocker& ml, GCCause::Cause cause) { + assert(_control_lock.is_locked(), "Request lock must be held here"); + if (ShenandoahCollectorPolicy::is_allocation_failure(_requested_gc_cause)) { + // We have already observed a request to handle an allocation failure. We cannot allow + // another request (System.gc or regulator) to subvert the degenerated cycle. + log_debug(gc, thread)("Not overwriting gc cause %s with %s", GCCause::to_string(_requested_gc_cause), GCCause::to_string(cause)); + } else { + log_debug(gc, thread)("Notify control (%s): %s", gc_mode_name(gc_mode()), GCCause::to_string(cause)); + _requested_gc_cause = cause; + ml.notify(); + } } bool ShenandoahGenerationalControlThread::preempt_old_marking(ShenandoahGeneration* generation) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp index b7dbedd5e84..13e69d25268 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp @@ -135,16 +135,13 @@ private: // Return printable name for the given gc mode. static const char* gc_mode_name(GCMode mode); - // Takes the request lock and updates the requested cause and generation, then notifies the control thread. - // The overloaded variant should be used when the _control_lock is already held. + // These notify the control thread after updating _requested_gc_cause and (optionally) _requested_generation. + // Updating the requested generation is not necessary for allocation failures nor when stopping the thread. + void notify_control_thread(GCCause::Cause cause); + void notify_control_thread(MonitorLocker& ml, GCCause::Cause cause); void notify_control_thread(GCCause::Cause cause, ShenandoahGeneration* generation); void notify_control_thread(MonitorLocker& ml, GCCause::Cause cause, ShenandoahGeneration* generation); - // Notifies the control thread, but does not update the requested cause or generation. - // The overloaded variant should be used when the _control_lock is already held. - void notify_cancellation(GCCause::Cause cause); - void notify_cancellation(MonitorLocker& ml, GCCause::Cause cause); - // Configure the heap to age objects and regions if the aging period has elapsed. void maybe_set_aging_cycle(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp index 736026916f7..a2ae4a68cd0 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp @@ -44,13 +44,13 @@ public: void post_initialize_heuristics() override; static ShenandoahGenerationalHeap* heap() { - assert(ShenandoahCardBarrier, "Should have card barrier to use genenrational heap"); + assert(ShenandoahCardBarrier, "Should have card barrier to use generational heap"); CollectedHeap* heap = Universe::heap(); return cast(heap); } static ShenandoahGenerationalHeap* cast(CollectedHeap* heap) { - assert(ShenandoahCardBarrier, "Should have card barrier to use genenrational heap"); + assert(ShenandoahCardBarrier, "Should have card barrier to use generational heap"); return checked_cast(heap); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp index 964b6f0a10a..ec4b7c7217c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp @@ -149,6 +149,13 @@ bool ShenandoahRegulatorThread::start_global_cycle() const { bool ShenandoahRegulatorThread::request_concurrent_gc(ShenandoahGeneration* generation) const { double now = os::elapsedTime(); + + // This call may find the control thread waiting on workers which have suspended + // to allow a safepoint to run. If this regulator thread does not yield, the safepoint + // will not run. The worker threads won't progress, the control thread won't progress, + // and the regulator thread may never yield. Therefore, we leave the suspendible + // thread set before making this call. + SuspendibleThreadSetLeaver leaver; bool accepted = _control_thread->request_concurrent_gc(generation); if (LogTarget(Debug, gc, thread)::is_enabled() && accepted) { double wait_time = os::elapsedTime() - now; From e89c1290ca8b3e07bef12f4c0465c3e83389fef4 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 13 Jan 2026 01:29:20 +0000 Subject: [PATCH 003/328] 8374181: failure_handler: The cores.html file is formatted incorrectly and so hides the core dump information Reviewed-by: erikj --- .../jtreg/GatherDiagnosticInfoObserver.java | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java index e63e55888d7..32dbedb5159 100644 --- a/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java @@ -29,13 +29,14 @@ import com.sun.javatest.TestResult; import com.sun.javatest.regtest.config.RegressionParameters; import jdk.test.failurehandler.*; -import java.io.File; import java.io.FileWriter; 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.util.List; +import java.util.stream.Stream; /** * The jtreg test execution observer, which gathers info about @@ -85,11 +86,15 @@ public class GatherDiagnosticInfoObserver implements Harness.Observer { testJdk, compileJdk); gatherEnvInfo(workDir, name, log, gathererFactory.getEnvironmentInfoGatherer()); - Files.walk(workDir) - .filter(Files::isRegularFile) - .filter(f -> (f.getFileName().toString().contains("core") || f.getFileName().toString().contains("mdmp"))) - .forEach(core -> gatherCoreInfo(workDir, name, - core, log, gathererFactory.getCoreInfoGatherer())); + // generate a cores.html file after parsing the core dump files (if any) + List coreFiles; + try (Stream paths = Files.walk(workDir)) { + coreFiles = paths.filter(Files::isRegularFile) + .filter(f -> (f.getFileName().toString().contains("core") + || f.getFileName().toString().contains("mdmp"))) + .toList(); + } + gatherCoreInfo(workDir, name, coreFiles, log, gathererFactory.getCoreInfoGatherer()); } catch (Throwable e) { log.printf("ERROR: exception in observer %s:", name); e.printStackTrace(log); @@ -103,16 +108,22 @@ public class GatherDiagnosticInfoObserver implements Harness.Observer { } } - private void gatherCoreInfo(Path workDir, String name, Path core, PrintWriter log, - CoreInfoGatherer gatherer) { + private void gatherCoreInfo(Path workDir, String name, List coreFiles, + PrintWriter log, CoreInfoGatherer gatherer) { + if (coreFiles.isEmpty()) { + return; + } try (HtmlPage html = new HtmlPage(workDir, CORES_OUTPUT, true)) { try (ElapsedTimePrinter timePrinter = new ElapsedTimePrinter(new Stopwatch(), name, log)) { - gatherer.gatherCoreInfo(html.getRootSection(), core); + // gather information from the contents of each core file + for (Path coreFile : coreFiles) { + gatherer.gatherCoreInfo(html.getRootSection(), coreFile); + } } } catch (Throwable e) { - log.printf("ERROR: exception in observer on getting environment " - + "information %s:", name); + log.printf("ERROR: exception in %s observer while gathering information from" + + " core dump file", name); e.printStackTrace(log); } } From 0b9d4c02e39191e9dba721115f422e28ee5b9869 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 13 Jan 2026 04:29:12 +0000 Subject: [PATCH 004/328] 4765299: componentResized() not always called with nested JSplitPanes Reviewed-by: tr, kizune --- .../swing/plaf/basic/BasicSplitPaneUI.java | 4 +- .../JSplitPane/TestSplitPaneCompResize.java | 173 ++++++++++++++++++ 2 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 test/jdk/javax/swing/JSplitPane/TestSplitPaneCompResize.java diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java index 5ff68f78d38..270181f4600 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -1405,7 +1405,7 @@ public class BasicSplitPaneUI extends SplitPaneUI // If the splitpane has a zero size then no op out of here. // If we execute this function now, we're going to cause ourselves // much grief. - if (containerSize.height <= 0 || containerSize.width <= 0 ) { + if (containerSize.height <= 0 && containerSize.width <= 0 ) { lastSplitPaneSize = 0; return; } diff --git a/test/jdk/javax/swing/JSplitPane/TestSplitPaneCompResize.java b/test/jdk/javax/swing/JSplitPane/TestSplitPaneCompResize.java new file mode 100644 index 00000000000..07d9b77f90e --- /dev/null +++ b/test/jdk/javax/swing/JSplitPane/TestSplitPaneCompResize.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2026, 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 4765299 + * @key headful + * @summary Verifies componentResized() is called with nested JSplitPanes + * @run main TestSplitPaneCompResize + */ + +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.InputEvent; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JPanel; +import javax.swing.ListSelectionModel; +import javax.swing.plaf.basic.BasicSplitPaneDivider; +import javax.swing.plaf.basic.BasicSplitPaneUI; +import javax.swing.SwingUtilities; + +public class TestSplitPaneCompResize { + + private static JFrame frame; + private JSplitPane outer; + private static JButton leftOneTouchButton; + private static volatile Point leftBtnPos; + private static volatile boolean resized; + + public TestSplitPaneCompResize() { + + // set up a simple list embedded inside a scroll pane + String[] listItems = {"Item1", "Item2"}; + JList list = new JList<>(listItems); + list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + list.setSelectedIndex(0); + + JScrollPane comp = new JScrollPane(list); + JSplitPane inner = new JSplitPane(JSplitPane.VERTICAL_SPLIT, + comp, new JPanel()); + JPanel rightPanel = new JPanel(); + + outer = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, + inner, rightPanel); + outer.setDividerLocation(150); + + //Provide minimum sizes for the two components in the split pane + Dimension minimumSize = new Dimension(100, 50); + comp.setMinimumSize(minimumSize); + inner.setMinimumSize(minimumSize); + rightPanel.setMinimumSize(minimumSize); + + //Provide a preferred size for the split pane + outer.setPreferredSize(new Dimension(400, 200)); + inner.addComponentListener(new ComponentAdapter() { + public void componentResized(ComponentEvent e) { + System.out.println("inner resized"); + } + }); + comp.addComponentListener(new ComponentAdapter() { + public void componentResized(ComponentEvent e) { + resized = true; + System.out.println("comp resized"); + } + }); + } + + public JSplitPane getSplitPane() { + return outer; + } + + + public static void main(String[] s) throws Exception { + Robot robot = new Robot(); + try { + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("SplitPaneDemo"); + + TestSplitPaneCompResize sp = new TestSplitPaneCompResize(); + JSplitPane jsp = sp.getSplitPane(); + frame.getContentPane().add(jsp); + jsp.setUI(new MySplitPaneUI()); + jsp.setOneTouchExpandable(true); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + leftBtnPos = leftOneTouchButton.getLocationOnScreen(); + leftBtnPos.x += leftOneTouchButton.getWidth() / 2; + leftBtnPos.y += leftOneTouchButton.getHeight() / 2; + }); + + resized = false; + robot.mouseMove(leftBtnPos.x, leftBtnPos.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(1000); + + if (!resized) { + throw new RuntimeException("ComponentResized not called"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + + static class MySplitPaneUI extends BasicSplitPaneUI { + + public MySplitPaneUI() { + super(); + } + + public BasicSplitPaneDivider createDefaultDivider() { + return new MySplitPaneDivider(this); + } + } + + static class MySplitPaneDivider extends BasicSplitPaneDivider { + + public MySplitPaneDivider(BasicSplitPaneUI ui) { + super(ui); + } + + protected JButton createLeftOneTouchButton() { + leftOneTouchButton = super.createLeftOneTouchButton(); + return leftOneTouchButton; + } + + protected JButton createRightOneTouchButton() { + JButton rightOneTouchButton = super.createRightOneTouchButton(); + return rightOneTouchButton; + } + } +} From f4ebf9585f63177584d8c48838ef793407ebce12 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 13 Jan 2026 06:02:01 +0000 Subject: [PATCH 005/328] 8370314: Update signals_posix with new Linux signal codes Reviewed-by: shade, jwaters --- src/hotspot/os/posix/signals_posix.cpp | 40 +++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index 85babea5603..203e13a46ac 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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 @@ -951,6 +951,32 @@ struct enum_sigcode_desc_t { const char* s_desc; }; +#if defined(LINUX) +// Additional kernel si_code definitions that are only exported by +// more recent glibc distributions, so we have to hard-code the values. +#ifndef BUS_MCEERR_AR // glibc 2.17 +#define BUS_MCEERR_AR 4 +#define BUS_MCEERR_AO 5 +#endif + +#ifndef SEGV_PKUERR // glibc 2.27 +#define SEGV_PKUERR 4 +#endif + +#ifndef SYS_SECCOMP // glibc 2.28 +#define SYS_SECCOMP 1 +#endif + +#ifndef TRAP_BRANCH // glibc 2.30 +#define TRAP_BRANCH 3 +#endif + +#ifndef TRAP_HWBKPT // not glibc version specific - gdb related +#define TRAP_HWBKPT 4 +#endif + +#endif // LINUX + static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t* out) { const struct { @@ -976,6 +1002,7 @@ static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t { SIGSEGV, SEGV_ACCERR, "SEGV_ACCERR", "Invalid permissions for mapped object." }, #if defined(LINUX) { SIGSEGV, SEGV_BNDERR, "SEGV_BNDERR", "Failed address bound checks." }, + { SIGSEGV, SEGV_PKUERR, "SEGV_PKUERR", "Protection key checking failure." }, #endif #if defined(AIX) // no explanation found what keyerr would be @@ -984,8 +1011,18 @@ static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t { SIGBUS, BUS_ADRALN, "BUS_ADRALN", "Invalid address alignment." }, { SIGBUS, BUS_ADRERR, "BUS_ADRERR", "Nonexistent physical address." }, { SIGBUS, BUS_OBJERR, "BUS_OBJERR", "Object-specific hardware error." }, +#if defined(LINUX) + { SIGBUS, BUS_MCEERR_AR,"BUS_MCEERR_AR","Hardware memory error consumed on a machine check: action required." }, + { SIGBUS, BUS_MCEERR_AO,"BUS_MCEERR_AO","Hardware memory error detected in process but not consumed: action optional." }, + + { SIGSYS, SYS_SECCOMP, "SYS_SECCOMP", "Secure computing (seccomp) filter failure." }, +#endif { SIGTRAP, TRAP_BRKPT, "TRAP_BRKPT", "Process breakpoint." }, { SIGTRAP, TRAP_TRACE, "TRAP_TRACE", "Process trace trap." }, +#if defined(LINUX) + { SIGTRAP, TRAP_BRANCH, "TRAP_BRANCH", "Process taken branch trap." }, + { SIGTRAP, TRAP_HWBKPT, "TRAP_HWBKPT", "Hardware breakpoint/watchpoint." }, +#endif { SIGCHLD, CLD_EXITED, "CLD_EXITED", "Child has exited." }, { SIGCHLD, CLD_KILLED, "CLD_KILLED", "Child has terminated abnormally and did not create a core file." }, { SIGCHLD, CLD_DUMPED, "CLD_DUMPED", "Child has terminated abnormally and created a core file." }, @@ -993,6 +1030,7 @@ static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t { SIGCHLD, CLD_STOPPED, "CLD_STOPPED", "Child has stopped." }, { SIGCHLD, CLD_CONTINUED,"CLD_CONTINUED","Stopped child has continued." }, #ifdef SIGPOLL + { SIGPOLL, POLL_IN, "POLL_IN", "Data input available." }, { SIGPOLL, POLL_OUT, "POLL_OUT", "Output buffers available." }, { SIGPOLL, POLL_MSG, "POLL_MSG", "Input message available." }, { SIGPOLL, POLL_ERR, "POLL_ERR", "I/O error." }, From 586846b84a38d285c5905437e903cfc57f609410 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 13 Jan 2026 06:49:04 +0000 Subject: [PATCH 006/328] 8374450: GTest opto.canonicalize_constraints cannot run without VM Reviewed-by: qamai, thartmann, shade --- test/hotspot/gtest/opto/test_rangeinference.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/gtest/opto/test_rangeinference.cpp b/test/hotspot/gtest/opto/test_rangeinference.cpp index 61a9ff7fb70..42767e9fcab 100644 --- a/test/hotspot/gtest/opto/test_rangeinference.cpp +++ b/test/hotspot/gtest/opto/test_rangeinference.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -202,7 +202,7 @@ static void test_canonicalize_constraints_random() { } } -TEST(opto, canonicalize_constraints) { +TEST_VM(opto, canonicalize_constraints) { test_canonicalize_constraints_trivial(); test_canonicalize_constraints_exhaustive, uintn_t<1>>(); test_canonicalize_constraints_exhaustive, uintn_t<2>>(); From c000343bbb1d822d2cee37e1a27672cfb3128bee Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 13 Jan 2026 07:30:13 +0000 Subject: [PATCH 007/328] 8374876: Epsilon: Convert to use Atomic Reviewed-by: tschatzl, stefank --- src/hotspot/share/gc/epsilon/epsilonHeap.cpp | 10 ++++------ src/hotspot/share/gc/epsilon/epsilonHeap.hpp | 5 +++-- .../share/gc/epsilon/epsilonMonitoringSupport.cpp | 5 ++--- .../share/gc/epsilon/epsilonMonitoringSupport.hpp | 3 ++- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp index 24182c22a23..59ab69b2427 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp @@ -62,8 +62,6 @@ jint EpsilonHeap::initialize() { // Enable monitoring _monitoring_support = new EpsilonMonitoringSupport(this); - _last_counter_update = 0; - _last_heap_print = 0; // Install barrier set BarrierSet::set_barrier_set(new EpsilonBarrierSet()); @@ -156,17 +154,17 @@ HeapWord* EpsilonHeap::allocate_work(size_t size) { // At this point, some diagnostic subsystems might not yet be initialized. // We pretend the printout happened either way. This keeps allocation path // from obsessively checking the subsystems' status on every allocation. - size_t last_counter = AtomicAccess::load(&_last_counter_update); + size_t last_counter = _last_counter_update.load_relaxed(); if ((used - last_counter >= _step_counter_update) && - AtomicAccess::cmpxchg(&_last_counter_update, last_counter, used) == last_counter) { + _last_counter_update.compare_set(last_counter, used)) { if (_monitoring_support->is_ready()) { _monitoring_support->update_counters(); } } - size_t last_heap = AtomicAccess::load(&_last_heap_print); + size_t last_heap = _last_heap_print.load_relaxed(); if ((used - last_heap >= _step_heap_print) && - AtomicAccess::cmpxchg(&_last_heap_print, last_heap, used) == last_heap) { + _last_heap_print.compare_set(last_heap, used)) { print_heap_info(used); if (Metaspace::initialized()) { print_metaspace_info(); diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp index 9693c63b15c..8d7aa7960fd 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp @@ -31,6 +31,7 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/space.hpp" #include "memory/virtualspace.hpp" +#include "runtime/atomic.hpp" #include "services/memoryManager.hpp" class EpsilonHeap : public CollectedHeap { @@ -45,8 +46,8 @@ private: size_t _step_counter_update; size_t _step_heap_print; int64_t _decay_time_ns; - volatile size_t _last_counter_update; - volatile size_t _last_heap_print; + Atomic _last_counter_update; + Atomic _last_heap_print; void print_tracing_info() const override; void stop() override {}; diff --git a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp index 38be736df74..213fc18b8ff 100644 --- a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp @@ -96,7 +96,6 @@ public: EpsilonMonitoringSupport::EpsilonMonitoringSupport(EpsilonHeap* heap) { _heap_counters = new EpsilonGenerationCounters(heap); _space_counters = new EpsilonSpaceCounters("Heap", 0, heap->max_capacity(), 0, _heap_counters); - _ready = false; } void EpsilonMonitoringSupport::update_counters() { @@ -114,9 +113,9 @@ void EpsilonMonitoringSupport::update_counters() { } bool EpsilonMonitoringSupport::is_ready() { - return AtomicAccess::load_acquire(&_ready); + return _ready.load_acquire(); } void EpsilonMonitoringSupport::mark_ready() { - return AtomicAccess::release_store(&_ready, true); + _ready.release_store(true); } diff --git a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.hpp b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.hpp index 76cdac6df1b..9dc52c2a659 100644 --- a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.hpp +++ b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.hpp @@ -26,6 +26,7 @@ #define SHARE_GC_EPSILON_EPSILONMONITORINGSUPPORT_HPP #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" class EpsilonGenerationCounters; class EpsilonSpaceCounters; @@ -35,7 +36,7 @@ class EpsilonMonitoringSupport : public CHeapObj { private: EpsilonGenerationCounters* _heap_counters; EpsilonSpaceCounters* _space_counters; - volatile bool _ready; + Atomic _ready; public: EpsilonMonitoringSupport(EpsilonHeap* heap); From d6f43d7329bf0ba08464f6d0a22de7e27ca8b399 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Tue, 13 Jan 2026 08:05:57 +0000 Subject: [PATCH 008/328] 8375066: Test tools/sincechecker/modules/java.base/JavaBaseCheckSince.java broken by JDK-8369564 Reviewed-by: jpai, shade --- .../share/classes/java/lang/foreign/MemorySegment.java | 2 ++ .../share/classes/java/lang/foreign/SegmentAllocator.java | 1 + 2 files changed, 3 insertions(+) diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java index 2b931a7d2e0..78098e39a17 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -1354,6 +1354,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if {@code byteLength < 0} + * @since 27 */ String getString(long offset, Charset charset, long byteLength); @@ -2669,6 +2670,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * @throws IndexOutOfBoundsException if {@code dstOffset > dstSegment.byteSize() - B} where {@code B} is the size, * in bytes, of the substring of {@code src} encoded using the given charset * @return the number of copied bytes. + * @since 27 */ @ForceInline static long copy(String src, Charset dstEncoding, int srcIndex, MemorySegment dst, long dstOffset, int numChars) { diff --git a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java index 5b213af544f..03d92ec24ef 100644 --- a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java +++ b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java @@ -183,6 +183,7 @@ public interface SegmentAllocator { * {@code this.allocate(B)}, where {@code B} is the size, in bytes, of * the string encoded using the provided charset * (e.g. {@code str.getBytes(charset).length}); + * @since 27 */ @ForceInline default MemorySegment allocateFrom(String str, Charset charset, int srcIndex, int numChars) { From 578204f8c49f06be8b9c4855359ca61c9e107678 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Tue, 13 Jan 2026 08:12:35 +0000 Subject: [PATCH 009/328] 8374379: Type annotation in new array dimension expression causes java.lang.AssertionError Reviewed-by: vromero --- .../sun/tools/javac/code/TypeAnnotations.java | 3 ++- .../com/sun/tools/javac/comp/Annotate.java | 3 ++- .../classfile/TestNewCastArray.java | 22 +++++++++++++++++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java index 6aae8eb855d..86319f20c73 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, 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 @@ -1403,6 +1403,7 @@ public class TypeAnnotations { break; } } + scan(tree.dims); scan(tree.elems); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java index f5fdc1578b8..f865afe11fb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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 @@ -1107,6 +1107,7 @@ public class Annotate { for (List dimAnnos : tree.dimAnnotations) enterTypeAnnotations(dimAnnos, env, sym, false); scan(tree.elemtype); + scan(tree.dims); scan(tree.elems); } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestNewCastArray.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestNewCastArray.java index 803e0c8865b..a65c4503238 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestNewCastArray.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestNewCastArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, 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 @@ -44,7 +44,8 @@ public class TestNewCastArray { // 'b' tests fail with only even numbers of annotations (8005681). String[] testclasses = {"Test1", "Test2a", "Test3a", "Test4a", "Test5a", - "Test2b", "Test3b", "Test4b", "Test5b" + "Test2b", "Test3b", "Test4b", "Test5b", + "Test6a" }; public static void main(String[] args) throws Exception { @@ -182,6 +183,11 @@ public class TestNewCastArray { case "ci2": expected = 0; break; case "ci22": expected = 0; break; + case "Test6a": cexpected=4; break; + case "test6aPrimitiveArray": expected = 0; break; + case "test6aRefArray": expected = 0; break; + case "test6aMethod": cexpected = 4; break; + default: expected = 0; break; } if(codeattr) @@ -353,6 +359,18 @@ public class TestNewCastArray { Integer ci22 = (@A @A @B @B Integer)o; // FAIL expect 3, got 1 } + static class Test6a { + Test6a(){} + long l = 0; + // Cast expressions inside new array dimensions: + int[] test6aPrimitiveArray = new int[(@A @A @B @B int) l]; + Integer[] test6aRefArray = new Integer[(@A @A @B @B int) l]; + private void test6aMethod() { + int[] primitiveArray = new int[(@A @A @B @B int) l]; + Integer[] refArray = new Integer[(@A @A @B @B int) l]; + } + } + @Retention(RUNTIME) @Target({TYPE_USE}) @Repeatable( AC.class ) @interface A { } @Retention(RUNTIME) @Target({TYPE_USE}) @Repeatable( BC.class ) @interface B { } @Retention(RUNTIME) @Target({FIELD}) @Repeatable( FC.class ) @interface F { } From 543a972222118155e4c72c6f2d32d154c5dfd442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Tue, 13 Jan 2026 11:44:32 +0000 Subject: [PATCH 010/328] 8373485: JFR Crash during sampling: assert(jt->has_last_Java_frame()) failed: invariant Reviewed-by: shade, egahlin --- .../jfr/periodic/sampling/jfrThreadSampler.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp index 7e7747ba396..805426078c4 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -351,15 +351,22 @@ bool JfrSamplerThread::sample_native_thread(JavaThread* jt) { // outside the safepoint protocol. // OrderAccess::fence() as part of acquiring the lock prevents loads from floating up. - JfrMutexTryLock threads_lock(Threads_lock); + JfrMutexTryLock lock(Threads_lock); - if (!threads_lock.acquired() || !jt->has_last_Java_frame()) { + if (!lock.acquired()) { // Remove the native sample request and release the potentially waiting thread. JfrSampleMonitor jsm(tl); return false; } - if (jt->thread_state() != _thread_in_native) { + // Separate the arming of the poll (above) from the reading of JavaThread state (below). + if (UseSystemMemoryBarrier) { + SystemMemoryBarrier::emit(); + } else { + OrderAccess::fence(); + } + + if (jt->thread_state() != _thread_in_native || !jt->has_last_Java_frame()) { assert_lock_strong(Threads_lock); JfrSampleMonitor jsm(tl); if (jsm.is_waiting()) { From a90c7eee6f7e950edea4d94cf2b109fdb5e49909 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Tue, 13 Jan 2026 12:42:25 +0000 Subject: [PATCH 011/328] 8374969: Incorrect results of LoadStoreNode::adr_type and SCMemProj::adr_type Reviewed-by: roland, mhaessig --- src/hotspot/share/opto/memnode.cpp | 7 ++++++- src/hotspot/share/opto/memnode.hpp | 11 ++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 5b76f5b42cf..0d4fb6791a4 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -3913,7 +3913,6 @@ const Type* SCMemProjNode::Value(PhaseGVN* phase) const LoadStoreNode::LoadStoreNode( Node *c, Node *mem, Node *adr, Node *val, const TypePtr* at, const Type* rt, uint required ) : Node(required), _type(rt), - _adr_type(at), _barrier_data(0) { init_req(MemNode::Control, c ); @@ -3921,6 +3920,7 @@ LoadStoreNode::LoadStoreNode( Node *c, Node *mem, Node *adr, Node *val, const Ty init_req(MemNode::Address, adr); init_req(MemNode::ValueIn, val); init_class_id(Class_LoadStore); + DEBUG_ONLY(_adr_type = at; adr_type();) } //------------------------------Value----------------------------------------- @@ -3944,6 +3944,11 @@ const Type* LoadStoreNode::Value(PhaseGVN* phase) const { return bottom_type(); } +const TypePtr* LoadStoreNode::adr_type() const { + const TypePtr* cross_check = DEBUG_ONLY(_adr_type) NOT_DEBUG(nullptr); + return MemNode::calculate_adr_type(in(MemNode::Address)->bottom_type(), cross_check); +} + uint LoadStoreNode::ideal_reg() const { return _type->ideal_reg(); } diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index d554c037012..e84556528e6 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -797,11 +797,6 @@ public: virtual int Opcode() const; virtual bool is_CFG() const { return false; } virtual const Type *bottom_type() const {return Type::MEMORY;} - virtual const TypePtr *adr_type() const { - Node* ctrl = in(0); - if (ctrl == nullptr) return nullptr; // node is dead - return ctrl->in(MemNode::Memory)->adr_type(); - } virtual uint ideal_reg() const { return 0;} // memory projections don't have a register virtual const Type* Value(PhaseGVN* phase) const; #ifndef PRODUCT @@ -814,9 +809,11 @@ public: class LoadStoreNode : public Node { private: const Type* const _type; // What kind of value is loaded? - const TypePtr* _adr_type; // What kind of memory is being addressed? uint8_t _barrier_data; // Bit field with barrier information virtual uint size_of() const; // Size is bigger +#ifdef ASSERT + const TypePtr* _adr_type; // What kind of memory is being addressed? +#endif // ASSERT public: LoadStoreNode( Node *c, Node *mem, Node *adr, Node *val, const TypePtr* at, const Type* rt, uint required ); virtual bool depends_only_on_test() const { return false; } @@ -824,7 +821,7 @@ public: virtual const Type *bottom_type() const { return _type; } virtual uint ideal_reg() const; - virtual const class TypePtr *adr_type() const { return _adr_type; } // returns bottom_type of address + virtual const TypePtr* adr_type() const; virtual const Type* Value(PhaseGVN* phase) const; bool result_not_used() const; From f7be1dcf296d28f8e004d180038ab715153a6c15 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 13 Jan 2026 13:33:41 +0000 Subject: [PATCH 012/328] 8375054: Removed "signed" property from jpackage app image file Reviewed-by: almatvee --- .../jdk/jpackage/internal/AppImageSigner.java | 1 + .../jdk/jpackage/internal/MacFromOptions.java | 23 ++-- .../internal/MacPackagingPipeline.java | 61 ++++++++-- .../internal/model/MacApplication.java | 6 +- .../internal/cli/OptionSpecBuilder.java | 39 +++++-- .../cli/StandardAppImageFileOption.java | 11 +- .../jpackage/internal/cli/StandardOption.java | 6 + .../internal/cli/StandardValidator.java | 7 +- .../jdk/jpackage/internal/cli/Validator.java | 54 ++++++--- .../resources/MainResources.properties | 1 + .../jpackage/internal/util}/MacBundle.java | 43 ++----- .../jdk/jpackage/test/AppImageFile.java | 13 +-- .../jdk/jpackage/test/JPackageCommand.java | 13 +-- .../helpers/jdk/jpackage/test/MacHelper.java | 67 +++++++---- .../jdk/jpackage/test/MacSignVerify.java | 51 ++++++--- .../jpackage/internal/AppImageFileTest.java | 8 +- .../jdk/jpackage/internal/cli/TestUtils.java | 29 ++++- .../jpackage/internal/cli/ValidatorTest.java | 107 ++++++++++++++---- .../jpackage/share/AppImagePackageTest.java | 24 +++- test/jdk/tools/jpackage/share/ErrorTest.java | 7 +- 20 files changed, 380 insertions(+), 191 deletions(-) rename src/jdk.jpackage/{macosx/classes/jdk/jpackage/internal => share/classes/jdk/jpackage/internal/util}/MacBundle.java (63%) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java index 81e04ad7ed1..4c5edf43627 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java @@ -47,6 +47,7 @@ import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.RuntimeLayout; +import jdk.jpackage.internal.util.MacBundle; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.Result; import jdk.jpackage.internal.util.function.ExceptionBox; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java index b1094331740..cdf33d6dcba 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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,8 +30,8 @@ import static jdk.jpackage.internal.MacPackagingPipeline.APPLICATION_LAYOUT; import static jdk.jpackage.internal.MacRuntimeValidator.validateRuntimeHasJliLib; import static jdk.jpackage.internal.MacRuntimeValidator.validateRuntimeHasNoBinDir; import static jdk.jpackage.internal.cli.StandardBundlingOperation.SIGN_MAC_APP_IMAGE; -import static jdk.jpackage.internal.cli.StandardOption.ICON; import static jdk.jpackage.internal.cli.StandardOption.APPCLASS; +import static jdk.jpackage.internal.cli.StandardOption.ICON; import static jdk.jpackage.internal.cli.StandardOption.MAC_APP_CATEGORY; import static jdk.jpackage.internal.cli.StandardOption.MAC_APP_IMAGE_SIGN_IDENTITY; import static jdk.jpackage.internal.cli.StandardOption.MAC_APP_STORE; @@ -52,11 +52,13 @@ import static jdk.jpackage.internal.model.StandardPackageType.MAC_PKG; import static jdk.jpackage.internal.util.function.ExceptionBox.toUnchecked; import java.nio.file.Path; +import java.util.List; import java.util.Objects; import java.util.Optional; import jdk.jpackage.internal.ApplicationBuilder.MainLauncherStartupInfo; import jdk.jpackage.internal.SigningIdentityBuilder.ExpiredCertificateException; import jdk.jpackage.internal.SigningIdentityBuilder.StandardCertificateSelector; +import jdk.jpackage.internal.cli.OptionValue; import jdk.jpackage.internal.cli.Options; import jdk.jpackage.internal.cli.StandardFaOption; import jdk.jpackage.internal.model.ApplicationLaunchers; @@ -71,6 +73,7 @@ import jdk.jpackage.internal.model.MacPackage; import jdk.jpackage.internal.model.MacPkgPackage; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.RuntimeLayout; +import jdk.jpackage.internal.util.MacBundle; import jdk.jpackage.internal.util.Result; import jdk.jpackage.internal.util.function.ExceptionBox; @@ -276,16 +279,12 @@ final class MacFromOptions { final var builder = new MacPackageBuilder(createPackageBuilder(options, app.app(), type)); - app.externalApp() - .map(ExternalApplication::extra) - .flatMap(MAC_SIGN::findIn) - .ifPresent(builder::predefinedAppImageSigned); - - PREDEFINED_RUNTIME_IMAGE.findIn(options) - .map(MacBundle::new) - .filter(MacBundle::isValid) - .map(MacBundle::isSigned) - .ifPresent(builder::predefinedAppImageSigned); + for (OptionValue ov : List.of(PREDEFINED_APP_IMAGE, PREDEFINED_RUNTIME_IMAGE)) { + ov.findIn(options) + .flatMap(MacBundle::fromPath) + .map(MacPackagingPipeline::isSigned) + .ifPresent(builder::predefinedAppImageSigned); + } return builder; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index 53f297282ba..a53df7f83c2 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -76,6 +76,8 @@ import jdk.jpackage.internal.model.MacPackage; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.MacBundle; +import jdk.jpackage.internal.util.PListReader; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; @@ -178,13 +180,10 @@ final class MacPackagingPipeline { builder.task(MacCopyAppImageTaskID.COPY_RUNTIME_JLILIB) .appImageAction(MacPackagingPipeline::copyJliLib).add(); - final var predefinedRuntimeBundle = Optional.of( - new MacBundle(p.predefinedAppImage().orElseThrow())).filter(MacBundle::isValid); - // Don't create ".package" file. disabledTasks.add(MacCopyAppImageTaskID.COPY_PACKAGE_FILE); - if (predefinedRuntimeBundle.isPresent()) { + if (MacBundle.fromPath(p.predefinedAppImage().orElseThrow()).isPresent()) { // The input runtime image is a macOS bundle. // Disable all alterations of the input bundle, but keep the signing enabled. disabledTasks.addAll(List.of(MacCopyAppImageTaskID.values())); @@ -195,7 +194,7 @@ final class MacPackagingPipeline { .appImageAction(MacPackagingPipeline::writeRuntimeInfoPlist).add(); } - if (predefinedRuntimeBundle.map(MacBundle::isSigned).orElse(false) && !((MacPackage)p).app().sign()) { + if (((MacPackage)p).predefinedAppImageSigned().orElse(false) && !((MacPackage)p).app().sign()) { // The input runtime is a signed bundle; explicit signing is not requested for the package. // Disable the signing, i.e. don't re-sign the input bundle. disabledTasks.add(MacCopyAppImageTaskID.COPY_SIGN); @@ -279,6 +278,30 @@ final class MacPackagingPipeline { } } + static boolean isSigned(MacBundle bundle) { + + var result = toSupplier(Executor.of( + "/usr/sbin/spctl", + "-vv", + "--raw", + "--assess", + "--type", "exec", + bundle.root().toString()).setQuiet(true).saveOutput(true).binaryOutput()::execute).get(); + + switch (result.getExitCode()) { + case 0, 3 -> { + // These exit codes are accompanied with valid plist xml. + return toSupplier(() -> { + return new PListReader(result.byteStdout()).findValue("assessment:originator").isPresent(); + }).get(); + } + default -> { + // Likely to be an "a sealed resource is missing or invalid" error. + return false; + } + } + } + private static void copyAppImage(MacPackage pkg, AppImageLayout srcAppImage, AppImageLayout dstAppImage) throws IOException { @@ -286,7 +309,7 @@ final class MacPackagingPipeline { final Optional srcMacBundle; if (pkg.isRuntimeInstaller()) { - srcMacBundle = MacBundle.fromAppImageLayout(srcAppImage); + srcMacBundle = macBundleFromAppImageLayout(srcAppImage); } else { srcMacBundle = Optional.empty(); } @@ -297,7 +320,7 @@ final class MacPackagingPipeline { try { FileUtils.copyRecursive( inputBundle.root(), - MacBundle.fromAppImageLayout(dstAppImage).orElseThrow().root(), + macBundleFromAppImageLayout(dstAppImage).orElseThrow().root(), LinkOption.NOFOLLOW_LINKS); } catch (IOException ex) { throw new UncheckedIOException(ex); @@ -415,7 +438,7 @@ final class MacPackagingPipeline { final var app = env.app(); - final var infoPlistFile = MacBundle.fromAppImageLayout(env.resolvedLayout()).orElseThrow().infoPlistFile(); + final var infoPlistFile = macBundleFromAppImageLayout(env.resolvedLayout()).orElseThrow().infoPlistFile(); Log.verbose(I18N.format("message.preparing-info-plist", PathUtils.normalizedAbsolutePathString(infoPlistFile))); @@ -468,7 +491,7 @@ final class MacPackagingPipeline { } final Runnable signAction = () -> { - AppImageSigner.createSigner(app, codesignConfigBuilder.create()).accept(MacBundle.fromAppImageLayout(env.resolvedLayout()).orElseThrow()); + AppImageSigner.createSigner(app, codesignConfigBuilder.create()).accept(macBundleFromAppImageLayout(env.resolvedLayout()).orElseThrow()); }; app.signingConfig().flatMap(AppImageSigningConfig::keychain).map(Keychain::new).ifPresentOrElse(keychain -> { @@ -550,7 +573,7 @@ final class MacPackagingPipeline { private static MacBundle runtimeBundle(AppImageBuildEnv env) { if (env.app().isRuntime()) { - return MacBundle.fromAppImageLayout(env.resolvedLayout()).orElseThrow(); + return macBundleFromAppImageLayout(env.resolvedLayout()).orElseThrow(); } else { return new MacBundle(((MacApplicationLayout)env.resolvedLayout()).runtimeRootDirectory()); } @@ -595,6 +618,22 @@ final class MacPackagingPipeline { }; } + private static Optional macBundleFromAppImageLayout(AppImageLayout layout) { + final var root = layout.rootDirectory(); + final var bundleSubdir = root.relativize(layout.runtimeDirectory()); + final var contentsDirname = Path.of("Contents"); + var bundleRoot = root; + for (int i = 0; i != bundleSubdir.getNameCount(); i++) { + var nameComponent = bundleSubdir.getName(i); + if (contentsDirname.equals(nameComponent)) { + return Optional.of(new MacBundle(bundleRoot)); + } else { + bundleRoot = bundleRoot.resolve(nameComponent); + } + } + return Optional.empty(); + } + private record TaskContextProxy(TaskContext delegate, boolean forApp, boolean copyAppImage) implements TaskContext { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java index cfe10e8a012..e2b3d30b7ae 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toUnmodifiableMap; import static jdk.jpackage.internal.cli.StandardAppImageFileOption.MAC_APP_STORE; import static jdk.jpackage.internal.cli.StandardAppImageFileOption.MAC_MAIN_CLASS; -import static jdk.jpackage.internal.cli.StandardAppImageFileOption.MAC_SIGNED; import java.nio.file.Path; import java.util.Map; @@ -96,9 +95,6 @@ public interface MacApplication extends Application, MacApplicationMixin { } public enum ExtraAppImageFileField { - SIGNED(MAC_SIGNED, app -> { - return Optional.of(Boolean.toString(app.sign())); - }), APP_STORE(MAC_APP_STORE, app -> { return Optional.of(Boolean.toString(app.appStore())); }), diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java index e27d6472369..6cd1c05b57e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,6 +73,7 @@ final class OptionSpecBuilder { valuePattern = other.valuePattern; converterBuilder = other.converterBuilder.copy(); validatorBuilder = other.validatorBuilder.copy(); + validator = other.validator; if (other.arrayDefaultValue != null) { arrayDefaultValue = Arrays.copyOf(other.arrayDefaultValue, other.arrayDefaultValue.length); @@ -135,10 +136,20 @@ final class OptionSpecBuilder { scope, OptionSpecBuilder.this.mergePolicy().orElse(MergePolicy.CONCATENATE), defaultArrayOptionalValue(), - Optional.of(arryValuePattern()), + Optional.of(arrayValuePattern()), OptionSpecBuilder.this.description().orElse("")); } + Optional> createValidator() { + return Optional.ofNullable(validator).or(() -> { + if (validatorBuilder.hasValidatingMethod()) { + return Optional.of(validatorBuilder.create()); + } else { + return Optional.empty(); + } + }); + } + OptionSpecBuilder tokenizer(String splitRegexp) { Objects.requireNonNull(splitRegexp); return tokenizer(str -> { @@ -162,11 +173,13 @@ final class OptionSpecBuilder { OptionSpecBuilder validatorExceptionFormatString(String v) { validatorBuilder.formatString(v); + validator = null; return this; } OptionSpecBuilder validatorExceptionFormatString(UnaryOperator mutator) { validatorBuilder.formatString(mutator.apply(validatorBuilder.formatString().orElse(null))); + validator = null; return this; } @@ -182,6 +195,7 @@ final class OptionSpecBuilder { OptionSpecBuilder validatorExceptionFactory(OptionValueExceptionFactory v) { validatorBuilder.exceptionFactory(v); + validator = null; return this; } @@ -225,18 +239,27 @@ final class OptionSpecBuilder { OptionSpecBuilder validator(Predicate v) { validatorBuilder.predicate(v::test); + validator = null; return this; } @SuppressWarnings("overloads") OptionSpecBuilder validator(Consumer v) { validatorBuilder.consumer(v::accept); + validator = null; return this; } @SuppressWarnings("overloads") OptionSpecBuilder validator(UnaryOperator> mutator) { validatorBuilder = mutator.apply(validatorBuilder); + validator = null; + return this; + } + + OptionSpecBuilder validator(Validator v) { + validatorBuilder.predicate(null).consumer(null); + validator = Objects.requireNonNull(v); return this; } @@ -247,6 +270,7 @@ final class OptionSpecBuilder { OptionSpecBuilder withoutValidator() { validatorBuilder.predicate(null).consumer(null); + validator = null; return this; } @@ -423,14 +447,6 @@ final class OptionSpecBuilder { } } - private Optional> createValidator() { - if (validatorBuilder.hasValidatingMethod()) { - return Optional.of(validatorBuilder.create()); - } else { - return Optional.empty(); - } - } - private OptionValueConverter createArrayConverter() { final var newBuilder = converterBuilder.copy(); newBuilder.tokenizer(Optional.ofNullable(arrayTokenizer).orElse(str -> { @@ -440,7 +456,7 @@ final class OptionSpecBuilder { return newBuilder.createArray(); } - private String arryValuePattern() { + private String arrayValuePattern() { final var elementValuePattern = OptionSpecBuilder.this.valuePattern().orElseThrow(); if (arrayValuePatternSeparator == null) { return elementValuePattern; @@ -468,6 +484,7 @@ final class OptionSpecBuilder { private String valuePattern; private OptionValueConverter.Builder converterBuilder = OptionValueConverter.build(); private Validator.Builder validatorBuilder = Validator.build(); + private Validator validator; private T[] arrayDefaultValue; private String arrayValuePatternSeparator; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardAppImageFileOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardAppImageFileOption.java index 330a650e513..42f90536753 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardAppImageFileOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardAppImageFileOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -169,15 +169,6 @@ public final class StandardAppImageFileOption { .mutate(setPlatformScope(OperatingSystem.MACOS)) .toOptionValueBuilder().id(StandardOption.MAC_APP_STORE.id()).create(); - /** - * Is an application image is signed. macOS-only. - */ - public static final OptionValue MAC_SIGNED = booleanOption("signed") - .inScope(AppImageFileOptionScope.APP) - .mutate(setPlatformScope(OperatingSystem.MACOS)) - .toOptionValueBuilder().id(StandardOption.MAC_SIGN.id()).create(); - - public static final class InvalidOptionValueException extends RuntimeException { InvalidOptionValueException(String str, Throwable t) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java index 0fa0af296dc..dddaef8399b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java @@ -233,6 +233,12 @@ public final class StandardOption { .mutate(createOptionSpecBuilderMutator((b, context) -> { if (context.os() == OperatingSystem.MACOS) { b.description("help.option.app-image" + resourceKeySuffix(context.os())); + var directoryValidator = b.createValidator().orElseThrow(); + var macBundleValidator = b + .validatorExceptionFormatString("error.parameter-not-mac-bundle") + .validator(StandardValidator.IS_VALID_MAC_BUNDLE) + .createValidator().orElseThrow(); + b.validator(Validator.and(directoryValidator, macBundleValidator)); } })) .create(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValidator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValidator.java index 0038740f9df..cfa97439592 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValidator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -38,6 +38,7 @@ import java.util.function.Consumer; import java.util.function.Predicate; import jdk.jpackage.internal.cli.Validator.ValidatingConsumerException; import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.MacBundle; final public class StandardValidator { @@ -138,6 +139,10 @@ final public class StandardValidator { return true; }; + public static Predicate IS_VALID_MAC_BUNDLE = path -> { + return MacBundle.fromPath(path).isPresent(); + }; + public static final class DirectoryListingIOException extends RuntimeException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Validator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Validator.java index 0ddf0e1984f..91d9d03bd9f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Validator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Validator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,20 +24,55 @@ */ package jdk.jpackage.internal.cli; -import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Predicate; +import java.util.stream.Stream; @FunctionalInterface interface Validator { List validate(OptionName optionName, ParsedValue optionValue); - default Validator andThen(Validator after) { - return reduce(this, after); + default Validator and(Validator after) { + Objects.requireNonNull(after); + var before = this; + return (optionName, optionValue) -> { + return Stream.concat( + before.validate(optionName, optionValue).stream(), + after.validate(optionName, optionValue).stream() + ).toList(); + }; + } + + default Validator or(Validator after) { + Objects.requireNonNull(after); + var before = this; + return (optionName, optionValue) -> { + var bErrors = before.validate(optionName, optionValue); + if (bErrors.isEmpty()) { + return List.of(); + } + + var aErrors = after.validate(optionName, optionValue); + if (aErrors.isEmpty()) { + return List.of(); + } + + return Stream.concat(bErrors.stream(), aErrors.stream()).toList(); + }; + } + + @SuppressWarnings("unchecked") + static Validator and(Validator first, Validator second) { + return (Validator)first.and(second); + } + + @SuppressWarnings("unchecked") + static Validator or(Validator first, Validator second) { + return (Validator)first.or(second); } /** @@ -251,15 +286,4 @@ interface Validator { } } } - - @SafeVarargs - private static Validator reduce(Validator... validators) { - @SuppressWarnings("varargs") - var theValidators = List.of(validators); - return (optionName, optionValue) -> { - return theValidators.stream().map(validator -> { - return validator.validate(optionName, optionValue); - }).flatMap(Collection::stream).map(Exception.class::cast).toList(); - }; - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index e97bee79e6e..245d3b892da 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -75,6 +75,7 @@ error.parameter-not-directory=The value "{0}" provided for parameter {1} is not error.parameter-not-empty-directory=The value "{0}" provided for parameter {1} is not an empty directory or non existent path error.parameter-not-url=The value "{0}" provided for parameter {1} is not a valid URL error.parameter-not-launcher-shortcut-dir=The value "{0}" provided for parameter {1} is not a valid shortcut startup directory +error.parameter-not-mac-bundle=The value "{0}" provided for parameter {1} is not a valid macOS bundle error.path-parameter-ioexception=I/O error accessing path value "{0}" of parameter {1} error.parameter-add-launcher-malformed=The value "{0}" provided for parameter {1} does not match the pattern = error.parameter-add-launcher-not-file=The value of path to a property file "{0}" provided for additional launcher "{1}" is not a valid file path diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundle.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MacBundle.java similarity index 63% rename from src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundle.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MacBundle.java index 723614f9bd6..95629e7d4b5 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundle.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MacBundle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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,54 +23,49 @@ * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.util; import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; import java.util.Optional; -import jdk.jpackage.internal.model.AppImageLayout; /** * An abstraction of macOS Application bundle. * * @see https://en.wikipedia.org/wiki/Bundle_(macOS)#Application_bundles */ -record MacBundle(Path root) { +public record MacBundle(Path root) { - MacBundle { + public MacBundle { Objects.requireNonNull(root); } - boolean isValid() { + public boolean isValid() { return Files.isDirectory(contentsDir()) && Files.isDirectory(macOsDir()) && Files.isRegularFile(infoPlistFile()); } - boolean isSigned() { - return Files.isDirectory(contentsDir().resolve("_CodeSignature")); - } - - Path contentsDir() { + public Path contentsDir() { return root.resolve("Contents"); } - Path homeDir() { + public Path homeDir() { return contentsDir().resolve("Home"); } - Path macOsDir() { + public Path macOsDir() { return contentsDir().resolve("MacOS"); } - Path resourcesDir() { + public Path resourcesDir() { return contentsDir().resolve("Resources"); } - Path infoPlistFile() { + public Path infoPlistFile() { return contentsDir().resolve("Info.plist"); } - static Optional fromPath(Path path) { + public static Optional fromPath(Path path) { var bundle = new MacBundle(path); if (bundle.isValid()) { return Optional.of(bundle); @@ -78,20 +73,4 @@ record MacBundle(Path root) { return Optional.empty(); } } - - static Optional fromAppImageLayout(AppImageLayout layout) { - final var root = layout.rootDirectory(); - final var bundleSubdir = root.relativize(layout.runtimeDirectory()); - final var contentsDirname = Path.of("Contents"); - var bundleRoot = root; - for (int i = 0; i != bundleSubdir.getNameCount(); i++) { - var nameComponent = bundleSubdir.getName(i); - if (contentsDirname.equals(nameComponent)) { - return Optional.of(new MacBundle(bundleRoot)); - } else { - bundleRoot = bundleRoot.resolve(nameComponent); - } - } - return Optional.empty(); - } } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java index 1c6c0ce4447..55b13a06620 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java @@ -47,7 +47,7 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; public record AppImageFile(String mainLauncherName, Optional mainLauncherClassName, - String version, boolean macSigned, boolean macAppStore, Map> launchers) { + String version, boolean macAppStore, Map> launchers) { public static Path getPathInAppImage(Path appImageDir) { return ApplicationLayout.platformAppImage() @@ -66,7 +66,7 @@ public record AppImageFile(String mainLauncherName, Optional mainLaunche } public AppImageFile(String mainLauncherName, Optional mainLauncherClassName) { - this(mainLauncherName, mainLauncherClassName, "1.0", false, false, Map.of(mainLauncherName, Map.of())); + this(mainLauncherName, mainLauncherClassName, "1.0", false, Map.of(mainLauncherName, Map.of())); } public AppImageFile(String mainLauncherName, String mainLauncherClassName) { @@ -103,10 +103,6 @@ public record AppImageFile(String mainLauncherName, Optional mainLaunche xml.writeEndElement(); })); - xml.writeStartElement("signed"); - xml.writeCharacters(Boolean.toString(macSigned)); - xml.writeEndElement(); - xml.writeStartElement("app-store"); xml.writeCharacters(Boolean.toString(macAppStore)); xml.writeEndElement(); @@ -140,10 +136,6 @@ public record AppImageFile(String mainLauncherName, Optional mainLaunche var mainLauncherClassName = Optional.ofNullable(xPath.evaluate( "/jpackage-state/main-class/text()", doc)); - var macSigned = Optional.ofNullable(xPath.evaluate( - "/jpackage-state/signed/text()", doc)).map( - Boolean::parseBoolean).orElse(false); - var macAppStore = Optional.ofNullable(xPath.evaluate( "/jpackage-state/app-store/text()", doc)).map( Boolean::parseBoolean).orElse(false); @@ -171,7 +163,6 @@ public record AppImageFile(String mainLauncherName, Optional mainLaunche mainLauncherName, mainLauncherClassName, version, - macSigned, macAppStore, Collections.unmodifiableMap(launchers)); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index c5c4f87b097..9cfb75bcdb3 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -1385,7 +1385,7 @@ public class JPackageCommand extends CommandArguments { if (!isImagePackageType() && hasArgument("--app-image")) { // Build native macOS package from an external app image. // If the external app image is signed, ".jpackage.xml" file should be kept, otherwise removed. - return AppImageFile.load(Path.of(getArgumentValue("--app-image"))).macSigned(); + return MacHelper.isBundleSigned(Path.of(getArgumentValue("--app-image"))); } } @@ -1406,13 +1406,8 @@ public class JPackageCommand extends CommandArguments { final AppImageFile aif = AppImageFile.load(rootDir); if (TKit.isOSX()) { - boolean expectedValue = MacHelper.appImageSigned(this); - boolean actualValue = aif.macSigned(); - TKit.assertEquals(expectedValue, actualValue, - "Check for unexpected value of property in app image file"); - - expectedValue = hasArgument("--mac-app-store"); - actualValue = aif.macAppStore(); + var expectedValue = hasArgument("--mac-app-store"); + var actualValue = aif.macAppStore(); TKit.assertEquals(expectedValue, actualValue, "Check for unexpected value of property in app image file"); } @@ -1437,7 +1432,7 @@ public class JPackageCommand extends CommandArguments { } else { if (TKit.isOSX() && hasArgument("--app-image")) { String appImage = getArgumentValue("--app-image"); - if (AppImageFile.load(Path.of(appImage)).macSigned()) { + if (MacHelper.isBundleSigned(Path.of(appImage))) { assertFileNotInAppImage(lookupPath); } else { assertFileInAppImage(lookupPath); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index 6a5be77457a..1cb5532d46a 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -33,6 +33,7 @@ import static jdk.jpackage.internal.util.PListWriter.writeStringArray; import static jdk.jpackage.internal.util.PListWriter.writeStringOptional; import static jdk.jpackage.internal.util.XmlUtils.initDocumentBuilder; import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; import java.io.ByteArrayInputStream; @@ -45,6 +46,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -59,14 +61,13 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.UnaryOperator; -import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.stream.Stream; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.MacBundle; import jdk.jpackage.internal.util.PListReader; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.RetryExecutor; @@ -89,8 +90,8 @@ public final class MacHelper { // See JDK-8373105. "hdiutil" does not handle such cases very good. final var mountRoot = TKit.createTempDirectory("mountRoot"); - // Explode DMG assuming this can require interaction, thus use `yes`. - final var attachStdout = Executor.of("sh", "-c", String.join(" ", + // Explode the DMG assuming this can require interaction if the DMG has a license, thus use `yes`. + final var attachExec = Executor.of("sh", "-c", String.join(" ", "yes", "|", "/usr/bin/hdiutil", @@ -99,14 +100,34 @@ public final class MacHelper { "-mountroot", PathUtils.normalizedAbsolutePathString(mountRoot), "-nobrowse", "-plist" - )).saveOutput().storeOutputInFiles().executeAndRepeatUntilExitCode(0, 10, 6).stdout(); + )).saveOutput().storeOutputInFiles().binaryOutput(); + + final var attachResult = attachExec.executeAndRepeatUntilExitCode(0, 10, 6); final Path mountPoint; boolean mountPointInitialized = false; try { + byte[] stdout = attachResult.byteStdout(); + + // If the DMG has a license, it will be printed to the stdout before the plist content. + // All bytes before the XML declaration of the plist must be skipped. + // We need to find the location of the {'<', '?', 'x', 'm', 'l'} byte array + // (the XML declaration) in the captured binary stdout. + // Instead of crafting an ad-hoc function that operates on byte arrays, + // we will convert the byte array into a String instance using + // an 8-bit character set (ISO-8859-1) and use the standard String#indexOf(). + var startPlistIndex = new String(stdout, StandardCharsets.ISO_8859_1).indexOf(" 0) { + plistXml = Arrays.copyOfRange(stdout, startPlistIndex, stdout.length); + } else { + plistXml = stdout; + } + // One of "dict" items of "system-entities" array property should contain "mount-point" string property. - mountPoint = readPList(attachStdout).queryArrayValue("system-entities", false) + mountPoint = readPList(plistXml).queryArrayValue("system-entities", false) .map(PListReader.class::cast) .map(dict -> { return dict.findValue("mount-point"); @@ -117,7 +138,7 @@ public final class MacHelper { } finally { if (!mountPointInitialized) { TKit.trace("Unexpected plist file missing `system-entities` array:"); - attachStdout.forEach(TKit::trace); + attachResult.toCharacterResult(attachExec.charset(), false).stdout().forEach(TKit::trace); TKit.trace("Done"); } } @@ -168,19 +189,13 @@ public final class MacHelper { public static PListReader readPList(Path path) { TKit.assertReadableFileExists(path); - return ThrowingSupplier.toSupplier(() -> readPList(Files.readAllLines( - path))).get(); + return readPList(toFunction(Files::readAllBytes).apply(path)); } - public static PListReader readPList(List lines) { - return readPList(lines.stream()); - } - - public static PListReader readPList(Stream lines) { - return ThrowingSupplier.toSupplier(() -> new PListReader(lines - // Skip leading lines before xml declaration - .dropWhile(Pattern.compile("\\s?<\\?xml\\b.+\\?>").asPredicate().negate()) - .collect(Collectors.joining()).getBytes(StandardCharsets.UTF_8))).get(); + public static PListReader readPList(byte[] xml) { + return ThrowingSupplier.toSupplier(() -> { + return new PListReader(xml); + }).get(); } public static Map flatMapPList(PListReader plistReader) { @@ -265,13 +280,13 @@ public final class MacHelper { throw new UnsupportedOperationException(); } - var runtimeImage = Optional.ofNullable(cmd.getArgumentValue("--runtime-image")).map(Path::of); + var runtimeImageBundle = Optional.ofNullable(cmd.getArgumentValue("--runtime-image")).map(Path::of).flatMap(MacBundle::fromPath); var appImage = Optional.ofNullable(cmd.getArgumentValue("--app-image")).map(Path::of); - if (cmd.isRuntime() && Files.isDirectory(runtimeImage.orElseThrow().resolve("Contents/_CodeSignature"))) { + if (cmd.isRuntime() && runtimeImageBundle.map(MacHelper::isBundleSigned).orElse(false)) { // If the predefined runtime is a signed bundle, bundled image should be signed too. return true; - } else if (appImage.map(AppImageFile::load).map(AppImageFile::macSigned).orElse(false)) { + } else if (appImage.map(MacHelper::isBundleSigned).orElse(false)) { // The external app image is signed, so the app image is signed too. return true; } @@ -301,6 +316,14 @@ public final class MacHelper { }).run(); } + static boolean isBundleSigned(Path bundleRoot) { + return isBundleSigned(MacBundle.fromPath(bundleRoot).orElseThrow(IllegalArgumentException::new)); + } + + static boolean isBundleSigned(MacBundle bundle) { + return MacSignVerify.findSpctlSignOrigin(MacSignVerify.SpctlType.EXEC, bundle.root(), true).isPresent(); + } + private static void createFaPListFragmentFromFaProperties(JPackageCommand cmd, XMLStreamWriter xml) throws XMLStreamException, IOException { @@ -383,7 +406,7 @@ public final class MacHelper { var predefinedAppImage = Path.of(Optional.ofNullable(cmd.getArgumentValue("--app-image")).orElseThrow(IllegalArgumentException::new)); - var plistPath = ApplicationLayout.macAppImage().resolveAt(predefinedAppImage).contentDirectory().resolve("Info.plist"); + var plistPath = MacBundle.fromPath(predefinedAppImage).orElseThrow().infoPlistFile(); try (var plistStream = Files.newInputStream(plistPath)) { var plist = new PListReader(initDocumentBuilder().parse(plistStream)); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java index 0ecfd4c3432..9c469c9362e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java @@ -22,7 +22,6 @@ */ package jdk.jpackage.test; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; import static jdk.jpackage.test.MacSign.DigestAlgorithm.SHA256; import java.nio.file.Path; @@ -30,10 +29,8 @@ import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.HexFormat; import java.util.List; -import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; -import java.util.Set; import java.util.regex.Pattern; import jdk.jpackage.internal.util.PListReader; import jdk.jpackage.test.MacSign.CertificateHash; @@ -66,7 +63,7 @@ public final class MacSignVerify { }); // Set to "null" if the sign origin is not found, instead of bailing out with an exception. - // Let is fail in the following TKit.assertEquals() call with a proper log message. + // Let it fail in the following TKit.assertEquals() call with a proper log message. var signOrigin = findSpctlSignOrigin(SpctlType.EXEC, bundleRoot).orElse(null); TKit.assertEquals(certRequest.name(), signOrigin, @@ -92,10 +89,14 @@ public final class MacSignVerify { } public static Optional findEntitlements(Path path) { - final var exec = Executor.of("/usr/bin/codesign", "-d", "--entitlements", "-", "--xml", path.toString()).saveOutput().dumpOutput(); + final var exec = Executor.of( + "/usr/bin/codesign", + "-d", + "--entitlements", "-", + "--xml", path.toString()).saveOutput().dumpOutput().binaryOutput(); final var result = exec.execute(); - var xml = result.stdout(); - if (xml.isEmpty()) { + var xml = result.byteStdout(); + if (xml.length == 0) { return Optional.empty(); } else { return Optional.of(MacHelper.readPList(xml)); @@ -135,17 +136,33 @@ public final class MacSignVerify { public static final String ADHOC_SIGN_ORIGIN = "-"; public static Optional findSpctlSignOrigin(SpctlType type, Path path) { - final var exec = Executor.of("/usr/sbin/spctl", "-vv", "--raw", "--assess", "--type", type.value(), path.toString()).saveOutput().discardStderr(); - final var result = exec.executeWithoutExitCodeCheck(); - TKit.assertTrue(Set.of(0, 3).contains(result.getExitCode()), - String.format("Check exit code of command %s is either 0 or 3", exec.getPrintableCommandLine())); - return toSupplier(() -> { - try { - return Optional.of(new PListReader(String.join("", result.getOutput()).getBytes()).queryValue("assessment:originator")); - } catch (NoSuchElementException ex) { - return Optional.empty(); + return findSpctlSignOrigin(type, path, false); + } + + public static Optional findSpctlSignOrigin(SpctlType type, Path path, boolean acceptBrokenSignature) { + final var exec = Executor.of( + "/usr/sbin/spctl", + "-vv", + "--raw", + "--assess", + "--type", type.value(), + path.toString()).saveOutput().discardStderr().binaryOutput(); + Executor.Result result; + if (acceptBrokenSignature) { + result = exec.executeWithoutExitCodeCheck(); + switch (result.getExitCode()) { + case 0, 3 -> { + // NOP + } + default -> { + // No plist XML to process. + return Optional.empty(); + } } - }).get(); + } else { + result = exec.execute(0, 3); + } + return MacHelper.readPList(result.byteStdout()).findValue("assessment:originator"); } public static Optional findCodesignSignOrigin(Path path) { diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java index 375c6aa637a..53f4b9b95aa 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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 @@ -29,7 +29,6 @@ import static jdk.jpackage.internal.cli.StandardAppImageFileOption.LAUNCHER_AS_S import static jdk.jpackage.internal.cli.StandardAppImageFileOption.LAUNCHER_NAME; import static jdk.jpackage.internal.cli.StandardAppImageFileOption.LINUX_LAUNCHER_SHORTCUT; import static jdk.jpackage.internal.cli.StandardAppImageFileOption.MAC_APP_STORE; -import static jdk.jpackage.internal.cli.StandardAppImageFileOption.MAC_SIGNED; import static jdk.jpackage.internal.cli.StandardAppImageFileOption.WIN_LAUNCHER_DESKTOP_SHORTCUT; import static jdk.jpackage.internal.cli.StandardAppImageFileOption.WIN_LAUNCHER_MENU_SHORTCUT; import static jdk.jpackage.internal.cli.StandardOption.APPCLASS; @@ -514,7 +513,6 @@ public class AppImageFileTest { "Foo", "", "property-x", - "true", "False", "", " Quick brown fox", @@ -546,8 +544,7 @@ public class AppImageFileTest { .addExtra(WIN_LAUNCHER_MENU_SHORTCUT, new LauncherShortcut(LauncherShortcutStartupDirectory.APP_DIR)).commit()).create()); testCases.add(builder.os(OperatingSystem.MACOS).expect(appBuilder.get().commit() - .addExtra(MAC_APP_STORE, false) - .addExtra(MAC_SIGNED, true)).create()); + .addExtra(MAC_APP_STORE, false)).create()); return testCases; } @@ -580,7 +577,6 @@ public class AppImageFileTest { "OverwrittenMain", "Main", "property-x", - "true", "", " foo", " service-launcher description", diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/TestUtils.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/TestUtils.java index d3e9ecb09e9..2acf45b663d 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/TestUtils.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/TestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,8 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.UnaryOperator; import java.util.stream.StreamSupport; +import jdk.jpackage.internal.cli.Validator.ParsedValue; +import jdk.jpackage.internal.cli.Validator.ValidatorException; import jdk.jpackage.test.JUnitUtils; final class TestUtils { @@ -152,6 +154,31 @@ final class TestUtils { } + static final class RecordingValidator implements Validator { + + RecordingValidator(Validator validator) { + this.validator = Objects.requireNonNull(validator); + } + + @Override + public List validate(OptionName optionName, ParsedValue optionValue) { + counter++; + return validator.validate(optionName, optionValue); + } + + int counter() { + return counter; + } + + void resetCounter() { + counter = 0; + } + + private final Validator validator; + private int counter; + } + + private record RecordingExceptionFactory(OptionValueExceptionFactory factory, Consumer sink) implements OptionValueExceptionFactory { diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/ValidatorTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/ValidatorTest.java index d4c48df6a0c..d8d69027f77 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/ValidatorTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/ValidatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,10 +32,11 @@ import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.Stream; import jdk.jpackage.internal.cli.TestUtils.TestException; +import jdk.jpackage.internal.cli.TestUtils.RecordingValidator; import jdk.jpackage.internal.cli.Validator.ParsedValue; import jdk.jpackage.internal.cli.Validator.ValidatingConsumerException; import jdk.jpackage.internal.cli.Validator.ValidatorException; @@ -187,46 +188,97 @@ public class ValidatorTest { } @Test - public void test_andThen() { - - Function> createFailingValidator = exceptionMessage -> { - Objects.requireNonNull(exceptionMessage); - var exceptionFactory = OptionValueExceptionFactory.build().ctor(TestException::new).messageFormatter((_, _) -> { - return exceptionMessage; - }).create(); - - return Validator.build() - .predicate(_ -> false) - .formatString("") - .exceptionFactory(exceptionFactory).create(); - }; + public void test_and() { Function, List> validate = validator -> { return validator.validate(OptionName.of("a"), ParsedValue.create("str", StringToken.of("str"))); }; - var pass = Validator.build().predicate(_ -> true).create(); + var pass = new RecordingValidator<>(Validator.build().predicate(_ -> true).create()); - var foo = createFailingValidator.apply("foo"); - var bar = createFailingValidator.apply("bar"); - var buz = createFailingValidator.apply("buz"); + var foo = failingValidator("foo"); + var bar = failingValidator("bar"); + var buz = failingValidator("buz"); assertExceptionListEquals(List.of( new TestException("foo"), new TestException("bar"), new TestException("buz") - ), validate.apply(foo.andThen(bar).andThen(pass).andThen(buz))); + ), validate.apply(foo.and(bar).and(pass).and(buz))); + assertEquals(1, pass.counter()); + pass.resetCounter(); assertExceptionListEquals(List.of( new TestException("bar"), new TestException("buz"), new TestException("foo") - ), validate.apply(pass.andThen(bar).andThen(buz).andThen(foo))); + ), validate.apply(pass.and(bar).and(buz).and(foo))); + assertEquals(1, pass.counter()); assertExceptionListEquals(List.of( new TestException("foo"), new TestException("foo") - ), validate.apply(foo.andThen(foo))); + ), validate.apply(foo.and(foo))); + + pass.resetCounter(); + assertExceptionListEquals(List.of( + ), validate.apply(pass.and(pass))); + assertEquals(2, pass.counter()); + } + + @Test + public void test_or() { + + Function, List> validate = validator -> { + return validator.validate(OptionName.of("a"), ParsedValue.create("str", StringToken.of("str"))); + }; + + var pass = new RecordingValidator<>(Validator.build().predicate(_ -> true).create()); + + var foo = new RecordingValidator<>(failingValidator("foo")); + var bar = new RecordingValidator<>(failingValidator("bar")); + var buz = new RecordingValidator<>(failingValidator("buz")); + + Runnable resetCounters = () -> { + Stream.of(pass, foo, bar, buz).forEach(RecordingValidator::resetCounter); + }; + + assertExceptionListEquals(List.of( + new TestException("foo"), + new TestException("bar"), + new TestException("buz") + ), validate.apply(foo.or(bar).or(buz))); + assertEquals(1, foo.counter()); + assertEquals(1, bar.counter()); + assertEquals(1, buz.counter()); + + resetCounters.run(); + assertExceptionListEquals(List.of( + ), validate.apply(foo.or(bar).or(pass).or(buz))); + assertEquals(1, foo.counter()); + assertEquals(1, bar.counter()); + assertEquals(1, pass.counter()); + assertEquals(0, buz.counter()); + + resetCounters.run(); + assertExceptionListEquals(List.of( + ), validate.apply(pass.or(bar).or(buz).or(foo))); + assertEquals(1, pass.counter()); + assertEquals(0, bar.counter()); + assertEquals(0, buz.counter()); + assertEquals(0, foo.counter()); + + resetCounters.run(); + assertExceptionListEquals(List.of( + new TestException("foo"), + new TestException("foo") + ), validate.apply(foo.or(foo))); + assertEquals(2, foo.counter()); + + resetCounters.run(); + assertExceptionListEquals(List.of( + ), validate.apply(pass.or(pass))); + assertEquals(1, pass.counter()); } @ParameterizedTest @@ -269,6 +321,17 @@ public class ValidatorTest { return data; } + private static Validator failingValidator(String exceptionMessage) { + var exceptionFactory = OptionValueExceptionFactory.build().ctor(TestException::new).messageFormatter((_, _) -> { + return exceptionMessage; + }).create(); + + return Validator.build() + .predicate(_ -> false) + .formatString("") + .exceptionFactory(exceptionFactory).create(); + } + static final class FooException extends Exception { diff --git a/test/jdk/tools/jpackage/share/AppImagePackageTest.java b/test/jdk/tools/jpackage/share/AppImagePackageTest.java index bfd731b67d5..ce2300c92d1 100644 --- a/test/jdk/tools/jpackage/share/AppImagePackageTest.java +++ b/test/jdk/tools/jpackage/share/AppImagePackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.function.Predicate; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.util.MacBundle; import jdk.jpackage.internal.util.XmlUtils; import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.Test; @@ -133,8 +134,7 @@ public class AppImagePackageTest { */ @Test public static void testBadAppImage() throws IOException { - Path appImageDir = TKit.createTempDirectory("appimage"); - Files.createFile(appImageDir.resolve("foo")); + Path appImageDir = createInvalidAppImage(); configureBadAppImage(appImageDir).addInitializer(cmd -> { cmd.removeArgumentWithValue("--name"); }).run(Action.CREATE); @@ -145,8 +145,7 @@ public class AppImagePackageTest { */ @Test public static void testBadAppImage2() throws IOException { - Path appImageDir = TKit.createTempDirectory("appimage"); - Files.createFile(appImageDir.resolve("foo")); + Path appImageDir = createInvalidAppImage(); configureBadAppImage(appImageDir).run(Action.CREATE); } @@ -227,4 +226,19 @@ public class AppImagePackageTest { + TKit.ICON_SUFFIX)); } + private static Path createInvalidAppImage() throws IOException { + Path appImageDir = TKit.createTempDirectory("appimage"); + if (TKit.isOSX()) { + // Create minimal macOS bundle to prevent jpackage bail out early + // with "error.parameter-not-mac-bundle" error. + var bundle = new MacBundle(appImageDir); + Files.createDirectories(bundle.macOsDir()); + Files.createFile(bundle.infoPlistFile()); + } else { + Files.createFile(appImageDir.resolve("foo")); + } + + return appImageDir; + } + } diff --git a/test/jdk/tools/jpackage/share/ErrorTest.java b/test/jdk/tools/jpackage/share/ErrorTest.java index ca1189a191e..f31ac42dea0 100644 --- a/test/jdk/tools/jpackage/share/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/ErrorTest.java @@ -643,7 +643,12 @@ public final class ErrorTest { .error("message.invalid-identifier", "#1"), // Bundle for mac app store should not have runtime commands testSpec().nativeType().addArgs("--mac-app-store", "--jlink-options", "--bind-services") - .error("ERR_MissingJLinkOptMacAppStore", "--strip-native-commands") + .error("ERR_MissingJLinkOptMacAppStore", "--strip-native-commands"), + // Predefined app image must be a valid macOS bundle. + testSpec().noAppDesc().nativeType().addArgs("--app-image", Token.EMPTY_DIR.token()) + .error("error.parameter-not-mac-bundle", JPackageCommand.cannedArgument(cmd -> { + return Path.of(cmd.getArgumentValue("--app-image")); + }, Token.EMPTY_DIR.token()), "--app-image") ).map(TestSpec.Builder::create).toList()); macInvalidRuntime(testCases::add); From 47029ccfec988e0a9298e35dcc729d9eeffc45e1 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 13 Jan 2026 13:36:44 +0000 Subject: [PATCH 013/328] 8375050: Simplify process management in jpackage tests Reviewed-by: almatvee --- .../helpers/jdk/jpackage/test/Executor.java | 33 ++----- .../helpers/jdk/jpackage/test/HelloApp.java | 30 ++++--- .../jdk/jpackage/test/WindowsHelper.java | 87 ------------------- .../macosx/ArgumentsFilteringTest.java | 12 ++- .../tools/jpackage/share/MainClassTest.java | 7 +- .../jpackage/windows/Win8301247Test.java | 47 +++++++--- .../jpackage/windows/WinChildProcessTest.java | 20 ++--- .../jpackage/windows/WinNoRestartTest.java | 45 ++++++++-- 8 files changed, 111 insertions(+), 170 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java index 5d3033e2e8c..6e94133a543 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -35,6 +35,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import java.util.function.Supplier; import java.util.spi.ToolProvider; import java.util.stream.IntStream; @@ -109,15 +110,6 @@ public final class Executor extends CommandArguments { return this; } - public Executor setWinRunWithEnglishOutput(boolean value) { - if (!TKit.isWindows()) { - throw new UnsupportedOperationException( - "setWinRunWithEnglishOutput is only valid on Windows platform"); - } - winEnglishOutput = value; - return this; - } - public Executor setWindowsTmpDir(String tmp) { if (!TKit.isWindows()) { throw new UnsupportedOperationException( @@ -195,6 +187,11 @@ public final class Executor extends CommandArguments { return storeOutputInFiles(true); } + public Executor processListener(Consumer v) { + commandOutputControl.processListener(v); + return this; + } + public record Result(CommandOutputControl.Result base) { public Result { Objects.requireNonNull(base); @@ -310,11 +307,6 @@ public final class Executor extends CommandArguments { "Can't change directory when using tool provider"); } - if (toolProvider != null && winEnglishOutput) { - throw new IllegalArgumentException( - "Can't change locale when using tool provider"); - } - return ThrowingSupplier.toSupplier(() -> { if (toolProvider != null) { return runToolProvider(); @@ -434,17 +426,8 @@ public final class Executor extends CommandArguments { return executable.toAbsolutePath(); } - private List prefixCommandLineArgs() { - if (winEnglishOutput) { - return List.of("cmd.exe", "/c", "chcp", "437", ">nul", "2>&1", "&&"); - } else { - return List.of(); - } - } - private Result runExecutable() throws IOException, InterruptedException { List command = new ArrayList<>(); - command.addAll(prefixCommandLineArgs()); command.add(executablePath().toString()); command.addAll(args); ProcessBuilder builder = new ProcessBuilder(command); @@ -522,8 +505,7 @@ public final class Executor extends CommandArguments { exec = executablePath().toString(); } - var cmdline = Stream.of(prefixCommandLineArgs(), List.of(exec), args).flatMap( - List::stream).toList(); + var cmdline = Stream.of(List.of(exec), args).flatMap(List::stream).toList(); return String.format(format, CommandLineFormat.DEFAULT.apply(cmdline), cmdline.size()); } @@ -559,6 +541,5 @@ public final class Executor extends CommandArguments { private Path directory; private Set removeEnvVars = new HashSet<>(); private Map setEnvVars = new HashMap<>(); - private boolean winEnglishOutput; private String winTmpDir = null; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java index 6c7b6a25255..bc731e18136 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.regex.Matcher; @@ -315,37 +316,33 @@ public final class HelloApp { public static void executeLauncherAndVerifyOutput(JPackageCommand cmd, String... args) { - AppOutputVerifier av = assertMainLauncher(cmd, args); - if (av != null) { + assertMainLauncher(cmd, args).ifPresent(av -> { av.executeAndVerifyOutput(args); - } + }); } public static Executor.Result executeLauncher(JPackageCommand cmd, String... args) { - AppOutputVerifier av = assertMainLauncher(cmd, args); - if (av != null) { + return assertMainLauncher(cmd, args).map(av -> { return av.saveOutput(true).execute(args); - } else { - return null; - } + }).orElseThrow(); } - public static AppOutputVerifier assertMainLauncher(JPackageCommand cmd, + public static Optional assertMainLauncher(JPackageCommand cmd, String... args) { final Path launcherPath = cmd.appLauncherPath(); if (!cmd.canRunLauncher(String.format("Not running [%s] launcher", launcherPath))) { - return null; + return Optional.empty(); } - return assertApp(launcherPath) + return Optional.of(assertApp(launcherPath) .addDefaultArguments(Optional .ofNullable(cmd.getAllArgumentValues("--arguments")) .orElseGet(() -> new String[0])) .addJavaOptions(Optional .ofNullable(cmd.getAllArgumentValues("--java-options")) - .orElseGet(() -> new String[0])); + .orElseGet(() -> new String[0]))); } @@ -426,6 +423,11 @@ public final class HelloApp { .collect(Collectors.toList())); } + public AppOutputVerifier processListener(Consumer v) { + processListener = v; + return this; + } + public void verifyOutput(String... args) { final List launcherArgs = List.of(args); final List appArgs; @@ -479,6 +481,7 @@ public final class HelloApp { .saveOutput(saveOutput) .dumpOutput() .setExecutable(executablePath) + .processListener(processListener) .addArguments(List.of(args)); env.forEach((envVarName, envVarValue) -> { @@ -493,6 +496,7 @@ public final class HelloApp { private final Path launcherPath; private Path outputFilePath; private int expectedExitCode; + private Consumer processListener; private final List defaultLauncherArgs; private final Map params; private final Map env; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java index f9fbf285b49..c7b55ed1de7 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java @@ -42,8 +42,6 @@ import java.util.Optional; import java.util.Properties; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Stream; import jdk.jpackage.internal.util.function.ThrowingRunnable; import jdk.jpackage.test.PackageTest.PackageHandlers; @@ -306,91 +304,6 @@ public class WindowsHelper { "Failed to get file description of [%s]", pathToExeFile)); } - public static void killProcess(long pid) { - Executor.of("taskkill", "/F", "/PID", Long.toString(pid)).dumpOutput(true).execute(); - } - - public static void killAppLauncherProcess(JPackageCommand cmd, - String launcherName, int expectedCount) { - var pids = findAppLauncherPIDs(cmd, launcherName); - try { - TKit.assertEquals(expectedCount, pids.length, String.format( - "Check [%d] %s app launcher processes found running", - expectedCount, Optional.ofNullable(launcherName).map( - str -> "[" + str + "]").orElse("
"))); - } finally { - if (pids.length != 0) { - killProcess(pids[0]); - } - } - } - - private static long[] findAppLauncherPIDs(JPackageCommand cmd, String launcherName) { - // Get the list of PIDs and PPIDs of app launcher processes. Run setWinRunWithEnglishOutput(true) for JDK-8344275. - // powershell -NoLogo -NoProfile -NonInteractive -Command - // "Get-CimInstance Win32_Process -Filter \"Name = 'foo.exe'\" | select ProcessID,ParentProcessID" - String command = "Get-CimInstance Win32_Process -Filter \\\"Name = '" - + cmd.appLauncherPath(launcherName).getFileName().toString() - + "'\\\" | select ProcessID,ParentProcessID"; - List output = Executor.of("powershell", "-NoLogo", "-NoProfile", "-NonInteractive", "-Command", command) - .dumpOutput(true).saveOutput().setWinRunWithEnglishOutput(true).executeAndGetOutput(); - - if (output.size() < 1) { - return new long[0]; - } - - String[] headers = Stream.of(output.get(1).split("\\s+", 2)).map( - String::trim).map(String::toLowerCase).toArray(String[]::new); - Pattern pattern; - if (headers[0].equals("parentprocessid") && headers[1].equals( - "processid")) { - pattern = Pattern.compile("^\\s+(?\\d+)\\s+(?\\d+)$"); - } else if (headers[1].equals("parentprocessid") && headers[0].equals( - "processid")) { - pattern = Pattern.compile("^\\s+(?\\d+)\\s+(?\\d+)$"); - } else { - throw new RuntimeException( - "Unrecognizable output of \'Get-CimInstance Win32_Process\' command"); - } - - List processes = output.stream().skip(3).map(line -> { - Matcher m = pattern.matcher(line); - long[] pids = null; - if (m.matches()) { - pids = new long[]{Long.parseLong(m.group("pid")), Long. - parseLong(m.group("ppid"))}; - } - return pids; - }).filter(Objects::nonNull).toList(); - - switch (processes.size()) { - case 2 -> { - final long parentPID; - final long childPID; - if (processes.get(0)[0] == processes.get(1)[1]) { - parentPID = processes.get(0)[0]; - childPID = processes.get(1)[0]; - } else if (processes.get(1)[0] == processes.get(0)[1]) { - parentPID = processes.get(1)[0]; - childPID = processes.get(0)[0]; - } else { - TKit.assertUnexpected("App launcher processes unrelated"); - return null; // Unreachable - } - return new long[]{parentPID, childPID}; - } - case 1 -> { - return new long[]{processes.get(0)[0]}; - } - default -> { - TKit.assertUnexpected(String.format( - "Unexpected number of running processes [%d]", - processes.size())); - return null; // Unreachable - } - } - } - static boolean isUserLocalInstall(JPackageCommand cmd) { return cmd.hasArgument("--win-per-user-install"); } diff --git a/test/jdk/tools/jpackage/macosx/ArgumentsFilteringTest.java b/test/jdk/tools/jpackage/macosx/ArgumentsFilteringTest.java index 1a42a30c00e..e4adf3b9616 100644 --- a/test/jdk/tools/jpackage/macosx/ArgumentsFilteringTest.java +++ b/test/jdk/tools/jpackage/macosx/ArgumentsFilteringTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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 @@ -49,11 +49,10 @@ public class ArgumentsFilteringTest { public void test1() { JPackageCommand cmd = JPackageCommand.helloAppImage(); cmd.executeAndAssertHelloAppImageCreated(); - var appVerifier = HelloApp.assertMainLauncher(cmd); - if (appVerifier != null) { + HelloApp.assertMainLauncher(cmd).ifPresent(appVerifier -> { appVerifier.execute("-psn_1_1"); appVerifier.verifyOutput(); - } + }); } @Test @@ -61,10 +60,9 @@ public class ArgumentsFilteringTest { JPackageCommand cmd = JPackageCommand.helloAppImage() .addArguments("--arguments", "-psn_2_2"); cmd.executeAndAssertHelloAppImageCreated(); - var appVerifier = HelloApp.assertMainLauncher(cmd); - if (appVerifier != null) { + HelloApp.assertMainLauncher(cmd).ifPresent(appVerifier -> { appVerifier.execute("-psn_1_1"); appVerifier.verifyOutput("-psn_2_2"); - } + }); } } diff --git a/test/jdk/tools/jpackage/share/MainClassTest.java b/test/jdk/tools/jpackage/share/MainClassTest.java index bc813c4ec15..72e77bbbff5 100644 --- a/test/jdk/tools/jpackage/share/MainClassTest.java +++ b/test/jdk/tools/jpackage/share/MainClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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 @@ -240,8 +240,7 @@ public final class MainClassTest { cmd.executeAndAssertHelloAppImageCreated(); } else { cmd.executeAndAssertImageCreated(); - var appVerifier = HelloApp.assertMainLauncher(cmd); - if (appVerifier != null) { + HelloApp.assertMainLauncher(cmd).ifPresent(appVerifier -> { List output = appVerifier .saveOutput(true) .expectedExitCode(1) @@ -249,7 +248,7 @@ public final class MainClassTest { TKit.assertTextStream(String.format( "Error: Could not find or load main class %s", nonExistingMainClass)).apply(output); - } + }); } CfgFile cfg = cmd.readLauncherCfgFile(); diff --git a/test/jdk/tools/jpackage/windows/Win8301247Test.java b/test/jdk/tools/jpackage/windows/Win8301247Test.java index 2f98141dcb4..3cdd9810d0f 100644 --- a/test/jdk/tools/jpackage/windows/Win8301247Test.java +++ b/test/jdk/tools/jpackage/windows/Win8301247Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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,12 +21,14 @@ * questions. */ -import static jdk.jpackage.test.WindowsHelper.killAppLauncherProcess; - import java.time.Duration; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.HelloApp; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.TKit; /** * Test that terminating of the parent app launcher process automatically @@ -46,7 +48,7 @@ import jdk.jpackage.test.JPackageCommand; public class Win8301247Test { @Test - public void test() throws InterruptedException { + public void test() throws InterruptedException, ExecutionException { var cmd = JPackageCommand.helloAppImage().ignoreFakeRuntime(); // Launch the app in a way it doesn't exit to let us trap app laucnher @@ -54,20 +56,41 @@ public class Win8301247Test { cmd.addArguments("--java-options", "-Djpackage.test.noexit=true"); cmd.executeAndAssertImageCreated(); + var f = new CompletableFuture(); + // Launch the app in a separate thread new Thread(() -> { - HelloApp.executeLauncher(cmd); + HelloApp.assertMainLauncher(cmd).get().processListener(f::complete).execute(); }).start(); - // Wait a bit to let the app start - Thread.sleep(Duration.ofSeconds(10)); + var mainLauncherProcess = f.get(); - // Find the main app launcher process and kill it - killAppLauncherProcess(cmd, null, 2); + Optional childProcess = Optional.empty(); - // Wait a bit and check if child app launcher process is still running (it must NOT) - Thread.sleep(Duration.ofSeconds(5)); + try { + // Wait a bit to let the app start + Thread.sleep(Duration.ofSeconds(10)); - killAppLauncherProcess(cmd, null, 0); + try (var children = mainLauncherProcess.children()) { + childProcess = children.filter(p -> { + return mainLauncherProcess.info().command().equals(p.info().command()); + }).findFirst(); + } + + TKit.assertTrue(childProcess.isPresent(), + String.format("Check the main launcher process with PID=%d restarted", mainLauncherProcess.pid())); + } finally { + // Kill the main app launcher process + TKit.trace("About to kill the main launcher process..."); + mainLauncherProcess.destroyForcibly(); + + // Wait a bit and check if child app launcher process is still running (it must NOT) + Thread.sleep(Duration.ofSeconds(5)); + + childProcess.ifPresent(p -> { + TKit.assertTrue(!p.isAlive(), String.format( + "Check restarted main launcher process with PID=%d is not alive", p.pid())); + }); + } } } diff --git a/test/jdk/tools/jpackage/windows/WinChildProcessTest.java b/test/jdk/tools/jpackage/windows/WinChildProcessTest.java index a83ef837331..e5de19d182a 100644 --- a/test/jdk/tools/jpackage/windows/WinChildProcessTest.java +++ b/test/jdk/tools/jpackage/windows/WinChildProcessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, 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 @@ -44,7 +44,6 @@ import static jdk.jpackage.test.HelloApp.configureAndExecute; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Executor; import jdk.jpackage.test.TKit; -import static jdk.jpackage.test.WindowsHelper.killProcess; public class WinChildProcessTest { private static final Path TEST_APP_JAVA = TKit.TEST_SRC_ROOT @@ -52,7 +51,7 @@ public class WinChildProcessTest { @Test public static void test() { - long childPid = 0; + Optional child = Optional.empty(); try { JPackageCommand cmd = JPackageCommand .helloAppImage(TEST_APP_JAVA + "*Hello") @@ -69,21 +68,18 @@ public class WinChildProcessTest { String pidStr = output.get(0); // parse child PID - childPid = Long.parseLong(pidStr.split("=", 2)[1]); + var childPid = Long.parseLong(pidStr.split("=", 2)[1]); // Check whether the termination of third party application launcher // also terminating the launched third party application // If third party application is not terminated the test is // successful else failure - Optional processHandle = ProcessHandle.of(childPid); - boolean isAlive = processHandle.isPresent() - && processHandle.get().isAlive(); - TKit.assertTrue(isAlive, "Check child process is alive"); + child = ProcessHandle.of(childPid); + boolean isAlive = child.map(ProcessHandle::isAlive).orElse(false); + TKit.assertTrue(isAlive, String.format("Check child process with PID=%d is alive", childPid)); } finally { - if (childPid != 0) { - // Kill only a specific child instance - killProcess(childPid); - } + TKit.trace("About to kill the child process..."); + child.ifPresent(ProcessHandle::destroyForcibly); } } } diff --git a/test/jdk/tools/jpackage/windows/WinNoRestartTest.java b/test/jdk/tools/jpackage/windows/WinNoRestartTest.java index 909ee06b01a..984ddfcdf06 100644 --- a/test/jdk/tools/jpackage/windows/WinNoRestartTest.java +++ b/test/jdk/tools/jpackage/windows/WinNoRestartTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, 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,15 +21,18 @@ * questions. */ -import static jdk.jpackage.test.WindowsHelper.killAppLauncherProcess; import java.io.IOException; import java.time.Duration; import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.CfgFile; import jdk.jpackage.test.HelloApp; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.TKit; /* @test * @bug 8340311 @@ -47,7 +50,7 @@ import jdk.jpackage.test.JPackageCommand; public class WinNoRestartTest { @Test - public static void test() throws InterruptedException, IOException { + public static void test() throws InterruptedException, IOException, ExecutionException { var cmd = JPackageCommand.helloAppImage().ignoreFakeRuntime(); // Configure test app to launch in a way it will not exit @@ -77,7 +80,7 @@ public class WinNoRestartTest { private static record NoRerunConfig(NoRerunSectionConfig firstSection, NoRerunSectionConfig secondSection, boolean expectedNoRestarted) { - void apply(JPackageCommand cmd, CfgFile origCfgFile) throws InterruptedException { + void apply(JPackageCommand cmd, CfgFile origCfgFile) throws InterruptedException, ExecutionException { // Alter the main launcher .cfg file var cfgFile = new CfgFile(); if (firstSection != null) { @@ -92,16 +95,40 @@ public class WinNoRestartTest { // Save updated main launcher .cfg file cfgFile.save(cmd.appLauncherCfgPath(null)); + var f = new CompletableFuture(); + // Launch the app in a separate thread new Thread(() -> { - HelloApp.executeLauncher(cmd); + HelloApp.assertMainLauncher(cmd).get().processListener(f::complete).execute(); }).start(); - // Wait a bit to let the app start - Thread.sleep(Duration.ofSeconds(10)); + var mainLauncherProcess = f.get(); - // Find the main app launcher process and kill it - killAppLauncherProcess(cmd, null, expectedNoRestarted ? 1 : 2); + try { + // Wait a bit to let the app start + Thread.sleep(Duration.ofSeconds(10)); + + try (var children = mainLauncherProcess.children()) { + Optional childPid = children.filter(p -> { + return mainLauncherProcess.info().command().equals(p.info().command()); + }).map(ProcessHandle::pid).map(Object::toString).findFirst(); + + Optional expectedChildPid; + if (expectedNoRestarted) { + expectedChildPid = Optional.empty(); + } else { + expectedChildPid = childPid.or(() -> { + return Optional.of(""); + }); + } + TKit.assertEquals(expectedChildPid, childPid, String.format( + "Check the main launcher process with PID=%d restarted", + mainLauncherProcess.pid())); + } + } finally { + TKit.trace("About to kill the main launcher process..."); + mainLauncherProcess.destroyForcibly(); + } } } From 7330e1a996fd43d92430a73b818f33552bc6ae9c Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 13 Jan 2026 13:51:00 +0000 Subject: [PATCH 014/328] 8374990: Check include and jmods folder of JDK image for unwanted files Reviewed-by: erikj --- test/jdk/build/CheckFiles.java | 37 ++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/test/jdk/build/CheckFiles.java b/test/jdk/build/CheckFiles.java index 412e66ebf01..eb903c0a224 100644 --- a/test/jdk/build/CheckFiles.java +++ b/test/jdk/build/CheckFiles.java @@ -60,6 +60,8 @@ public class CheckFiles { System.out.println("Main directory to scan:" + mainDirToScan); Path binDir = mainDirToScan.resolve("bin"); Path libDir = mainDirToScan.resolve("lib"); + Path includeDir = mainDirToScan.resolve("include"); + Path jmodsDir = mainDirToScan.resolve("jmods"); System.out.println("Bin directory to scan:" + binDir); ArrayList allowedEndingsBinDir = new ArrayList<>(); @@ -108,13 +110,44 @@ public class CheckFiles { } boolean libDirRes = scanFiles(libDir, allowedEndingsLibDir); - if (!binDirRes) { + if (binDirRes) { + System.out.println("Bin directory scan successful."); + } else { throw new Error("bin dir scan failed"); } - if (!libDirRes) { + if (libDirRes) { + System.out.println("Lib directory scan successful."); + } else { throw new Error("lib dir scan failed"); } + + if (Files.isDirectory(includeDir)) { + System.out.println("Include directory to scan:" + includeDir); + ArrayList allowedEndingsIncludeDir = new ArrayList<>(); + allowedEndingsIncludeDir.add(".h"); + allowedEndingsIncludeDir.add(".hpp"); + boolean includeDirRes = scanFiles(includeDir, allowedEndingsIncludeDir); + if (includeDirRes) { + System.out.println("Include directory scan successful."); + } else { + throw new Error("include dir scan failed"); + } + } + + // when enabling "JEP 493: Linking Run-Time Images without JMODs" we do not + // have the jmods folder at all, so first test the presence of the folder + if (Files.isDirectory(jmodsDir)) { + System.out.println("Jmods directory to scan:" + jmodsDir); + ArrayList allowedEndingsJmodsDir = new ArrayList<>(); + allowedEndingsJmodsDir.add(".jmod"); + boolean jmodsDirRes = scanFiles(jmodsDir, allowedEndingsJmodsDir); + if (jmodsDirRes) { + System.out.println("Jmods directory scan successful."); + } else { + throw new Error("jmods dir scan failed"); + } + } } private static boolean scanFiles(Path root, ArrayList allowedEndings) throws IOException { From 49f7265894652ea243f3a531cf3f9d0b06e53565 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 13 Jan 2026 13:54:04 +0000 Subject: [PATCH 015/328] 8374872: Cleanup outdated SAP AG copyright header info Reviewed-by: clanger, mdoerr --- .../jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE78_A.java | 2 +- .../runtime/exceptionMsgs/IllegalAccessError/IAE_Loader2.java | 2 +- test/hotspot/jtreg/runtime/execstack/Test.java | 2 +- test/hotspot/jtreg/runtime/execstack/TestMT.java | 2 +- test/hotspot/jtreg/runtime/execstack/libtest-rw.c | 2 +- test/hotspot/jtreg/runtime/execstack/libtest-rwx.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE78_A.java b/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE78_A.java index e0491b4b89f..0684ad1aacc 100644 --- a/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE78_A.java +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE78_A.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 by SAP AG, Walldorf, Germany. + * Copyright (c) 2018, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE_Loader2.java b/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE_Loader2.java index 373ee584679..d13e5e5d3c1 100644 --- a/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE_Loader2.java +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE_Loader2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 by SAP AG, Walldorf, Germany. + * Copyright (c) 2018, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/hotspot/jtreg/runtime/execstack/Test.java b/test/hotspot/jtreg/runtime/execstack/Test.java index 67891a523aa..22063a56dd5 100644 --- a/test/hotspot/jtreg/runtime/execstack/Test.java +++ b/test/hotspot/jtreg/runtime/execstack/Test.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011 SAP AG. All Rights Reserved. + * Copyright (c) 2011, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/hotspot/jtreg/runtime/execstack/TestMT.java b/test/hotspot/jtreg/runtime/execstack/TestMT.java index 0be1a461c0a..282b09f9a35 100644 --- a/test/hotspot/jtreg/runtime/execstack/TestMT.java +++ b/test/hotspot/jtreg/runtime/execstack/TestMT.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011 SAP AG. All Rights Reserved. + * Copyright (c) 2011, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/hotspot/jtreg/runtime/execstack/libtest-rw.c b/test/hotspot/jtreg/runtime/execstack/libtest-rw.c index 7ad4b95d25e..52e1e8328a1 100644 --- a/test/hotspot/jtreg/runtime/execstack/libtest-rw.c +++ b/test/hotspot/jtreg/runtime/execstack/libtest-rw.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011 SAP AG. All Rights Reserved. + * Copyright (c) 2011, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/hotspot/jtreg/runtime/execstack/libtest-rwx.c b/test/hotspot/jtreg/runtime/execstack/libtest-rwx.c index bce4f853106..e0d8e424809 100644 --- a/test/hotspot/jtreg/runtime/execstack/libtest-rwx.c +++ b/test/hotspot/jtreg/runtime/execstack/libtest-rwx.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011 SAP AG. All Rights Reserved. + * Copyright (c) 2011, 2026 SAP SE. 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 From 45990d796ffafc228c6e843049c80aefedb0f12b Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Tue, 13 Jan 2026 15:15:36 +0000 Subject: [PATCH 016/328] 8374570: Assertion failure in ClearArray.java with -XX:+EnableX86EcoreOpts Reviewed-by: thartmann, epeter, qamai --- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 4 ++-- test/hotspot/jtreg/compiler/c2/ClearArray.java | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index be7deb884ce..7f7bb2c4c7f 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -6086,7 +6086,7 @@ void MacroAssembler::generate_fill(BasicType t, bool aligned, vpbroadcastd(xtmp, xtmp, Assembler::AVX_512bit); subptr(count, 16 << shift); - jccb(Assembler::less, L_check_fill_32_bytes); + jcc(Assembler::less, L_check_fill_32_bytes); align(16); BIND(L_fill_64_bytes_loop_avx3); diff --git a/test/hotspot/jtreg/compiler/c2/ClearArray.java b/test/hotspot/jtreg/compiler/c2/ClearArray.java index ee376641650..d218eef5780 100644 --- a/test/hotspot/jtreg/compiler/c2/ClearArray.java +++ b/test/hotspot/jtreg/compiler/c2/ClearArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test ClearArray.java - * @bug 8284883 + * @bug 8284883 8374570 * @compile ClearArray.java * @summary ClearArray instruction overflows scratch buffer * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -Xbatch @@ -33,6 +33,8 @@ * -XX:InitArrayShortSize=32768 -XX:-IdealizeClearArrayNode -XX:UseAVX=3 compiler.c2.ClearArray * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -Xbatch * -XX:InitArrayShortSize=32768 -XX:MaxVectorSize=8 -XX:-IdealizeClearArrayNode -XX:UseAVX=3 compiler.c2.ClearArray + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -Xbatch + * -XX:+EnableX86ECoreOpts -XX:MaxVectorSize=8 -XX:UseAVX=3 compiler.c2.ClearArray */ package compiler.c2; From 7f707ba8e746d859ac171d71ef8f731953a92e6a Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Tue, 13 Jan 2026 16:55:03 +0000 Subject: [PATCH 017/328] 8373727: New XBM images parser regression: only the first line of the bitmap array is parsed Reviewed-by: prr, jdv --- .../sun/awt/image/XbmImageDecoder.java | 138 +++++++++++------- .../awt/image/XBMDecoder/XBMDecoderTest.java | 28 +++- .../awt/image/XBMDecoder/invalid_empty.xbm | 6 + .../java/awt/image/XBMDecoder/invalid_hex.xbm | 4 +- .../awt/image/XBMDecoder/invalid_plus.xbm | 3 + .../awt/image/XBMDecoder/valid_multiline.xbm | 8 + 6 files changed, 128 insertions(+), 59 deletions(-) create mode 100644 test/jdk/java/awt/image/XBMDecoder/invalid_empty.xbm create mode 100644 test/jdk/java/awt/image/XBMDecoder/invalid_plus.xbm create mode 100644 test/jdk/java/awt/image/XBMDecoder/valid_multiline.xbm diff --git a/src/java.desktop/share/classes/sun/awt/image/XbmImageDecoder.java b/src/java.desktop/share/classes/sun/awt/image/XbmImageDecoder.java index cac9f8baab2..bc025b87f3c 100644 --- a/src/java.desktop/share/classes/sun/awt/image/XbmImageDecoder.java +++ b/src/java.desktop/share/classes/sun/awt/image/XbmImageDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2026, 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 @@ -92,8 +92,8 @@ public class XbmImageDecoder extends ImageDecoder { byte[] raster = null; IndexColorModel model = null; - String matchRegex = "(0[xX])?[0-9a-fA-F]+[\\s+]?[,|};]"; - String replaceRegex = "(0[xX])|,|[\\s+]|[};]"; + String matchRegex = "\\s*(0[xX])?((?:(?!,|\\};).)+)(,|\\};)"; + String replaceRegex = "0[xX]|,|\\s+|\\};"; String line; int lineNum = 0; @@ -111,11 +111,19 @@ public class XbmImageDecoder extends ImageDecoder { } try { if (!token[2].isBlank() && state == 0) { - W = Integer.parseInt(token[2]); - state = 1; // after width is set + if (token[1].endsWith("th")) { + W = Integer.parseInt(token[2]); + } else if (token[1].endsWith("t")) { + H = Integer.parseInt(token[2]); + } + state = 1; // after first dimension is set } else if (!token[2].isBlank() && state == 1) { - H = Integer.parseInt(token[2]); - state = 2; // after height is set + if (token[1].endsWith("th")) { + W = Integer.parseInt(token[2]); + } else if (token[1].endsWith("t")) { + H = Integer.parseInt(token[2]); + } + state = 2; // after second dimension is set } } catch (NumberFormatException nfe) { // parseInt() can throw NFE @@ -147,59 +155,81 @@ public class XbmImageDecoder extends ImageDecoder { error("Width or Height of XBM file not defined"); } + boolean contFlag = false; + StringBuilder sb = new StringBuilder(); + // loop to process image data while (!aborted && (line = br.readLine()) != null) { lineNum++; - if (line.contains("[]")) { - Matcher matcher = Pattern.compile(matchRegex).matcher(line); - while (matcher.find()) { - if (y >= H) { - error("Scan size of XBM file exceeds" - + " the defined width x height"); - } - - int startIndex = matcher.start(); - int endIndex = matcher.end(); - String hexByte = line.substring(startIndex, endIndex); - - if (!(hexByte.startsWith("0x") - || hexByte.startsWith("0X"))) { - error("Invalid hexadecimal number at Ln#:" + lineNum - + " Col#:" + (startIndex + 1)); - } - hexByte = hexByte.replaceAll(replaceRegex, ""); - if (hexByte.length() != 2) { - error("Invalid hexadecimal number at Ln#:" + lineNum - + " Col#:" + (startIndex + 1)); - } - - try { - n = Integer.parseInt(hexByte, 16); - } catch (NumberFormatException nfe) { - error("Error parsing hexadecimal at Ln#:" + lineNum - + " Col#:" + (startIndex + 1)); - } - for (int mask = 1; mask <= 0x80; mask <<= 1) { - if (x < W) { - if ((n & mask) != 0) - raster[x] = 1; - else - raster[x] = 0; - } - x++; - } - - if (x >= W) { - int result = setPixels(0, y, W, 1, model, raster, 0, W); - if (result <= 0) { - error("Unexpected error occurred during setPixel()"); - } - x = 0; - y++; - } + if (!contFlag) { + if (line.contains("[]")) { + contFlag = true; + } else { + continue; } } + + int end = line.indexOf(';'); + if (end >= 0) { + sb.append(line, 0, end + 1); + break; + } else { + sb.append(line).append(System.lineSeparator()); + } + } + + String resultLine = sb.toString(); + int cutOffIndex = resultLine.indexOf('{'); + resultLine = resultLine.substring(cutOffIndex + 1); + + Matcher matcher = Pattern.compile(matchRegex).matcher(resultLine); + while (matcher.find()) { + if (y >= H) { + error("Scan size of XBM file exceeds" + + " the defined width x height"); + } + + int startIndex = matcher.start(); + int endIndex = matcher.end(); + String hexByte = resultLine.substring(startIndex, endIndex); + hexByte = hexByte.replaceAll("^\\s+", ""); + + if (!(hexByte.startsWith("0x") + || hexByte.startsWith("0X"))) { + error("Invalid hexadecimal number at Ln#:" + lineNum + + " Col#:" + (startIndex + 1)); + } + hexByte = hexByte.replaceAll(replaceRegex, ""); + if (hexByte.length() != 2) { + error("Invalid hexadecimal number at Ln#:" + lineNum + + " Col#:" + (startIndex + 1)); + } + + try { + n = Integer.parseInt(hexByte, 16); + } catch (NumberFormatException nfe) { + error("Error parsing hexadecimal at Ln#:" + lineNum + + " Col#:" + (startIndex + 1)); + } + for (int mask = 1; mask <= 0x80; mask <<= 1) { + if (x < W) { + if ((n & mask) != 0) + raster[x] = 1; + else + raster[x] = 0; + } + x++; + } + + if (x >= W) { + int result = setPixels(0, y, W, 1, model, raster, 0, W); + if (result <= 0) { + error("Unexpected error occurred during setPixel()"); + } + x = 0; + y++; + } } imageComplete(ImageConsumer.STATICIMAGEDONE, true); } diff --git a/test/jdk/java/awt/image/XBMDecoder/XBMDecoderTest.java b/test/jdk/java/awt/image/XBMDecoder/XBMDecoderTest.java index 19bc6d95c39..9694043d1bb 100644 --- a/test/jdk/java/awt/image/XBMDecoder/XBMDecoderTest.java +++ b/test/jdk/java/awt/image/XBMDecoder/XBMDecoderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, 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 @@ -29,10 +29,14 @@ * @run main XBMDecoderTest */ +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.PrintStream; +import java.util.Arrays; import javax.swing.ImageIcon; public class XBMDecoderTest { @@ -57,21 +61,39 @@ public class XBMDecoderTest { ImageIcon icon = new ImageIcon(fis.readAllBytes()); boolean isErrEmpty = errContent.toString().isEmpty(); + if (!isErrEmpty) { System.out.println("Expected ImageFormatException occurred."); System.out.print(errContent); } - if (validCase && !isErrEmpty) { throw new RuntimeException("Test failed: Error stream not empty"); - } else if (!validCase && isErrEmpty) { + } else if (!validCase && isErrEmpty && hasPixelData(icon.getImage())) { throw new RuntimeException("Test failed: ImageFormatException" + " expected but not thrown"); } + if (validCase && !hasPixelData(icon.getImage())) { + throw new RuntimeException("Test failed: the parsed image " + + "does not contain any pixel data"); + } System.out.println("PASSED\n"); } finally { System.setErr(originalErr); } } } + + private static boolean hasPixelData(Image img) { + int w = img.getWidth(null); + int h = img.getHeight(null); + BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = bi.createGraphics(); + g.drawImage(img, 0, 0, null); + g.dispose(); + int[] pixels = bi.getRGB(0, 0, w, h, null, 0, w); + if (Arrays.stream(pixels).allMatch(i -> i == 0)) { + return false; + } + return true; + } } diff --git a/test/jdk/java/awt/image/XBMDecoder/invalid_empty.xbm b/test/jdk/java/awt/image/XBMDecoder/invalid_empty.xbm new file mode 100644 index 00000000000..5cfb8e21cf8 --- /dev/null +++ b/test/jdk/java/awt/image/XBMDecoder/invalid_empty.xbm @@ -0,0 +1,6 @@ +#define test_width 16 +#define test_height 3 +#define ht_x 1 +#define ht_y 2 +static unsigned char test_bits[] = { +}; diff --git a/test/jdk/java/awt/image/XBMDecoder/invalid_hex.xbm b/test/jdk/java/awt/image/XBMDecoder/invalid_hex.xbm index c6f819582d0..1286eee1d9b 100644 --- a/test/jdk/java/awt/image/XBMDecoder/invalid_hex.xbm +++ b/test/jdk/java/awt/image/XBMDecoder/invalid_hex.xbm @@ -1,3 +1,3 @@ -#define k_wt 16 -#define k_ht 1 +#define k_width 16 +#define k_height 1 k[] = { 0x10, 1234567890}; diff --git a/test/jdk/java/awt/image/XBMDecoder/invalid_plus.xbm b/test/jdk/java/awt/image/XBMDecoder/invalid_plus.xbm new file mode 100644 index 00000000000..714907084f2 --- /dev/null +++ b/test/jdk/java/awt/image/XBMDecoder/invalid_plus.xbm @@ -0,0 +1,3 @@ +#define test_width 16 +#define test_height 2 +static unsigned char test_bits[] = { 0x13, 0x11, 0xAB+, 0xff }; \ No newline at end of file diff --git a/test/jdk/java/awt/image/XBMDecoder/valid_multiline.xbm b/test/jdk/java/awt/image/XBMDecoder/valid_multiline.xbm new file mode 100644 index 00000000000..e24bc10e9b0 --- /dev/null +++ b/test/jdk/java/awt/image/XBMDecoder/valid_multiline.xbm @@ -0,0 +1,8 @@ +#define test_width 16 +#define test_height 3 +#define ht_x 1 +#define ht_y 2 +static unsigned char test_bits[] = { +0x20, 0x10, +0x25, 0x01, +0xAC, 0xab }; From 074038438f5b8b91e9390430b4fa58ff53e5df26 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 13 Jan 2026 16:57:30 +0000 Subject: [PATCH 018/328] 8374727: Audio configuration Platform class - use nio for getting endianness of the underlying platform Reviewed-by: prr, kizune --- .../libjsound/PLATFORM_API_MacOSX_PCM.cpp | 7 ++- .../classes/com/sun/media/sound/Platform.java | 17 ++------ .../share/native/libjsound/Platform.c | 43 ------------------- .../share/native/libjsound/Utilities.c | 11 +---- .../share/native/libjsound/Utilities.h | 6 +-- 5 files changed, 8 insertions(+), 76 deletions(-) delete mode 100644 src/java.desktop/share/native/libjsound/Platform.c diff --git a/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_PCM.cpp b/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_PCM.cpp index 441a71f5c50..bae16cb0a9c 100644 --- a/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_PCM.cpp +++ b/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_PCM.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, 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 @@ -162,8 +162,7 @@ void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* cre sampleRate, // sample rate DAUDIO_PCM, // only accept PCM bits == 8 ? FALSE : TRUE, // signed - bits == 8 ? FALSE // little-endian for 8bit - : UTIL_IsBigEndianPlatform()); + FALSE); // all supported macOS versions run on LE } } // add default format @@ -175,7 +174,7 @@ void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* cre defSampleRate, // sample rate DAUDIO_PCM, // PCM TRUE, // signed - UTIL_IsBigEndianPlatform()); // native endianness + FALSE); // native endianness; all supported macOS versions run on LE } TRACE0("< Date: Tue, 13 Jan 2026 18:06:04 +0000 Subject: [PATCH 019/328] 8371014: Dump JFR recording on CrashOnOutOfMemoryError is incorrectly implemented Reviewed-by: ysuenaga --- src/hotspot/share/jfr/jfr.cpp | 14 +- src/hotspot/share/jfr/jfr.hpp | 5 +- src/hotspot/share/jfr/jni/jfrJniMethod.cpp | 5 +- .../recorder/repository/jfrEmergencyDump.cpp | 56 +++--- .../recorder/repository/jfrEmergencyDump.hpp | 4 +- .../share/jfr/recorder/service/jfrPostBox.cpp | 7 +- .../share/jfr/recorder/service/jfrPostBox.hpp | 25 +-- .../recorder/service/jfrRecorderService.cpp | 186 ++++++++++++++++-- .../recorder/service/jfrRecorderService.hpp | 20 +- .../service/jfrRecorderThreadLoop.cpp | 8 +- src/hotspot/share/runtime/java.cpp | 7 +- src/hotspot/share/utilities/debug.cpp | 7 +- src/hotspot/share/utilities/vmError.cpp | 4 +- test/jdk/ProblemList.txt | 1 - .../oldobject/TestEmergencyDumpAtOOM.java | 6 +- 15 files changed, 278 insertions(+), 77 deletions(-) diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index b09a89594ad..d9892f80b6f 100644 --- a/src/hotspot/share/jfr/jfr.cpp +++ b/src/hotspot/share/jfr/jfr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ #include "jfr/recorder/repository/jfrEmergencyDump.hpp" #include "jfr/recorder/repository/jfrRepository.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" +#include "jfr/recorder/service/jfrRecorderService.hpp" #include "jfr/support/jfrClassDefineEvent.hpp" #include "jfr/support/jfrKlassExtension.hpp" #include "jfr/support/jfrResolution.hpp" @@ -43,6 +44,7 @@ #include "runtime/java.hpp" #include "runtime/javaThread.hpp" + bool Jfr::is_enabled() { return JfrRecorder::is_enabled(); } @@ -153,9 +155,9 @@ void Jfr::on_resolution(const Method* caller, const Method* target, TRAPS) { } #endif -void Jfr::on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown, bool halt) { +void Jfr::on_vm_shutdown(bool exception_handler /* false */, bool halt /* false */, bool oom /* false */) { if (!halt && JfrRecorder::is_recording()) { - JfrEmergencyDump::on_vm_shutdown(emit_old_object_samples, emit_event_shutdown); + JfrEmergencyDump::on_vm_shutdown(exception_handler, oom); } } @@ -173,6 +175,12 @@ bool Jfr::on_start_flight_recording_option(const JavaVMOption** option, char* de return JfrOptionSet::parse_start_flight_recording_option(option, delimiter); } +void Jfr::on_report_java_out_of_memory() { + if (CrashOnOutOfMemoryError && JfrRecorder::is_recording()) { + JfrRecorderService::emit_leakprofiler_events_on_oom(); + } +} + #if INCLUDE_CDS void Jfr::on_restoration(const Klass* k, JavaThread* jt) { assert(k != nullptr, "invariant"); diff --git a/src/hotspot/share/jfr/jfr.hpp b/src/hotspot/share/jfr/jfr.hpp index db567cc9a29..ac6a232dda1 100644 --- a/src/hotspot/share/jfr/jfr.hpp +++ b/src/hotspot/share/jfr/jfr.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -71,7 +71,7 @@ class Jfr : AllStatic { static void on_resolution(const Method* caller, const Method* target, TRAPS); static void on_java_thread_start(JavaThread* starter, JavaThread* startee); static void on_set_current_thread(JavaThread* jt, oop thread); - static void on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown, bool halt = false); + static void on_vm_shutdown(bool exception_handler = false, bool halt = false, bool oom = false); static void on_vm_error_report(outputStream* st); static bool on_flight_recorder_option(const JavaVMOption** option, char* delimiter); static bool on_start_flight_recording_option(const JavaVMOption** option, char* delimiter); @@ -79,6 +79,7 @@ class Jfr : AllStatic { static void initialize_main_thread(JavaThread* jt); static bool has_sample_request(JavaThread* jt); static void check_and_process_sample_request(JavaThread* jt); + static void on_report_java_out_of_memory(); CDS_ONLY(static void on_restoration(const Klass* k, JavaThread* jt);) }; diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index 6a1146587bc..d8a30f9b5ee 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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 @@ -364,8 +364,7 @@ JVM_ENTRY_NO_ENV(void, jfr_set_force_instrumentation(JNIEnv* env, jclass jvm, jb JVM_END NO_TRANSITION(void, jfr_emit_old_object_samples(JNIEnv* env, jclass jvm, jlong cutoff_ticks, jboolean emit_all, jboolean skip_bfs)) - JfrRecorderService service; - service.emit_leakprofiler_events(cutoff_ticks, emit_all == JNI_TRUE, skip_bfs == JNI_TRUE); + JfrRecorderService::emit_leakprofiler_events(cutoff_ticks, emit_all == JNI_TRUE, skip_bfs == JNI_TRUE); NO_TRANSITION_END JVM_ENTRY_NO_ENV(void, jfr_exclude_thread(JNIEnv* env, jclass jvm, jobject t)) diff --git a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp index 309ae961808..cdebcbcfcb5 100644 --- a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp +++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, 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 @@ -38,6 +38,8 @@ #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" #include "runtime/thread.inline.hpp" +#include "runtime/vmOperations.hpp" +#include "runtime/vmThread.hpp" #include "utilities/growableArray.hpp" #include "utilities/ostream.hpp" @@ -460,15 +462,6 @@ static void release_locks(Thread* thread) { assert(thread != nullptr, "invariant"); assert(!thread->is_Java_thread() || JavaThread::cast(thread)->thread_state() == _thread_in_vm, "invariant"); -#ifdef ASSERT - Mutex* owned_lock = thread->owned_locks(); - while (owned_lock != nullptr) { - Mutex* next = owned_lock->next(); - owned_lock->unlock(); - owned_lock = next; - } -#endif // ASSERT - if (Threads_lock->owned_by_self()) { Threads_lock->unlock(); } @@ -550,17 +543,14 @@ class JavaThreadInVMAndNative : public StackObj { } }; -static void post_events(bool emit_old_object_samples, bool emit_event_shutdown, Thread* thread) { - if (emit_old_object_samples) { - LeakProfiler::emit_events(max_jlong, false, false); - } - if (emit_event_shutdown) { +static void post_events(bool exception_handler, bool oom, Thread * thread) { + if (exception_handler) { EventShutdown e; - e.set_reason("VM Error"); + e.set_reason(oom ? "CrashOnOutOfMemoryError" : "VM Error"); e.commit(); } EventDumpReason event; - event.set_reason(emit_old_object_samples ? "Out of Memory" : "Crash"); + event.set_reason(exception_handler && oom ? "CrashOnOutOfMemoryError" : exception_handler ? "Crash" : "Out of Memory"); event.set_recordingId(-1); event.commit(); } @@ -594,20 +584,40 @@ static bool guard_reentrancy() { return false; } -void JfrEmergencyDump::on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown) { +void JfrEmergencyDump::on_vm_shutdown(bool exception_handler, bool oom) { if (!guard_reentrancy()) { return; } + Thread* const thread = Thread::current_or_null_safe(); assert(thread != nullptr, "invariant"); - if (thread->is_Watcher_thread()) { - log_info(jfr, system)("The Watcher thread crashed so no jfr emergency dump will be generated."); - return; - } + // Ensure a JavaThread is _thread_in_vm when we make this call JavaThreadInVMAndNative jtivm(thread); + post_events(exception_handler, oom, thread); + + if (thread->is_Watcher_thread()) { + // We cannot attempt an emergency dump using the Watcher thread + // because we rely on the WatcherThread task "is_error_reported()", + // to exit the VM after a hardcoded timeout, should the relatively + // risky operation of an emergency dump fail (deadlock, livelock). + log_warning(jfr, system) + ("The Watcher thread crashed so no jfr emergency dump will be generated."); + return; + } + + if (thread->is_VM_thread()) { + const VM_Operation* const operation = VMThread::vm_operation(); + if (operation != nullptr && operation->type() == VM_Operation::VMOp_JFROldObject) { + // We will not be able to issue a rotation because the rotation lock + // is held by the JFR Recorder Thread that issued the VM_Operation. + log_warning(jfr, system) + ("The VM Thread crashed as part of emitting leak profiler events so no jfr emergency dump will be generated."); + return; + } + } + release_locks(thread); - post_events(emit_old_object_samples, emit_event_shutdown, thread); // if JavaThread, transition to _thread_in_native to issue a final flushpoint NoHandleMark nhm; diff --git a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp index 04c2851a516..b337d73364a 100644 --- a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp +++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -39,7 +39,7 @@ class JfrEmergencyDump : AllStatic { static const char* chunk_path(const char* repository_path); static void on_vm_error(const char* repository_path); static void on_vm_error_report(outputStream* st, const char* repository_path); - static void on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown); + static void on_vm_shutdown(bool exception_handler, bool oom); }; #endif // SHARE_JFR_RECORDER_REPOSITORY_JFREMERGENCYDUMP_HPP diff --git a/src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp b/src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp index a9ba456ad76..6db7a42ab27 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,8 @@ (MSGBIT(MSG_START)) | \ (MSGBIT(MSG_CLONE_IN_MEMORY)) | \ (MSGBIT(MSG_VM_ERROR)) | \ - (MSGBIT(MSG_FLUSHPOINT)) \ + (MSGBIT(MSG_FLUSHPOINT)) | \ + (MSGBIT(MSG_EMIT_LEAKP_REFCHAINS)) \ ) static JfrPostBox* _instance = nullptr; @@ -165,7 +166,7 @@ void JfrPostBox::notify_waiters() { assert(JfrMsg_lock->owned_by_self(), "incrementing _msg_handled_serial is protected by JfrMsg_lock."); // Update made visible on release of JfrMsg_lock via fence instruction in Monitor::IUnlock. ++_msg_handled_serial; - JfrMsg_lock->notify(); + JfrMsg_lock->notify_all(); } // safeguard to ensure no threads are left waiting diff --git a/src/hotspot/share/jfr/recorder/service/jfrPostBox.hpp b/src/hotspot/share/jfr/recorder/service/jfrPostBox.hpp index 10457261643..92f70b1dc9b 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrPostBox.hpp +++ b/src/hotspot/share/jfr/recorder/service/jfrPostBox.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, 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 @@ -43,6 +43,7 @@ enum JFR_Msg { MSG_SHUTDOWN, MSG_VM_ERROR, MSG_FLUSHPOINT, + MSG_EMIT_LEAKP_REFCHAINS, MSG_NO_OF_MSGS }; @@ -51,23 +52,25 @@ enum JFR_Msg { * * Synchronous messages (posting thread waits for message completion): * - * MSG_CLONE_IN_MEMORY (0) ; MSGBIT(MSG_CLONE_IN_MEMORY) == (1 << 0) == 0x1 - * MSG_START(1) ; MSGBIT(MSG_START) == (1 << 0x1) == 0x2 - * MSG_STOP (2) ; MSGBIT(MSG_STOP) == (1 << 0x2) == 0x4 - * MSG_ROTATE (3) ; MSGBIT(MSG_ROTATE) == (1 << 0x3) == 0x8 - * MSG_VM_ERROR (8) ; MSGBIT(MSG_VM_ERROR) == (1 << 0x8) == 0x100 - * MSG_FLUSHPOINT (9) ; MSGBIT(MSG_FLUSHPOINT) == (1 << 0x9) == 0x200 + * MSG_CLONE_IN_MEMORY (0) ; MSGBIT(MSG_CLONE_IN_MEMORY) == (1 << 0) == 0x1 + * MSG_START(1) ; MSGBIT(MSG_START) == (1 << 0x1) == 0x2 + * MSG_STOP (2) ; MSGBIT(MSG_STOP) == (1 << 0x2) == 0x4 + * MSG_ROTATE (3) ; MSGBIT(MSG_ROTATE) == (1 << 0x3) == 0x8 + * MSG_VM_ERROR (8) ; MSGBIT(MSG_VM_ERROR) == (1 << 0x8) == 0x100 + * MSG_FLUSHPOINT (9) ; MSGBIT(MSG_FLUSHPOINT) == (1 << 0x9) == 0x200 + * MSG_EMIT_LEAKP_REFCHAINS (10); MSGBIT(MSG_EMIT_LEAKP_REFCHAINS) == (1 << 0xa) == 0x400 * * Asynchronous messages (posting thread returns immediately upon deposit): * - * MSG_FULLBUFFER (4) ; MSGBIT(MSG_FULLBUFFER) == (1 << 0x4) == 0x10 - * MSG_CHECKPOINT (5) ; MSGBIT(CHECKPOINT) == (1 << 0x5) == 0x20 - * MSG_WAKEUP (6) ; MSGBIT(WAKEUP) == (1 << 0x6) == 0x40 - * MSG_SHUTDOWN (7) ; MSGBIT(MSG_SHUTDOWN) == (1 << 0x7) == 0x80 + * MSG_FULLBUFFER (4) ; MSGBIT(MSG_FULLBUFFER) == (1 << 0x4) == 0x10 + * MSG_CHECKPOINT (5) ; MSGBIT(CHECKPOINT) == (1 << 0x5) == 0x20 + * MSG_WAKEUP (6) ; MSGBIT(WAKEUP) == (1 << 0x6) == 0x40 + * MSG_SHUTDOWN (7) ; MSGBIT(MSG_SHUTDOWN) == (1 << 0x7) == 0x80 */ class JfrPostBox : public JfrCHeapObj { friend class JfrRecorder; + friend class JfrRecorderService; public: void post(JFR_Msg msg); diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index 08250a1ae59..6f8d44fb1a4 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,7 @@ #include "runtime/safepoint.hpp" #include "runtime/vmOperations.hpp" #include "runtime/vmThread.hpp" +#include "utilities/growableArray.hpp" // incremented on each flushpoint static u8 flushpoint_id = 0; @@ -391,6 +392,7 @@ class JfrSafepointWriteVMOperation : public VM_Operation { JfrRecorderService::JfrRecorderService() : _checkpoint_manager(JfrCheckpointManager::instance()), _chunkwriter(JfrRepository::chunkwriter()), + _post_box(JfrPostBox::instance()), _repository(JfrRepository::instance()), _stack_trace_repository(JfrStackTraceRepository::instance()), _storage(JfrStorage::instance()), @@ -670,17 +672,173 @@ void JfrRecorderService::evaluate_chunk_size_for_rotation() { JfrChunkRotation::evaluate(_chunkwriter); } -void JfrRecorderService::emit_leakprofiler_events(int64_t cutoff_ticks, bool emit_all, bool skip_bfs) { - DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(JavaThread::current())); - // Take the rotation lock to exclude flush() during event emits. This is because event emit - // also creates a number checkpoint events. Those checkpoint events require a future typeset checkpoint - // event for completeness, i.e. to be generated before being flushed to a segment. - // The upcoming flush() or rotation() after event emit completes this typeset checkpoint - // and serializes all event emit checkpoint events to the same segment. - JfrRotationLock lock; - // Take the rotation lock before the transition. - JavaThread* current_thread = JavaThread::current(); - MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current_thread)); - ThreadInVMfromNative transition(current_thread); - LeakProfiler::emit_events(cutoff_ticks, emit_all, skip_bfs); +// LeakProfiler event serialization support. + +struct JfrLeakProfilerEmitRequest { + int64_t cutoff_ticks; + bool emit_all; + bool skip_bfs; + bool oom; +}; + +typedef GrowableArrayCHeap JfrLeakProfilerEmitRequestQueue; +static JfrLeakProfilerEmitRequestQueue* _queue = nullptr; +constexpr const static int64_t _no_path_to_gc_roots = 0; +static bool _oom_emit_request_posted = false; +static bool _oom_emit_request_delivered = false; + +static inline bool exclude_paths_to_gc_roots(int64_t cutoff_ticks) { + return cutoff_ticks <= _no_path_to_gc_roots; +} + +static void enqueue(const JfrLeakProfilerEmitRequest& request) { + assert(JfrRotationLock::is_owner(), "invariant"); + if (_queue == nullptr) { + _queue = new JfrLeakProfilerEmitRequestQueue(4); + } + assert(_queue != nullptr, "invariant"); + assert(!_oom_emit_request_posted, "invariant"); + if (request.oom) { + _oom_emit_request_posted = true; + } + _queue->append(request); +} + +static JfrLeakProfilerEmitRequest dequeue() { + assert(JfrRotationLock::is_owner(), "invariant"); + assert(_queue != nullptr, "invariant"); + assert(_queue->is_nonempty(), "invariant"); + const JfrLeakProfilerEmitRequest& request = _queue->first(); + _queue->remove_at(0); + return request; +} + +// This version of emit excludes path-to-gc-roots, i.e. it skips reference chains. +static void emit_leakprofiler_events(bool emit_all, bool skip_bfs, JavaThread* jt) { + assert(jt != nullptr, "invariant"); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); + // Take the rotation lock to exclude flush() during event emits. This is because the event emit operation + // also creates a number of checkpoint events. Those checkpoint events require a future typeset checkpoint + // event for completeness, i.e., to be generated before being flushed to a segment. + // The upcoming flush() or rotation() after event emit completes this typeset checkpoint + // and serializes all checkpoint events to the same segment. + JfrRotationLock lock; + // Take the rotation lock before the thread transition, to avoid blocking safepoints. + if (_oom_emit_request_posted) { + // A request to emit leakprofiler events in response to CrashOnOutOfMemoryError + // is pending or has already been completed. We are about to crash at any time now. + assert(CrashOnOutOfMemoryError, "invariant"); + return; + } + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, jt)); + ThreadInVMfromNative transition(jt); + // Since we are not requesting path-to-gc-roots, i.e., reference chains, we need not issue a VM_Operation. + // Therefore, we can let the requesting thread process the request directly, since it already holds the requisite lock. + LeakProfiler::emit_events(_no_path_to_gc_roots, emit_all, skip_bfs); +} + +void JfrRecorderService::transition_and_post_leakprofiler_emit_msg(JavaThread* jt) { + assert(jt != nullptr, "invariant"); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt);) + assert(!JfrRotationLock::is_owner(), "invariant"); + // Transition to _thread_in_VM and post a synchronous message to the JFR Recorder Thread + // for it to process our enqueued request, which includes paths-to-gc-roots, i.e., reference chains. + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, jt)); + ThreadInVMfromNative transition(jt); + _post_box.post(MSG_EMIT_LEAKP_REFCHAINS); +} + +// This version of emit includes path-to-gc-roots, i.e., it includes in the request traversing of reference chains. +// Traversing reference chains is performed as part of a VM_Operation, and we initiate it from the JFR Recorder Thread. +// Because multiple threads can concurrently report_on_java_out_of_memory(), having them all post a synchronous JFR msg, +// they rendezvous at a safepoint in a convenient state, ThreadBlockInVM. This mechanism prevents any thread from racing past +// this point and begin executing VMError::report_and_die(), until at least one oom request has been delivered. +void JfrRecorderService::emit_leakprofiler_events_paths_to_gc_roots(int64_t cutoff_ticks, + bool emit_all, + bool skip_bfs, + bool oom, + JavaThread* jt) { + assert(jt != nullptr, "invariant"); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt);) + assert(!exclude_paths_to_gc_roots(cutoff_ticks), "invariant"); + + { + JfrRotationLock lock; + // Take the rotation lock to read and post a request for the JFR Recorder Thread. + if (_oom_emit_request_posted) { + if (!oom) { + // A request to emit leakprofiler events in response to CrashOnOutOfMemoryError + // is pending or has already been completed. We are about to crash at any time now. + assert(CrashOnOutOfMemoryError, "invariant"); + return; + } + } else { + assert(!_oom_emit_request_posted, "invariant"); + JfrLeakProfilerEmitRequest request = { cutoff_ticks, emit_all, skip_bfs, oom }; + enqueue(request); + } + } + JfrRecorderService service; + service.transition_and_post_leakprofiler_emit_msg(jt); +} + +// Leakprofiler serialization request, the jdk.jfr.internal.JVM.emitOldObjectSamples() Java entry point. +void JfrRecorderService::emit_leakprofiler_events(int64_t cutoff_ticks, + bool emit_all, + bool skip_bfs) { + JavaThread* const jt = JavaThread::current(); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt);) + if (exclude_paths_to_gc_roots(cutoff_ticks)) { + ::emit_leakprofiler_events(emit_all, skip_bfs, jt); + return; + } + emit_leakprofiler_events_paths_to_gc_roots(cutoff_ticks, emit_all, skip_bfs, /* oom */ false, jt); +} + +// Leakprofiler serialization request, the report_on_java_out_of_memory VM entry point. +void JfrRecorderService::emit_leakprofiler_events_on_oom() { + assert(CrashOnOutOfMemoryError, "invariant"); + if (EventOldObjectSample::is_enabled()) { + JavaThread* const jt = JavaThread::current(); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt);) + ThreadToNativeFromVM transition(jt); + emit_leakprofiler_events_paths_to_gc_roots(max_jlong, false, false, /* oom */ true, jt); + } +} + +// The worker routine for the JFR Recorder Thread when processing MSG_EMIT_LEAKP_REFCHAINS messages. +void JfrRecorderService::emit_leakprofiler_events() { + JavaThread* const jt = JavaThread::current(); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); + // Take the rotation lock before the transition. + JfrRotationLock lock; + if (_oom_emit_request_delivered) { + // A request to emit leakprofiler events in response to CrashOnOutOfMemoryError + // has already been completed. We are about to crash at any time now. + assert(_oom_emit_request_posted, "invariant"); + assert(CrashOnOutOfMemoryError, "invariant"); + return; + } + + assert(_queue->is_nonempty(), "invariant"); + + { + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, jt)); + ThreadInVMfromNative transition(jt); + while (_queue->is_nonempty()) { + const JfrLeakProfilerEmitRequest& request = dequeue(); + LeakProfiler::emit_events(request.cutoff_ticks, request.emit_all, request.skip_bfs); + if (_oom_emit_request_posted && request.oom) { + assert(CrashOnOutOfMemoryError, "invariant"); + _oom_emit_request_delivered = true; + break; + } + } + } + + // If processing involved an out-of-memory request, issue an immediate flush operation. + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); + if (_chunkwriter.is_valid() && _oom_emit_request_delivered) { + invoke_flush(); + } } diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp index e5b4500afc0..3759ff98828 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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,19 +27,23 @@ #include "jfr/utilities/jfrAllocation.hpp" +class JavaThread; class JfrCheckpointManager; class JfrChunkWriter; +class JfrPostBox; class JfrRepository; class JfrStackTraceRepository; class JfrStorage; class JfrStringPool; class JfrRecorderService : public StackObj { + friend class Jfr; friend class JfrSafepointClearVMOperation; friend class JfrSafepointWriteVMOperation; private: JfrCheckpointManager& _checkpoint_manager; JfrChunkWriter& _chunkwriter; + JfrPostBox& _post_box; JfrRepository& _repository; JfrStackTraceRepository& _stack_trace_repository; JfrStorage& _storage; @@ -64,6 +68,14 @@ class JfrRecorderService : public StackObj { void invoke_safepoint_write(); void post_safepoint_write(); + void transition_and_post_leakprofiler_emit_msg(JavaThread* jt); + + static void emit_leakprofiler_events_on_oom(); + static void emit_leakprofiler_events_paths_to_gc_roots(int64_t cutoff_ticks, + bool emit_all, + bool skip_bfs, + bool oom, + JavaThread* jt); public: JfrRecorderService(); void start(); @@ -72,8 +84,12 @@ class JfrRecorderService : public StackObj { void flushpoint(); void process_full_buffers(); void evaluate_chunk_size_for_rotation(); - void emit_leakprofiler_events(int64_t cutoff_ticks, bool emit_all, bool skip_bfs); + void emit_leakprofiler_events(); + static bool is_recording(); + static void emit_leakprofiler_events(int64_t cutoff_ticks, + bool emit_all, + bool skip_bfs); }; #endif // SHARE_JFR_RECORDER_SERVICE_JFRRECORDERSERVICE_HPP diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp index de015e9a502..bd01adf5b3a 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, 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 @@ -44,6 +44,7 @@ void recorderthread_entry(JavaThread* thread, JavaThread* unused) { #define ROTATE (msgs & (MSGBIT(MSG_ROTATE)|MSGBIT(MSG_STOP))) #define FLUSHPOINT (msgs & (MSGBIT(MSG_FLUSHPOINT))) #define PROCESS_FULL_BUFFERS (msgs & (MSGBIT(MSG_ROTATE)|MSGBIT(MSG_STOP)|MSGBIT(MSG_FULLBUFFER))) + #define LEAKPROFILER_REFCHAINS (msgs & MSGBIT(MSG_EMIT_LEAKP_REFCHAINS)) JfrPostBox& post_box = JfrRecorderThreadEntry::post_box(); log_debug(jfr, system)("Recorder thread STARTED"); @@ -70,6 +71,9 @@ void recorderthread_entry(JavaThread* thread, JavaThread* unused) { if (PROCESS_FULL_BUFFERS) { service.process_full_buffers(); } + if (LEAKPROFILER_REFCHAINS) { + service.emit_leakprofiler_events(); + } // Check amount of data written to chunk already // if it warrants asking for a new chunk. service.evaluate_chunk_size_for_rotation(); @@ -98,5 +102,5 @@ void recorderthread_entry(JavaThread* thread, JavaThread* unused) { #undef ROTATE #undef FLUSHPOINT #undef PROCESS_FULL_BUFFERS - #undef SCAVENGE + #undef LEAKPROFILER_REFCHAINS } diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index c49a9f5d4b8..ee4f776df06 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -466,10 +466,7 @@ void before_exit(JavaThread* thread, bool halt) { event.commit(); } - // 2nd argument (emit_event_shutdown) should be set to false - // because EventShutdown would be emitted at Threads::destroy_vm(). - // (one of the callers of before_exit()) - JFR_ONLY(Jfr::on_vm_shutdown(true, false, halt);) + JFR_ONLY(Jfr::on_vm_shutdown(false, halt);) // Stop the WatcherThread. We do this before disenrolling various // PeriodicTasks to reduce the likelihood of races. diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp index de39fe32dc1..9e167141259 100644 --- a/src/hotspot/share/utilities/debug.cpp +++ b/src/hotspot/share/utilities/debug.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -63,6 +63,9 @@ #include "utilities/nativeStackPrinter.hpp" #include "utilities/unsigned5.hpp" #include "utilities/vmError.hpp" +#if INCLUDE_JFR +#include "jfr/jfr.hpp" +#endif #include #include @@ -262,6 +265,8 @@ void report_untested(const char* file, int line, const char* message) { void report_java_out_of_memory(const char* message) { static int out_of_memory_reported = 0; + JFR_ONLY(Jfr::on_report_java_out_of_memory();) + // A number of threads may attempt to report OutOfMemoryError at around the // same time. To avoid dumping the heap or executing the data collection // commands multiple times we just do it once when the first threads reports diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index a290602e0be..88f81b31293 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2024 SAP SE. All rights reserved. * Copyright (c) 2023, 2025, Red Hat, Inc. and/or its affiliates. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -1898,7 +1898,7 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt log.set_fd(-1); } - JFR_ONLY(Jfr::on_vm_shutdown(static_cast(_id) == OOM_JAVA_HEAP_FATAL, true);) + JFR_ONLY(Jfr::on_vm_shutdown(true, false, static_cast(_id) == OOM_JAVA_HEAP_FATAL);) if (PrintNMTStatistics) { fdStream fds(fd_out); diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 9cfc23ea8da..291b2163b0d 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -710,7 +710,6 @@ jdk/incubator/vector/LoadJsvmlTest.java 8305390 windows- # jdk_jfr jdk/jfr/event/compiler/TestCodeSweeper.java 8338127 generic-all -jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java 8371014 aix-ppc64,linux-ppc64le jdk/jfr/event/oldobject/TestShenandoah.java 8342951 generic-all jdk/jfr/event/runtime/TestResidentSetSizeEvent.java 8309846 aix-ppc64 jdk/jfr/jvm/TestWaste.java 8371630 generic-all diff --git a/test/jdk/jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java b/test/jdk/jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java index d540acd853b..b3630fa7f77 100644 --- a/test/jdk/jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java +++ b/test/jdk/jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2025, NTT DATA. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -98,8 +98,8 @@ public class TestEmergencyDumpAtOOM { // Check OldObjectSample events if (oldObjects.get() > 0L) { if (shouldCrash) { - Asserts.assertEquals("VM Error", shutdownReason.get()); - Asserts.assertEquals("Out of Memory", dumpReason.get()); + Asserts.assertEquals("CrashOnOutOfMemoryError", shutdownReason.get()); + Asserts.assertEquals("CrashOnOutOfMemoryError", dumpReason.get()); } else { Asserts.assertEquals("No remaining non-daemon Java threads", shutdownReason.get()); } From b070367bdf980ef1c257cab485927db39b544241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Tue, 13 Jan 2026 19:40:20 +0000 Subject: [PATCH 020/328] 8373106: JFR suspend/resume deadlock on macOS in pthreads library Reviewed-by: egahlin --- .../periodic/sampling/jfrThreadSampler.cpp | 92 +++++++++---------- 1 file changed, 43 insertions(+), 49 deletions(-) diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp index 805426078c4..0a8b3975139 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp @@ -232,41 +232,50 @@ void JfrSamplerThread::task_stacktrace(JfrSampleRequestType type, JavaThread** l JavaThread* start = nullptr; elapsedTimer sample_time; sample_time.start(); - ThreadsListHandle tlh; - // Resolve a sample session relative start position index into the thread list array. - // In cases where the last sampled thread is null or not-null but stale, find_index() returns -1. - _cur_index = tlh.list()->find_index_of_JavaThread(*last_thread); - JavaThread* current = _cur_index != -1 ? *last_thread : nullptr; + { + /* + * Take the Threads_lock for three purposes: + * + * 1) Avoid sampling right through a safepoint, + * which could result in touching oops in case of virtual threads. + * 2) Prevent JFR from issuing an epoch rotation while the sampler thread + * is actively processing a thread in state native, as both threads are outside the safepoint protocol. + * 3) Some operating systems (BSD / Mac) require a process lock when sending a signal with pthread_kill. + * Holding the Threads_lock prevents a JavaThread from calling os::create_thread(), which also takes the process lock. + * In a sense, we provide a coarse signal mask, so we can always send the resume signal. + */ + MutexLocker tlock(Threads_lock); + ThreadsListHandle tlh; + // Resolve a sample session relative start position index into the thread list array. + // In cases where the last sampled thread is null or not-null but stale, find_index() returns -1. + _cur_index = tlh.list()->find_index_of_JavaThread(*last_thread); + JavaThread* current = _cur_index != -1 ? *last_thread : nullptr; - while (num_samples < sample_limit) { - current = next_thread(tlh.list(), start, current); - if (current == nullptr) { - break; - } - if (is_excluded(current)) { - continue; - } - if (start == nullptr) { - start = current; // remember the thread where we started to attempt sampling - } - bool success; - if (JAVA_SAMPLE == type) { - success = sample_java_thread(current); - } else { - assert(type == NATIVE_SAMPLE, "invariant"); - success = sample_native_thread(current); - } - if (success) { - num_samples++; - } - if (SafepointSynchronize::is_at_safepoint()) { - // For _thread_in_native, we cannot get the Threads_lock. - // For _thread_in_Java, well, there are none. - break; + while (num_samples < sample_limit) { + current = next_thread(tlh.list(), start, current); + if (current == nullptr) { + break; + } + if (is_excluded(current)) { + continue; + } + if (start == nullptr) { + start = current; // remember the thread where we started to attempt sampling + } + bool success; + if (JAVA_SAMPLE == type) { + success = sample_java_thread(current); + } else { + assert(type == NATIVE_SAMPLE, "invariant"); + success = sample_native_thread(current); + } + if (success) { + num_samples++; + } } + + *last_thread = current; // remember the thread we last attempted to sample } - - *last_thread = current; // remember the thread we last attempted to sample sample_time.stop(); log_trace(jfr)("JFR thread sampling done in %3.7f secs with %d java %d native samples", sample_time.seconds(), type == JAVA_SAMPLE ? num_samples : 0, type == NATIVE_SAMPLE ? num_samples : 0); @@ -297,6 +306,7 @@ class OSThreadSampler : public SuspendedThreadTask { // Sampling a thread in state _thread_in_Java // involves a platform-specific thread suspend and CPU context retrieval. bool JfrSamplerThread::sample_java_thread(JavaThread* jt) { + assert_lock_strong(Threads_lock); if (jt->thread_state() != _thread_in_Java) { return false; } @@ -328,6 +338,7 @@ static JfrSamplerThread* _sampler_thread = nullptr; // without thread suspension and CPU context retrieval, // if we carefully order the loads of the thread state. bool JfrSamplerThread::sample_native_thread(JavaThread* jt) { + assert_lock_strong(Threads_lock); if (jt->thread_state() != _thread_in_native) { return false; } @@ -343,22 +354,6 @@ bool JfrSamplerThread::sample_native_thread(JavaThread* jt) { SafepointMechanism::arm_local_poll_release(jt); - // Take the Threads_lock for two purposes: - // 1) Avoid sampling through a safepoint which could result - // in touching oops in case of virtual threads. - // 2) Prevent JFR from issuing an epoch rotation while the sampler thread - // is actively processing a thread in native, as both threads are now - // outside the safepoint protocol. - - // OrderAccess::fence() as part of acquiring the lock prevents loads from floating up. - JfrMutexTryLock lock(Threads_lock); - - if (!lock.acquired()) { - // Remove the native sample request and release the potentially waiting thread. - JfrSampleMonitor jsm(tl); - return false; - } - // Separate the arming of the poll (above) from the reading of JavaThread state (below). if (UseSystemMemoryBarrier) { SystemMemoryBarrier::emit(); @@ -367,7 +362,6 @@ bool JfrSamplerThread::sample_native_thread(JavaThread* jt) { } if (jt->thread_state() != _thread_in_native || !jt->has_last_Java_frame()) { - assert_lock_strong(Threads_lock); JfrSampleMonitor jsm(tl); if (jsm.is_waiting()) { // The thread has already returned from native, From 4d0ad0a4a391286c683ebb8c8d711ea0be68c31a Mon Sep 17 00:00:00 2001 From: Brent Christian Date: Tue, 13 Jan 2026 19:47:11 +0000 Subject: [PATCH 021/328] 8373718: jdk/internal/misc/VM/RuntimeArguments.java test fails in Virtual threads mode Reviewed-by: alanb --- test/jdk/jdk/internal/misc/VM/RuntimeArguments.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/jdk/internal/misc/VM/RuntimeArguments.java b/test/jdk/jdk/internal/misc/VM/RuntimeArguments.java index dbcb30255a8..b86593d84ba 100644 --- a/test/jdk/jdk/internal/misc/VM/RuntimeArguments.java +++ b/test/jdk/jdk/internal/misc/VM/RuntimeArguments.java @@ -24,6 +24,7 @@ /** * @test * @requires vm.flagless + * @requires test.thread.factory == null * @library /test/lib * @modules java.base/jdk.internal.misc * jdk.zipfs From 9ed0ecbcc1b4796bc56b7cb341ff8f9d3898713d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 13 Jan 2026 22:38:12 +0000 Subject: [PATCH 022/328] 8375061: Multiple jpackage tool providers may share the same logging config Reviewed-by: almatvee --- .../jdk/jpackage/internal/Globals.java | 14 + .../classes/jdk/jpackage/internal/Log.java | 41 +-- .../jdk/jpackage/internal/cli/Main.java | 16 +- .../jpackage/test/JPackageCommandTest.java | 183 +++++++++++++ .../helpers/jdk/jpackage/test/Executor.java | 5 + .../jdk/jpackage/test/JPackageCommand.java | 150 +++++++---- .../helpers/jdk/jpackage/test/Main.java | 55 +++- .../helpers/jdk/jpackage/test/TKit.java | 247 +++++++++--------- .../cli/OptionsValidationFailTest.java | 7 +- .../tools/jdk/jpackage/test/JUnitAdapter.java | 16 +- test/jdk/tools/jpackage/share/AsyncTest.java | 96 +++---- .../jpackage/windows/Win8301247Test.java | 5 +- .../jpackage/windows/WinNoRestartTest.java | 5 +- 13 files changed, 532 insertions(+), 308 deletions(-) create mode 100644 test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JPackageCommandTest.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Globals.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Globals.java index c1b56b24e0a..91ae37870a5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Globals.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Globals.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import java.io.PrintWriter; import java.util.Optional; import java.util.function.Supplier; @@ -46,6 +47,18 @@ public final class Globals { return objectFactory(ObjectFactory.build(objectFactory).executorFactory(v).create()); } + Log.Logger logger() { + return logger; + } + + public void loggerOutputStreams(PrintWriter out, PrintWriter err) { + logger.setPrintWriter(out, err); + } + + public void loggerVerbose() { + logger.setVerbose(); + } + public static int main(Supplier mainBody) { if (INSTANCE.isBound()) { return mainBody.get(); @@ -65,6 +78,7 @@ public final class Globals { } private ObjectFactory objectFactory = ObjectFactory.DEFAULT; + private final Log.Logger logger = new Log.Logger(); private static final ScopedValue INSTANCE = ScopedValue.newInstance(); private static final Globals DEFAULT = new Globals(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Log.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Log.java index 0f51fa166f9..5c27ef67500 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Log.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Log.java @@ -61,16 +61,6 @@ public class Log { this.err = err; } - public void flush() { - if (out != null) { - out.flush(); - } - - if (err != null) { - err.flush(); - } - } - public void info(String msg) { if (out != null) { out.println(msg); @@ -111,46 +101,27 @@ public class Log { } } - private static final InheritableThreadLocal instance = - new InheritableThreadLocal() { - @Override protected Logger initialValue() { - return new Logger(); - } - }; - - public static void setPrintWriter (PrintWriter out, PrintWriter err) { - instance.get().setPrintWriter(out, err); - } - - public static void flush() { - instance.get().flush(); - } - public static void info(String msg) { - instance.get().info(msg); + Globals.instance().logger().info(msg); } public static void fatalError(String msg) { - instance.get().fatalError(msg); + Globals.instance().logger().fatalError(msg); } public static void error(String msg) { - instance.get().error(msg); - } - - public static void setVerbose() { - instance.get().setVerbose(); + Globals.instance().logger().error(msg); } public static boolean isVerbose() { - return instance.get().isVerbose(); + return Globals.instance().logger().isVerbose(); } public static void verbose(String msg) { - instance.get().verbose(msg); + Globals.instance().logger().verbose(msg); } public static void verbose(Throwable t) { - instance.get().verbose(t); + Globals.instance().logger().verbose(t); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java index 31be2bb33c5..270ba0c927f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java @@ -79,8 +79,8 @@ public final class Main { @Override public int run(PrintStream out, PrintStream err, String... args) { - PrintWriter outWriter = new PrintWriter(out, true); - PrintWriter errWriter = new PrintWriter(err, true); + PrintWriter outWriter = toPrintWriter(out); + PrintWriter errWriter = toPrintWriter(err); try { try { return run(outWriter, errWriter, args); @@ -98,8 +98,8 @@ public final class Main { } public static void main(String... args) { - var out = new PrintWriter(System.out, true); - var err = new PrintWriter(System.err, true); + var out = toPrintWriter(System.out); + var err = toPrintWriter(System.err); System.exit(run(out, err, args)); } @@ -127,7 +127,7 @@ public final class Main { Objects.requireNonNull(out); Objects.requireNonNull(err); - Log.setPrintWriter(out, err); + Globals.instance().loggerOutputStreams(out, err); final var runner = new Runner(t -> { new ErrorReporter(_ -> { @@ -179,7 +179,7 @@ public final class Main { } if (VERBOSE.containsIn(options)) { - Log.setVerbose(); + Globals.instance().loggerVerbose(); } final var optionsProcessor = new OptionsProcessor(parsedOptionsBuilder, bundlingEnv); @@ -310,6 +310,10 @@ public final class Main { return System.getProperty("java.version"); } + private static PrintWriter toPrintWriter(PrintStream ps) { + return new PrintWriter(ps, true, ps.charset()); + } + private enum DefaultBundlingEnvironmentLoader implements Supplier { INSTANCE; diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JPackageCommandTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JPackageCommandTest.java new file mode 100644 index 00000000000..b0d44702d47 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JPackageCommandTest.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.spi.ToolProvider; +import jdk.jpackage.internal.util.function.ExceptionBox; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +class JPackageCommandTest extends JUnitAdapter.TestSrcInitializer { + + @ParameterizedTest + @MethodSource + void testUseToolProvider(UseToolProviderTestSpec spec) { + // Run the test with the new state to avoid UnsupportedOperationException + // that will be thrown if it attempts to alter global variables in the default R/O state. + TKit.withNewState(spec::test); + } + + private static List testUseToolProvider() { + + var testCases = new ArrayList(); + + for (var globalToolProvider : ExecutableSetterType.values()) { + for (var instanceToolProvider : ExecutableSetterType.values()) { + testCases.add(new UseToolProviderTestSpec(globalToolProvider, instanceToolProvider)); + } + } + + return testCases; + } + + record UseToolProviderTestSpec(ExecutableSetterType globalType, ExecutableSetterType instanceType) { + + UseToolProviderTestSpec { + Objects.requireNonNull(globalType); + Objects.requireNonNull(instanceType); + } + + @Override + public String toString() { + return String.format("%s, global=%s", instanceType, globalType); + } + + void test() { + + final Optional global; + switch (globalType) { + case SET_CUSTOM_TOOL_PROVIDER -> { + global = Optional.of(createNewToolProvider("jpackage-mock-global")); + JPackageCommand.useToolProviderByDefault(global.get()); + } + case SET_DEFAULT_TOOL_PROVIDER -> { + global = Optional.of(JavaTool.JPACKAGE.asToolProvider()); + JPackageCommand.useToolProviderByDefault(); + } + case SET_PROCESS -> { + global = Optional.empty(); + JPackageCommand.useExecutableByDefault(); + } + case SET_NONE -> { + global = Optional.empty(); + } + default -> { + throw ExceptionBox.reachedUnreachable(); + } + } + + var cmd = new JPackageCommand(); + + final Optional instance; + switch (instanceType) { + case SET_CUSTOM_TOOL_PROVIDER -> { + instance = Optional.of(createNewToolProvider("jpackage-mock")); + cmd.useToolProvider(instance.get()); + } + case SET_DEFAULT_TOOL_PROVIDER -> { + instance = Optional.of(JavaTool.JPACKAGE.asToolProvider()); + cmd.useToolProvider(true); + } + case SET_PROCESS -> { + instance = Optional.empty(); + cmd.useToolProvider(false); + } + case SET_NONE -> { + instance = Optional.empty(); + } + default -> { + throw ExceptionBox.reachedUnreachable(); + } + } + + var actual = cmd.createExecutor().getToolProvider(); + + switch (instanceType) { + case SET_CUSTOM_TOOL_PROVIDER -> { + assertSame(actual.get(), instance.get()); + assertTrue(cmd.isWithToolProvider()); + } + case SET_DEFAULT_TOOL_PROVIDER -> { + global.ifPresentOrElse(expected -> { + assertEquals(expected.name(), actual.orElseThrow().name()); + }, () -> { + assertEquals(instance.get().name(), actual.get().name()); + }); + assertTrue(cmd.isWithToolProvider()); + } + case SET_PROCESS -> { + assertFalse(actual.isPresent()); + assertFalse(cmd.isWithToolProvider()); + } + case SET_NONE -> { + switch (globalType) { + case SET_CUSTOM_TOOL_PROVIDER -> { + assertSame(global.get(), actual.get()); + assertTrue(cmd.isWithToolProvider()); + } + case SET_DEFAULT_TOOL_PROVIDER -> { + assertEquals(global.get().name(), actual.orElseThrow().name()); + assertTrue(cmd.isWithToolProvider()); + } + case SET_PROCESS, SET_NONE -> { + assertFalse(actual.isPresent()); + assertFalse(cmd.isWithToolProvider()); + } + } + } + } + } + + private static ToolProvider createNewToolProvider(String name) { + return new ToolProvider() { + @Override + public int run(PrintWriter out, PrintWriter err, String... args) { + throw new UnsupportedOperationException(); + } + + @Override + public String name() { + return name; + } + }; + } + } + + enum ExecutableSetterType { + SET_DEFAULT_TOOL_PROVIDER, + SET_CUSTOM_TOOL_PROVIDER, + SET_PROCESS, + SET_NONE, + ; + } +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java index 6e94133a543..d4833eb9736 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -63,6 +63,7 @@ public final class Executor extends CommandArguments { } public Executor() { + commandOutputControl.dumpStdout(TKit.state().out()).dumpStderr(TKit.state().err()); } public Executor setExecutable(String v) { @@ -85,6 +86,10 @@ public final class Executor extends CommandArguments { return setToolProvider(v.asToolProvider()); } + public Optional getToolProvider() { + return Optional.ofNullable(toolProvider); + } + public Optional getExecutable() { return Optional.ofNullable(executable); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 9cfb75bcdb3..d2b423b2ed2 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -52,8 +52,6 @@ import java.util.Optional; import java.util.OptionalInt; import java.util.Set; import java.util.TreeSet; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -63,6 +61,7 @@ import java.util.spi.ToolProvider; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import jdk.jpackage.internal.util.function.ExceptionBox; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.internal.util.function.ThrowingFunction; import jdk.jpackage.internal.util.function.ThrowingRunnable; @@ -77,6 +76,7 @@ public class JPackageCommand extends CommandArguments { @SuppressWarnings("this-escape") public JPackageCommand() { + toolProviderSource = new ToolProviderSource(); prerequisiteActions = new Actions(); verifyActions = new Actions(); excludeStandardAsserts(StandardAssert.MAIN_LAUNCHER_DESCRIPTION); @@ -84,7 +84,7 @@ public class JPackageCommand extends CommandArguments { private JPackageCommand(JPackageCommand cmd, boolean immutable) { args.addAll(cmd.args); - withToolProvider = cmd.withToolProvider; + toolProviderSource = cmd.toolProviderSource.copy(); saveConsoleOutput = cmd.saveConsoleOutput; discardStdout = cmd.discardStdout; discardStderr = cmd.discardStderr; @@ -770,7 +770,7 @@ public class JPackageCommand extends CommandArguments { } public static void useToolProviderByDefault(ToolProvider jpackageToolProvider) { - defaultToolProvider.set(Optional.of(jpackageToolProvider)); + TKit.state().setProperty(DefaultToolProviderKey.VALUE, Objects.requireNonNull(jpackageToolProvider)); } public static void useToolProviderByDefault() { @@ -778,45 +778,22 @@ public class JPackageCommand extends CommandArguments { } public static void useExecutableByDefault() { - defaultToolProvider.set(Optional.empty()); - } - - /** - * In a separate thread calls {@link #useToolProviderByDefault(ToolProvider)} - * with the specified {@code jpackageToolProvider} and then calls - * {@code workload.run()}. Joins the thread. - *

- * The idea is to run the {@code workload} in the context of the specified - * jpackage {@code ToolProvider} without altering the global variable holding - * the default jpackage {@code ToolProvider}. The global variable is - * thread-local; setting its value in a new thread doesn't alter its copy in the - * calling thread. - * - * @param jpackageToolProvider jpackage {@code ToolProvider} - * @param workload the workload to run - */ - public static void withToolProvider(Runnable workload, ToolProvider jpackageToolProvider) { - Objects.requireNonNull(workload); - Objects.requireNonNull(jpackageToolProvider); - - CompletableFuture.runAsync(() -> { - var oldValue = defaultToolProvider.get(); - useToolProviderByDefault(jpackageToolProvider); - try { - workload.run(); - } finally { - defaultToolProvider.set(oldValue); - } - // Run the future in a new native thread. Don't run it in a virtual/pooled thread. - // Pooled and/or virtual threads are problematic when used with inheritable thread-local variables. - // TKit class depends on such a variable, which results in intermittent test failures - // if the default executor runs this future. - }, Executors.newThreadPerTaskExecutor(Thread.ofPlatform().factory())).join(); + TKit.state().setProperty(DefaultToolProviderKey.VALUE, null); } public JPackageCommand useToolProvider(boolean v) { verifyMutable(); - withToolProvider = v; + if (v) { + toolProviderSource.useDefaultToolProvider(); + } else { + toolProviderSource.useProcess(); + } + return this; + } + + public JPackageCommand useToolProvider(ToolProvider v) { + verifyMutable(); + toolProviderSource.useToolProvider(v); return this; } @@ -928,9 +905,7 @@ public class JPackageCommand extends CommandArguments { } public boolean isWithToolProvider() { - return Optional.ofNullable(withToolProvider).orElseGet(() -> { - return defaultToolProvider.get().isPresent(); - }); + return toolProviderSource.toolProvider().isPresent(); } public JPackageCommand executePrerequisiteActions() { @@ -938,21 +913,19 @@ public class JPackageCommand extends CommandArguments { return this; } - private Executor createExecutor() { + Executor createExecutor() { Executor exec = new Executor() .saveOutput(saveConsoleOutput).dumpOutput(!suppressOutput) .discardStdout(discardStdout).discardStderr(discardStderr) .setDirectory(executeInDirectory) .addArguments(args); - if (isWithToolProvider()) { - exec.setToolProvider(defaultToolProvider.get().orElseGet(JavaTool.JPACKAGE::asToolProvider)); - } else { - exec.setExecutable(JavaTool.JPACKAGE); - if (TKit.isWindows()) { - exec.setWindowsTmpDir(System.getProperty("java.io.tmpdir")); - } - } + toolProviderSource.toolProvider().ifPresentOrElse(exec::setToolProvider, () -> { + exec.setExecutable(JavaTool.JPACKAGE); + if (TKit.isWindows()) { + exec.setWindowsTmpDir(System.getProperty("java.io.tmpdir")); + } + }); return exec; } @@ -1731,7 +1704,70 @@ public class JPackageCommand extends CommandArguments { private final List actions; } - private Boolean withToolProvider; + private static final class ToolProviderSource { + + ToolProviderSource copy() { + return new ToolProviderSource(this); + } + + void useDefaultToolProvider() { + customToolProvider = null; + mode = Mode.USE_TOOL_PROVIDER; + } + + void useToolProvider(ToolProvider tp) { + customToolProvider = Objects.requireNonNull(tp); + mode = Mode.USE_TOOL_PROVIDER; + } + + void useProcess() { + customToolProvider = null; + mode = Mode.USE_PROCESS; + } + + Optional toolProvider() { + switch (mode) { + case USE_PROCESS -> { + return Optional.empty(); + } + case USE_TOOL_PROVIDER -> { + if (customToolProvider != null) { + return Optional.of(customToolProvider); + } else { + return TKit.state().findProperty(DefaultToolProviderKey.VALUE).map(ToolProvider.class::cast).or(() -> { + return Optional.of(JavaTool.JPACKAGE.asToolProvider()); + }); + } + } + case INHERIT_DEFAULTS -> { + return TKit.state().findProperty(DefaultToolProviderKey.VALUE).map(ToolProvider.class::cast); + } + default -> { + throw ExceptionBox.reachedUnreachable(); + } + } + } + + ToolProviderSource() { + mode = Mode.INHERIT_DEFAULTS; + } + + private ToolProviderSource(ToolProviderSource other) { + this.customToolProvider = other.customToolProvider; + this.mode = other.mode; + } + + private enum Mode { + INHERIT_DEFAULTS, + USE_PROCESS, + USE_TOOL_PROVIDER + } + + private ToolProvider customToolProvider; + private Mode mode; + } + + private final ToolProviderSource toolProviderSource; private boolean saveConsoleOutput; private boolean discardStdout; private boolean discardStderr; @@ -1747,12 +1783,10 @@ public class JPackageCommand extends CommandArguments { private Set readOnlyPathAsserts = Set.of(ReadOnlyPathAssert.values()); private Set standardAsserts = Set.of(StandardAssert.values()); private List>> outputValidators = new ArrayList<>(); - private static InheritableThreadLocal> defaultToolProvider = new InheritableThreadLocal<>() { - @Override - protected Optional initialValue() { - return Optional.empty(); - } - }; + + private enum DefaultToolProviderKey { + VALUE + } private static final Map PACKAGE_TYPES = Stream.of(PackageType.values()).collect(toMap(PackageType::getType, x -> x)); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java index fee5b65c897..c0bc858eb1e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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,17 +27,24 @@ import static java.util.stream.Collectors.toCollection; import static java.util.stream.Collectors.toMap; import static jdk.jpackage.test.TestBuilder.CMDLINE_ARG_PREFIX; +import java.io.IOException; +import java.io.PrintStream; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Comparator; import java.util.Deque; import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; import jdk.jpackage.internal.util.function.ExceptionBox; +import jdk.jpackage.internal.util.function.ThrowingRunnable; public final class Main { @@ -47,10 +54,52 @@ public final class Main { } public static void main(TestBuilder.Builder builder, String... args) throws Exception { + Objects.requireNonNull(builder); + + var argList = List.of(args); + + var ignoreLogfile = argList.contains(CMDLINE_ARG_PREFIX + "ignore-logfile"); + + List filteredArgs; + if (ignoreLogfile) { + filteredArgs = argList.stream().filter(Predicate.isEqual(CMDLINE_ARG_PREFIX + "ignore-logfile").negate()).toList(); + } else { + filteredArgs = argList; + } + + ThrowingRunnable workload = () -> { + run(builder, filteredArgs); + }; + + try { + Optional.ofNullable(TKit.getConfigProperty("logfile")).filter(_ -> { + return !ignoreLogfile; + }).map(Path::of).ifPresentOrElse(logfile -> { + + try (var out = new PrintStream( + Files.newOutputStream(logfile, StandardOpenOption.CREATE, StandardOpenOption.APPEND), + true, + System.out.charset())) { + + TKit.withOutput(workload, out, out); + + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + + }, () -> { + ThrowingRunnable.toRunnable(workload).run(); + }); + } catch (Exception ex) { + throw ExceptionBox.unbox(ex); + } + } + + private static void run(TestBuilder.Builder builder, List args) throws Exception { boolean listTests = false; List tests = new ArrayList<>(); try (TestBuilder testBuilder = builder.testConsumer(tests::add).create()) { - Deque argsAsList = new ArrayDeque<>(List.of(args)); + Deque argsAsList = new ArrayDeque<>(args); while (!argsAsList.isEmpty()) { var arg = argsAsList.pop(); TestBuilder.trace(String.format("Parsing [%s]...", arg)); @@ -115,7 +164,7 @@ public final class Main { return; } - TKit.withExtraLogStream(() -> runTests(orderedTests)); + runTests(orderedTests); } private static void runTests(List tests) { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index 47ab838f8d6..1639beadb28 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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 @@ -38,7 +38,6 @@ import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import java.nio.file.StandardOpenOption; import java.nio.file.StandardWatchEventKinds; import java.nio.file.WatchEvent; import java.nio.file.WatchKey; @@ -52,6 +51,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -109,56 +109,45 @@ public final class TKit { throw throwUnknownPlatformError(); }).get(); - static void withExtraLogStream(ThrowingRunnable action) { - if (state().extraLogStream != null) { - ThrowingRunnable.toRunnable(action).run(); - } else { - try (PrintStream logStream = openLogStream()) { - withExtraLogStream(action, logStream); + public static void withOutput(ThrowingRunnable action, PrintStream out, PrintStream err) { + Objects.requireNonNull(action); + Objects.requireNonNull(out); + Objects.requireNonNull(err); + + try { + withState(action, stateBuilder -> { + stateBuilder.out(out).err(err); + }); + } finally { + try { + out.flush(); + } finally { + err.flush(); } } } - static void withExtraLogStream(ThrowingRunnable action, PrintStream logStream) { - withNewState(action, stateBuilder -> { - stateBuilder.extraLogStream(logStream); - }); - } - - public static void withMainLogStream(ThrowingRunnable action, PrintStream logStream) { - withNewState(action, stateBuilder -> { - stateBuilder.mainLogStream(logStream); - }); - } - - public static void withStackTraceStream(ThrowingRunnable action, PrintStream logStream) { - withNewState(action, stateBuilder -> { - stateBuilder.stackTraceStream(logStream); - }); - } - - public static State state() { - return STATE.get(); - } - - public static void state(State v) { - STATE.set(Objects.requireNonNull(v)); - } - - private static void withNewState(ThrowingRunnable action, Consumer stateBuilderMutator) { + public static void withState(ThrowingRunnable action, Consumer stateBuilderMutator) { Objects.requireNonNull(action); Objects.requireNonNull(stateBuilderMutator); - var oldState = state(); - var builder = oldState.buildCopy(); - stateBuilderMutator.accept(builder); - var newState = builder.create(); - try { - state(newState); - ThrowingRunnable.toRunnable(action).run(); - } finally { - state(oldState); - } + var stateBuilder = state().buildCopy(); + stateBuilderMutator.accept(stateBuilder); + withState(action, stateBuilder.create()); + } + + public static void withNewState(ThrowingRunnable action) { + withState(action, _ -> {}); + } + + public static void withState(ThrowingRunnable action, State state) { + Objects.requireNonNull(action); + Objects.requireNonNull(state); + ScopedValue.where(STATE, state).run(ThrowingRunnable.toRunnable(action)); + } + + public static State state() { + return STATE.orElse(DEFAULT_STATE); } enum RunTestMode { @@ -178,33 +167,19 @@ public final class TKit { throw new IllegalStateException("Unexpected nested Test.run() call"); } - withExtraLogStream(() -> { - tests.stream().forEach(test -> { - withNewState(() -> { - try { - if (modes.contains(RunTestMode.FAIL_FAST)) { - test.run(); - } else { - ignoreExceptions(test).run(); - } - } finally { - Optional.ofNullable(state().extraLogStream).ifPresent(PrintStream::flush); - } - }, stateBuilder -> { - stateBuilder.currentTest(test); - }); + tests.stream().forEach(test -> { + withState(() -> { + if (modes.contains(RunTestMode.FAIL_FAST)) { + test.run(); + } else { + ignoreExceptions(test).run(); + } + }, stateBuilder -> { + stateBuilder.currentTest(test); }); }); } - static T runAdhocTest(ThrowingSupplier action) { - final List box = new ArrayList<>(); - runAdhocTest(() -> { - box.add(action.get()); - }); - return box.getFirst(); - } - static void runAdhocTest(ThrowingRunnable action) { Objects.requireNonNull(action); @@ -281,10 +256,7 @@ public final class TKit { static void log(String v) { v = addTimestamp(v); var state = state(); - state.mainLogStream.println(v); - if (state.extraLogStream != null) { - state.extraLogStream.println(v); - } + state.out.println(v); } static Path removeRootFromAbsolutePath(Path v) { @@ -692,8 +664,7 @@ public final class TKit { static void printStackTrace(Throwable throwable) { var state = state(); - Optional.ofNullable(state.extraLogStream).ifPresent(throwable::printStackTrace); - throwable.printStackTrace(state.stackTraceStream); + throwable.printStackTrace(state.err); } private static String concatMessages(String msg, String msg2) { @@ -1255,16 +1226,6 @@ public final class TKit { return new TextStreamVerifier(what); } - private static PrintStream openLogStream() { - return state().logFile.map(logfile -> { - try { - return Files.newOutputStream(logfile, StandardOpenOption.CREATE, StandardOpenOption.APPEND); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - }).map(PrintStream::new).orElse(null); - } - public record PathSnapshot(List contentHashes) { public PathSnapshot { contentHashes.forEach(Objects::requireNonNull); @@ -1376,25 +1337,23 @@ public final class TKit { public static final class State { private State( - Optional logFile, TestInstance currentTest, - PrintStream mainLogStream, - PrintStream stackTraceStream, - PrintStream extraLogStream, + PrintStream out, + PrintStream err, + Map properties, boolean trace, boolean traceAsserts, boolean verboseJPackage, boolean verboseTestSetup) { - Objects.requireNonNull(logFile); - Objects.requireNonNull(mainLogStream); - Objects.requireNonNull(stackTraceStream); + Objects.requireNonNull(out); + Objects.requireNonNull(err); + Objects.requireNonNull(properties); - this.logFile = logFile; this.currentTest = currentTest; - this.mainLogStream = mainLogStream; - this.stackTraceStream = stackTraceStream; - this.extraLogStream = extraLogStream; + this.out = out; + this.err = err; + this.properties = Collections.synchronizedMap(properties); this.trace = trace; this.traceAsserts = traceAsserts; @@ -1403,11 +1362,30 @@ public final class TKit { this.verboseTestSetup = verboseTestSetup; } - Builder buildCopy() { return build().initFrom(this); } + PrintStream out() { + return out; + } + + PrintStream err() { + return err; + } + + Optional findProperty(Object key) { + return Optional.ofNullable(properties.get(Objects.requireNonNull(key))); + } + + void setProperty(Object key, Object value) { + if (value == null) { + properties.remove(Objects.requireNonNull(key)); + } else { + properties.put(Objects.requireNonNull(key), value); + } + } + static Builder build() { return new Builder(); } @@ -1416,11 +1394,9 @@ public final class TKit { static final class Builder { Builder initDefaults() { - logFile = Optional.ofNullable(getConfigProperty("logfile")).map(Path::of); currentTest = null; - mainLogStream = System.out; - stackTraceStream = System.err; - extraLogStream = null; + out = System.out; + err = System.err; var logOptions = tokenizeConfigProperty("suppress-logging"); if (logOptions == null) { @@ -1444,15 +1420,17 @@ public final class TKit { verboseTestSetup = isNonOf.test(Set.of("init", "i")); } + mutable = true; + return this; } Builder initFrom(State state) { - logFile = state.logFile; currentTest = state.currentTest; - mainLogStream = state.mainLogStream; - stackTraceStream = state.stackTraceStream; - extraLogStream = state.extraLogStream; + out = state.out; + err = state.err; + properties.clear(); + properties.putAll(state.properties); trace = state.trace; traceAsserts = state.traceAsserts; @@ -1463,54 +1441,67 @@ public final class TKit { return this; } - Builder logFile(Optional v) { - logFile = v; - return this; - } - Builder currentTest(TestInstance v) { currentTest = v; return this; } - Builder mainLogStream(PrintStream v) { - mainLogStream = v; + Builder out(PrintStream v) { + out = v; return this; } - Builder stackTraceStream(PrintStream v) { - stackTraceStream = v; + Builder err(PrintStream v) { + err = v; return this; } - Builder extraLogStream(PrintStream v) { - extraLogStream = v; + Builder property(Object key, Object value) { + if (value == null) { + properties.remove(Objects.requireNonNull(key)); + } else { + properties.put(Objects.requireNonNull(key), value); + } + return this; + } + + Builder mutable(boolean v) { + mutable = v; return this; } State create() { - return new State(logFile, currentTest, mainLogStream, stackTraceStream, extraLogStream, trace, traceAsserts, verboseJPackage, verboseTestSetup); + return new State( + currentTest, + out, + err, + mutable ? new HashMap<>(properties) : Map.copyOf(properties), + trace, + traceAsserts, + verboseJPackage, + verboseTestSetup); } - private Optional logFile; private TestInstance currentTest; - private PrintStream mainLogStream; - private PrintStream stackTraceStream; - private PrintStream extraLogStream; + private PrintStream out; + private PrintStream err; + private Map properties = new HashMap<>(); private boolean trace; private boolean traceAsserts; private boolean verboseJPackage; private boolean verboseTestSetup; + + private boolean mutable = true; } - private final Optional logFile; private final TestInstance currentTest; - private final PrintStream mainLogStream; - private final PrintStream stackTraceStream; - private final PrintStream extraLogStream; + private final PrintStream out; + private final PrintStream err; + + private final Map properties; private final boolean trace; private final boolean traceAsserts; @@ -1520,10 +1511,6 @@ public final class TKit { } - private static final InheritableThreadLocal STATE = new InheritableThreadLocal<>() { - @Override - protected State initialValue() { - return State.build().initDefaults().create(); - } - }; + private static final ScopedValue STATE = ScopedValue.newInstance(); + private static final State DEFAULT_STATE = State.build().initDefaults().mutable(false).create(); } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.java index e15d5130d43..9826f0e9069 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -200,13 +200,14 @@ public class OptionsValidationFailTest { Stream.of("--jpt-run=ErrorTest") ).flatMap(x -> x).toArray(String[]::new)).map(dynamicTest -> { return DynamicTest.dynamicTest(dynamicTest.getDisplayName(), () -> { - JPackageCommand.withToolProvider(() -> { + TKit.withNewState(() -> { + JPackageCommand.useToolProviderByDefault(jpackageToolProviderMock); try { dynamicTest.getExecutable().execute(); } catch (Throwable t) { throw ExceptionBox.toUnchecked(ExceptionBox.unbox(t)); } - }, jpackageToolProviderMock); + }); }); }); } diff --git a/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitAdapter.java b/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitAdapter.java index 952b4b520d5..4ab2c89873c 100644 --- a/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitAdapter.java +++ b/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -29,11 +29,11 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.UncheckedIOException; -import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; +import jdk.jpackage.internal.util.TeeOutputStream; import jdk.jpackage.internal.util.function.ThrowingRunnable; import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.TestFactory; @@ -70,12 +70,16 @@ public class JUnitAdapter { static List captureJPackageTestLog(ThrowingRunnable runnable) { final var buf = new ByteArrayOutputStream(); - try (PrintStream ps = new PrintStream(buf, true, StandardCharsets.UTF_8)) { - TKit.withExtraLogStream(runnable, ps); - } + var ps = new PrintStream(buf, false, TKit.state().out().charset()); + + final var out = new PrintStream(new TeeOutputStream(List.of(TKit.state().out(), ps)), true, ps.charset()); + + TKit.withOutput(runnable, out, TKit.state().err()); + + ps.flush(); try (final var in = new ByteArrayInputStream(buf.toByteArray()); - final var reader = new InputStreamReader(in, StandardCharsets.UTF_8); + final var reader = new InputStreamReader(in, ps.charset()); final var bufReader = new BufferedReader(reader)) { return bufReader.lines().map(line -> { // Skip timestamp diff --git a/test/jdk/tools/jpackage/share/AsyncTest.java b/test/jdk/tools/jpackage/share/AsyncTest.java index e3a3f7e3cb8..b7dd13f91fa 100644 --- a/test/jdk/tools/jpackage/share/AsyncTest.java +++ b/test/jdk/tools/jpackage/share/AsyncTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,6 @@ import java.io.ByteArrayOutputStream; import java.io.PrintStream; -import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.Collection; @@ -34,15 +33,12 @@ import java.util.concurrent.Callable; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; -import java.util.spi.ToolProvider; import java.util.stream.IntStream; -import jdk.jpackage.internal.util.function.ThrowingRunnable; import jdk.jpackage.internal.util.Slot; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.HelloApp; import jdk.jpackage.test.JPackageCommand; -import jdk.jpackage.test.JavaTool; import jdk.jpackage.test.JavaAppDesc; import jdk.jpackage.test.Main; import jdk.jpackage.test.PackageTest; @@ -66,10 +62,10 @@ public class AsyncTest { // Create test jar only once. // Besides of saving time, this avoids asynchronous invocations of java tool provider that randomly fail. - APP_JAR.set(HelloApp.createBundle(JavaAppDesc.parse("Hello!"), TKit.workDir())); + var appJar = HelloApp.createBundle(JavaAppDesc.parse("Hello!"), TKit.workDir()); // - // Run test cases from InternalAsyncTest class asynchronously. + // Run test cases from AsyncInnerTest class asynchronously. // Spawn a thread for every test case. // Input data for test cases will be cooked asynchronously but in a safe way because every test case has an isolated work directory. // Multiple jpackage tool provider instances will be invoked asynchronously. @@ -79,14 +75,10 @@ public class AsyncTest { var testFuncNames = List.of("testAppImage", "testNativeBundle"); - var runArg = String.format("--jpt-run=%s", AsyncInnerTest.class.getName()); - var futures = executor.invokeAll(IntStream.range(0, JOB_COUNT).mapToObj(Integer::toString).mapMulti((idx, consumer) -> { for (var testFuncName : testFuncNames) { var id = String.format("%s(%s)", testFuncName, idx); - consumer.accept(new Workload(() -> { - Main.main(runArg, String.format("--jpt-include=%s", id)); - }, id)); + consumer.accept(new Workload(id, appJar)); } }).toList()); @@ -99,10 +91,8 @@ public class AsyncTest { for (var future : futures) { var result = future.get(); - TKit.trace(String.format("[%s] STDOUT BEGIN\n%s", result.id(), result.stdoutBuffer())); - TKit.trace(String.format("[%s] STDOUT END", result.id())); - TKit.trace(String.format("[%s] STDERR BEGIN\n%s", result.id(), result.stderrBuffer())); - TKit.trace(String.format("[%s] STDERR END", result.id())); + TKit.trace(String.format("[%s] OUTPUT BEGIN\n%s", result.testCaseId(), result.testOutput())); + TKit.trace(String.format("[%s] OUTPUT END", result.testCaseId())); result.exception().filter(Predicate.not(TKit::isSkippedException)).ifPresent(fatalError::set); } @@ -142,80 +132,56 @@ public class AsyncTest { } - private record Result(String stdoutBuffer, String stderrBuffer, String id, Optional exception) { + private record Result(String testOutput, String testCaseId, Optional exception) { Result { - Objects.requireNonNull(stdoutBuffer); - Objects.requireNonNull(stderrBuffer); - Objects.requireNonNull(id); + Objects.requireNonNull(testOutput); + Objects.requireNonNull(testCaseId); Objects.requireNonNull(exception); } } private record Workload( - ByteArrayOutputStream stdoutBuffer, - ByteArrayOutputStream stderrBuffer, - ThrowingRunnable runnable, - String id) implements Callable { + String testCaseId, + ByteArrayOutputStream outputSink, + Path appJar) implements Callable { Workload { - Objects.requireNonNull(stdoutBuffer); - Objects.requireNonNull(stderrBuffer); - Objects.requireNonNull(runnable); - Objects.requireNonNull(id); + Objects.requireNonNull(testCaseId); + Objects.requireNonNull(outputSink); + Objects.requireNonNull(appJar); } - Workload(ThrowingRunnable runnable, String id) { - this(new ByteArrayOutputStream(), new ByteArrayOutputStream(), runnable, id); + Workload(String testCaseId, Path appJar) { + this(testCaseId, new ByteArrayOutputStream(), appJar); } - private String stdoutBufferAsString() { - return new String(stdoutBuffer.toByteArray(), StandardCharsets.UTF_8); - } - - private String stderrBufferAsString() { - return new String(stderrBuffer.toByteArray(), StandardCharsets.UTF_8); + private String testOutput() { + return new String(outputSink.toByteArray(), StandardCharsets.UTF_8); } @Override public Result call() { - // Reset the current test inherited in the state from the parent thread. - TKit.state(DEFAULT_STATE); - - var defaultToolProvider = JavaTool.JPACKAGE.asToolProvider(); - - JPackageCommand.useToolProviderByDefault(new ToolProvider() { - - @Override - public int run(PrintWriter out, PrintWriter err, String... args) { - try (var bufOut = new PrintWriter(stdoutBuffer, true, StandardCharsets.UTF_8); - var bufErr = new PrintWriter(stderrBuffer, true, StandardCharsets.UTF_8)) { - return defaultToolProvider.run(bufOut, bufErr, args); - } - } - - @Override - public String name() { - return defaultToolProvider.name(); - } - }); + var runArg = String.format("--jpt-run=%s", AsyncInnerTest.class.getName()); Optional err = Optional.empty(); - try (var bufOut = new PrintStream(stdoutBuffer, true, StandardCharsets.UTF_8); - var bufErr = new PrintStream(stderrBuffer, true, StandardCharsets.UTF_8)) { - TKit.withStackTraceStream(() -> { - TKit.withMainLogStream(runnable, bufOut); - }, bufErr); + try { + try (var out = new PrintStream(outputSink, false, System.out.charset())) { + ScopedValue.where(APP_JAR, appJar).run(() -> { + TKit.withOutput(() -> { + JPackageCommand.useToolProviderByDefault(); + Main.main("--jpt-ignore-logfile", runArg, String.format("--jpt-include=%s", testCaseId)); + }, out, out); + }); + } } catch (Exception ex) { err = Optional.of(ex); } - return new Result(stdoutBufferAsString(), stderrBufferAsString(), id, err); + return new Result(testOutput(), testCaseId, err); } } - private static final int JOB_COUNT = 30; - private static final TKit.State DEFAULT_STATE = TKit.state(); - private static final InheritableThreadLocal APP_JAR = new InheritableThreadLocal<>(); + private static final ScopedValue APP_JAR = ScopedValue.newInstance(); } diff --git a/test/jdk/tools/jpackage/windows/Win8301247Test.java b/test/jdk/tools/jpackage/windows/Win8301247Test.java index 3cdd9810d0f..bed795281f4 100644 --- a/test/jdk/tools/jpackage/windows/Win8301247Test.java +++ b/test/jdk/tools/jpackage/windows/Win8301247Test.java @@ -56,11 +56,14 @@ public class Win8301247Test { cmd.addArguments("--java-options", "-Djpackage.test.noexit=true"); cmd.executeAndAssertImageCreated(); + var state = TKit.state(); var f = new CompletableFuture(); // Launch the app in a separate thread new Thread(() -> { - HelloApp.assertMainLauncher(cmd).get().processListener(f::complete).execute(); + TKit.withState(() -> { + HelloApp.assertMainLauncher(cmd).get().processListener(f::complete).execute(); + }, state); }).start(); var mainLauncherProcess = f.get(); diff --git a/test/jdk/tools/jpackage/windows/WinNoRestartTest.java b/test/jdk/tools/jpackage/windows/WinNoRestartTest.java index 984ddfcdf06..7390b2f79a3 100644 --- a/test/jdk/tools/jpackage/windows/WinNoRestartTest.java +++ b/test/jdk/tools/jpackage/windows/WinNoRestartTest.java @@ -95,11 +95,14 @@ public class WinNoRestartTest { // Save updated main launcher .cfg file cfgFile.save(cmd.appLauncherCfgPath(null)); + var state = TKit.state(); var f = new CompletableFuture(); // Launch the app in a separate thread new Thread(() -> { - HelloApp.assertMainLauncher(cmd).get().processListener(f::complete).execute(); + TKit.withState(() -> { + HelloApp.assertMainLauncher(cmd).get().processListener(f::complete).execute(); + }, state); }).start(); var mainLauncherProcess = f.get(); From 0d19d91b44e5232dbd99d34dcdf6500f892e3048 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Tue, 13 Jan 2026 23:48:14 +0000 Subject: [PATCH 023/328] 8369048: GenShen: Defer ShenFreeSet::available() during rebuild Reviewed-by: wkemper, ysr --- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 11 ++- .../share/gc/shenandoah/shenandoahFreeSet.hpp | 74 +++++++++++++------ .../share/gc/shenandoah/shenandoahFullGC.cpp | 21 +++--- .../gc/shenandoah/shenandoahGeneration.cpp | 3 +- .../share/gc/shenandoah/shenandoahHeap.cpp | 16 ++-- .../share/gc/shenandoah/shenandoahMetrics.cpp | 5 +- .../gc/shenandoah/shenandoahOldGeneration.cpp | 7 +- 7 files changed, 84 insertions(+), 53 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index c03e66e28da..a8c97801824 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -338,7 +338,7 @@ void ShenandoahRegionPartitions::make_all_regions_unavailable() { _empty_region_counts[partition_id] = 0; _used[partition_id] = 0; _humongous_waste[partition_id] = 0; - _available[partition_id] = FreeSetUnderConstruction; + _available[partition_id] = 0; } } @@ -2495,6 +2495,10 @@ void ShenandoahFreeSet::move_regions_from_collector_to_mutator(size_t max_xfer_r void ShenandoahFreeSet::prepare_to_rebuild(size_t &young_trashed_regions, size_t &old_trashed_regions, size_t &first_old_region, size_t &last_old_region, size_t &old_region_count) { shenandoah_assert_heaplocked(); + assert(rebuild_lock() != nullptr, "sanity"); + rebuild_lock()->lock(false); + // This resets all state information, removing all regions from all sets. + clear(); log_debug(gc, free)("Rebuilding FreeSet"); // This places regions that have alloc_capacity into the old_collector set if they identify as is_old() or the @@ -2524,6 +2528,9 @@ void ShenandoahFreeSet::finish_rebuild(size_t young_trashed_regions, size_t old_ _total_young_regions = _heap->num_regions() - old_region_count; _total_global_regions = _heap->num_regions(); establish_old_collector_alloc_bias(); + + // Release the rebuild lock now. What remains in this function is read-only + rebuild_lock()->unlock(); _partitions.assert_bounds(true); log_status(); } @@ -3058,7 +3065,7 @@ void ShenandoahFreeSet::log_status() { size_t max_humongous = max_contig * ShenandoahHeapRegion::region_size_bytes(); // capacity() is capacity of mutator // used() is used of mutator - size_t free = capacity() - used(); + size_t free = capacity_holding_lock() - used_holding_lock(); // Since certain regions that belonged to the Mutator free partition at the time of most recent rebuild may have been // retired, the sum of used and capacities within regions that are still in the Mutator free partition may not match // my internally tracked values of used() and free(). diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index 95f9fbe6856..364637740f2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -28,9 +28,13 @@ #include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahHeapRegionSet.hpp" +#include "gc/shenandoah/shenandoahLock.hpp" #include "gc/shenandoah/shenandoahSimpleBitMap.hpp" #include "logging/logStream.hpp" +typedef ShenandoahLock ShenandoahRebuildLock; +typedef ShenandoahLocker ShenandoahRebuildLocker; + // Each ShenandoahHeapRegion is associated with a ShenandoahFreeSetPartitionId. enum class ShenandoahFreeSetPartitionId : uint8_t { Mutator, // Region is in the Mutator free set: available memory is available to mutators. @@ -139,8 +143,6 @@ public: ShenandoahRegionPartitions(size_t max_regions, ShenandoahFreeSet* free_set); ~ShenandoahRegionPartitions() {} - static const size_t FreeSetUnderConstruction = SIZE_MAX; - inline idx_t max() const { return _max; } // At initialization, reset OldCollector tallies @@ -352,6 +354,16 @@ public: return _available[int(which_partition)]; } + // Return available_in assuming caller does not hold the heap lock but does hold the rebuild_lock. + // The returned value may be "slightly stale" because we do not assure that every fetch of this value + // sees the most recent update of this value. Requiring the caller to hold the rebuild_lock assures + // that we don't see "bogus" values that are "worse than stale". During rebuild of the freeset, the + // value of _available is not reliable. + inline size_t available_in_locked_for_rebuild(ShenandoahFreeSetPartitionId which_partition) const { + assert (which_partition < NumPartitions, "selected free set must be valid"); + return _available[int(which_partition)]; + } + // Returns bytes of humongous waste inline size_t humongous_waste(ShenandoahFreeSetPartitionId which_partition) const { assert (which_partition < NumPartitions, "selected free set must be valid"); @@ -359,23 +371,6 @@ public: return _humongous_waste[int(which_partition)]; } - // Return available_in assuming caller does not hold the heap lock. In production builds, available is - // returned without acquiring the lock. In debug builds, the global heap lock is acquired in order to - // enforce a consistency assert. - inline size_t available_in_not_locked(ShenandoahFreeSetPartitionId which_partition) const { - assert (which_partition < NumPartitions, "selected free set must be valid"); - shenandoah_assert_not_heaplocked(); -#ifdef ASSERT - ShenandoahHeapLocker locker(ShenandoahHeap::heap()->lock()); - assert((_available[int(which_partition)] == FreeSetUnderConstruction) || - (_available[int(which_partition)] == _capacity[int(which_partition)] - _used[int(which_partition)]), - "Expect available (%zu) equals capacity (%zu) - used (%zu) for partition %s", - _available[int(which_partition)], _capacity[int(which_partition)], _used[int(which_partition)], - partition_membership_name(idx_t(which_partition))); -#endif - return _available[int(which_partition)]; - } - inline void set_capacity_of(ShenandoahFreeSetPartitionId which_partition, size_t value); inline void set_used_by(ShenandoahFreeSetPartitionId which_partition, size_t value) { @@ -440,6 +435,15 @@ private: ShenandoahHeap* const _heap; ShenandoahRegionPartitions _partitions; + // This locks the rebuild process (in combination with the global heap lock). Whenever we rebuild the free set, + // we first acquire the global heap lock and then we acquire this _rebuild_lock in a nested context. Threads that + // need to check available, acquire only the _rebuild_lock to make sure that they are not obtaining the value of + // available for a partially reconstructed free-set. + // + // Note that there is rank ordering of nested locks to prevent deadlock. All threads that need to acquire both + // locks will acquire them in the same order: first the global heap lock and then the rebuild lock. + ShenandoahRebuildLock _rebuild_lock; + size_t _total_humongous_waste; HeapWord* allocate_aligned_plab(size_t size, ShenandoahAllocRequest& req, ShenandoahHeapRegion* r); @@ -635,10 +639,12 @@ private: void log_status(); public: - static const size_t FreeSetUnderConstruction = ShenandoahRegionPartitions::FreeSetUnderConstruction; - ShenandoahFreeSet(ShenandoahHeap* heap, size_t max_regions); + ShenandoahRebuildLock* rebuild_lock() { + return &_rebuild_lock; + } + inline size_t max_regions() const { return _partitions.max(); } ShenandoahFreeSetPartitionId membership(size_t index) const { return _partitions.membership(index); } inline void shrink_interval_if_range_modifies_either_boundary(ShenandoahFreeSetPartitionId partition, @@ -776,9 +782,29 @@ public: // adjusts available with respect to lock holders. However, sequential calls to these three functions may produce // inconsistent data: available may not equal capacity - used because the intermediate states of any "atomic" // locked action can be seen by these unlocked functions. - inline size_t capacity() const { return _partitions.capacity_of(ShenandoahFreeSetPartitionId::Mutator); } - inline size_t used() const { return _partitions.used_by(ShenandoahFreeSetPartitionId::Mutator); } - inline size_t available() const { return _partitions.available_in_not_locked(ShenandoahFreeSetPartitionId::Mutator); } + inline size_t capacity_holding_lock() const { + shenandoah_assert_heaplocked(); + return _partitions.capacity_of(ShenandoahFreeSetPartitionId::Mutator); + } + inline size_t capacity_not_holding_lock() { + shenandoah_assert_not_heaplocked(); + ShenandoahRebuildLocker locker(rebuild_lock()); + return _partitions.capacity_of(ShenandoahFreeSetPartitionId::Mutator); + } + inline size_t used_holding_lock() const { + shenandoah_assert_heaplocked(); + return _partitions.used_by(ShenandoahFreeSetPartitionId::Mutator); + } + inline size_t used_not_holding_lock() { + shenandoah_assert_not_heaplocked(); + ShenandoahRebuildLocker locker(rebuild_lock()); + return _partitions.used_by(ShenandoahFreeSetPartitionId::Mutator); + } + inline size_t available() { + shenandoah_assert_not_heaplocked(); + ShenandoahRebuildLocker locker(rebuild_lock()); + return _partitions.available_in_locked_for_rebuild(ShenandoahFreeSetPartitionId::Mutator); + } inline size_t total_humongous_waste() const { return _total_humongous_waste; } inline size_t humongous_waste_in_mutator() const { return _partitions.humongous_waste(ShenandoahFreeSetPartitionId::Mutator); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index 027d7e02268..fa3a7a42209 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -1113,18 +1113,17 @@ void ShenandoahFullGC::phase5_epilog() { ShenandoahPostCompactClosure post_compact; heap->heap_region_iterate(&post_compact); heap->collection_set()->clear(); - size_t young_cset_regions, old_cset_regions; - size_t first_old, last_old, num_old; - heap->free_set()->prepare_to_rebuild(young_cset_regions, old_cset_regions, first_old, last_old, num_old); - - // We also do not expand old generation size following Full GC because we have scrambled age populations and - // no longer have objects separated by age into distinct regions. - if (heap->mode()->is_generational()) { - ShenandoahGenerationalFullGC::compute_balances(); + size_t young_cset_regions, old_cset_regions, first_old, last_old, num_old; + ShenandoahFreeSet* free_set = heap->free_set(); + { + free_set->prepare_to_rebuild(young_cset_regions, old_cset_regions, first_old, last_old, num_old); + // We also do not expand old generation size following Full GC because we have scrambled age populations and + // no longer have objects separated by age into distinct regions. + if (heap->mode()->is_generational()) { + ShenandoahGenerationalFullGC::compute_balances(); + } + free_set->finish_rebuild(young_cset_regions, old_cset_regions, num_old); } - - heap->free_set()->finish_rebuild(young_cset_regions, old_cset_regions, num_old); - // Set mark incomplete because the marking bitmaps have been reset except pinned regions. _generation->set_mark_incomplete(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index d74ee872cd1..a5d8cca458d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -815,10 +815,9 @@ void ShenandoahGeneration::prepare_regions_and_collection_set(bool concurrent) { ShenandoahGCPhase phase(concurrent ? ShenandoahPhaseTimings::final_rebuild_freeset : ShenandoahPhaseTimings::degen_gc_final_rebuild_freeset); ShenandoahHeapLocker locker(heap->lock()); - size_t young_cset_regions, old_cset_regions; // We are preparing for evacuation. At this time, we ignore cset region tallies. - size_t first_old, last_old, num_old; + size_t young_cset_regions, old_cset_regions, first_old, last_old, num_old; _free_set->prepare_to_rebuild(young_cset_regions, old_cset_regions, first_old, last_old, num_old); if (heap->mode()->is_generational()) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 3bf53f800a2..683e2959a92 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -426,8 +426,6 @@ jint ShenandoahHeap::initialize() { _affiliations[i] = ShenandoahAffiliation::FREE; } _free_set = new ShenandoahFreeSet(this, _num_regions); - - post_initialize_heuristics(); // We are initializing free set. We ignore cset region tallies. size_t young_cset_regions, old_cset_regions, first_old, last_old, num_old; @@ -1658,7 +1656,7 @@ void ShenandoahHeap::verify(VerifyOption vo) { } } size_t ShenandoahHeap::tlab_capacity() const { - return _free_set->capacity(); + return _free_set->capacity_not_holding_lock(); } class ObjectIterateScanRootClosure : public BasicOopIterateClosure { @@ -2138,7 +2136,7 @@ GCTracer* ShenandoahHeap::tracer() { } size_t ShenandoahHeap::tlab_used() const { - return _free_set->used(); + return _free_set->used_not_holding_lock(); } bool ShenandoahHeap::try_cancel_gc(GCCause::Cause cause) { @@ -2528,8 +2526,7 @@ void ShenandoahHeap::rebuild_free_set(bool concurrent) { ShenandoahPhaseTimings::final_update_refs_rebuild_freeset : ShenandoahPhaseTimings::degen_gc_final_update_refs_rebuild_freeset); ShenandoahHeapLocker locker(lock()); - size_t young_cset_regions, old_cset_regions; - size_t first_old_region, last_old_region, old_region_count; + size_t young_cset_regions, old_cset_regions, first_old_region, last_old_region, old_region_count; _free_set->prepare_to_rebuild(young_cset_regions, old_cset_regions, first_old_region, last_old_region, old_region_count); // If there are no old regions, first_old_region will be greater than last_old_region assert((first_old_region > last_old_region) || @@ -2548,13 +2545,14 @@ void ShenandoahHeap::rebuild_free_set(bool concurrent) { // The computation of bytes_of_allocation_runway_before_gc_trigger is quite conservative so consider all of this // available for transfer to old. Note that transfer of humongous regions does not impact available. ShenandoahGenerationalHeap* gen_heap = ShenandoahGenerationalHeap::heap(); - size_t allocation_runway = gen_heap->young_generation()->heuristics()->bytes_of_allocation_runway_before_gc_trigger(young_cset_regions); + size_t allocation_runway = + gen_heap->young_generation()->heuristics()->bytes_of_allocation_runway_before_gc_trigger(young_cset_regions); gen_heap->compute_old_generation_balance(allocation_runway, old_cset_regions); // Total old_available may have been expanded to hold anticipated promotions. We trigger if the fragmented available // memory represents more than 16 regions worth of data. Note that fragmentation may increase when we promote regular - // regions in place when many of these regular regions have an abundant amount of available memory within them. Fragmentation - // will decrease as promote-by-copy consumes the available memory within these partially consumed regions. + // regions in place when many of these regular regions have an abundant amount of available memory within them. + // Fragmentation will decrease as promote-by-copy consumes the available memory within these partially consumed regions. // // We consider old-gen to have excessive fragmentation if more than 12.5% of old-gen is free memory that resides // within partially consumed regions of memory. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp index d774a8dba42..81c62ebbda9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp @@ -30,7 +30,7 @@ ShenandoahMetricsSnapshot::ShenandoahMetricsSnapshot(ShenandoahFreeSet* free_set) : _free_set(free_set) - , _used_before(free_set->used()) + , _used_before(free_set->used_not_holding_lock()) , _if_before(free_set->internal_fragmentation()) , _ef_before(free_set->external_fragmentation()) { } @@ -38,7 +38,6 @@ ShenandoahMetricsSnapshot::ShenandoahMetricsSnapshot(ShenandoahFreeSet* free_set bool ShenandoahMetricsSnapshot::is_good_progress() const { // Under the critical threshold? const size_t free_actual = _free_set->available(); - assert(free_actual != ShenandoahFreeSet::FreeSetUnderConstruction, "Avoid this race"); // ShenandoahCriticalFreeThreshold is expressed as a percentage. We multiply this percentage by 1/100th // of the soft max capacity to determine whether the available memory within the mutator partition of the @@ -52,7 +51,7 @@ bool ShenandoahMetricsSnapshot::is_good_progress() const { } // Freed up enough? - const size_t used_after = _free_set->used(); + const size_t used_after = _free_set->used_not_holding_lock(); const size_t progress_actual = (_used_before > used_after) ? _used_before - used_after : 0; const size_t progress_expected = ShenandoahHeapRegion::region_size_bytes(); const bool prog_used = progress_actual >= progress_expected; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index c7cf013d034..c795eda3d96 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -412,9 +412,12 @@ void ShenandoahOldGeneration::prepare_regions_and_collection_set(bool concurrent ShenandoahGCPhase phase(concurrent ? ShenandoahPhaseTimings::final_rebuild_freeset : ShenandoahPhaseTimings::degen_gc_final_rebuild_freeset); + ShenandoahFreeSet* free_set = heap->free_set(); ShenandoahHeapLocker locker(heap->lock()); - size_t young_trash_regions, old_trash_regions; - size_t first_old, last_old, num_old; + + // This is completion of old-gen marking. We rebuild in order to reclaim immediate garbage and to + // prepare for subsequent mixed evacuations. + size_t young_trash_regions, old_trash_regions, first_old, last_old, num_old; heap->free_set()->prepare_to_rebuild(young_trash_regions, old_trash_regions, first_old, last_old, num_old); // At the end of old-gen, we may find that we have reclaimed immediate garbage, allowing a longer allocation runway. // We may also find that we have accumulated canddiate regions for mixed evacuation. If so, we will want to expand From de6f35eff988e737496d5e99e991868e97d72db4 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Wed, 14 Jan 2026 01:01:52 +0000 Subject: [PATCH 024/328] 8375094: RISC-V: Fix client builds after JDK-8368732 Reviewed-by: fyang, wenanjian, fjiang --- src/hotspot/cpu/riscv/vm_version_riscv.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 22f19c4f5ea..36f0864da0b 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -167,11 +167,6 @@ void VM_Version::common_initialize() { (unaligned_scalar.value() == MISALIGNED_SCALAR_FAST)); } - if (FLAG_IS_DEFAULT(AlignVector)) { - FLAG_SET_DEFAULT(AlignVector, - unaligned_vector.value() != MISALIGNED_VECTOR_FAST); - } - #ifdef __riscv_ztso // Hotspot is compiled with TSO support, it will only run on hardware which // supports Ztso @@ -242,6 +237,11 @@ void VM_Version::c2_initialize() { } } + if (FLAG_IS_DEFAULT(AlignVector)) { + FLAG_SET_DEFAULT(AlignVector, + unaligned_vector.value() != MISALIGNED_VECTOR_FAST); + } + // NOTE: Make sure codes dependent on UseRVV are put after MaxVectorSize initialize, // as there are extra checks inside it which could disable UseRVV // in some situations. From 5da70b180461d46b1aa44f24ba3c05efdeb03f49 Mon Sep 17 00:00:00 2001 From: Jonas Norlinder Date: Wed, 14 Jan 2026 02:13:13 +0000 Subject: [PATCH 025/328] 8375006: [Linux] Remove obsolete O_CLOEXEC check in os::open Reviewed-by: dholmes, jsjolen --- src/hotspot/os/linux/os_linux.cpp | 40 +------------------------------ 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 88e5e9b582a..6a2a3974a16 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4878,31 +4878,8 @@ int os::open(const char *path, int oflag, int mode) { // All file descriptors that are opened in the Java process and not // specifically destined for a subprocess should have the close-on-exec // flag set. If we don't set it, then careless 3rd party native code - // might fork and exec without closing all appropriate file descriptors, - // and this in turn might: - // - // - cause end-of-file to fail to be detected on some file - // descriptors, resulting in mysterious hangs, or - // - // - might cause an fopen in the subprocess to fail on a system - // suffering from bug 1085341. - // - // (Yes, the default setting of the close-on-exec flag is a Unix - // design flaw) - // - // See: - // 1085341: 32-bit stdio routines should support file descriptors >255 - // 4843136: (process) pipe file descriptor from Runtime.exec not being closed - // 6339493: (process) Runtime.exec does not close all file descriptors on Solaris 9 - // - // Modern Linux kernels (after 2.6.23 2007) support O_CLOEXEC with open(). - // O_CLOEXEC is preferable to using FD_CLOEXEC on an open file descriptor - // because it saves a system call and removes a small window where the flag - // is unset. On ancient Linux kernels the O_CLOEXEC flag will be ignored - // and we fall back to using FD_CLOEXEC (see below). -#ifdef O_CLOEXEC + // might fork and exec without closing all appropriate file descriptors. oflag |= O_CLOEXEC; -#endif int fd = ::open(path, oflag, mode); if (fd == -1) return -1; @@ -4925,21 +4902,6 @@ int os::open(const char *path, int oflag, int mode) { } } -#ifdef FD_CLOEXEC - // Validate that the use of the O_CLOEXEC flag on open above worked. - // With recent kernels, we will perform this check exactly once. - static sig_atomic_t O_CLOEXEC_is_known_to_work = 0; - if (!O_CLOEXEC_is_known_to_work) { - int flags = ::fcntl(fd, F_GETFD); - if (flags != -1) { - if ((flags & FD_CLOEXEC) != 0) - O_CLOEXEC_is_known_to_work = 1; - else - ::fcntl(fd, F_SETFD, flags | FD_CLOEXEC); - } - } -#endif - return fd; } From b082a390b77fca7134000bfe631f73bfd082bfa1 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 14 Jan 2026 04:04:08 +0000 Subject: [PATCH 026/328] 8375240: Make bundling progress messages issued by jpackage consistent across platforms Reviewed-by: almatvee --- .../jpackage/internal/LinuxDebPackager.java | 4 - .../jpackage/internal/LinuxRpmPackager.java | 6 +- .../resources/LinuxResources.properties | 6 +- .../internal/MacBundlingEnvironment.java | 6 +- .../jdk/jpackage/internal/MacDmgPackager.java | 16 -- .../internal/MacPackagingPipeline.java | 5 + .../resources/MacResources.properties | 5 - .../internal/DefaultBundlingEnvironment.java | 86 ++------ .../jpackage/internal/PackagingPipeline.java | 200 +++++++++++++++--- .../internal/cli/OptionsAnalyzer.java | 33 +-- .../cli/StandardBundlingOperation.java | 42 ++-- .../jpackage/internal/cli/StandardOption.java | 30 ++- .../internal/model/AppImageBundleType.java | 51 +++++ ...pImagePackageType.java => BundleType.java} | 20 +- .../jpackage/internal/model/PackageType.java | 6 +- .../internal/model/StandardPackageType.java | 27 ++- .../resources/MainResources.properties | 19 +- .../jdk/jpackage/internal/WinExePackager.java | 6 +- .../jdk/jpackage/internal/WinMsiPackager.java | 3 +- .../resources/WinResources.properties | 6 +- .../jdk/jpackage/test/JPackageCommand.java | 54 +++-- .../jdk/jpackage/test/PackageTest.java | 26 ++- .../DefaultBundlingEnvironmentTest.java | 8 +- .../internal/PackagingPipelineTest.java | 9 +- .../internal/cli/StandardOptionTest.java | 29 ++- test/jdk/tools/jpackage/share/BasicTest.java | 106 ++++++---- .../tools/jpackage/share/OutputErrorTest.java | 119 +++++++++++ 27 files changed, 639 insertions(+), 289 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageBundleType.java rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/{AppImagePackageType.java => BundleType.java} (77%) create mode 100644 test/jdk/tools/jpackage/share/OutputErrorTest.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java index 0ec6a77e683..7c1f06f54a3 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java @@ -147,8 +147,6 @@ final class LinuxDebPackager extends LinuxPackager { Path debFile = outputPackageFile(); - Log.verbose(I18N.format("message.outputting-to-location", debFile.toAbsolutePath())); - List cmdline = new ArrayList<>(); Stream.of(sysEnv.fakeroot(), sysEnv.dpkgdeb()).map(Path::toString).forEach(cmdline::add); if (Log.isVerbose()) { @@ -159,8 +157,6 @@ final class LinuxDebPackager extends LinuxPackager { // run dpkg Executor.of(cmdline).retryOnKnownErrorMessage( "semop(1): encountered an error: Invalid argument").execute(); - - Log.verbose(I18N.format("message.output-to-location", debFile.toAbsolutePath())); } @Override diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackager.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackager.java index 60355d0d1a2..e22b9c24fdd 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackager.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -133,8 +133,6 @@ final class LinuxRpmPackager extends LinuxPackager { Path rpmFile = outputPackageFile(); - Log.verbose(I18N.format("message.outputting-bundle-location", rpmFile.getParent())); - //run rpmbuild Executor.of(sysEnv.rpmbuild().toString(), "-bb", specFile().toAbsolutePath().toString(), @@ -147,8 +145,6 @@ final class LinuxRpmPackager extends LinuxPackager { env.buildRoot().toAbsolutePath()), "--define", String.format("%%_rpmfilename %s", rpmFile.getFileName()) ).executeExpectSuccess(); - - Log.verbose(I18N.format("message.output-bundle-location", rpmFile.getParent())); } private Path installPrefix() { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties index 3aabe1f4ba5..3aa0e0e92a0 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2026, 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 @@ -49,11 +49,7 @@ error.rpm-arch-not-detected="Failed to detect RPM arch" message.icon-not-png=The specified icon "{0}" is not a PNG file and will not be used. The default icon will be used in it's place. message.test-for-tool=Test for [{0}]. Result: {1} -message.outputting-to-location=Generating DEB for installer to: {0}. -message.output-to-location=Package (.deb) saved to: {0}. message.debs-like-licenses=Debian packages should specify a license. The absence of a license will cause some linux distributions to complain about the quality of the application. -message.outputting-bundle-location=Generating RPM for installer to: {0}. -message.output-bundle-location=Package (.rpm) saved to: {0}. message.ldd-not-available=ldd command not found. Package dependencies will not be generated. message.deb-ldd-not-available.advice=Install "libc-bin" DEB package to get ldd. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundlingEnvironment.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundlingEnvironment.java index 0531559e052..224ea20f249 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundlingEnvironment.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundlingEnvironment.java @@ -54,7 +54,6 @@ public class MacBundlingEnvironment extends DefaultBundlingEnvironment { buildEnv()::create, MacBundlingEnvironment::buildPipeline, (env, pkg, outputDir) -> { - Log.verbose(I18N.format("message.building-dmg", pkg.app().name())); return new MacDmgPackager(env, pkg, outputDir, sysEnv); }); } @@ -64,10 +63,7 @@ public class MacBundlingEnvironment extends DefaultBundlingEnvironment { MacFromOptions.createMacPkgPackage(options), buildEnv()::create, MacBundlingEnvironment::buildPipeline, - (env, pkg, outputDir) -> { - Log.verbose(I18N.format("message.building-pkg", pkg.app().name())); - return new MacPkgPackager(env, pkg, outputDir); - }); + MacPkgPackager::new); } private static void signAppImage(Options options) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java index 20a687487ef..82bb9fc4dad 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java @@ -235,17 +235,6 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, final Path srcFolder = env.appImageDir(); - Log.verbose(MessageFormat.format(I18N.getString( - "message.creating-dmg-file"), finalDMG.toAbsolutePath())); - - try { - Files.deleteIfExists(finalDMG); - } catch (IOException ex) { - throw new IOException(MessageFormat.format(I18N.getString( - "message.dmg-cannot-be-overwritten"), - finalDMG.toAbsolutePath())); - } - Files.createDirectories(protoDMG.getParent()); Files.createDirectories(finalDMG.getParent()); @@ -383,11 +372,6 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, } catch (IOException ex) { // Don't care if fails } - - Log.verbose(MessageFormat.format(I18N.getString( - "message.output-to-location"), - pkg.app().name(), normalizedAbsolutePathString(finalDMG))); - } private void detachVolume() throws IOException { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index a53df7f83c2..4e63f6db178 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -217,6 +217,11 @@ final class MacPackagingPipeline { enum SignAppImagePackageType implements PackageType { VALUE; + + @Override + public String label() { + throw new UnsupportedOperationException(); + } } static Package createSignAppImagePackage(MacApplication app, BuildEnv env) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties index 240e82dcc9b..ceeab587f66 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties @@ -57,12 +57,7 @@ message.version-string-first-number-not-zero=The first number in an app-version message.keychain.error=Unable to get keychain list. message.invalid-identifier=Invalid mac bundle identifier [{0}]. message.invalid-identifier.advice=specify identifier with "--mac-package-identifier". -message.building-dmg=Building DMG package for {0}. message.preparing-dmg-setup=Preparing dmg setup: {0}. -message.creating-dmg-file=Creating DMG file: {0}. -message.dmg-cannot-be-overwritten=Dmg file exists [{0}] and can not be removed. -message.output-to-location=Result DMG installer for {0}: {1}. -message.building-pkg=Building PKG package for {0}. message.preparing-scripts=Preparing package scripts. message.preparing-distribution-dist=Preparing distribution.dist: {0}. message.signing.pkg=Warning: For signing PKG, you might need to set "Always Trust" for your certificate using "Keychain Access" tool. diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java index e4473b1e5ce..3a99dfb04da 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java @@ -42,17 +42,15 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; -import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; import jdk.jpackage.internal.cli.CliBundlingEnvironment; import jdk.jpackage.internal.cli.Options; import jdk.jpackage.internal.cli.StandardBundlingOperation; -import jdk.jpackage.internal.model.AppImagePackageType; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.BundlingOperationDescriptor; import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.PackageType; -import jdk.jpackage.internal.model.StandardPackageType; +import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.Result; class DefaultBundlingEnvironment implements CliBundlingEnvironment { @@ -134,7 +132,9 @@ class DefaultBundlingEnvironment implements CliBundlingEnvironment { Objects.requireNonNull(app); Objects.requireNonNull(pipelineBuilder); - final var outputDir = OptionUtils.outputDir(options).resolve(app.appImageDirName()); + final var outputDir = PathUtils.normalizedAbsolutePath(OptionUtils.outputDir(options).resolve(app.appImageDirName())); + + Log.verbose(I18N.getString("message.create-app-image")); IOUtils.writableOutputDir(outputDir.getParent()); @@ -142,14 +142,14 @@ class DefaultBundlingEnvironment implements CliBundlingEnvironment { .predefinedAppImageLayout(app.asApplicationLayout().orElseThrow()) .create(options, app); - Log.verbose(I18N.format("message.creating-app-bundle", outputDir.getFileName(), outputDir.toAbsolutePath().getParent())); - if (Files.exists(outputDir)) { - throw new JPackageException(I18N.format("error.root-exists", outputDir.toAbsolutePath())); + throw new JPackageException(I18N.format("error.root-exists", outputDir)); } pipelineBuilder.excludeDirFromCopying(outputDir.getParent()) .create().execute(BuildEnv.withAppImageDir(env, outputDir), app); + + Log.verbose(I18N.getString("message.app-image-created")); } static void createNativePackage(Options options, @@ -174,11 +174,20 @@ class DefaultBundlingEnvironment implements CliBundlingEnvironment { Objects.requireNonNull(createPipelineBuilder); Objects.requireNonNull(pipelineBuilderMutatorFactory); + var pipelineBuilder = Objects.requireNonNull(createPipelineBuilder.apply(pkg)); + + // Delete an old output package file (if any) before creating a new one. + pipelineBuilder.task(PackageTaskID.DELETE_OLD_PACKAGE_FILE) + .addDependencies(pipelineBuilder.taskGraphSnapshot().getTailsOf(PackageTaskID.CREATE_PACKAGE_FILE)) + .addDependent(PackageTaskID.CREATE_PACKAGE_FILE) + .packageAction(PackagingPipeline::deleteOutputBundle) + .add(); + Packager.build().pkg(pkg) - .outputDir(OptionUtils.outputDir(options)) - .env(Objects.requireNonNull(createBuildEnv.apply(options, pkg))) - .pipelineBuilderMutatorFactory(pipelineBuilderMutatorFactory) - .execute(Objects.requireNonNull(createPipelineBuilder.apply(pkg))); + .outputDir(OptionUtils.outputDir(options)) + .env(Objects.requireNonNull(createBuildEnv.apply(options, pkg))) + .pipelineBuilderMutatorFactory(pipelineBuilderMutatorFactory) + .execute(pipelineBuilder); } @Override @@ -195,10 +204,6 @@ class DefaultBundlingEnvironment implements CliBundlingEnvironment { permanentWorkDirectory = Optional.of(tempDir.path()); } bundler.accept(tempDir.options()); - - var packageType = OptionUtils.bundlingOperation(cmdline).packageType(); - - Log.verbose(I18N.format("message.bundle-created", I18N.getString(bundleTypeDescription(packageType, op.os())))); } catch (IOException ex) { throw new UncheckedIOException(ex); } finally { @@ -219,55 +224,6 @@ class DefaultBundlingEnvironment implements CliBundlingEnvironment { }); } - private String bundleTypeDescription(PackageType type, OperatingSystem os) { - switch (type) { - case StandardPackageType stdType -> { - switch (stdType) { - case WIN_MSI -> { - return "bundle-type.win-msi"; - } - case WIN_EXE -> { - return "bundle-type.win-exe"; - } - case LINUX_DEB -> { - return "bundle-type.linux-deb"; - } - case LINUX_RPM -> { - return "bundle-type.linux-rpm"; - } - case MAC_DMG -> { - return "bundle-type.mac-dmg"; - } - case MAC_PKG -> { - return "bundle-type.mac-pkg"; - } - default -> { - throw new AssertionError(); - } - } - } - case AppImagePackageType appImageType -> { - switch (os) { - case WINDOWS -> { - return "bundle-type.win-app"; - } - case LINUX -> { - return "bundle-type.linux-app"; - } - case MACOS -> { - return "bundle-type.mac-app"; - } - default -> { - throw new AssertionError(); - } - } - } - default -> { - throw new AssertionError(); - } - } - } - private static final class CachingSupplier implements Supplier { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java index c94dada9262..f15768b2cbf 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -29,6 +29,7 @@ import static java.util.stream.Collectors.toMap; import static jdk.jpackage.internal.model.AppImageLayout.toPathGroup; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.util.ArrayList; @@ -39,12 +40,16 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.concurrent.Callable; +import java.util.function.BiConsumer; +import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.function.UnaryOperator; import java.util.stream.Stream; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.pipeline.DirectedEdge; import jdk.jpackage.internal.pipeline.FixedDAG; @@ -97,7 +102,7 @@ final class PackagingPipeline { /** * The way to access packaging build environment before building a package in a pipeline. */ - interface StartupParameters { + sealed interface StartupParameters { BuildEnv packagingEnv(); } @@ -127,6 +132,7 @@ final class PackagingPipeline { enum PackageTaskID implements TaskID { RUN_POST_IMAGE_USER_SCRIPT, CREATE_CONFIG_FILES, + DELETE_OLD_PACKAGE_FILE, CREATE_PACKAGE_FILE } @@ -183,9 +189,11 @@ final class PackagingPipeline { void execute() throws IOException; } - record TaskConfig(Optional action) { + record TaskConfig(Optional action, Optional beforeAction, Optional afterAction) { TaskConfig { Objects.requireNonNull(action); + Objects.requireNonNull(beforeAction); + Objects.requireNonNull(afterAction); } } @@ -196,47 +204,64 @@ final class PackagingPipeline { final class TaskBuilder extends TaskSpecBuilder { - private TaskBuilder(TaskID id) { - super(id); - } - - private TaskBuilder(TaskID id, TaskConfig config) { - this(id); - config.action().ifPresent(this::setAction); - } - - private TaskBuilder setAction(TaskAction v) { - action = v; - return this; - } - TaskBuilder noaction() { - action = null; - return this; + return setAction(ActionRole.WORKLOAD, null); } TaskBuilder applicationAction(ApplicationImageTaskAction action) { - return setAction(action); + return applicationAction(ActionRole.WORKLOAD, action); } TaskBuilder appImageAction(AppImageTaskAction action) { - return setAction(action); + return appImageAction(ActionRole.WORKLOAD, action); } TaskBuilder copyAction(CopyAppImageTaskAction action) { - return setAction(action); + return copyAction(ActionRole.WORKLOAD, action); } TaskBuilder packageAction(PackageTaskAction action) { - return setAction(action); + return packageAction(ActionRole.WORKLOAD, action); } TaskBuilder action(NoArgTaskAction action) { - return setAction(action); + return action(ActionRole.WORKLOAD, action); + } + + TaskBuilder logAppImageActionBegin(String keyId, Function, Object[]> formatArgsSupplier) { + return logAppImageAction(ActionRole.BEFORE, keyId, formatArgsSupplier); + } + + TaskBuilder logAppImageActionEnd(String keyId, Function, Object[]> formatArgsSupplier) { + return logAppImageAction(ActionRole.AFTER, keyId, formatArgsSupplier); + } + + TaskBuilder logPackageActionBegin(String keyId, Function, Object[]> argsSupplier) { + return logPackageAction(ActionRole.BEFORE, keyId, argsSupplier); + } + + TaskBuilder logPackageActionEnd(String keyId, Function, Object[]> argsSupplier) { + return logPackageAction(ActionRole.AFTER, keyId, argsSupplier); + } + + TaskBuilder logActionBegin(String keyId, Supplier formatArgsSupplier) { + return logAction(ActionRole.BEFORE, keyId, formatArgsSupplier); + } + + TaskBuilder logActionBegin(String keyId, Object... formatArgsSupplier) { + return logAction(ActionRole.BEFORE, keyId, () -> formatArgsSupplier); + } + + TaskBuilder logActionEnd(String keyId, Supplier formatArgsSupplier) { + return logAction(ActionRole.AFTER, keyId, formatArgsSupplier); + } + + TaskBuilder logActionEnd(String keyId, Object... formatArgsSupplier) { + return logAction(ActionRole.AFTER, keyId, () -> formatArgsSupplier); } boolean hasAction() { - return action != null; + return workloadAction != null; } @Override @@ -272,13 +297,109 @@ final class PackagingPipeline { } Builder add() { - final var config = new TaskConfig(Optional.ofNullable(action)); + final var config = new TaskConfig( + Optional.ofNullable(workloadAction), + Optional.ofNullable(beforeAction), + Optional.ofNullable(afterAction)); taskConfig.put(task(), config); createLinks().forEach(Builder.this::linkTasks); return Builder.this; } - private TaskAction action; + + private enum ActionRole { + WORKLOAD(TaskBuilder::setWorkloadAction), + BEFORE(TaskBuilder::setBeforeAction), + AFTER(TaskBuilder::setAfterAction), + ; + + ActionRole(BiConsumer actionSetter) { + this.actionSetter = Objects.requireNonNull(actionSetter); + } + + TaskBuilder setAction(TaskBuilder taskBuilder, TaskAction action) { + actionSetter.accept(taskBuilder, action); + return taskBuilder; + } + + private final BiConsumer actionSetter; + } + + + private TaskBuilder(TaskID id) { + super(id); + } + + private TaskBuilder(TaskID id, TaskConfig config) { + this(id); + config.action().ifPresent(this::setWorkloadAction); + config.beforeAction().ifPresent(this::setBeforeAction); + config.afterAction().ifPresent(this::setAfterAction); + } + + private TaskBuilder setAction(ActionRole role, TaskAction v) { + return role.setAction(this, v); + } + + private TaskBuilder setWorkloadAction(TaskAction v) { + workloadAction = v; + return this; + } + + private TaskBuilder setBeforeAction(TaskAction v) { + beforeAction = v; + return this; + } + + private TaskBuilder setAfterAction(TaskAction v) { + afterAction = v; + return this; + } + + private TaskBuilder applicationAction(ActionRole role, ApplicationImageTaskAction action) { + return setAction(role, action); + } + + private TaskBuilder appImageAction(ActionRole role, AppImageTaskAction action) { + return setAction(role, action); + } + + private TaskBuilder copyAction(ActionRole role, CopyAppImageTaskAction action) { + return setAction(role, action); + } + + private TaskBuilder packageAction(ActionRole role, PackageTaskAction action) { + return setAction(role, action); + } + + private TaskBuilder action(ActionRole role, NoArgTaskAction action) { + return setAction(role, action); + } + + private TaskBuilder logAppImageAction(ActionRole role, String keyId, Function, Object[]> formatArgsSupplier) { + Objects.requireNonNull(keyId); + return appImageAction(role, (AppImageBuildEnv env) -> { + Log.verbose(I18N.format(keyId, formatArgsSupplier.apply(env))); + }); + } + + private TaskBuilder logPackageAction(ActionRole role, String keyId, Function, Object[]> formatArgsSupplier) { + Objects.requireNonNull(keyId); + return packageAction(role, (PackageBuildEnv env) -> { + Log.verbose(I18N.format(keyId, formatArgsSupplier.apply(env))); + }); + } + + private TaskBuilder logAction(ActionRole role, String keyId, Supplier formatArgsSupplier) { + Objects.requireNonNull(keyId); + return action(role, () -> { + Log.verbose(I18N.format(keyId, formatArgsSupplier.get())); + }); + } + + private TaskAction workloadAction; + private TaskAction beforeAction; + private TaskAction afterAction; } Builder linkTasks(DirectedEdge edge) { @@ -294,7 +415,11 @@ final class PackagingPipeline { } TaskBuilder task(TaskID id) { - return new TaskBuilder(id); + return Optional.ofNullable(taskConfig.get(id)).map(taskConfig -> { + return new TaskBuilder(id, taskConfig); + }).orElseGet(() -> { + return new TaskBuilder(id); + }); } Stream configuredTasks() { @@ -392,6 +517,8 @@ final class PackagingPipeline { builder.task(PackageTaskID.CREATE_PACKAGE_FILE) .addDependent(PrimaryTaskID.PACKAGE) + .logActionBegin("message.create-package") + .logActionEnd("message.package-created") .add(); builder.task(PrimaryTaskID.PACKAGE).add(); @@ -425,6 +552,17 @@ final class PackagingPipeline { .run(env.env(), env.pkg().app().name()); } + static void deleteOutputBundle(PackageBuildEnv env) throws IOException { + + var outputBundle = env.outputDir().resolve(env.pkg().packageFileNameWithSuffix()); + + try { + Files.deleteIfExists(outputBundle); + } catch (IOException ex) { + throw new JPackageException(I18N.format("error.output-bundle-cannot-be-overwritten", outputBundle.toAbsolutePath()), ex); + } + } + private PackagingPipeline(FixedDAG taskGraph, Map taskConfig, UnaryOperator contextMapper) { this.taskGraph = Objects.requireNonNull(taskGraph); @@ -645,7 +783,13 @@ final class PackagingPipeline { } if (accepted) { + if (config.beforeAction.isPresent()) { + context.execute(config.beforeAction.orElseThrow()); + } context.execute(config.action.orElseThrow()); + if (config.afterAction.isPresent()) { + context.execute(config.afterAction.orElseThrow()); + } } return null; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsAnalyzer.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsAnalyzer.java index 67e87d55d8b..363aa1b863e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsAnalyzer.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsAnalyzer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -56,7 +56,7 @@ import jdk.jpackage.internal.model.BundlingEnvironment; import jdk.jpackage.internal.model.BundlingOperationDescriptor; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.JPackageException; -import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.BundleType; /** * Analyzes jpackage command line structure. @@ -250,7 +250,7 @@ final class OptionsAnalyzer { return error("ERR_NoInstallerEntryPoint", mapFormatArguments(optionSpec)); } else { return error("ERR_InvalidTypeOption", mapFormatArguments( - optionSpec, bundlingOperation.packageTypeValue())); + optionSpec, bundlingOperation.bundleTypeValue())); } } @@ -267,30 +267,31 @@ final class OptionsAnalyzer { final var typeOption = TYPE.getOption(); return cmdline.find(typeOption).map(obj -> { - if (obj instanceof PackageType packageType) { - return packageType; + if (obj instanceof BundleType bundleType) { + return bundleType; } else { - return typeOption.spec() + var spec = new StandardOptionContext(os).mapOptionSpec(typeOption.spec()); + return spec .converter().orElseThrow() - .convert(typeOption.spec().name(), StringToken.of(((String[])obj)[0])) + .convert(spec.name(), StringToken.of(((String[])obj)[0])) .orElseThrow(); } - }).map(packageType -> { - // Find standard bundling operations producing the given package type. + }).map(bundleType -> { + // Find standard bundling operations producing the given bundle type. var bundlingOperations = Stream.of(StandardBundlingOperation.values()).filter(op -> { - return op.packageType().equals(packageType); + return op.bundleType().equals(bundleType); }).toList(); if (bundlingOperations.isEmpty()) { // jpackage internal error: none of the standard bundling operations produce - // bundles of the `packageType`. + // bundles of the `bundleType`. throw new AssertionError(String.format( "None of the standard bundling operations produce bundles of type [%s]", - packageType)); + bundleType)); } else if (bundlingOperations.size() == 1) { return bundlingOperations.getFirst(); } else { - // Multiple standard bundling operations produce the `packageType` package type. + // Multiple standard bundling operations produce the `bundleType` bundle type. // Filter those that belong to the current OS bundlingOperations = bundlingOperations.stream().filter(op -> { return op.os().equals(OperatingSystem.current()); @@ -298,10 +299,10 @@ final class OptionsAnalyzer { if (bundlingOperations.isEmpty()) { // jpackage internal error: none of the standard bundling operations produce - // bundles of the `packageType` on the current OS. + // bundles of the `bundleType` on the current OS. throw new AssertionError(String.format( "None of the standard bundling operations produce bundles of type [%s] on %s", - packageType, OperatingSystem.current())); + bundleType, OperatingSystem.current())); } else if (bundlingOperations.size() == 1) { return bundlingOperations.getFirst(); } else if (StandardBundlingOperation.MACOS_APP_IMAGE.containsAll(bundlingOperations)) { @@ -316,7 +317,7 @@ final class OptionsAnalyzer { } } }).orElseGet(() -> { - // No package type specified, use the default bundling operation in the given environment. + // No bundle type specified, use the default bundling operation in the given environment. return env.defaultOperation().map(descriptor -> { return Stream.of(StandardBundlingOperation.values()).filter(op -> { return descriptor.equals(op.descriptor()); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardBundlingOperation.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardBundlingOperation.java index 45f9194db0b..f6fcd68a6d8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardBundlingOperation.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardBundlingOperation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,6 @@ */ package jdk.jpackage.internal.cli; -import static jdk.jpackage.internal.model.AppImagePackageType.APP_IMAGE; - import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -34,6 +32,8 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.AppImageBundleType; +import jdk.jpackage.internal.model.BundleType; import jdk.jpackage.internal.model.BundlingOperationDescriptor; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.StandardPackageType; @@ -44,16 +44,16 @@ import jdk.jpackage.internal.util.SetBuilder; * Standard jpackage operations. */ public enum StandardBundlingOperation implements BundlingOperationOptionScope { - CREATE_WIN_APP_IMAGE(APP_IMAGE, "^(?!(linux-|mac-|win-exe-|win-msi-))", OperatingSystem.WINDOWS), - CREATE_LINUX_APP_IMAGE(APP_IMAGE, "^(?!(win-|mac-|linux-rpm-|linux-deb-))", OperatingSystem.LINUX), - CREATE_MAC_APP_IMAGE(APP_IMAGE, "^(?!(linux-|win-|mac-dmg-|mac-pkg-))", OperatingSystem.MACOS), + CREATE_WIN_APP_IMAGE(AppImageBundleType.WIN_APP_IMAGE, "^(?!(linux-|mac-|win-exe-|win-msi-))", OperatingSystem.WINDOWS), + CREATE_LINUX_APP_IMAGE(AppImageBundleType.LINUX_APP_IMAGE, "^(?!(win-|mac-|linux-rpm-|linux-deb-))", OperatingSystem.LINUX), + CREATE_MAC_APP_IMAGE(AppImageBundleType.MAC_APP_IMAGE, "^(?!(linux-|win-|mac-dmg-|mac-pkg-))", OperatingSystem.MACOS), CREATE_WIN_EXE(StandardPackageType.WIN_EXE, "^(?!(linux-|mac-|win-msi-))", OperatingSystem.WINDOWS), CREATE_WIN_MSI(StandardPackageType.WIN_MSI, "^(?!(linux-|mac-|win-exe-))", OperatingSystem.WINDOWS), CREATE_LINUX_RPM(StandardPackageType.LINUX_RPM, "^(?!(win-|mac-|linux-deb-))", OperatingSystem.LINUX), CREATE_LINUX_DEB(StandardPackageType.LINUX_DEB, "^(?!(win-|mac-|linux-rpm-))", OperatingSystem.LINUX), CREATE_MAC_PKG(StandardPackageType.MAC_PKG, "^(?!(linux-|win-|mac-dmg-))", OperatingSystem.MACOS), CREATE_MAC_DMG(StandardPackageType.MAC_DMG, "^(?!(linux-|win-|mac-pkg-))", OperatingSystem.MACOS), - SIGN_MAC_APP_IMAGE(APP_IMAGE, OperatingSystem.MACOS, Verb.SIGN); + SIGN_MAC_APP_IMAGE(AppImageBundleType.MAC_APP_IMAGE, OperatingSystem.MACOS, Verb.SIGN); /** * Supported values of the {@link BundlingOperationDescriptor#verb()} property. @@ -78,19 +78,19 @@ public enum StandardBundlingOperation implements BundlingOperationOptionScope { private final String value; } - StandardBundlingOperation(PackageType packageType, String optionNameRegexp, OperatingSystem os, Verb descriptorVerb) { - this.packageType = Objects.requireNonNull(packageType); + StandardBundlingOperation(BundleType bundleType, String optionNameRegexp, OperatingSystem os, Verb descriptorVerb) { + this.bundleType = Objects.requireNonNull(bundleType); optionNamePredicate = Pattern.compile(optionNameRegexp).asPredicate(); this.os = Objects.requireNonNull(os); this.descriptorVerb = Objects.requireNonNull(descriptorVerb); } - StandardBundlingOperation(PackageType packageType, String optionNameRegexp, OperatingSystem os) { - this(packageType, optionNameRegexp, os, Verb.CREATE); + StandardBundlingOperation(BundleType bundleType, String optionNameRegexp, OperatingSystem os) { + this(bundleType, optionNameRegexp, os, Verb.CREATE); } - StandardBundlingOperation(PackageType packageType, OperatingSystem os, Verb descriptorVerb) { - this.packageType = Objects.requireNonNull(packageType); + StandardBundlingOperation(BundleType bundleType, OperatingSystem os, Verb descriptorVerb) { + this.bundleType = Objects.requireNonNull(bundleType); optionNamePredicate = v -> false; this.os = Objects.requireNonNull(os); this.descriptorVerb = Objects.requireNonNull(descriptorVerb); @@ -100,16 +100,20 @@ public enum StandardBundlingOperation implements BundlingOperationOptionScope { return os; } - public String packageTypeValue() { - if (packageType.equals(APP_IMAGE)) { + public String bundleTypeValue() { + if (bundleType instanceof AppImageBundleType) { return "app-image"; } else { - return ((StandardPackageType)packageType).suffix().substring(1); + return ((StandardPackageType)bundleType).suffix().substring(1); } } + public BundleType bundleType() { + return bundleType; + } + public PackageType packageType() { - return packageType; + return (PackageType)bundleType(); } /** @@ -122,7 +126,7 @@ public enum StandardBundlingOperation implements BundlingOperationOptionScope { @Override public BundlingOperationDescriptor descriptor() { - return new BundlingOperationDescriptor(os(), packageTypeValue(), descriptorVerb.value()); + return new BundlingOperationDescriptor(os(), bundleTypeValue(), descriptorVerb.value()); } public static Optional valueOf(BundlingOperationDescriptor descriptor) { @@ -199,6 +203,6 @@ public enum StandardBundlingOperation implements BundlingOperationOptionScope { private final Predicate optionNamePredicate; private final OperatingSystem os; - private final PackageType packageType; + private final BundleType bundleType; private final Verb descriptorVerb; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java index dddaef8399b..9c828705a4d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java @@ -55,11 +55,12 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.AppImageBundleType; +import jdk.jpackage.internal.model.BundleType; import jdk.jpackage.internal.model.BundlingOperationDescriptor; import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.LauncherShortcut; import jdk.jpackage.internal.model.LauncherShortcutStartupDirectory; -import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.util.SetBuilder; /** @@ -103,18 +104,18 @@ public final class StandardOption { public static final OptionValue VERBOSE = auxilaryOption("verbose").create(); - public static final OptionValue TYPE = option("type", PackageType.class).addAliases("t") + public static final OptionValue TYPE = option("type", BundleType.class).addAliases("t") .scope(StandardBundlingOperation.values()).inScope(NOT_BUILDING_APP_IMAGE) .converterExceptionFactory(ERROR_WITH_VALUE).converterExceptionFormatString("ERR_InvalidInstallerType") .converter(str -> { - Objects.requireNonNull(str); - return Stream.of(StandardBundlingOperation.values()).filter(bundlingOperation -> { - return bundlingOperation.packageTypeValue().equals(str); - }).map(StandardBundlingOperation::packageType).findFirst().orElseThrow(IllegalArgumentException::new); + return parseBundleType(str, OperatingSystem.current()); }) .description("help.option.type" + resourceKeySuffix(OperatingSystem.current())) .mutate(createOptionSpecBuilderMutator((b, context) -> { b.description("help.option.type" + resourceKeySuffix(context.os())); + b.converter(str -> { + return parseBundleType(str, context.os()); + }); })).create(); public static final OptionValue INPUT = directoryOption("input").addAliases("i") @@ -665,6 +666,23 @@ public final class StandardOption { }).defaultArrayValue(new AdditionalLauncher[0]).createArray(); } + private static BundleType parseBundleType(String str, OperatingSystem appImageOS) { + Objects.requireNonNull(str); + Objects.requireNonNull(appImageOS); + + return Stream.of(StandardBundlingOperation.values()).filter(bundlingOperation -> { + return bundlingOperation.bundleTypeValue().equals(str); + }) + .filter(bundlingOperation -> { + // Skip app image bundle type if it is from another platform. + return !(bundlingOperation.bundleType() instanceof AppImageBundleType) + || (bundlingOperation.os() == appImageOS); + }) + .map(StandardBundlingOperation::bundleType) + .findFirst() + .orElseThrow(IllegalArgumentException::new); + } + private static String resourceKeySuffix(OperatingSystem os) { switch (os) { case LINUX -> { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageBundleType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageBundleType.java new file mode 100644 index 00000000000..c5d2f0d1569 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageBundleType.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.util.Objects; + +/** + * App image bundle type. + * + * @see StandardPackageType + */ +public enum AppImageBundleType implements BundleType { + + WIN_APP_IMAGE("bundle-type.win-app"), + LINUX_APP_IMAGE("bundle-type.linux-app"), + MAC_APP_IMAGE("bundle-type.mac-app"), + ; + + private AppImageBundleType(String key) { + this.key = Objects.requireNonNull(key); + } + + @Override + public String label() { + return I18N.getString(key); + } + + private final String key; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundleType.java similarity index 77% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundleType.java index 4e28bb05aef..009725f3e92 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundleType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,20 +22,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.jpackage.internal.model; -/** - * App image packaging type. - * - * @see StandardPackageType - */ -public final class AppImagePackageType implements PackageType { - private AppImagePackageType() { - } +/** + * Generic bundle type. E.g.: application image, rpm, msi are all bundle types. + */ +public sealed interface BundleType permits PackageType, AppImageBundleType { /** - * Singleton + * Returns a user-facing label of this bundle type. + * @return a user-facing label of this bundle type. */ - public static final AppImagePackageType APP_IMAGE = new AppImagePackageType(); + String label(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java index d0a4fd010e6..e7273d27ba5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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,8 @@ package jdk.jpackage.internal.model; /** - * Generic package type. E.g.: application image, rpm, msi are all package types. + * Native package type. E.g.: dmg, rpm, msi are all package types. * * @see jdk.jpackage.internal.model.Package */ -public interface PackageType {} +public non-sealed interface PackageType extends BundleType {} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java index ccdeceb4a04..6fadc748ecc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,19 +24,22 @@ */ package jdk.jpackage.internal.model; +import java.util.Objects; + /** * Standard native package types. */ public enum StandardPackageType implements PackageType { - WIN_MSI(".msi"), - WIN_EXE(".exe"), - LINUX_DEB(".deb"), - LINUX_RPM(".rpm"), - MAC_PKG(".pkg"), - MAC_DMG(".dmg"); + WIN_MSI("bundle-type.win-msi", ".msi"), + WIN_EXE("bundle-type.win-exe", ".exe"), + LINUX_DEB("bundle-type.linux-deb", ".deb"), + LINUX_RPM("bundle-type.linux-rpm", ".rpm"), + MAC_PKG("bundle-type.mac-pkg", ".pkg"), + MAC_DMG("bundle-type.mac-dmg", ".dmg"); - StandardPackageType(String suffix) { - this.suffix = suffix; + StandardPackageType(String key, String suffix) { + this.key = Objects.requireNonNull(key); + this.suffix = Objects.requireNonNull(suffix); } /** @@ -48,5 +51,11 @@ public enum StandardPackageType implements PackageType { return suffix; } + @Override + public String label() { + return I18N.getString(key); + } + + private final String key; private final String suffix; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index 245d3b892da..588a3702839 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -28,14 +28,14 @@ param.copyright.default=Copyright (C) {0,date,YYYY} param.vendor.default=Unknown bundle-type.win-app=Windows Application Image -bundle-type.win-exe=EXE Installer Package -bundle-type.win-msi=MSI Installer Package +bundle-type.win-exe=Windows EXE Installer +bundle-type.win-msi=Windows MSI Installer bundle-type.mac-app=Mac Application Image bundle-type.mac-dmg=Mac DMG Package bundle-type.mac-pkg=Mac PKG Package bundle-type.linux-app=Linux Application Image -bundle-type.linux-deb=DEB Bundle -bundle-type.linux-rpm=RPM Bundle +bundle-type.linux-deb=Linux DEB Package +bundle-type.linux-rpm=Linux RPM Package resource.post-app-image-script=script to run after application image is populated @@ -43,9 +43,14 @@ message.using-default-resource=Using default package resource {0} {1} (add {2} t message.no-default-resource=No default package resource {0} (add {1} to the resource-dir to customize). message.using-custom-resource-from-file=Using custom package resource {0} (loaded from file {1}). message.using-custom-resource=Using custom package resource {0} (loaded from {1}). -message.creating-app-bundle=Creating app package: {0} in {1} + +message.create-package=Building output package file... +message.create-app-image=Building output application image directory... +message.package-created=Succeeded in building output package file +message.app-image-created=Succeeded in building output application image directory + message.debug-working-directory=Kept working directory for debug: {0} -message.bundle-created=Succeeded in building {0} package + message.module-version=Using version "{0}" from module "{1}" as application version message.error-header=Error: {0} @@ -97,6 +102,8 @@ error.tool-not-found.advice=Please install "{0}" error.tool-old-version=Can not find "{0}" {1} or newer error.tool-old-version.advice=Please install "{0}" {1} or newer +error.output-bundle-cannot-be-overwritten=Output package file "{0}" exists and can not be removed. + error.blocked.option=jlink option [{0}] is not permitted in --jlink-options error.no.name=Name not specified with --name and cannot infer one from app-image error.no.name.advice=Specify name with --name diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java index 9a13a0f954d..fd86331e2f1 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -79,8 +79,6 @@ final record WinExePackager(BuildEnv env, WinExePackage pkg, Path outputDir, Pat private void wrapMsiInExe() throws IOException { - Log.verbose(I18N.format("message.outputting-to-location", outputDir.toAbsolutePath())); - final var msi = msi(); // Copy template msi wrapper next to msi file @@ -102,7 +100,5 @@ final record WinExePackager(BuildEnv env, WinExePackage pkg, Path outputDir, Pat Files.copy(exePath, dstExePath, StandardCopyOption.REPLACE_EXISTING); dstExePath.toFile().setExecutable(true); - - Log.verbose(I18N.format("message.output-location", outputDir.toAbsolutePath())); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java index 915d034bd82..c52be726fd2 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -315,7 +315,6 @@ final class WinMsiPackager implements Consumer { private void buildPackage() throws IOException { final var msiOut = outputDir.resolve(pkg.packageFileNameWithSuffix()); - Log.verbose(I18N.format("message.generating-msi", msiOut.toAbsolutePath())); wixPipeline.buildMsi(msiOut.toAbsolutePath()); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties index 1f485e6c6c8..38d0bd02bbb 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2026, 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 @@ -56,13 +56,9 @@ error.missing-service-installer.advice=Add 'service-installer.exe' service insta message.icon-not-ico=The specified icon "{0}" is not an ICO file and will not be used. The default icon will be used in it's place. message.potential.windows.defender.issue=Warning: Windows Defender may prevent jpackage from functioning. If there is an issue, it can be addressed by either disabling realtime monitoring, or adding an exclusion for the directory "{0}". -message.outputting-to-location=Generating EXE for installer to: {0}. -message.output-location=Installer (.exe) saved to: {0} message.tool-version=Detected [{0}] version [{1}]. message.wrong-tool-version=Detected [{0}] version {1} but version {2} is required. message.use-wix36-features=WiX {0} detected. Enabling advanced cleanup action. message.product-code=MSI ProductCode: {0}. message.upgrade-code=MSI UpgradeCode: {0}. message.preparing-msi-config=Preparing MSI config: {0}. -message.generating-msi=Generating MSI: {0}. - diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index d2b423b2ed2..9b8b05af93b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -80,6 +80,7 @@ public class JPackageCommand extends CommandArguments { prerequisiteActions = new Actions(); verifyActions = new Actions(); excludeStandardAsserts(StandardAssert.MAIN_LAUNCHER_DESCRIPTION); + removeOldOutputBundle = true; } private JPackageCommand(JPackageCommand cmd, boolean immutable) { @@ -91,6 +92,7 @@ public class JPackageCommand extends CommandArguments { suppressOutput = cmd.suppressOutput; ignoreDefaultRuntime = cmd.ignoreDefaultRuntime; ignoreDefaultVerbose = cmd.ignoreDefaultVerbose; + removeOldOutputBundle = cmd.removeOldOutputBundle; this.immutable = immutable; prerequisiteActions = new Actions(cmd.prerequisiteActions); verifyActions = new Actions(cmd.verifyActions); @@ -844,6 +846,28 @@ public class JPackageCommand extends CommandArguments { return this; } + /** + * Configures this instance to optionally remove the existing output bundle + * before running the jpackage command. + * + * @param v {@code true} to remove existing output bundle before running the + * jpackage command, and {@code false} otherwise + * @return this + */ + public JPackageCommand removeOldOutputBundle(boolean v) { + verifyMutable(); + removeOldOutputBundle = v; + return this; + } + + /** + * Returns {@code true} if this instance will remove existing output bundle + * before running the jpackage command, and {@code false} otherwise. + */ + public boolean isRemoveOldOutputBundle() { + return removeOldOutputBundle; + } + public JPackageCommand validateOutput(TKit.TextStreamVerifier validator) { return validateOutput(validator::apply); } @@ -946,21 +970,18 @@ public class JPackageCommand extends CommandArguments { verifyMutable(); executePrerequisiteActions(); - if (hasArgument("--dest")) { - nullableOutputBundle().ifPresent(path -> { - ThrowingRunnable.toRunnable(() -> { - if (Files.isDirectory(path)) { - TKit.deleteDirectoryRecursive(path, String.format( - "Delete [%s] folder before running jpackage", - path)); - } else if (TKit.deleteIfExists(path)) { - TKit.trace(String.format( - "Deleted [%s] file before running jpackage", - path)); - } - }).run(); - }); - } + nullableOutputBundle().filter(_ -> { + return removeOldOutputBundle; + }).ifPresent(path -> { + ThrowingRunnable.toRunnable(() -> { + if (Files.isDirectory(path)) { + TKit.deleteDirectoryRecursive(path, + String.format("Delete [%s] folder before running jpackage", path)); + } else if (TKit.deleteIfExists(path)) { + TKit.trace(String.format("Deleted [%s] file before running jpackage", path)); + } + }).run(); + }); Path resourceDir = getArgumentValue("--resource-dir", () -> null, Path::of); if (resourceDir != null && Files.isDirectory(resourceDir)) { @@ -1090,7 +1111,7 @@ public class JPackageCommand extends CommandArguments { private final Map> snapshots; } - public static enum ReadOnlyPathAssert{ + public static enum ReadOnlyPathAssert { APP_IMAGE(new Builder("--app-image").enable(cmd -> { // External app image should be R/O unless it is an app image signing on macOS. return !(TKit.isOSX() && MacHelper.signPredefinedAppImage(cmd)); @@ -1774,6 +1795,7 @@ public class JPackageCommand extends CommandArguments { private boolean suppressOutput; private boolean ignoreDefaultRuntime; private boolean ignoreDefaultVerbose; + private boolean removeOldOutputBundle; private boolean immutable; private final Actions prerequisiteActions; private final Actions verifyActions; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java index 2e4f11d056f..2baf6683fdf 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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 @@ -726,12 +726,30 @@ public final class PackageTest extends RunnablePackageTest { } case CREATE -> { - Executor.Result result = cmd.execute(expectedJPackageExitCode); + var nullableOutputBundle = cmd.nullableOutputBundle(); + + var oldOutputBundleSnapshot = nullableOutputBundle + .filter(Files::exists) + .filter(_ -> { + return !cmd.isRemoveOldOutputBundle(); + }) + .map(TKit.PathSnapshot::new); + + var result = cmd.execute(expectedJPackageExitCode); + if (expectedJPackageExitCode == 0) { TKit.assertFileExists(cmd.outputBundle()); } else { - cmd.nullableOutputBundle().ifPresent(outputBundle -> { - TKit.assertPathExists(outputBundle, false); + nullableOutputBundle.ifPresent(outputBundle -> { + oldOutputBundleSnapshot.ifPresentOrElse(snapshot -> { + // jpackage failed, but the output bundle exists. + // This output bundle existed before the jpackage was invoked. + // Verify jpackage didn't modify it. + new TKit.PathSnapshot(outputBundle).assertEquals(snapshot, String.format( + "Check jpackage didn't modify the old output bundle [%s]", outputBundle)); + }, () -> { + TKit.assertPathExists(outputBundle, false); + }); }); } verifyPackageBundle(cmd, result, expectedJPackageExitCode); diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DefaultBundlingEnvironmentTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DefaultBundlingEnvironmentTest.java index 1a14330fe6e..709f0f8413b 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DefaultBundlingEnvironmentTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DefaultBundlingEnvironmentTest.java @@ -41,7 +41,7 @@ import java.util.spi.ToolProvider; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.cli.StandardBundlingOperation; -import jdk.jpackage.internal.model.AppImagePackageType; +import jdk.jpackage.internal.model.AppImageBundleType; import jdk.jpackage.internal.model.BundlingOperationDescriptor; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.StandardPackageType; @@ -119,9 +119,9 @@ public class DefaultBundlingEnvironmentTest extends JUnitAdapter { // #2 - jpackage should bail out earlier). // - final var type = op.packageTypeValue(); + final var type = op.bundleTypeValue(); final int iterationCount; - if (op.packageType() instanceof AppImagePackageType) { + if (op.bundleType() instanceof AppImageBundleType) { iterationCount = 1; } else { iterationCount = 2; @@ -165,7 +165,7 @@ public class DefaultBundlingEnvironmentTest extends JUnitAdapter { private static Script createMockScript(StandardBundlingOperation op) { - if (op.packageType() instanceof AppImagePackageType) { + if (op.bundleType() instanceof AppImageBundleType) { return Script.build().createSequence(); } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java index 721e0802d16..86a6cb075d0 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -633,7 +633,12 @@ public class PackagingPipelineTest { Package create() { return new Package.Stub( app, - new PackageType() {}, + new PackageType() { + @Override + public String label() { + throw new UnsupportedOperationException(); + } + }, "the-package", "My package", "1.0", diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardOptionTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardOptionTest.java index 4aa3d5f72c1..0b70f4151cc 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardOptionTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardOptionTest.java @@ -53,6 +53,8 @@ import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.cli.JOptSimpleOptionsBuilder.ConvertedOptionsBuilder; import jdk.jpackage.internal.cli.JOptSimpleOptionsBuilder.OptionsBuilder; import jdk.jpackage.internal.cli.StandardOption.LauncherProperty; +import jdk.jpackage.internal.model.AppImageBundleType; +import jdk.jpackage.internal.model.BundleType; import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.LauncherShortcut; import jdk.jpackage.internal.model.LauncherShortcutStartupDirectory; @@ -175,16 +177,21 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { assertEquals(DirectoryNotEmptyException.class, ex.getCause().getClass()); } + @ParameterizedTest + @EnumSource(names = {"WINDOWS", "LINUX", "MACOS"}) + public void test_TYPE_valid(OperatingSystem appImageOS) { + + var spec = new StandardOptionContext(appImageOS).mapOptionSpec(StandardOption.TYPE.getSpec()); + + test_TYPE_valid(spec, appImageOS); + } + @Test public void test_TYPE_valid() { var spec = StandardOption.TYPE.getSpec(); - Stream.of(StandardBundlingOperation.values()).forEach(bundlingOperation -> { - var pkgTypeStr = bundlingOperation.packageTypeValue(); - var pkgType = spec.converter().orElseThrow().convert(spec.name(), StringToken.of(pkgTypeStr)).orElseThrow(); - assertSame(bundlingOperation.packageType(), pkgType); - }); + test_TYPE_valid(spec, OperatingSystem.current()); } @ParameterizedTest @@ -336,6 +343,18 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { assertEquals(expectedOptionTable, optionTable); } + private void test_TYPE_valid(OptionSpec spec, OperatingSystem appImageOS) { + Stream.of(StandardBundlingOperation.values()).filter(bundlingOperation -> { + // Skip app image bundle type if it is from another platform. + return !(bundlingOperation.bundleType() instanceof AppImageBundleType) + || (bundlingOperation.os() == appImageOS); + }).forEach(bundlingOperation -> { + var bundleTypeStr = bundlingOperation.bundleTypeValue(); + var bundleType = spec.converter().orElseThrow().convert(spec.name(), StringToken.of(bundleTypeStr)).orElseThrow(); + assertSame(bundlingOperation.bundleType(), bundleType); + }); + } + private static Collection test_ARGUMENTS() { return List.of( Arguments.of("abc", List.of("abc")), diff --git a/test/jdk/tools/jpackage/share/BasicTest.java b/test/jdk/tools/jpackage/share/BasicTest.java index afa847f6e1b..977b7c7c057 100644 --- a/test/jdk/tools/jpackage/share/BasicTest.java +++ b/test/jdk/tools/jpackage/share/BasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ */ +import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE; import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE_AND_UNPACK; import java.io.IOException; @@ -32,6 +33,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.regex.Pattern; @@ -41,6 +43,7 @@ import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.CannedFormattedString; +import jdk.jpackage.test.ConfigurationTarget; import jdk.jpackage.test.Executor; import jdk.jpackage.test.HelloApp; import jdk.jpackage.test.JPackageCommand; @@ -176,57 +179,74 @@ public final class BasicTest { } @Test - @SuppressWarnings("unchecked") - public void testVerbose() { - JPackageCommand cmd = JPackageCommand.helloAppImage() - // Disable default logic adding `--verbose` option - // to jpackage command line. - .ignoreDefaultVerbose(true) - .saveConsoleOutput(true) - .setFakeRuntime().executePrerequisiteActions(); + @Parameter("false") + @Parameter("true") + public void testQuiet(boolean appImage) { - List expectedVerboseOutputStrings = new ArrayList<>(); - expectedVerboseOutputStrings.add("Creating app package:"); - if (TKit.isWindows()) { - expectedVerboseOutputStrings.add( - "Succeeded in building Windows Application Image package"); - } else if (TKit.isLinux()) { - expectedVerboseOutputStrings.add( - "Succeeded in building Linux Application Image package"); - } else if (TKit.isOSX()) { - expectedVerboseOutputStrings.add("Preparing Info.plist:"); - expectedVerboseOutputStrings.add( - "Succeeded in building Mac Application Image package"); + ConfigurationTarget target; + if (appImage) { + target = new ConfigurationTarget(JPackageCommand.helloAppImage()); } else { - TKit.throwUnknownPlatformError(); + target = new ConfigurationTarget(new PackageTest().configureHelloApp()); } - TKit.deleteDirectoryContentsRecursive(cmd.outputDir()); - List nonVerboseOutput = cmd.execute().getOutput(); - List[] verboseOutput = (List[])new List[1]; - - // Directory clean up is not 100% reliable on Windows because of - // antivirus software that can lock .exe files. Setup - // different output directory instead of cleaning the default one for - // verbose jpackage run. - TKit.withTempDirectory("verbose-output", tempDir -> { - cmd.setArgumentValue("--dest", tempDir); - cmd.addArgument("--verbose"); - verboseOutput[0] = cmd.execute().getOutput(); + target.addInitializer(cmd -> { + // Disable the default logic adding `--verbose` option to jpackage command line. + cmd.ignoreDefaultVerbose(true) + .useToolProvider(true) + .saveConsoleOutput(true) + .setFakeRuntime(); }); - TKit.assertTrue(nonVerboseOutput.size() < verboseOutput[0].size(), - "Check verbose output is longer than regular"); + Consumer asserter = result -> { + TKit.assertStringListEquals(List.of(), result.getOutput(), "Check output is empty"); + }; - expectedVerboseOutputStrings.forEach(str -> { - TKit.assertTextStream(str).label("regular output") - .predicate(String::contains).negate() - .apply(nonVerboseOutput); + target.cmd().map(JPackageCommand::execute).ifPresent(asserter); + target.test().ifPresent(test -> { + test.addBundleVerifier((_, result) -> { + asserter.accept(result); + }).run(CREATE); + }); + } + + @Test + @Parameter("false") + @Parameter("true") + public void testVerbose(boolean appImage) { + + ConfigurationTarget target; + if (appImage) { + target = new ConfigurationTarget(JPackageCommand.helloAppImage()); + } else { + target = new ConfigurationTarget(new PackageTest().configureHelloApp()); + } + + target.addInitializer(cmd -> { + // Disable the default logic adding `--verbose` option to jpackage command line. + cmd.ignoreDefaultVerbose(true) + .useToolProvider(true) + .addArgument("--verbose") + .saveConsoleOutput(true) + .setFakeRuntime(); + + List verboseContent; + if (appImage) { + verboseContent = List.of( + JPackageStringBundle.MAIN.cannedFormattedString("message.create-app-image"), + JPackageStringBundle.MAIN.cannedFormattedString("message.app-image-created")); + } else { + verboseContent = List.of( + JPackageStringBundle.MAIN.cannedFormattedString("message.create-package"), + JPackageStringBundle.MAIN.cannedFormattedString("message.package-created")); + } + + cmd.validateOutput(verboseContent.toArray(CannedFormattedString[]::new)); }); - expectedVerboseOutputStrings.forEach(str -> { - TKit.assertTextStream(str).label("verbose output") - .apply(verboseOutput[0]); + target.cmd().ifPresent(JPackageCommand::execute); + target.test().ifPresent(test -> { + test.run(CREATE); }); } diff --git a/test/jdk/tools/jpackage/share/OutputErrorTest.java b/test/jdk/tools/jpackage/share/OutputErrorTest.java new file mode 100644 index 00000000000..110e86e67d9 --- /dev/null +++ b/test/jdk/tools/jpackage/share/OutputErrorTest.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2026, 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.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.spi.ToolProvider; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageStringBundle; +import jdk.jpackage.test.JavaTool; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.TKit; + +/* + * @test + * @summary Test how jpackage handles errors writing output bundle + * @library /test/jdk/tools/jpackage/helpers + * @build jdk.jpackage.test.* + * @compile -Xlint:all -Werror OutputErrorTest.java + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=OutputErrorTest + */ + +public final class OutputErrorTest { + + @Test + @Parameter("DIR") + // "Locked file error" reliably works only on Windows + @Parameter(value = "LOCKED_FILE", ifOS = OperatingSystem.WINDOWS) + public void testPackage(ExistingOutputBundleType existingOutputBundleType) { + + new PackageTest().configureHelloApp().addInitializer(cmd -> { + + cmd.setFakeRuntime(); + cmd.setArgumentValue("--dest", TKit.createTempDirectory("output")); + cmd.removeOldOutputBundle(false); + cmd.validateOutput(JPackageCommand.makeError(JPackageStringBundle.MAIN.cannedFormattedString( + "error.output-bundle-cannot-be-overwritten", cmd.outputBundle().toAbsolutePath()))); + + var outputBundle = cmd.outputBundle(); + + switch (existingOutputBundleType) { + case DIR -> { + Files.createDirectories(outputBundle); + Files.writeString(outputBundle.resolve("foo.txt"), "Hello"); + } + case LOCKED_FILE -> { + Files.writeString(outputBundle, "Hello"); + cmd.useToolProvider(createToolProviderWithLockedFile( + JavaTool.JPACKAGE.asToolProvider(), outputBundle)); + } + } + + }).setExpectedExitCode(1).run(); + } + + enum ExistingOutputBundleType { + DIR, + LOCKED_FILE, + ; + } + + private static ToolProvider createToolProviderWithLockedFile(ToolProvider tp, Path lockedFile) { + Objects.requireNonNull(tp); + if (!Files.isRegularFile(lockedFile)) { + throw new IllegalArgumentException(); + } + + return new ToolProvider() { + + @Override + public String name() { + return "jpackage-mock"; + } + + @SuppressWarnings("try") + @Override + public int run(PrintWriter out, PrintWriter err, String... args) { + try { + var lastModifiedTime = Files.getLastModifiedTime(lockedFile); + try (var fos = new FileOutputStream(lockedFile.toFile()); var lock = fos.getChannel().lock()) { + Files.setLastModifiedTime(lockedFile, lastModifiedTime); + return tp.run(out, err, args); + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + }; + } +} From 56d7b524b3ddb49b985b4e6f061a7128b10cffb5 Mon Sep 17 00:00:00 2001 From: Eric Fang Date: Wed, 14 Jan 2026 06:17:04 +0000 Subject: [PATCH 027/328] 8372978: [VectorAPI] Fix incorrect identity values in UMIN/UMAX reductions Reviewed-by: psandoz, qamai, xgong --- .../jdk/incubator/vector/ByteVector.java | 8 +- .../jdk/incubator/vector/DoubleVector.java | 2 +- .../jdk/incubator/vector/FloatVector.java | 2 +- .../jdk/incubator/vector/IntVector.java | 8 +- .../jdk/incubator/vector/LongVector.java | 8 +- .../jdk/incubator/vector/ShortVector.java | 8 +- .../incubator/vector/X-Vector.java.template | 8 +- .../incubator/vector/Byte128VectorTests.java | 671 +++++++++++------- .../incubator/vector/Byte256VectorTests.java | 671 +++++++++++------- .../incubator/vector/Byte512VectorTests.java | 671 +++++++++++------- .../incubator/vector/Byte64VectorTests.java | 671 +++++++++++------- .../incubator/vector/ByteMaxVectorTests.java | 670 ++++++++++------- .../vector/Double128VectorTests.java | 309 ++++---- .../vector/Double256VectorTests.java | 309 ++++---- .../vector/Double512VectorTests.java | 309 ++++---- .../incubator/vector/Double64VectorTests.java | 309 ++++---- .../vector/DoubleMaxVectorTests.java | 310 ++++---- .../incubator/vector/Float128VectorTests.java | 309 ++++---- .../incubator/vector/Float256VectorTests.java | 309 ++++---- .../incubator/vector/Float512VectorTests.java | 309 ++++---- .../incubator/vector/Float64VectorTests.java | 309 ++++---- .../incubator/vector/FloatMaxVectorTests.java | 310 ++++---- .../incubator/vector/Int128VectorTests.java | 671 +++++++++++------- .../incubator/vector/Int256VectorTests.java | 671 +++++++++++------- .../incubator/vector/Int512VectorTests.java | 671 +++++++++++------- .../incubator/vector/Int64VectorTests.java | 671 +++++++++++------- .../incubator/vector/IntMaxVectorTests.java | 670 ++++++++++------- .../incubator/vector/Long128VectorTests.java | 671 +++++++++++------- .../incubator/vector/Long256VectorTests.java | 671 +++++++++++------- .../incubator/vector/Long512VectorTests.java | 671 +++++++++++------- .../incubator/vector/Long64VectorTests.java | 671 +++++++++++------- .../incubator/vector/LongMaxVectorTests.java | 670 ++++++++++------- .../incubator/vector/Short128VectorTests.java | 671 +++++++++++------- .../incubator/vector/Short256VectorTests.java | 671 +++++++++++------- .../incubator/vector/Short512VectorTests.java | 671 +++++++++++------- .../incubator/vector/Short64VectorTests.java | 671 +++++++++++------- .../incubator/vector/ShortMaxVectorTests.java | 670 ++++++++++------- test/jdk/jdk/incubator/vector/gen-template.sh | 24 +- .../Kernel-Reduction-Masked-op-func.template | 13 +- .../Kernel-Reduction-Masked-op.template | 13 +- .../Kernel-Reduction-op-func.template | 13 +- .../templates/Kernel-Reduction-op.template | 13 +- ...nel-SaturatingReduction-Masked-op.template | 13 +- .../Kernel-SaturatingReduction-op.template | 13 +- .../templates/Unit-Reduction-op-func.template | 23 + .../templates/Unit-Reduction-op.template | 23 + .../Unit-SaturatingReduction-op.template | 23 + .../vector/templates/Unit-header.template | 24 +- 48 files changed, 10315 insertions(+), 6432 deletions(-) diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java index 08406fef518..02e15d5f8dd 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -2873,9 +2873,9 @@ public abstract class ByteVector extends AbstractVector { case VECTOR_OP_MAX: return (v, m) -> toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> (byte) Math.max(a, b))); case VECTOR_OP_UMIN: return (v, m) -> - toBits(v.rOp(MAX_OR_INF, m, (i, a, b) -> (byte) VectorMath.minUnsigned(a, b))); + toBits(v.rOp(UMAX_VALUE, m, (i, a, b) -> (byte) VectorMath.minUnsigned(a, b))); case VECTOR_OP_UMAX: return (v, m) -> - toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> (byte) VectorMath.maxUnsigned(a, b))); + toBits(v.rOp(UMIN_VALUE, m, (i, a, b) -> (byte) VectorMath.maxUnsigned(a, b))); case VECTOR_OP_SUADD: return (v, m) -> toBits(v.rOp((byte)0, m, (i, a, b) -> (byte) VectorMath.addSaturatingUnsigned(a, b))); case VECTOR_OP_AND: return (v, m) -> @@ -2890,6 +2890,8 @@ public abstract class ByteVector extends AbstractVector { private static final byte MIN_OR_INF = Byte.MIN_VALUE; private static final byte MAX_OR_INF = Byte.MAX_VALUE; + private static final byte UMIN_VALUE = (byte)0; // Minimum unsigned value + private static final byte UMAX_VALUE = (byte)-1; // Maximum unsigned value public @Override abstract long reduceLanesToLong(VectorOperators.Associative op); public @Override abstract long reduceLanesToLong(VectorOperators.Associative op, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java index 786cd089ebe..08fda9c96e6 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java index b481d5a51d7..0f70a2b81c8 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java index 43356b9ea6c..23e703dcada 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -2858,9 +2858,9 @@ public abstract class IntVector extends AbstractVector { case VECTOR_OP_MAX: return (v, m) -> toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> (int) Math.max(a, b))); case VECTOR_OP_UMIN: return (v, m) -> - toBits(v.rOp(MAX_OR_INF, m, (i, a, b) -> (int) VectorMath.minUnsigned(a, b))); + toBits(v.rOp(UMAX_VALUE, m, (i, a, b) -> (int) VectorMath.minUnsigned(a, b))); case VECTOR_OP_UMAX: return (v, m) -> - toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> (int) VectorMath.maxUnsigned(a, b))); + toBits(v.rOp(UMIN_VALUE, m, (i, a, b) -> (int) VectorMath.maxUnsigned(a, b))); case VECTOR_OP_SUADD: return (v, m) -> toBits(v.rOp((int)0, m, (i, a, b) -> (int) VectorMath.addSaturatingUnsigned(a, b))); case VECTOR_OP_AND: return (v, m) -> @@ -2875,6 +2875,8 @@ public abstract class IntVector extends AbstractVector { private static final int MIN_OR_INF = Integer.MIN_VALUE; private static final int MAX_OR_INF = Integer.MAX_VALUE; + private static final int UMIN_VALUE = (int)0; // Minimum unsigned value + private static final int UMAX_VALUE = (int)-1; // Maximum unsigned value public @Override abstract long reduceLanesToLong(VectorOperators.Associative op); public @Override abstract long reduceLanesToLong(VectorOperators.Associative op, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java index 8947343ff30..58bfd4d7772 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -2724,9 +2724,9 @@ public abstract class LongVector extends AbstractVector { case VECTOR_OP_MAX: return (v, m) -> toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> (long) Math.max(a, b))); case VECTOR_OP_UMIN: return (v, m) -> - toBits(v.rOp(MAX_OR_INF, m, (i, a, b) -> (long) VectorMath.minUnsigned(a, b))); + toBits(v.rOp(UMAX_VALUE, m, (i, a, b) -> (long) VectorMath.minUnsigned(a, b))); case VECTOR_OP_UMAX: return (v, m) -> - toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> (long) VectorMath.maxUnsigned(a, b))); + toBits(v.rOp(UMIN_VALUE, m, (i, a, b) -> (long) VectorMath.maxUnsigned(a, b))); case VECTOR_OP_SUADD: return (v, m) -> toBits(v.rOp((long)0, m, (i, a, b) -> (long) VectorMath.addSaturatingUnsigned(a, b))); case VECTOR_OP_AND: return (v, m) -> @@ -2741,6 +2741,8 @@ public abstract class LongVector extends AbstractVector { private static final long MIN_OR_INF = Long.MIN_VALUE; private static final long MAX_OR_INF = Long.MAX_VALUE; + private static final long UMIN_VALUE = (long)0; // Minimum unsigned value + private static final long UMAX_VALUE = (long)-1; // Maximum unsigned value public @Override abstract long reduceLanesToLong(VectorOperators.Associative op); public @Override abstract long reduceLanesToLong(VectorOperators.Associative op, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java index e222c6d25f3..7ab7e7c4417 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -2874,9 +2874,9 @@ public abstract class ShortVector extends AbstractVector { case VECTOR_OP_MAX: return (v, m) -> toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> (short) Math.max(a, b))); case VECTOR_OP_UMIN: return (v, m) -> - toBits(v.rOp(MAX_OR_INF, m, (i, a, b) -> (short) VectorMath.minUnsigned(a, b))); + toBits(v.rOp(UMAX_VALUE, m, (i, a, b) -> (short) VectorMath.minUnsigned(a, b))); case VECTOR_OP_UMAX: return (v, m) -> - toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> (short) VectorMath.maxUnsigned(a, b))); + toBits(v.rOp(UMIN_VALUE, m, (i, a, b) -> (short) VectorMath.maxUnsigned(a, b))); case VECTOR_OP_SUADD: return (v, m) -> toBits(v.rOp((short)0, m, (i, a, b) -> (short) VectorMath.addSaturatingUnsigned(a, b))); case VECTOR_OP_AND: return (v, m) -> @@ -2891,6 +2891,8 @@ public abstract class ShortVector extends AbstractVector { private static final short MIN_OR_INF = Short.MIN_VALUE; private static final short MAX_OR_INF = Short.MAX_VALUE; + private static final short UMIN_VALUE = (short)0; // Minimum unsigned value + private static final short UMAX_VALUE = (short)-1; // Maximum unsigned value public @Override abstract long reduceLanesToLong(VectorOperators.Associative op); public @Override abstract long reduceLanesToLong(VectorOperators.Associative op, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template index f7d987fd280..ce3b7512c93 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -3448,9 +3448,9 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> ($type$) Math.max(a, b))); #if[!FP] case VECTOR_OP_UMIN: return (v, m) -> - toBits(v.rOp(MAX_OR_INF, m, (i, a, b) -> ($type$) VectorMath.minUnsigned(a, b))); + toBits(v.rOp(UMAX_VALUE, m, (i, a, b) -> ($type$) VectorMath.minUnsigned(a, b))); case VECTOR_OP_UMAX: return (v, m) -> - toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> ($type$) VectorMath.maxUnsigned(a, b))); + toBits(v.rOp(UMIN_VALUE, m, (i, a, b) -> ($type$) VectorMath.maxUnsigned(a, b))); case VECTOR_OP_SUADD: return (v, m) -> toBits(v.rOp(($type$)0, m, (i, a, b) -> ($type$) VectorMath.addSaturatingUnsigned(a, b))); #end[!FP] @@ -3472,6 +3472,8 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { #else[FP] private static final $type$ MIN_OR_INF = $Boxtype$.MIN_VALUE; private static final $type$ MAX_OR_INF = $Boxtype$.MAX_VALUE; + private static final $type$ UMIN_VALUE = ($type$)0; // Minimum unsigned value + private static final $type$ UMAX_VALUE = ($type$)-1; // Maximum unsigned value #end[FP] public @Override abstract long reduceLanesToLong(VectorOperators.Associative op); diff --git a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java index 3ad6d6f320f..fae7b678a09 100644 --- a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -63,9 +63,21 @@ public class Byte128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final byte CONST_SHIFT = Byte.SIZE / 2; + // Identity values for reduction operations + private static final byte ADD_IDENTITY = (byte)0; + private static final byte AND_IDENTITY = (byte)-1; + private static final byte FIRST_NONZERO_IDENTITY = (byte)0; + private static final byte MAX_IDENTITY = Byte.MIN_VALUE; + private static final byte MIN_IDENTITY = Byte.MAX_VALUE; + private static final byte MUL_IDENTITY = (byte)1; + private static final byte OR_IDENTITY = (byte)0; + private static final byte SUADD_IDENTITY = (byte)0; + private static final byte UMAX_IDENTITY = (byte)0; // Minimum unsigned value + private static final byte UMIN_IDENTITY = (byte)-1; // Maximum unsigned value + private static final byte XOR_IDENTITY = (byte)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); static void assertArraysStrictlyEquals(byte[] r, byte[] a) { @@ -3611,7 +3623,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ANDReduce(byte[] a, int idx) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3620,7 +3632,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ANDReduceAll(byte[] a) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3632,20 +3644,15 @@ public class Byte128VectorTests extends AbstractVectorTest { static void ANDReduceByte128VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + byte v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3653,8 +3660,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::ANDReduce, Byte128VectorTests::ANDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = AND_IDENTITY; + + Assert.assertEquals((byte) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id & x), x); + Assert.assertEquals((byte) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static byte ANDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3664,7 +3694,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ANDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3678,20 +3708,15 @@ public class Byte128VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + byte v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3700,7 +3725,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ORReduce(byte[] a, int idx) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3709,7 +3734,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ORReduceAll(byte[] a) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3724,17 +3749,12 @@ public class Byte128VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + byte v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3742,8 +3762,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::ORReduce, Byte128VectorTests::ORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = OR_IDENTITY; + + Assert.assertEquals((byte) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id | x), x); + Assert.assertEquals((byte) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static byte ORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3753,7 +3796,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3770,17 +3813,12 @@ public class Byte128VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + byte v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3789,7 +3827,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte XORReduce(byte[] a, int idx) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3798,7 +3836,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte XORReduceAll(byte[] a) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3813,17 +3851,12 @@ public class Byte128VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + byte v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3831,8 +3864,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::XORReduce, Byte128VectorTests::XORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = XOR_IDENTITY; + + Assert.assertEquals((byte) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id ^ x), x); + Assert.assertEquals((byte) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static byte XORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3842,7 +3898,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte XORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3859,17 +3915,12 @@ public class Byte128VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + byte v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3878,7 +3929,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3887,7 +3938,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ADDReduceAll(byte[] a) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3902,17 +3953,12 @@ public class Byte128VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + byte v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3920,8 +3966,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::ADDReduce, Byte128VectorTests::ADDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = ADD_IDENTITY; + + Assert.assertEquals((byte) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id + x), x); + Assert.assertEquals((byte) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static byte ADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3931,7 +4000,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3948,17 +4017,12 @@ public class Byte128VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + byte v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3967,7 +4031,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MULReduce(byte[] a, int idx) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3976,7 +4040,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MULReduceAll(byte[] a) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3988,20 +4052,15 @@ public class Byte128VectorTests extends AbstractVectorTest { static void MULReduceByte128VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + byte v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4009,8 +4068,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::MULReduce, Byte128VectorTests::MULReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MUL_IDENTITY; + + Assert.assertEquals((byte) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id * x), x); + Assert.assertEquals((byte) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static byte MULReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4020,7 +4102,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MULReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4034,20 +4116,15 @@ public class Byte128VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + byte v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4056,7 +4133,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.min(res, a[i]); } @@ -4065,7 +4142,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduce(a, i)); } @@ -4077,20 +4154,15 @@ public class Byte128VectorTests extends AbstractVectorTest { static void MINReduceByte128VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + byte v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4098,8 +4170,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::MINReduce, Byte128VectorTests::MINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MIN_IDENTITY; + + Assert.assertEquals((byte) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.min(id, x), x); + Assert.assertEquals((byte) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.min(res, a[i]); @@ -4109,7 +4204,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4123,20 +4218,15 @@ public class Byte128VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + byte v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4145,7 +4235,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.max(res, a[i]); } @@ -4154,7 +4244,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduce(a, i)); } @@ -4166,20 +4256,15 @@ public class Byte128VectorTests extends AbstractVectorTest { static void MAXReduceByte128VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + byte v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4187,8 +4272,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::MAXReduce, Byte128VectorTests::MAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MAX_IDENTITY; + + Assert.assertEquals((byte) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.max(id, x), x); + Assert.assertEquals((byte) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.max(res, a[i]); @@ -4198,7 +4306,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4212,20 +4320,15 @@ public class Byte128VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + byte v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4234,7 +4337,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte UMINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.minUnsigned(res, a[i]); } @@ -4243,7 +4346,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte UMINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4255,20 +4358,15 @@ public class Byte128VectorTests extends AbstractVectorTest { static void UMINReduceByte128VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + byte v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4276,8 +4374,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::UMINReduce, Byte128VectorTests::UMINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMIN_IDENTITY; + + Assert.assertEquals((byte) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static byte UMINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.minUnsigned(res, a[i]); @@ -4287,7 +4408,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte UMINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4301,20 +4422,15 @@ public class Byte128VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + byte v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4323,7 +4439,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte UMAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.maxUnsigned(res, a[i]); } @@ -4332,7 +4448,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte UMAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4344,20 +4460,15 @@ public class Byte128VectorTests extends AbstractVectorTest { static void UMAXReduceByte128VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + byte v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4365,8 +4476,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::UMAXReduce, Byte128VectorTests::UMAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMAX_IDENTITY; + + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static byte UMAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.maxUnsigned(res, a[i]); @@ -4376,7 +4510,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte UMAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4390,20 +4524,15 @@ public class Byte128VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + byte v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4412,7 +4541,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduce(byte[] a, int idx) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4421,7 +4550,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAll(byte[] a) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4433,20 +4562,15 @@ public class Byte128VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceByte128VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4454,8 +4578,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::FIRST_NONZEROReduce, Byte128VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4465,7 +4612,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4479,20 +4626,15 @@ public class Byte128VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4549,7 +4691,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte SUADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4558,7 +4700,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte SUADDReduceAll(byte[] a) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4573,17 +4715,12 @@ public class Byte128VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + byte v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4591,8 +4728,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::SUADDReduce, Byte128VectorTests::SUADDReduceAll); } + @Test(dataProvider = "byteSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = SUADD_IDENTITY; + + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static byte SUADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4602,7 +4762,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte SUADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4618,17 +4778,12 @@ public class Byte128VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + byte v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java index d64caa3424f..0e59db7d05d 100644 --- a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -63,9 +63,21 @@ public class Byte256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final byte CONST_SHIFT = Byte.SIZE / 2; + // Identity values for reduction operations + private static final byte ADD_IDENTITY = (byte)0; + private static final byte AND_IDENTITY = (byte)-1; + private static final byte FIRST_NONZERO_IDENTITY = (byte)0; + private static final byte MAX_IDENTITY = Byte.MIN_VALUE; + private static final byte MIN_IDENTITY = Byte.MAX_VALUE; + private static final byte MUL_IDENTITY = (byte)1; + private static final byte OR_IDENTITY = (byte)0; + private static final byte SUADD_IDENTITY = (byte)0; + private static final byte UMAX_IDENTITY = (byte)0; // Minimum unsigned value + private static final byte UMIN_IDENTITY = (byte)-1; // Maximum unsigned value + private static final byte XOR_IDENTITY = (byte)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); static void assertArraysStrictlyEquals(byte[] r, byte[] a) { @@ -3611,7 +3623,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ANDReduce(byte[] a, int idx) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3620,7 +3632,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ANDReduceAll(byte[] a) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3632,20 +3644,15 @@ public class Byte256VectorTests extends AbstractVectorTest { static void ANDReduceByte256VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + byte v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3653,8 +3660,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::ANDReduce, Byte256VectorTests::ANDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = AND_IDENTITY; + + Assert.assertEquals((byte) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id & x), x); + Assert.assertEquals((byte) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static byte ANDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3664,7 +3694,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ANDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3678,20 +3708,15 @@ public class Byte256VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + byte v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3700,7 +3725,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ORReduce(byte[] a, int idx) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3709,7 +3734,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ORReduceAll(byte[] a) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3724,17 +3749,12 @@ public class Byte256VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + byte v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3742,8 +3762,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::ORReduce, Byte256VectorTests::ORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = OR_IDENTITY; + + Assert.assertEquals((byte) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id | x), x); + Assert.assertEquals((byte) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static byte ORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3753,7 +3796,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3770,17 +3813,12 @@ public class Byte256VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + byte v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3789,7 +3827,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte XORReduce(byte[] a, int idx) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3798,7 +3836,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte XORReduceAll(byte[] a) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3813,17 +3851,12 @@ public class Byte256VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + byte v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3831,8 +3864,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::XORReduce, Byte256VectorTests::XORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = XOR_IDENTITY; + + Assert.assertEquals((byte) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id ^ x), x); + Assert.assertEquals((byte) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static byte XORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3842,7 +3898,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte XORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3859,17 +3915,12 @@ public class Byte256VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + byte v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3878,7 +3929,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3887,7 +3938,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ADDReduceAll(byte[] a) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3902,17 +3953,12 @@ public class Byte256VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + byte v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3920,8 +3966,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::ADDReduce, Byte256VectorTests::ADDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = ADD_IDENTITY; + + Assert.assertEquals((byte) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id + x), x); + Assert.assertEquals((byte) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static byte ADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3931,7 +4000,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3948,17 +4017,12 @@ public class Byte256VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + byte v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3967,7 +4031,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MULReduce(byte[] a, int idx) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3976,7 +4040,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MULReduceAll(byte[] a) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3988,20 +4052,15 @@ public class Byte256VectorTests extends AbstractVectorTest { static void MULReduceByte256VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + byte v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4009,8 +4068,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::MULReduce, Byte256VectorTests::MULReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MUL_IDENTITY; + + Assert.assertEquals((byte) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id * x), x); + Assert.assertEquals((byte) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static byte MULReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4020,7 +4102,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MULReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4034,20 +4116,15 @@ public class Byte256VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + byte v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4056,7 +4133,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.min(res, a[i]); } @@ -4065,7 +4142,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduce(a, i)); } @@ -4077,20 +4154,15 @@ public class Byte256VectorTests extends AbstractVectorTest { static void MINReduceByte256VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + byte v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4098,8 +4170,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::MINReduce, Byte256VectorTests::MINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MIN_IDENTITY; + + Assert.assertEquals((byte) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.min(id, x), x); + Assert.assertEquals((byte) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.min(res, a[i]); @@ -4109,7 +4204,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4123,20 +4218,15 @@ public class Byte256VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + byte v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4145,7 +4235,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.max(res, a[i]); } @@ -4154,7 +4244,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduce(a, i)); } @@ -4166,20 +4256,15 @@ public class Byte256VectorTests extends AbstractVectorTest { static void MAXReduceByte256VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + byte v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4187,8 +4272,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::MAXReduce, Byte256VectorTests::MAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MAX_IDENTITY; + + Assert.assertEquals((byte) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.max(id, x), x); + Assert.assertEquals((byte) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.max(res, a[i]); @@ -4198,7 +4306,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4212,20 +4320,15 @@ public class Byte256VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + byte v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4234,7 +4337,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte UMINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.minUnsigned(res, a[i]); } @@ -4243,7 +4346,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte UMINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4255,20 +4358,15 @@ public class Byte256VectorTests extends AbstractVectorTest { static void UMINReduceByte256VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + byte v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4276,8 +4374,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::UMINReduce, Byte256VectorTests::UMINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMIN_IDENTITY; + + Assert.assertEquals((byte) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static byte UMINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.minUnsigned(res, a[i]); @@ -4287,7 +4408,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte UMINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4301,20 +4422,15 @@ public class Byte256VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + byte v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4323,7 +4439,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte UMAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.maxUnsigned(res, a[i]); } @@ -4332,7 +4448,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte UMAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4344,20 +4460,15 @@ public class Byte256VectorTests extends AbstractVectorTest { static void UMAXReduceByte256VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + byte v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4365,8 +4476,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::UMAXReduce, Byte256VectorTests::UMAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMAX_IDENTITY; + + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static byte UMAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.maxUnsigned(res, a[i]); @@ -4376,7 +4510,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte UMAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4390,20 +4524,15 @@ public class Byte256VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + byte v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4412,7 +4541,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduce(byte[] a, int idx) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4421,7 +4550,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAll(byte[] a) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4433,20 +4562,15 @@ public class Byte256VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceByte256VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4454,8 +4578,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::FIRST_NONZEROReduce, Byte256VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4465,7 +4612,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4479,20 +4626,15 @@ public class Byte256VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4549,7 +4691,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte SUADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4558,7 +4700,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte SUADDReduceAll(byte[] a) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4573,17 +4715,12 @@ public class Byte256VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + byte v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4591,8 +4728,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::SUADDReduce, Byte256VectorTests::SUADDReduceAll); } + @Test(dataProvider = "byteSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = SUADD_IDENTITY; + + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static byte SUADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4602,7 +4762,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte SUADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4618,17 +4778,12 @@ public class Byte256VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + byte v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java index f494e3d3ae8..5ad3bbdbc05 100644 --- a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -63,9 +63,21 @@ public class Byte512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final byte CONST_SHIFT = Byte.SIZE / 2; + // Identity values for reduction operations + private static final byte ADD_IDENTITY = (byte)0; + private static final byte AND_IDENTITY = (byte)-1; + private static final byte FIRST_NONZERO_IDENTITY = (byte)0; + private static final byte MAX_IDENTITY = Byte.MIN_VALUE; + private static final byte MIN_IDENTITY = Byte.MAX_VALUE; + private static final byte MUL_IDENTITY = (byte)1; + private static final byte OR_IDENTITY = (byte)0; + private static final byte SUADD_IDENTITY = (byte)0; + private static final byte UMAX_IDENTITY = (byte)0; // Minimum unsigned value + private static final byte UMIN_IDENTITY = (byte)-1; // Maximum unsigned value + private static final byte XOR_IDENTITY = (byte)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); static void assertArraysStrictlyEquals(byte[] r, byte[] a) { @@ -3611,7 +3623,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ANDReduce(byte[] a, int idx) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3620,7 +3632,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ANDReduceAll(byte[] a) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3632,20 +3644,15 @@ public class Byte512VectorTests extends AbstractVectorTest { static void ANDReduceByte512VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + byte v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3653,8 +3660,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::ANDReduce, Byte512VectorTests::ANDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = AND_IDENTITY; + + Assert.assertEquals((byte) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id & x), x); + Assert.assertEquals((byte) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static byte ANDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3664,7 +3694,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ANDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3678,20 +3708,15 @@ public class Byte512VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + byte v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3700,7 +3725,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ORReduce(byte[] a, int idx) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3709,7 +3734,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ORReduceAll(byte[] a) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3724,17 +3749,12 @@ public class Byte512VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + byte v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3742,8 +3762,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::ORReduce, Byte512VectorTests::ORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = OR_IDENTITY; + + Assert.assertEquals((byte) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id | x), x); + Assert.assertEquals((byte) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static byte ORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3753,7 +3796,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3770,17 +3813,12 @@ public class Byte512VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + byte v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3789,7 +3827,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte XORReduce(byte[] a, int idx) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3798,7 +3836,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte XORReduceAll(byte[] a) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3813,17 +3851,12 @@ public class Byte512VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + byte v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3831,8 +3864,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::XORReduce, Byte512VectorTests::XORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = XOR_IDENTITY; + + Assert.assertEquals((byte) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id ^ x), x); + Assert.assertEquals((byte) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static byte XORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3842,7 +3898,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte XORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3859,17 +3915,12 @@ public class Byte512VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + byte v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3878,7 +3929,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3887,7 +3938,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ADDReduceAll(byte[] a) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3902,17 +3953,12 @@ public class Byte512VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + byte v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3920,8 +3966,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::ADDReduce, Byte512VectorTests::ADDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = ADD_IDENTITY; + + Assert.assertEquals((byte) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id + x), x); + Assert.assertEquals((byte) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static byte ADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3931,7 +4000,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3948,17 +4017,12 @@ public class Byte512VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + byte v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3967,7 +4031,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MULReduce(byte[] a, int idx) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3976,7 +4040,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MULReduceAll(byte[] a) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3988,20 +4052,15 @@ public class Byte512VectorTests extends AbstractVectorTest { static void MULReduceByte512VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + byte v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4009,8 +4068,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::MULReduce, Byte512VectorTests::MULReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MUL_IDENTITY; + + Assert.assertEquals((byte) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id * x), x); + Assert.assertEquals((byte) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static byte MULReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4020,7 +4102,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MULReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4034,20 +4116,15 @@ public class Byte512VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + byte v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4056,7 +4133,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.min(res, a[i]); } @@ -4065,7 +4142,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduce(a, i)); } @@ -4077,20 +4154,15 @@ public class Byte512VectorTests extends AbstractVectorTest { static void MINReduceByte512VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + byte v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4098,8 +4170,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::MINReduce, Byte512VectorTests::MINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MIN_IDENTITY; + + Assert.assertEquals((byte) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.min(id, x), x); + Assert.assertEquals((byte) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.min(res, a[i]); @@ -4109,7 +4204,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4123,20 +4218,15 @@ public class Byte512VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + byte v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4145,7 +4235,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.max(res, a[i]); } @@ -4154,7 +4244,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduce(a, i)); } @@ -4166,20 +4256,15 @@ public class Byte512VectorTests extends AbstractVectorTest { static void MAXReduceByte512VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + byte v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4187,8 +4272,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::MAXReduce, Byte512VectorTests::MAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MAX_IDENTITY; + + Assert.assertEquals((byte) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.max(id, x), x); + Assert.assertEquals((byte) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.max(res, a[i]); @@ -4198,7 +4306,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4212,20 +4320,15 @@ public class Byte512VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + byte v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4234,7 +4337,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte UMINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.minUnsigned(res, a[i]); } @@ -4243,7 +4346,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte UMINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4255,20 +4358,15 @@ public class Byte512VectorTests extends AbstractVectorTest { static void UMINReduceByte512VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + byte v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4276,8 +4374,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::UMINReduce, Byte512VectorTests::UMINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMIN_IDENTITY; + + Assert.assertEquals((byte) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static byte UMINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.minUnsigned(res, a[i]); @@ -4287,7 +4408,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte UMINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4301,20 +4422,15 @@ public class Byte512VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + byte v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4323,7 +4439,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte UMAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.maxUnsigned(res, a[i]); } @@ -4332,7 +4448,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte UMAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4344,20 +4460,15 @@ public class Byte512VectorTests extends AbstractVectorTest { static void UMAXReduceByte512VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + byte v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4365,8 +4476,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::UMAXReduce, Byte512VectorTests::UMAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMAX_IDENTITY; + + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static byte UMAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.maxUnsigned(res, a[i]); @@ -4376,7 +4510,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte UMAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4390,20 +4524,15 @@ public class Byte512VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + byte v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4412,7 +4541,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduce(byte[] a, int idx) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4421,7 +4550,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAll(byte[] a) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4433,20 +4562,15 @@ public class Byte512VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceByte512VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4454,8 +4578,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::FIRST_NONZEROReduce, Byte512VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4465,7 +4612,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4479,20 +4626,15 @@ public class Byte512VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4549,7 +4691,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte SUADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4558,7 +4700,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte SUADDReduceAll(byte[] a) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4573,17 +4715,12 @@ public class Byte512VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + byte v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4591,8 +4728,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::SUADDReduce, Byte512VectorTests::SUADDReduceAll); } + @Test(dataProvider = "byteSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = SUADD_IDENTITY; + + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static byte SUADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4602,7 +4762,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte SUADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4618,17 +4778,12 @@ public class Byte512VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + byte v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java index da2961cd97b..e28fb2b2001 100644 --- a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -63,9 +63,21 @@ public class Byte64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final byte CONST_SHIFT = Byte.SIZE / 2; + // Identity values for reduction operations + private static final byte ADD_IDENTITY = (byte)0; + private static final byte AND_IDENTITY = (byte)-1; + private static final byte FIRST_NONZERO_IDENTITY = (byte)0; + private static final byte MAX_IDENTITY = Byte.MIN_VALUE; + private static final byte MIN_IDENTITY = Byte.MAX_VALUE; + private static final byte MUL_IDENTITY = (byte)1; + private static final byte OR_IDENTITY = (byte)0; + private static final byte SUADD_IDENTITY = (byte)0; + private static final byte UMAX_IDENTITY = (byte)0; // Minimum unsigned value + private static final byte UMIN_IDENTITY = (byte)-1; // Maximum unsigned value + private static final byte XOR_IDENTITY = (byte)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); static void assertArraysStrictlyEquals(byte[] r, byte[] a) { @@ -3611,7 +3623,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ANDReduce(byte[] a, int idx) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3620,7 +3632,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ANDReduceAll(byte[] a) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3632,20 +3644,15 @@ public class Byte64VectorTests extends AbstractVectorTest { static void ANDReduceByte64VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + byte v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3653,8 +3660,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::ANDReduce, Byte64VectorTests::ANDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = AND_IDENTITY; + + Assert.assertEquals((byte) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id & x), x); + Assert.assertEquals((byte) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static byte ANDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3664,7 +3694,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ANDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3678,20 +3708,15 @@ public class Byte64VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + byte v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3700,7 +3725,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ORReduce(byte[] a, int idx) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3709,7 +3734,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ORReduceAll(byte[] a) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3724,17 +3749,12 @@ public class Byte64VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + byte v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3742,8 +3762,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::ORReduce, Byte64VectorTests::ORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = OR_IDENTITY; + + Assert.assertEquals((byte) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id | x), x); + Assert.assertEquals((byte) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static byte ORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3753,7 +3796,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3770,17 +3813,12 @@ public class Byte64VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + byte v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3789,7 +3827,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte XORReduce(byte[] a, int idx) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3798,7 +3836,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte XORReduceAll(byte[] a) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3813,17 +3851,12 @@ public class Byte64VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + byte v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3831,8 +3864,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::XORReduce, Byte64VectorTests::XORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = XOR_IDENTITY; + + Assert.assertEquals((byte) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id ^ x), x); + Assert.assertEquals((byte) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static byte XORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3842,7 +3898,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte XORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3859,17 +3915,12 @@ public class Byte64VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + byte v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3878,7 +3929,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3887,7 +3938,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ADDReduceAll(byte[] a) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3902,17 +3953,12 @@ public class Byte64VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + byte v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3920,8 +3966,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::ADDReduce, Byte64VectorTests::ADDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = ADD_IDENTITY; + + Assert.assertEquals((byte) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id + x), x); + Assert.assertEquals((byte) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static byte ADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3931,7 +4000,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3948,17 +4017,12 @@ public class Byte64VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + byte v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3967,7 +4031,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MULReduce(byte[] a, int idx) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3976,7 +4040,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MULReduceAll(byte[] a) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3988,20 +4052,15 @@ public class Byte64VectorTests extends AbstractVectorTest { static void MULReduceByte64VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + byte v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4009,8 +4068,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::MULReduce, Byte64VectorTests::MULReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MUL_IDENTITY; + + Assert.assertEquals((byte) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id * x), x); + Assert.assertEquals((byte) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static byte MULReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4020,7 +4102,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MULReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4034,20 +4116,15 @@ public class Byte64VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + byte v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4056,7 +4133,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.min(res, a[i]); } @@ -4065,7 +4142,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduce(a, i)); } @@ -4077,20 +4154,15 @@ public class Byte64VectorTests extends AbstractVectorTest { static void MINReduceByte64VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + byte v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4098,8 +4170,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::MINReduce, Byte64VectorTests::MINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MIN_IDENTITY; + + Assert.assertEquals((byte) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.min(id, x), x); + Assert.assertEquals((byte) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.min(res, a[i]); @@ -4109,7 +4204,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4123,20 +4218,15 @@ public class Byte64VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + byte v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4145,7 +4235,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.max(res, a[i]); } @@ -4154,7 +4244,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduce(a, i)); } @@ -4166,20 +4256,15 @@ public class Byte64VectorTests extends AbstractVectorTest { static void MAXReduceByte64VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + byte v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4187,8 +4272,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::MAXReduce, Byte64VectorTests::MAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MAX_IDENTITY; + + Assert.assertEquals((byte) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.max(id, x), x); + Assert.assertEquals((byte) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.max(res, a[i]); @@ -4198,7 +4306,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4212,20 +4320,15 @@ public class Byte64VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + byte v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4234,7 +4337,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte UMINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.minUnsigned(res, a[i]); } @@ -4243,7 +4346,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte UMINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4255,20 +4358,15 @@ public class Byte64VectorTests extends AbstractVectorTest { static void UMINReduceByte64VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + byte v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4276,8 +4374,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::UMINReduce, Byte64VectorTests::UMINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMIN_IDENTITY; + + Assert.assertEquals((byte) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static byte UMINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.minUnsigned(res, a[i]); @@ -4287,7 +4408,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte UMINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4301,20 +4422,15 @@ public class Byte64VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + byte v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4323,7 +4439,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte UMAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.maxUnsigned(res, a[i]); } @@ -4332,7 +4448,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte UMAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4344,20 +4460,15 @@ public class Byte64VectorTests extends AbstractVectorTest { static void UMAXReduceByte64VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + byte v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4365,8 +4476,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::UMAXReduce, Byte64VectorTests::UMAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMAX_IDENTITY; + + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static byte UMAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.maxUnsigned(res, a[i]); @@ -4376,7 +4510,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte UMAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4390,20 +4524,15 @@ public class Byte64VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + byte v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4412,7 +4541,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduce(byte[] a, int idx) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4421,7 +4550,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAll(byte[] a) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4433,20 +4562,15 @@ public class Byte64VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceByte64VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4454,8 +4578,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::FIRST_NONZEROReduce, Byte64VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4465,7 +4612,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4479,20 +4626,15 @@ public class Byte64VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4549,7 +4691,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte SUADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4558,7 +4700,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte SUADDReduceAll(byte[] a) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4573,17 +4715,12 @@ public class Byte64VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + byte v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4591,8 +4728,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::SUADDReduce, Byte64VectorTests::SUADDReduceAll); } + @Test(dataProvider = "byteSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = SUADD_IDENTITY; + + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static byte SUADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4602,7 +4762,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte SUADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4618,17 +4778,12 @@ public class Byte64VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + byte v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java index a5872219f10..b6932785b55 100644 --- a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -71,6 +71,19 @@ public class ByteMaxVectorTests extends AbstractVectorTest { private static final byte CONST_SHIFT = Byte.SIZE / 2; + // Identity values for reduction operations + private static final byte ADD_IDENTITY = (byte)0; + private static final byte AND_IDENTITY = (byte)-1; + private static final byte FIRST_NONZERO_IDENTITY = (byte)0; + private static final byte MAX_IDENTITY = Byte.MIN_VALUE; + private static final byte MIN_IDENTITY = Byte.MAX_VALUE; + private static final byte MUL_IDENTITY = (byte)1; + private static final byte OR_IDENTITY = (byte)0; + private static final byte SUADD_IDENTITY = (byte)0; + private static final byte UMAX_IDENTITY = (byte)0; // Minimum unsigned value + private static final byte UMIN_IDENTITY = (byte)-1; // Maximum unsigned value + private static final byte XOR_IDENTITY = (byte)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); static void assertArraysStrictlyEquals(byte[] r, byte[] a) { @@ -3616,7 +3629,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ANDReduce(byte[] a, int idx) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3625,7 +3638,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ANDReduceAll(byte[] a) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3637,20 +3650,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static void ANDReduceByteMaxVectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + byte v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3658,8 +3666,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::ANDReduce, ByteMaxVectorTests::ANDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = AND_IDENTITY; + + Assert.assertEquals((byte) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id & x), x); + Assert.assertEquals((byte) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static byte ANDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3669,7 +3700,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ANDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3683,20 +3714,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + byte v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3705,7 +3731,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ORReduce(byte[] a, int idx) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3714,7 +3740,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ORReduceAll(byte[] a) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3729,17 +3755,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + byte v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3747,8 +3768,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::ORReduce, ByteMaxVectorTests::ORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = OR_IDENTITY; + + Assert.assertEquals((byte) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id | x), x); + Assert.assertEquals((byte) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static byte ORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3758,7 +3802,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3775,17 +3819,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + byte v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3794,7 +3833,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte XORReduce(byte[] a, int idx) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3803,7 +3842,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte XORReduceAll(byte[] a) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3818,17 +3857,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + byte v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3836,8 +3870,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::XORReduce, ByteMaxVectorTests::XORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = XOR_IDENTITY; + + Assert.assertEquals((byte) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id ^ x), x); + Assert.assertEquals((byte) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static byte XORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3847,7 +3904,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte XORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3864,17 +3921,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + byte v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3883,7 +3935,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3892,7 +3944,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ADDReduceAll(byte[] a) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3907,17 +3959,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + byte v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3925,8 +3972,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::ADDReduce, ByteMaxVectorTests::ADDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = ADD_IDENTITY; + + Assert.assertEquals((byte) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id + x), x); + Assert.assertEquals((byte) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static byte ADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3936,7 +4006,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3953,17 +4023,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + byte v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3972,7 +4037,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MULReduce(byte[] a, int idx) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3981,7 +4046,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MULReduceAll(byte[] a) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3993,20 +4058,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static void MULReduceByteMaxVectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + byte v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4014,8 +4074,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::MULReduce, ByteMaxVectorTests::MULReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MUL_IDENTITY; + + Assert.assertEquals((byte) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id * x), x); + Assert.assertEquals((byte) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static byte MULReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4025,7 +4108,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MULReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4039,20 +4122,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + byte v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4061,7 +4139,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.min(res, a[i]); } @@ -4070,7 +4148,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduce(a, i)); } @@ -4082,20 +4160,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static void MINReduceByteMaxVectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + byte v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4103,8 +4176,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::MINReduce, ByteMaxVectorTests::MINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MIN_IDENTITY; + + Assert.assertEquals((byte) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.min(id, x), x); + Assert.assertEquals((byte) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.min(res, a[i]); @@ -4114,7 +4210,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4128,20 +4224,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + byte v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4150,7 +4241,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.max(res, a[i]); } @@ -4159,7 +4250,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduce(a, i)); } @@ -4171,20 +4262,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static void MAXReduceByteMaxVectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + byte v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4192,8 +4278,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::MAXReduce, ByteMaxVectorTests::MAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MAX_IDENTITY; + + Assert.assertEquals((byte) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.max(id, x), x); + Assert.assertEquals((byte) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.max(res, a[i]); @@ -4203,7 +4312,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4217,20 +4326,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + byte v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4239,7 +4343,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte UMINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.minUnsigned(res, a[i]); } @@ -4248,7 +4352,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte UMINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4260,20 +4364,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static void UMINReduceByteMaxVectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + byte v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4281,8 +4380,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::UMINReduce, ByteMaxVectorTests::UMINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMIN_IDENTITY; + + Assert.assertEquals((byte) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static byte UMINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.minUnsigned(res, a[i]); @@ -4292,7 +4414,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte UMINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4306,20 +4428,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + byte v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4328,7 +4445,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte UMAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.maxUnsigned(res, a[i]); } @@ -4337,7 +4454,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte UMAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4349,20 +4466,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static void UMAXReduceByteMaxVectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + byte v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4370,8 +4482,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::UMAXReduce, ByteMaxVectorTests::UMAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMAX_IDENTITY; + + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static byte UMAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.maxUnsigned(res, a[i]); @@ -4381,7 +4516,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte UMAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4395,20 +4530,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + byte v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4417,7 +4547,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduce(byte[] a, int idx) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4426,7 +4556,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAll(byte[] a) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4438,20 +4568,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceByteMaxVectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4459,8 +4584,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::FIRST_NONZEROReduce, ByteMaxVectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4470,7 +4618,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4484,20 +4632,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4554,7 +4697,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte SUADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4563,7 +4706,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte SUADDReduceAll(byte[] a) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4578,17 +4721,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + byte v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4596,8 +4734,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::SUADDReduce, ByteMaxVectorTests::SUADDReduceAll); } + @Test(dataProvider = "byteSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = SUADD_IDENTITY; + + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static byte SUADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4607,7 +4768,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte SUADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4623,17 +4784,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + byte v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Double128VectorTests.java b/test/jdk/jdk/incubator/vector/Double128VectorTests.java index 215edbb3a66..1d4cadd2158 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,6 +62,12 @@ public class Double128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // Identity values for reduction operations + private static final double ADD_IDENTITY = (double)0; + private static final double FIRST_NONZERO_IDENTITY = (double)0; + private static final double MAX_IDENTITY = Double.NEGATIVE_INFINITY; + private static final double MIN_IDENTITY = Double.POSITIVE_INFINITY; + private static final double MUL_IDENTITY = (double)1; // for floating point addition reduction ops that may introduce rounding errors private static final double RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (double)10.0; @@ -2384,7 +2390,7 @@ relativeError)); } static double ADDReduce(double[] a, int idx) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2393,7 +2399,7 @@ relativeError)); } static double ADDReduceAll(double[] a) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2408,17 +2414,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + double v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2426,8 +2427,31 @@ relativeError)); Double128VectorTests::ADDReduce, Double128VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = ADD_IDENTITY; + + Assert.assertEquals((double) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id + x), x); + Assert.assertEquals((double) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2437,7 +2461,7 @@ relativeError)); } static double ADDReduceAllMasked(double[] a, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2454,17 +2478,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + double v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2473,7 +2492,7 @@ relativeError)); } static double MULReduce(double[] a, int idx) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2482,7 +2501,7 @@ relativeError)); } static double MULReduceAll(double[] a) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2494,20 +2513,15 @@ relativeError)); static void MULReduceDouble128VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + double v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2515,8 +2529,31 @@ relativeError)); Double128VectorTests::MULReduce, Double128VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MUL_IDENTITY; + + Assert.assertEquals((double) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id * x), x); + Assert.assertEquals((double) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static double MULReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2526,7 +2563,7 @@ relativeError)); } static double MULReduceAllMasked(double[] a, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2540,20 +2577,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + double v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2562,7 +2594,7 @@ relativeError)); } static double MINReduce(double[] a, int idx) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.min(res, a[i]); } @@ -2571,7 +2603,7 @@ relativeError)); } static double MINReduceAll(double[] a) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduce(a, i)); } @@ -2583,20 +2615,15 @@ relativeError)); static void MINReduceDouble128VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + double v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2604,8 +2631,31 @@ relativeError)); Double128VectorTests::MINReduce, Double128VectorTests::MINReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MIN_IDENTITY; + + Assert.assertEquals((double) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.min(id, x), x); + Assert.assertEquals((double) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static double MINReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.min(res, a[i]); @@ -2615,7 +2665,7 @@ relativeError)); } static double MINReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2629,20 +2679,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + double v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2651,7 +2696,7 @@ relativeError)); } static double MAXReduce(double[] a, int idx) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.max(res, a[i]); } @@ -2660,7 +2705,7 @@ relativeError)); } static double MAXReduceAll(double[] a) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduce(a, i)); } @@ -2672,20 +2717,15 @@ relativeError)); static void MAXReduceDouble128VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + double v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2693,8 +2733,31 @@ relativeError)); Double128VectorTests::MAXReduce, Double128VectorTests::MAXReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MAX_IDENTITY; + + Assert.assertEquals((double) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.max(id, x), x); + Assert.assertEquals((double) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.max(res, a[i]); @@ -2704,7 +2767,7 @@ relativeError)); } static double MAXReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2718,20 +2781,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + double v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2740,7 +2798,7 @@ relativeError)); } static double FIRST_NONZEROReduce(double[] a, int idx) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2749,7 +2807,7 @@ relativeError)); } static double FIRST_NONZEROReduceAll(double[] a) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2761,20 +2819,15 @@ relativeError)); static void FIRST_NONZEROReduceDouble128VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2782,8 +2835,31 @@ relativeError)); Double128VectorTests::FIRST_NONZEROReduce, Double128VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2793,7 +2869,7 @@ relativeError)); } static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2807,20 +2883,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Double256VectorTests.java b/test/jdk/jdk/incubator/vector/Double256VectorTests.java index 14d52320ce8..b5acfe0ef34 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,6 +62,12 @@ public class Double256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // Identity values for reduction operations + private static final double ADD_IDENTITY = (double)0; + private static final double FIRST_NONZERO_IDENTITY = (double)0; + private static final double MAX_IDENTITY = Double.NEGATIVE_INFINITY; + private static final double MIN_IDENTITY = Double.POSITIVE_INFINITY; + private static final double MUL_IDENTITY = (double)1; // for floating point addition reduction ops that may introduce rounding errors private static final double RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (double)10.0; @@ -2384,7 +2390,7 @@ relativeError)); } static double ADDReduce(double[] a, int idx) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2393,7 +2399,7 @@ relativeError)); } static double ADDReduceAll(double[] a) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2408,17 +2414,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + double v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2426,8 +2427,31 @@ relativeError)); Double256VectorTests::ADDReduce, Double256VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = ADD_IDENTITY; + + Assert.assertEquals((double) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id + x), x); + Assert.assertEquals((double) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2437,7 +2461,7 @@ relativeError)); } static double ADDReduceAllMasked(double[] a, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2454,17 +2478,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + double v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2473,7 +2492,7 @@ relativeError)); } static double MULReduce(double[] a, int idx) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2482,7 +2501,7 @@ relativeError)); } static double MULReduceAll(double[] a) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2494,20 +2513,15 @@ relativeError)); static void MULReduceDouble256VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + double v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2515,8 +2529,31 @@ relativeError)); Double256VectorTests::MULReduce, Double256VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MUL_IDENTITY; + + Assert.assertEquals((double) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id * x), x); + Assert.assertEquals((double) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static double MULReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2526,7 +2563,7 @@ relativeError)); } static double MULReduceAllMasked(double[] a, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2540,20 +2577,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + double v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2562,7 +2594,7 @@ relativeError)); } static double MINReduce(double[] a, int idx) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.min(res, a[i]); } @@ -2571,7 +2603,7 @@ relativeError)); } static double MINReduceAll(double[] a) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduce(a, i)); } @@ -2583,20 +2615,15 @@ relativeError)); static void MINReduceDouble256VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + double v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2604,8 +2631,31 @@ relativeError)); Double256VectorTests::MINReduce, Double256VectorTests::MINReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MIN_IDENTITY; + + Assert.assertEquals((double) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.min(id, x), x); + Assert.assertEquals((double) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static double MINReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.min(res, a[i]); @@ -2615,7 +2665,7 @@ relativeError)); } static double MINReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2629,20 +2679,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + double v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2651,7 +2696,7 @@ relativeError)); } static double MAXReduce(double[] a, int idx) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.max(res, a[i]); } @@ -2660,7 +2705,7 @@ relativeError)); } static double MAXReduceAll(double[] a) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduce(a, i)); } @@ -2672,20 +2717,15 @@ relativeError)); static void MAXReduceDouble256VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + double v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2693,8 +2733,31 @@ relativeError)); Double256VectorTests::MAXReduce, Double256VectorTests::MAXReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MAX_IDENTITY; + + Assert.assertEquals((double) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.max(id, x), x); + Assert.assertEquals((double) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.max(res, a[i]); @@ -2704,7 +2767,7 @@ relativeError)); } static double MAXReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2718,20 +2781,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + double v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2740,7 +2798,7 @@ relativeError)); } static double FIRST_NONZEROReduce(double[] a, int idx) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2749,7 +2807,7 @@ relativeError)); } static double FIRST_NONZEROReduceAll(double[] a) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2761,20 +2819,15 @@ relativeError)); static void FIRST_NONZEROReduceDouble256VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2782,8 +2835,31 @@ relativeError)); Double256VectorTests::FIRST_NONZEROReduce, Double256VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2793,7 +2869,7 @@ relativeError)); } static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2807,20 +2883,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Double512VectorTests.java b/test/jdk/jdk/incubator/vector/Double512VectorTests.java index 91a4669a1b1..3f85d0e52a6 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,6 +62,12 @@ public class Double512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // Identity values for reduction operations + private static final double ADD_IDENTITY = (double)0; + private static final double FIRST_NONZERO_IDENTITY = (double)0; + private static final double MAX_IDENTITY = Double.NEGATIVE_INFINITY; + private static final double MIN_IDENTITY = Double.POSITIVE_INFINITY; + private static final double MUL_IDENTITY = (double)1; // for floating point addition reduction ops that may introduce rounding errors private static final double RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (double)10.0; @@ -2384,7 +2390,7 @@ relativeError)); } static double ADDReduce(double[] a, int idx) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2393,7 +2399,7 @@ relativeError)); } static double ADDReduceAll(double[] a) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2408,17 +2414,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + double v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2426,8 +2427,31 @@ relativeError)); Double512VectorTests::ADDReduce, Double512VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = ADD_IDENTITY; + + Assert.assertEquals((double) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id + x), x); + Assert.assertEquals((double) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2437,7 +2461,7 @@ relativeError)); } static double ADDReduceAllMasked(double[] a, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2454,17 +2478,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + double v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2473,7 +2492,7 @@ relativeError)); } static double MULReduce(double[] a, int idx) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2482,7 +2501,7 @@ relativeError)); } static double MULReduceAll(double[] a) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2494,20 +2513,15 @@ relativeError)); static void MULReduceDouble512VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + double v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2515,8 +2529,31 @@ relativeError)); Double512VectorTests::MULReduce, Double512VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MUL_IDENTITY; + + Assert.assertEquals((double) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id * x), x); + Assert.assertEquals((double) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static double MULReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2526,7 +2563,7 @@ relativeError)); } static double MULReduceAllMasked(double[] a, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2540,20 +2577,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + double v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2562,7 +2594,7 @@ relativeError)); } static double MINReduce(double[] a, int idx) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.min(res, a[i]); } @@ -2571,7 +2603,7 @@ relativeError)); } static double MINReduceAll(double[] a) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduce(a, i)); } @@ -2583,20 +2615,15 @@ relativeError)); static void MINReduceDouble512VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + double v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2604,8 +2631,31 @@ relativeError)); Double512VectorTests::MINReduce, Double512VectorTests::MINReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MIN_IDENTITY; + + Assert.assertEquals((double) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.min(id, x), x); + Assert.assertEquals((double) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static double MINReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.min(res, a[i]); @@ -2615,7 +2665,7 @@ relativeError)); } static double MINReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2629,20 +2679,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + double v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2651,7 +2696,7 @@ relativeError)); } static double MAXReduce(double[] a, int idx) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.max(res, a[i]); } @@ -2660,7 +2705,7 @@ relativeError)); } static double MAXReduceAll(double[] a) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduce(a, i)); } @@ -2672,20 +2717,15 @@ relativeError)); static void MAXReduceDouble512VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + double v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2693,8 +2733,31 @@ relativeError)); Double512VectorTests::MAXReduce, Double512VectorTests::MAXReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MAX_IDENTITY; + + Assert.assertEquals((double) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.max(id, x), x); + Assert.assertEquals((double) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.max(res, a[i]); @@ -2704,7 +2767,7 @@ relativeError)); } static double MAXReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2718,20 +2781,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + double v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2740,7 +2798,7 @@ relativeError)); } static double FIRST_NONZEROReduce(double[] a, int idx) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2749,7 +2807,7 @@ relativeError)); } static double FIRST_NONZEROReduceAll(double[] a) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2761,20 +2819,15 @@ relativeError)); static void FIRST_NONZEROReduceDouble512VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2782,8 +2835,31 @@ relativeError)); Double512VectorTests::FIRST_NONZEROReduce, Double512VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2793,7 +2869,7 @@ relativeError)); } static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2807,20 +2883,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Double64VectorTests.java b/test/jdk/jdk/incubator/vector/Double64VectorTests.java index 659e18cd8af..ab3586fb424 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,6 +62,12 @@ public class Double64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // Identity values for reduction operations + private static final double ADD_IDENTITY = (double)0; + private static final double FIRST_NONZERO_IDENTITY = (double)0; + private static final double MAX_IDENTITY = Double.NEGATIVE_INFINITY; + private static final double MIN_IDENTITY = Double.POSITIVE_INFINITY; + private static final double MUL_IDENTITY = (double)1; // for floating point addition reduction ops that may introduce rounding errors private static final double RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (double)10.0; @@ -2384,7 +2390,7 @@ relativeError)); } static double ADDReduce(double[] a, int idx) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2393,7 +2399,7 @@ relativeError)); } static double ADDReduceAll(double[] a) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2408,17 +2414,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + double v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2426,8 +2427,31 @@ relativeError)); Double64VectorTests::ADDReduce, Double64VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = ADD_IDENTITY; + + Assert.assertEquals((double) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id + x), x); + Assert.assertEquals((double) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2437,7 +2461,7 @@ relativeError)); } static double ADDReduceAllMasked(double[] a, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2454,17 +2478,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + double v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2473,7 +2492,7 @@ relativeError)); } static double MULReduce(double[] a, int idx) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2482,7 +2501,7 @@ relativeError)); } static double MULReduceAll(double[] a) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2494,20 +2513,15 @@ relativeError)); static void MULReduceDouble64VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + double v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2515,8 +2529,31 @@ relativeError)); Double64VectorTests::MULReduce, Double64VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MUL_IDENTITY; + + Assert.assertEquals((double) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id * x), x); + Assert.assertEquals((double) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static double MULReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2526,7 +2563,7 @@ relativeError)); } static double MULReduceAllMasked(double[] a, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2540,20 +2577,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + double v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2562,7 +2594,7 @@ relativeError)); } static double MINReduce(double[] a, int idx) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.min(res, a[i]); } @@ -2571,7 +2603,7 @@ relativeError)); } static double MINReduceAll(double[] a) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduce(a, i)); } @@ -2583,20 +2615,15 @@ relativeError)); static void MINReduceDouble64VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + double v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2604,8 +2631,31 @@ relativeError)); Double64VectorTests::MINReduce, Double64VectorTests::MINReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MIN_IDENTITY; + + Assert.assertEquals((double) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.min(id, x), x); + Assert.assertEquals((double) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static double MINReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.min(res, a[i]); @@ -2615,7 +2665,7 @@ relativeError)); } static double MINReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2629,20 +2679,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + double v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2651,7 +2696,7 @@ relativeError)); } static double MAXReduce(double[] a, int idx) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.max(res, a[i]); } @@ -2660,7 +2705,7 @@ relativeError)); } static double MAXReduceAll(double[] a) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduce(a, i)); } @@ -2672,20 +2717,15 @@ relativeError)); static void MAXReduceDouble64VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + double v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2693,8 +2733,31 @@ relativeError)); Double64VectorTests::MAXReduce, Double64VectorTests::MAXReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MAX_IDENTITY; + + Assert.assertEquals((double) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.max(id, x), x); + Assert.assertEquals((double) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.max(res, a[i]); @@ -2704,7 +2767,7 @@ relativeError)); } static double MAXReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2718,20 +2781,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + double v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2740,7 +2798,7 @@ relativeError)); } static double FIRST_NONZEROReduce(double[] a, int idx) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2749,7 +2807,7 @@ relativeError)); } static double FIRST_NONZEROReduceAll(double[] a) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2761,20 +2819,15 @@ relativeError)); static void FIRST_NONZEROReduceDouble64VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2782,8 +2835,31 @@ relativeError)); Double64VectorTests::FIRST_NONZEROReduce, Double64VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2793,7 +2869,7 @@ relativeError)); } static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2807,20 +2883,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java index ac85f0bd07b..8f135cd221a 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -68,6 +68,13 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { private static final int Max = 256; // juts so we can do N/Max + // Identity values for reduction operations + private static final double ADD_IDENTITY = (double)0; + private static final double FIRST_NONZERO_IDENTITY = (double)0; + private static final double MAX_IDENTITY = Double.NEGATIVE_INFINITY; + private static final double MIN_IDENTITY = Double.POSITIVE_INFINITY; + private static final double MUL_IDENTITY = (double)1; + // for floating point addition reduction ops that may introduce rounding errors private static final double RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (double)10.0; @@ -2389,7 +2396,7 @@ relativeError)); } static double ADDReduce(double[] a, int idx) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2398,7 +2405,7 @@ relativeError)); } static double ADDReduceAll(double[] a) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2413,17 +2420,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + double v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2431,8 +2433,31 @@ relativeError)); DoubleMaxVectorTests::ADDReduce, DoubleMaxVectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = ADD_IDENTITY; + + Assert.assertEquals((double) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id + x), x); + Assert.assertEquals((double) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2442,7 +2467,7 @@ relativeError)); } static double ADDReduceAllMasked(double[] a, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2459,17 +2484,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + double v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2478,7 +2498,7 @@ relativeError)); } static double MULReduce(double[] a, int idx) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2487,7 +2507,7 @@ relativeError)); } static double MULReduceAll(double[] a) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2499,20 +2519,15 @@ relativeError)); static void MULReduceDoubleMaxVectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + double v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2520,8 +2535,31 @@ relativeError)); DoubleMaxVectorTests::MULReduce, DoubleMaxVectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MUL_IDENTITY; + + Assert.assertEquals((double) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id * x), x); + Assert.assertEquals((double) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static double MULReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2531,7 +2569,7 @@ relativeError)); } static double MULReduceAllMasked(double[] a, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2545,20 +2583,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + double v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2567,7 +2600,7 @@ relativeError)); } static double MINReduce(double[] a, int idx) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.min(res, a[i]); } @@ -2576,7 +2609,7 @@ relativeError)); } static double MINReduceAll(double[] a) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduce(a, i)); } @@ -2588,20 +2621,15 @@ relativeError)); static void MINReduceDoubleMaxVectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + double v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2609,8 +2637,31 @@ relativeError)); DoubleMaxVectorTests::MINReduce, DoubleMaxVectorTests::MINReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MIN_IDENTITY; + + Assert.assertEquals((double) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.min(id, x), x); + Assert.assertEquals((double) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static double MINReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.min(res, a[i]); @@ -2620,7 +2671,7 @@ relativeError)); } static double MINReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2634,20 +2685,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + double v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2656,7 +2702,7 @@ relativeError)); } static double MAXReduce(double[] a, int idx) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.max(res, a[i]); } @@ -2665,7 +2711,7 @@ relativeError)); } static double MAXReduceAll(double[] a) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduce(a, i)); } @@ -2677,20 +2723,15 @@ relativeError)); static void MAXReduceDoubleMaxVectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + double v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2698,8 +2739,31 @@ relativeError)); DoubleMaxVectorTests::MAXReduce, DoubleMaxVectorTests::MAXReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MAX_IDENTITY; + + Assert.assertEquals((double) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.max(id, x), x); + Assert.assertEquals((double) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.max(res, a[i]); @@ -2709,7 +2773,7 @@ relativeError)); } static double MAXReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2723,20 +2787,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + double v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2745,7 +2804,7 @@ relativeError)); } static double FIRST_NONZEROReduce(double[] a, int idx) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2754,7 +2813,7 @@ relativeError)); } static double FIRST_NONZEROReduceAll(double[] a) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2766,20 +2825,15 @@ relativeError)); static void FIRST_NONZEROReduceDoubleMaxVectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2787,8 +2841,31 @@ relativeError)); DoubleMaxVectorTests::FIRST_NONZEROReduce, DoubleMaxVectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2798,7 +2875,7 @@ relativeError)); } static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2812,20 +2889,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Float128VectorTests.java b/test/jdk/jdk/incubator/vector/Float128VectorTests.java index 32b93293fb9..f97c5b0064c 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,6 +62,12 @@ public class Float128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // Identity values for reduction operations + private static final float ADD_IDENTITY = (float)0; + private static final float FIRST_NONZERO_IDENTITY = (float)0; + private static final float MAX_IDENTITY = Float.NEGATIVE_INFINITY; + private static final float MIN_IDENTITY = Float.POSITIVE_INFINITY; + private static final float MUL_IDENTITY = (float)1; // for floating point addition reduction ops that may introduce rounding errors private static final float RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (float)10.0; @@ -2395,7 +2401,7 @@ relativeError)); } static float ADDReduce(float[] a, int idx) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2404,7 +2410,7 @@ relativeError)); } static float ADDReduceAll(float[] a) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2419,17 +2425,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + float v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2437,8 +2438,31 @@ relativeError)); Float128VectorTests::ADDReduce, Float128VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "floatUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = ADD_IDENTITY; + + Assert.assertEquals((float) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id + x), x); + Assert.assertEquals((float) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2448,7 +2472,7 @@ relativeError)); } static float ADDReduceAllMasked(float[] a, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2465,17 +2489,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + float v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2484,7 +2503,7 @@ relativeError)); } static float MULReduce(float[] a, int idx) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2493,7 +2512,7 @@ relativeError)); } static float MULReduceAll(float[] a) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2505,20 +2524,15 @@ relativeError)); static void MULReduceFloat128VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + float v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2526,8 +2540,31 @@ relativeError)); Float128VectorTests::MULReduce, Float128VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MUL_IDENTITY; + + Assert.assertEquals((float) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id * x), x); + Assert.assertEquals((float) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static float MULReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2537,7 +2574,7 @@ relativeError)); } static float MULReduceAllMasked(float[] a, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2551,20 +2588,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + float v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2573,7 +2605,7 @@ relativeError)); } static float MINReduce(float[] a, int idx) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.min(res, a[i]); } @@ -2582,7 +2614,7 @@ relativeError)); } static float MINReduceAll(float[] a) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduce(a, i)); } @@ -2594,20 +2626,15 @@ relativeError)); static void MINReduceFloat128VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + float v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2615,8 +2642,31 @@ relativeError)); Float128VectorTests::MINReduce, Float128VectorTests::MINReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MIN_IDENTITY; + + Assert.assertEquals((float) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.min(id, x), x); + Assert.assertEquals((float) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static float MINReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.min(res, a[i]); @@ -2626,7 +2676,7 @@ relativeError)); } static float MINReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2640,20 +2690,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + float v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2662,7 +2707,7 @@ relativeError)); } static float MAXReduce(float[] a, int idx) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.max(res, a[i]); } @@ -2671,7 +2716,7 @@ relativeError)); } static float MAXReduceAll(float[] a) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduce(a, i)); } @@ -2683,20 +2728,15 @@ relativeError)); static void MAXReduceFloat128VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + float v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2704,8 +2744,31 @@ relativeError)); Float128VectorTests::MAXReduce, Float128VectorTests::MAXReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MAX_IDENTITY; + + Assert.assertEquals((float) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.max(id, x), x); + Assert.assertEquals((float) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.max(res, a[i]); @@ -2715,7 +2778,7 @@ relativeError)); } static float MAXReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2729,20 +2792,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + float v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2751,7 +2809,7 @@ relativeError)); } static float FIRST_NONZEROReduce(float[] a, int idx) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2760,7 +2818,7 @@ relativeError)); } static float FIRST_NONZEROReduceAll(float[] a) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2772,20 +2830,15 @@ relativeError)); static void FIRST_NONZEROReduceFloat128VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2793,8 +2846,31 @@ relativeError)); Float128VectorTests::FIRST_NONZEROReduce, Float128VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2804,7 +2880,7 @@ relativeError)); } static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2818,20 +2894,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Float256VectorTests.java b/test/jdk/jdk/incubator/vector/Float256VectorTests.java index 9847865eacb..d9746d3291c 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,6 +62,12 @@ public class Float256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // Identity values for reduction operations + private static final float ADD_IDENTITY = (float)0; + private static final float FIRST_NONZERO_IDENTITY = (float)0; + private static final float MAX_IDENTITY = Float.NEGATIVE_INFINITY; + private static final float MIN_IDENTITY = Float.POSITIVE_INFINITY; + private static final float MUL_IDENTITY = (float)1; // for floating point addition reduction ops that may introduce rounding errors private static final float RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (float)10.0; @@ -2395,7 +2401,7 @@ relativeError)); } static float ADDReduce(float[] a, int idx) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2404,7 +2410,7 @@ relativeError)); } static float ADDReduceAll(float[] a) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2419,17 +2425,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + float v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2437,8 +2438,31 @@ relativeError)); Float256VectorTests::ADDReduce, Float256VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "floatUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = ADD_IDENTITY; + + Assert.assertEquals((float) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id + x), x); + Assert.assertEquals((float) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2448,7 +2472,7 @@ relativeError)); } static float ADDReduceAllMasked(float[] a, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2465,17 +2489,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + float v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2484,7 +2503,7 @@ relativeError)); } static float MULReduce(float[] a, int idx) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2493,7 +2512,7 @@ relativeError)); } static float MULReduceAll(float[] a) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2505,20 +2524,15 @@ relativeError)); static void MULReduceFloat256VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + float v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2526,8 +2540,31 @@ relativeError)); Float256VectorTests::MULReduce, Float256VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MUL_IDENTITY; + + Assert.assertEquals((float) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id * x), x); + Assert.assertEquals((float) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static float MULReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2537,7 +2574,7 @@ relativeError)); } static float MULReduceAllMasked(float[] a, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2551,20 +2588,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + float v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2573,7 +2605,7 @@ relativeError)); } static float MINReduce(float[] a, int idx) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.min(res, a[i]); } @@ -2582,7 +2614,7 @@ relativeError)); } static float MINReduceAll(float[] a) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduce(a, i)); } @@ -2594,20 +2626,15 @@ relativeError)); static void MINReduceFloat256VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + float v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2615,8 +2642,31 @@ relativeError)); Float256VectorTests::MINReduce, Float256VectorTests::MINReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MIN_IDENTITY; + + Assert.assertEquals((float) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.min(id, x), x); + Assert.assertEquals((float) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static float MINReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.min(res, a[i]); @@ -2626,7 +2676,7 @@ relativeError)); } static float MINReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2640,20 +2690,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + float v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2662,7 +2707,7 @@ relativeError)); } static float MAXReduce(float[] a, int idx) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.max(res, a[i]); } @@ -2671,7 +2716,7 @@ relativeError)); } static float MAXReduceAll(float[] a) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduce(a, i)); } @@ -2683,20 +2728,15 @@ relativeError)); static void MAXReduceFloat256VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + float v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2704,8 +2744,31 @@ relativeError)); Float256VectorTests::MAXReduce, Float256VectorTests::MAXReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MAX_IDENTITY; + + Assert.assertEquals((float) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.max(id, x), x); + Assert.assertEquals((float) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.max(res, a[i]); @@ -2715,7 +2778,7 @@ relativeError)); } static float MAXReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2729,20 +2792,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + float v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2751,7 +2809,7 @@ relativeError)); } static float FIRST_NONZEROReduce(float[] a, int idx) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2760,7 +2818,7 @@ relativeError)); } static float FIRST_NONZEROReduceAll(float[] a) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2772,20 +2830,15 @@ relativeError)); static void FIRST_NONZEROReduceFloat256VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2793,8 +2846,31 @@ relativeError)); Float256VectorTests::FIRST_NONZEROReduce, Float256VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2804,7 +2880,7 @@ relativeError)); } static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2818,20 +2894,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Float512VectorTests.java b/test/jdk/jdk/incubator/vector/Float512VectorTests.java index 0daa5310ff0..ca395221c6b 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,6 +62,12 @@ public class Float512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // Identity values for reduction operations + private static final float ADD_IDENTITY = (float)0; + private static final float FIRST_NONZERO_IDENTITY = (float)0; + private static final float MAX_IDENTITY = Float.NEGATIVE_INFINITY; + private static final float MIN_IDENTITY = Float.POSITIVE_INFINITY; + private static final float MUL_IDENTITY = (float)1; // for floating point addition reduction ops that may introduce rounding errors private static final float RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (float)10.0; @@ -2395,7 +2401,7 @@ relativeError)); } static float ADDReduce(float[] a, int idx) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2404,7 +2410,7 @@ relativeError)); } static float ADDReduceAll(float[] a) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2419,17 +2425,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + float v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2437,8 +2438,31 @@ relativeError)); Float512VectorTests::ADDReduce, Float512VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "floatUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = ADD_IDENTITY; + + Assert.assertEquals((float) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id + x), x); + Assert.assertEquals((float) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2448,7 +2472,7 @@ relativeError)); } static float ADDReduceAllMasked(float[] a, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2465,17 +2489,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + float v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2484,7 +2503,7 @@ relativeError)); } static float MULReduce(float[] a, int idx) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2493,7 +2512,7 @@ relativeError)); } static float MULReduceAll(float[] a) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2505,20 +2524,15 @@ relativeError)); static void MULReduceFloat512VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + float v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2526,8 +2540,31 @@ relativeError)); Float512VectorTests::MULReduce, Float512VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MUL_IDENTITY; + + Assert.assertEquals((float) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id * x), x); + Assert.assertEquals((float) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static float MULReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2537,7 +2574,7 @@ relativeError)); } static float MULReduceAllMasked(float[] a, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2551,20 +2588,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + float v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2573,7 +2605,7 @@ relativeError)); } static float MINReduce(float[] a, int idx) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.min(res, a[i]); } @@ -2582,7 +2614,7 @@ relativeError)); } static float MINReduceAll(float[] a) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduce(a, i)); } @@ -2594,20 +2626,15 @@ relativeError)); static void MINReduceFloat512VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + float v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2615,8 +2642,31 @@ relativeError)); Float512VectorTests::MINReduce, Float512VectorTests::MINReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MIN_IDENTITY; + + Assert.assertEquals((float) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.min(id, x), x); + Assert.assertEquals((float) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static float MINReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.min(res, a[i]); @@ -2626,7 +2676,7 @@ relativeError)); } static float MINReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2640,20 +2690,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + float v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2662,7 +2707,7 @@ relativeError)); } static float MAXReduce(float[] a, int idx) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.max(res, a[i]); } @@ -2671,7 +2716,7 @@ relativeError)); } static float MAXReduceAll(float[] a) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduce(a, i)); } @@ -2683,20 +2728,15 @@ relativeError)); static void MAXReduceFloat512VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + float v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2704,8 +2744,31 @@ relativeError)); Float512VectorTests::MAXReduce, Float512VectorTests::MAXReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MAX_IDENTITY; + + Assert.assertEquals((float) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.max(id, x), x); + Assert.assertEquals((float) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.max(res, a[i]); @@ -2715,7 +2778,7 @@ relativeError)); } static float MAXReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2729,20 +2792,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + float v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2751,7 +2809,7 @@ relativeError)); } static float FIRST_NONZEROReduce(float[] a, int idx) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2760,7 +2818,7 @@ relativeError)); } static float FIRST_NONZEROReduceAll(float[] a) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2772,20 +2830,15 @@ relativeError)); static void FIRST_NONZEROReduceFloat512VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2793,8 +2846,31 @@ relativeError)); Float512VectorTests::FIRST_NONZEROReduce, Float512VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2804,7 +2880,7 @@ relativeError)); } static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2818,20 +2894,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Float64VectorTests.java b/test/jdk/jdk/incubator/vector/Float64VectorTests.java index 921264fc4e2..1b14cdb7791 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,6 +62,12 @@ public class Float64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // Identity values for reduction operations + private static final float ADD_IDENTITY = (float)0; + private static final float FIRST_NONZERO_IDENTITY = (float)0; + private static final float MAX_IDENTITY = Float.NEGATIVE_INFINITY; + private static final float MIN_IDENTITY = Float.POSITIVE_INFINITY; + private static final float MUL_IDENTITY = (float)1; // for floating point addition reduction ops that may introduce rounding errors private static final float RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (float)10.0; @@ -2395,7 +2401,7 @@ relativeError)); } static float ADDReduce(float[] a, int idx) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2404,7 +2410,7 @@ relativeError)); } static float ADDReduceAll(float[] a) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2419,17 +2425,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + float v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2437,8 +2438,31 @@ relativeError)); Float64VectorTests::ADDReduce, Float64VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "floatUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = ADD_IDENTITY; + + Assert.assertEquals((float) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id + x), x); + Assert.assertEquals((float) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2448,7 +2472,7 @@ relativeError)); } static float ADDReduceAllMasked(float[] a, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2465,17 +2489,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + float v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2484,7 +2503,7 @@ relativeError)); } static float MULReduce(float[] a, int idx) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2493,7 +2512,7 @@ relativeError)); } static float MULReduceAll(float[] a) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2505,20 +2524,15 @@ relativeError)); static void MULReduceFloat64VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + float v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2526,8 +2540,31 @@ relativeError)); Float64VectorTests::MULReduce, Float64VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MUL_IDENTITY; + + Assert.assertEquals((float) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id * x), x); + Assert.assertEquals((float) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static float MULReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2537,7 +2574,7 @@ relativeError)); } static float MULReduceAllMasked(float[] a, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2551,20 +2588,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + float v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2573,7 +2605,7 @@ relativeError)); } static float MINReduce(float[] a, int idx) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.min(res, a[i]); } @@ -2582,7 +2614,7 @@ relativeError)); } static float MINReduceAll(float[] a) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduce(a, i)); } @@ -2594,20 +2626,15 @@ relativeError)); static void MINReduceFloat64VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + float v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2615,8 +2642,31 @@ relativeError)); Float64VectorTests::MINReduce, Float64VectorTests::MINReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MIN_IDENTITY; + + Assert.assertEquals((float) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.min(id, x), x); + Assert.assertEquals((float) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static float MINReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.min(res, a[i]); @@ -2626,7 +2676,7 @@ relativeError)); } static float MINReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2640,20 +2690,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + float v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2662,7 +2707,7 @@ relativeError)); } static float MAXReduce(float[] a, int idx) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.max(res, a[i]); } @@ -2671,7 +2716,7 @@ relativeError)); } static float MAXReduceAll(float[] a) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduce(a, i)); } @@ -2683,20 +2728,15 @@ relativeError)); static void MAXReduceFloat64VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + float v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2704,8 +2744,31 @@ relativeError)); Float64VectorTests::MAXReduce, Float64VectorTests::MAXReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MAX_IDENTITY; + + Assert.assertEquals((float) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.max(id, x), x); + Assert.assertEquals((float) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.max(res, a[i]); @@ -2715,7 +2778,7 @@ relativeError)); } static float MAXReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2729,20 +2792,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + float v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2751,7 +2809,7 @@ relativeError)); } static float FIRST_NONZEROReduce(float[] a, int idx) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2760,7 +2818,7 @@ relativeError)); } static float FIRST_NONZEROReduceAll(float[] a) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2772,20 +2830,15 @@ relativeError)); static void FIRST_NONZEROReduceFloat64VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2793,8 +2846,31 @@ relativeError)); Float64VectorTests::FIRST_NONZEROReduce, Float64VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2804,7 +2880,7 @@ relativeError)); } static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2818,20 +2894,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java index 07c9b7d0ef9..53edb408035 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -68,6 +68,13 @@ public class FloatMaxVectorTests extends AbstractVectorTest { private static final int Max = 256; // juts so we can do N/Max + // Identity values for reduction operations + private static final float ADD_IDENTITY = (float)0; + private static final float FIRST_NONZERO_IDENTITY = (float)0; + private static final float MAX_IDENTITY = Float.NEGATIVE_INFINITY; + private static final float MIN_IDENTITY = Float.POSITIVE_INFINITY; + private static final float MUL_IDENTITY = (float)1; + // for floating point addition reduction ops that may introduce rounding errors private static final float RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (float)10.0; @@ -2400,7 +2407,7 @@ relativeError)); } static float ADDReduce(float[] a, int idx) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2409,7 +2416,7 @@ relativeError)); } static float ADDReduceAll(float[] a) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2424,17 +2431,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + float v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2442,8 +2444,31 @@ relativeError)); FloatMaxVectorTests::ADDReduce, FloatMaxVectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "floatUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = ADD_IDENTITY; + + Assert.assertEquals((float) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id + x), x); + Assert.assertEquals((float) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2453,7 +2478,7 @@ relativeError)); } static float ADDReduceAllMasked(float[] a, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2470,17 +2495,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + float v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2489,7 +2509,7 @@ relativeError)); } static float MULReduce(float[] a, int idx) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2498,7 +2518,7 @@ relativeError)); } static float MULReduceAll(float[] a) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2510,20 +2530,15 @@ relativeError)); static void MULReduceFloatMaxVectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + float v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2531,8 +2546,31 @@ relativeError)); FloatMaxVectorTests::MULReduce, FloatMaxVectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MUL_IDENTITY; + + Assert.assertEquals((float) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id * x), x); + Assert.assertEquals((float) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static float MULReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2542,7 +2580,7 @@ relativeError)); } static float MULReduceAllMasked(float[] a, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2556,20 +2594,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + float v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2578,7 +2611,7 @@ relativeError)); } static float MINReduce(float[] a, int idx) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.min(res, a[i]); } @@ -2587,7 +2620,7 @@ relativeError)); } static float MINReduceAll(float[] a) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduce(a, i)); } @@ -2599,20 +2632,15 @@ relativeError)); static void MINReduceFloatMaxVectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + float v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2620,8 +2648,31 @@ relativeError)); FloatMaxVectorTests::MINReduce, FloatMaxVectorTests::MINReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MIN_IDENTITY; + + Assert.assertEquals((float) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.min(id, x), x); + Assert.assertEquals((float) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static float MINReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.min(res, a[i]); @@ -2631,7 +2682,7 @@ relativeError)); } static float MINReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2645,20 +2696,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + float v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2667,7 +2713,7 @@ relativeError)); } static float MAXReduce(float[] a, int idx) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.max(res, a[i]); } @@ -2676,7 +2722,7 @@ relativeError)); } static float MAXReduceAll(float[] a) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduce(a, i)); } @@ -2688,20 +2734,15 @@ relativeError)); static void MAXReduceFloatMaxVectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + float v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2709,8 +2750,31 @@ relativeError)); FloatMaxVectorTests::MAXReduce, FloatMaxVectorTests::MAXReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MAX_IDENTITY; + + Assert.assertEquals((float) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.max(id, x), x); + Assert.assertEquals((float) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.max(res, a[i]); @@ -2720,7 +2784,7 @@ relativeError)); } static float MAXReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2734,20 +2798,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + float v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2756,7 +2815,7 @@ relativeError)); } static float FIRST_NONZEROReduce(float[] a, int idx) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2765,7 +2824,7 @@ relativeError)); } static float FIRST_NONZEROReduceAll(float[] a) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2777,20 +2836,15 @@ relativeError)); static void FIRST_NONZEROReduceFloatMaxVectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2798,8 +2852,31 @@ relativeError)); FloatMaxVectorTests::FIRST_NONZEROReduce, FloatMaxVectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2809,7 +2886,7 @@ relativeError)); } static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2823,20 +2900,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Int128VectorTests.java b/test/jdk/jdk/incubator/vector/Int128VectorTests.java index 93912243ecd..69bb0c84588 100644 --- a/test/jdk/jdk/incubator/vector/Int128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -63,9 +63,21 @@ public class Int128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final int CONST_SHIFT = Integer.SIZE / 2; + // Identity values for reduction operations + private static final int ADD_IDENTITY = (int)0; + private static final int AND_IDENTITY = (int)-1; + private static final int FIRST_NONZERO_IDENTITY = (int)0; + private static final int MAX_IDENTITY = Integer.MIN_VALUE; + private static final int MIN_IDENTITY = Integer.MAX_VALUE; + private static final int MUL_IDENTITY = (int)1; + private static final int OR_IDENTITY = (int)0; + private static final int SUADD_IDENTITY = (int)0; + private static final int UMAX_IDENTITY = (int)0; // Minimum unsigned value + private static final int UMIN_IDENTITY = (int)-1; // Maximum unsigned value + private static final int XOR_IDENTITY = (int)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); static void assertArraysStrictlyEquals(int[] r, int[] a) { @@ -3655,7 +3667,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ANDReduce(int[] a, int idx) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3664,7 +3676,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ANDReduceAll(int[] a) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3676,20 +3688,15 @@ public class Int128VectorTests extends AbstractVectorTest { static void ANDReduceInt128VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + int v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3697,8 +3704,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::ANDReduce, Int128VectorTests::ANDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = AND_IDENTITY; + + Assert.assertEquals((int) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id & x), x); + Assert.assertEquals((int) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static int ANDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3708,7 +3738,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ANDReduceAllMasked(int[] a, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3722,20 +3752,15 @@ public class Int128VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + int v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3744,7 +3769,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ORReduce(int[] a, int idx) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3753,7 +3778,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ORReduceAll(int[] a) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3768,17 +3793,12 @@ public class Int128VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + int v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3786,8 +3806,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::ORReduce, Int128VectorTests::ORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = OR_IDENTITY; + + Assert.assertEquals((int) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id | x), x); + Assert.assertEquals((int) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static int ORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3797,7 +3840,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3814,17 +3857,12 @@ public class Int128VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + int v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3833,7 +3871,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int XORReduce(int[] a, int idx) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3842,7 +3880,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int XORReduceAll(int[] a) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3857,17 +3895,12 @@ public class Int128VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + int v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3875,8 +3908,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::XORReduce, Int128VectorTests::XORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = XOR_IDENTITY; + + Assert.assertEquals((int) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id ^ x), x); + Assert.assertEquals((int) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static int XORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3886,7 +3942,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int XORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3903,17 +3959,12 @@ public class Int128VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + int v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3922,7 +3973,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ADDReduce(int[] a, int idx) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3931,7 +3982,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ADDReduceAll(int[] a) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3946,17 +3997,12 @@ public class Int128VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + int v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3964,8 +4010,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::ADDReduce, Int128VectorTests::ADDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = ADD_IDENTITY; + + Assert.assertEquals((int) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id + x), x); + Assert.assertEquals((int) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static int ADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3975,7 +4044,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3992,17 +4061,12 @@ public class Int128VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + int v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4011,7 +4075,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MULReduce(int[] a, int idx) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4020,7 +4084,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MULReduceAll(int[] a) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4032,20 +4096,15 @@ public class Int128VectorTests extends AbstractVectorTest { static void MULReduceInt128VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + int v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4053,8 +4112,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::MULReduce, Int128VectorTests::MULReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MUL_IDENTITY; + + Assert.assertEquals((int) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id * x), x); + Assert.assertEquals((int) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static int MULReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4064,7 +4146,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MULReduceAllMasked(int[] a, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4078,20 +4160,15 @@ public class Int128VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + int v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4100,7 +4177,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.min(res, a[i]); } @@ -4109,7 +4186,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduce(a, i)); } @@ -4121,20 +4198,15 @@ public class Int128VectorTests extends AbstractVectorTest { static void MINReduceInt128VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + int v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4142,8 +4214,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::MINReduce, Int128VectorTests::MINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MIN_IDENTITY; + + Assert.assertEquals((int) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.min(id, x), x); + Assert.assertEquals((int) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static int MINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.min(res, a[i]); @@ -4153,7 +4248,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4167,20 +4262,15 @@ public class Int128VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + int v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4189,7 +4279,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.max(res, a[i]); } @@ -4198,7 +4288,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduce(a, i)); } @@ -4210,20 +4300,15 @@ public class Int128VectorTests extends AbstractVectorTest { static void MAXReduceInt128VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + int v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4231,8 +4316,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::MAXReduce, Int128VectorTests::MAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MAX_IDENTITY; + + Assert.assertEquals((int) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.max(id, x), x); + Assert.assertEquals((int) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.max(res, a[i]); @@ -4242,7 +4350,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4256,20 +4364,15 @@ public class Int128VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + int v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4278,7 +4381,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int UMINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.minUnsigned(res, a[i]); } @@ -4287,7 +4390,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int UMINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4299,20 +4402,15 @@ public class Int128VectorTests extends AbstractVectorTest { static void UMINReduceInt128VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + int v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4320,8 +4418,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::UMINReduce, Int128VectorTests::UMINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMIN_IDENTITY; + + Assert.assertEquals((int) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static int UMINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.minUnsigned(res, a[i]); @@ -4331,7 +4452,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int UMINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4345,20 +4466,15 @@ public class Int128VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + int v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4367,7 +4483,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int UMAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.maxUnsigned(res, a[i]); } @@ -4376,7 +4492,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int UMAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4388,20 +4504,15 @@ public class Int128VectorTests extends AbstractVectorTest { static void UMAXReduceInt128VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + int v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4409,8 +4520,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::UMAXReduce, Int128VectorTests::UMAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMAX_IDENTITY; + + Assert.assertEquals((int) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static int UMAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.maxUnsigned(res, a[i]); @@ -4420,7 +4554,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int UMAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4434,20 +4568,15 @@ public class Int128VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + int v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4456,7 +4585,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduce(int[] a, int idx) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4465,7 +4594,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAll(int[] a) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4477,20 +4606,15 @@ public class Int128VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceInt128VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4498,8 +4622,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::FIRST_NONZEROReduce, Int128VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4509,7 +4656,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4523,20 +4670,15 @@ public class Int128VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4593,7 +4735,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int SUADDReduce(int[] a, int idx) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4602,7 +4744,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int SUADDReduceAll(int[] a) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4617,17 +4759,12 @@ public class Int128VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + int v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4635,8 +4772,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::SUADDReduce, Int128VectorTests::SUADDReduceAll); } + @Test(dataProvider = "intSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = SUADD_IDENTITY; + + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static int SUADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4646,7 +4806,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int SUADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4662,17 +4822,12 @@ public class Int128VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + int v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Int256VectorTests.java b/test/jdk/jdk/incubator/vector/Int256VectorTests.java index e8d6f3311ac..4e63de95b7b 100644 --- a/test/jdk/jdk/incubator/vector/Int256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -63,9 +63,21 @@ public class Int256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final int CONST_SHIFT = Integer.SIZE / 2; + // Identity values for reduction operations + private static final int ADD_IDENTITY = (int)0; + private static final int AND_IDENTITY = (int)-1; + private static final int FIRST_NONZERO_IDENTITY = (int)0; + private static final int MAX_IDENTITY = Integer.MIN_VALUE; + private static final int MIN_IDENTITY = Integer.MAX_VALUE; + private static final int MUL_IDENTITY = (int)1; + private static final int OR_IDENTITY = (int)0; + private static final int SUADD_IDENTITY = (int)0; + private static final int UMAX_IDENTITY = (int)0; // Minimum unsigned value + private static final int UMIN_IDENTITY = (int)-1; // Maximum unsigned value + private static final int XOR_IDENTITY = (int)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); static void assertArraysStrictlyEquals(int[] r, int[] a) { @@ -3655,7 +3667,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ANDReduce(int[] a, int idx) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3664,7 +3676,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ANDReduceAll(int[] a) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3676,20 +3688,15 @@ public class Int256VectorTests extends AbstractVectorTest { static void ANDReduceInt256VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + int v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3697,8 +3704,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::ANDReduce, Int256VectorTests::ANDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = AND_IDENTITY; + + Assert.assertEquals((int) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id & x), x); + Assert.assertEquals((int) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static int ANDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3708,7 +3738,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ANDReduceAllMasked(int[] a, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3722,20 +3752,15 @@ public class Int256VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + int v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3744,7 +3769,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ORReduce(int[] a, int idx) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3753,7 +3778,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ORReduceAll(int[] a) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3768,17 +3793,12 @@ public class Int256VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + int v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3786,8 +3806,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::ORReduce, Int256VectorTests::ORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = OR_IDENTITY; + + Assert.assertEquals((int) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id | x), x); + Assert.assertEquals((int) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static int ORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3797,7 +3840,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3814,17 +3857,12 @@ public class Int256VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + int v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3833,7 +3871,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int XORReduce(int[] a, int idx) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3842,7 +3880,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int XORReduceAll(int[] a) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3857,17 +3895,12 @@ public class Int256VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + int v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3875,8 +3908,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::XORReduce, Int256VectorTests::XORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = XOR_IDENTITY; + + Assert.assertEquals((int) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id ^ x), x); + Assert.assertEquals((int) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static int XORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3886,7 +3942,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int XORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3903,17 +3959,12 @@ public class Int256VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + int v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3922,7 +3973,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ADDReduce(int[] a, int idx) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3931,7 +3982,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ADDReduceAll(int[] a) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3946,17 +3997,12 @@ public class Int256VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + int v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3964,8 +4010,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::ADDReduce, Int256VectorTests::ADDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = ADD_IDENTITY; + + Assert.assertEquals((int) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id + x), x); + Assert.assertEquals((int) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static int ADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3975,7 +4044,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3992,17 +4061,12 @@ public class Int256VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + int v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4011,7 +4075,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MULReduce(int[] a, int idx) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4020,7 +4084,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MULReduceAll(int[] a) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4032,20 +4096,15 @@ public class Int256VectorTests extends AbstractVectorTest { static void MULReduceInt256VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + int v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4053,8 +4112,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::MULReduce, Int256VectorTests::MULReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MUL_IDENTITY; + + Assert.assertEquals((int) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id * x), x); + Assert.assertEquals((int) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static int MULReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4064,7 +4146,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MULReduceAllMasked(int[] a, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4078,20 +4160,15 @@ public class Int256VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + int v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4100,7 +4177,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.min(res, a[i]); } @@ -4109,7 +4186,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduce(a, i)); } @@ -4121,20 +4198,15 @@ public class Int256VectorTests extends AbstractVectorTest { static void MINReduceInt256VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + int v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4142,8 +4214,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::MINReduce, Int256VectorTests::MINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MIN_IDENTITY; + + Assert.assertEquals((int) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.min(id, x), x); + Assert.assertEquals((int) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static int MINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.min(res, a[i]); @@ -4153,7 +4248,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4167,20 +4262,15 @@ public class Int256VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + int v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4189,7 +4279,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.max(res, a[i]); } @@ -4198,7 +4288,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduce(a, i)); } @@ -4210,20 +4300,15 @@ public class Int256VectorTests extends AbstractVectorTest { static void MAXReduceInt256VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + int v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4231,8 +4316,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::MAXReduce, Int256VectorTests::MAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MAX_IDENTITY; + + Assert.assertEquals((int) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.max(id, x), x); + Assert.assertEquals((int) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.max(res, a[i]); @@ -4242,7 +4350,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4256,20 +4364,15 @@ public class Int256VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + int v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4278,7 +4381,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int UMINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.minUnsigned(res, a[i]); } @@ -4287,7 +4390,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int UMINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4299,20 +4402,15 @@ public class Int256VectorTests extends AbstractVectorTest { static void UMINReduceInt256VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + int v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4320,8 +4418,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::UMINReduce, Int256VectorTests::UMINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMIN_IDENTITY; + + Assert.assertEquals((int) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static int UMINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.minUnsigned(res, a[i]); @@ -4331,7 +4452,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int UMINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4345,20 +4466,15 @@ public class Int256VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + int v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4367,7 +4483,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int UMAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.maxUnsigned(res, a[i]); } @@ -4376,7 +4492,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int UMAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4388,20 +4504,15 @@ public class Int256VectorTests extends AbstractVectorTest { static void UMAXReduceInt256VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + int v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4409,8 +4520,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::UMAXReduce, Int256VectorTests::UMAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMAX_IDENTITY; + + Assert.assertEquals((int) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static int UMAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.maxUnsigned(res, a[i]); @@ -4420,7 +4554,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int UMAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4434,20 +4568,15 @@ public class Int256VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + int v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4456,7 +4585,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduce(int[] a, int idx) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4465,7 +4594,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAll(int[] a) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4477,20 +4606,15 @@ public class Int256VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceInt256VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4498,8 +4622,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::FIRST_NONZEROReduce, Int256VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4509,7 +4656,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4523,20 +4670,15 @@ public class Int256VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4593,7 +4735,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int SUADDReduce(int[] a, int idx) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4602,7 +4744,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int SUADDReduceAll(int[] a) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4617,17 +4759,12 @@ public class Int256VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + int v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4635,8 +4772,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::SUADDReduce, Int256VectorTests::SUADDReduceAll); } + @Test(dataProvider = "intSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = SUADD_IDENTITY; + + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static int SUADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4646,7 +4806,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int SUADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4662,17 +4822,12 @@ public class Int256VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + int v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Int512VectorTests.java b/test/jdk/jdk/incubator/vector/Int512VectorTests.java index 932d9ee4487..e2de7905a83 100644 --- a/test/jdk/jdk/incubator/vector/Int512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -63,9 +63,21 @@ public class Int512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final int CONST_SHIFT = Integer.SIZE / 2; + // Identity values for reduction operations + private static final int ADD_IDENTITY = (int)0; + private static final int AND_IDENTITY = (int)-1; + private static final int FIRST_NONZERO_IDENTITY = (int)0; + private static final int MAX_IDENTITY = Integer.MIN_VALUE; + private static final int MIN_IDENTITY = Integer.MAX_VALUE; + private static final int MUL_IDENTITY = (int)1; + private static final int OR_IDENTITY = (int)0; + private static final int SUADD_IDENTITY = (int)0; + private static final int UMAX_IDENTITY = (int)0; // Minimum unsigned value + private static final int UMIN_IDENTITY = (int)-1; // Maximum unsigned value + private static final int XOR_IDENTITY = (int)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); static void assertArraysStrictlyEquals(int[] r, int[] a) { @@ -3655,7 +3667,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ANDReduce(int[] a, int idx) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3664,7 +3676,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ANDReduceAll(int[] a) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3676,20 +3688,15 @@ public class Int512VectorTests extends AbstractVectorTest { static void ANDReduceInt512VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + int v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3697,8 +3704,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::ANDReduce, Int512VectorTests::ANDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = AND_IDENTITY; + + Assert.assertEquals((int) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id & x), x); + Assert.assertEquals((int) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static int ANDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3708,7 +3738,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ANDReduceAllMasked(int[] a, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3722,20 +3752,15 @@ public class Int512VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + int v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3744,7 +3769,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ORReduce(int[] a, int idx) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3753,7 +3778,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ORReduceAll(int[] a) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3768,17 +3793,12 @@ public class Int512VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + int v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3786,8 +3806,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::ORReduce, Int512VectorTests::ORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = OR_IDENTITY; + + Assert.assertEquals((int) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id | x), x); + Assert.assertEquals((int) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static int ORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3797,7 +3840,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3814,17 +3857,12 @@ public class Int512VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + int v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3833,7 +3871,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int XORReduce(int[] a, int idx) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3842,7 +3880,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int XORReduceAll(int[] a) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3857,17 +3895,12 @@ public class Int512VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + int v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3875,8 +3908,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::XORReduce, Int512VectorTests::XORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = XOR_IDENTITY; + + Assert.assertEquals((int) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id ^ x), x); + Assert.assertEquals((int) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static int XORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3886,7 +3942,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int XORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3903,17 +3959,12 @@ public class Int512VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + int v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3922,7 +3973,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ADDReduce(int[] a, int idx) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3931,7 +3982,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ADDReduceAll(int[] a) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3946,17 +3997,12 @@ public class Int512VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + int v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3964,8 +4010,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::ADDReduce, Int512VectorTests::ADDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = ADD_IDENTITY; + + Assert.assertEquals((int) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id + x), x); + Assert.assertEquals((int) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static int ADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3975,7 +4044,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3992,17 +4061,12 @@ public class Int512VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + int v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4011,7 +4075,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MULReduce(int[] a, int idx) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4020,7 +4084,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MULReduceAll(int[] a) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4032,20 +4096,15 @@ public class Int512VectorTests extends AbstractVectorTest { static void MULReduceInt512VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + int v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4053,8 +4112,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::MULReduce, Int512VectorTests::MULReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MUL_IDENTITY; + + Assert.assertEquals((int) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id * x), x); + Assert.assertEquals((int) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static int MULReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4064,7 +4146,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MULReduceAllMasked(int[] a, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4078,20 +4160,15 @@ public class Int512VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + int v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4100,7 +4177,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.min(res, a[i]); } @@ -4109,7 +4186,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduce(a, i)); } @@ -4121,20 +4198,15 @@ public class Int512VectorTests extends AbstractVectorTest { static void MINReduceInt512VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + int v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4142,8 +4214,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::MINReduce, Int512VectorTests::MINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MIN_IDENTITY; + + Assert.assertEquals((int) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.min(id, x), x); + Assert.assertEquals((int) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static int MINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.min(res, a[i]); @@ -4153,7 +4248,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4167,20 +4262,15 @@ public class Int512VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + int v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4189,7 +4279,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.max(res, a[i]); } @@ -4198,7 +4288,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduce(a, i)); } @@ -4210,20 +4300,15 @@ public class Int512VectorTests extends AbstractVectorTest { static void MAXReduceInt512VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + int v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4231,8 +4316,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::MAXReduce, Int512VectorTests::MAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MAX_IDENTITY; + + Assert.assertEquals((int) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.max(id, x), x); + Assert.assertEquals((int) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.max(res, a[i]); @@ -4242,7 +4350,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4256,20 +4364,15 @@ public class Int512VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + int v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4278,7 +4381,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int UMINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.minUnsigned(res, a[i]); } @@ -4287,7 +4390,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int UMINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4299,20 +4402,15 @@ public class Int512VectorTests extends AbstractVectorTest { static void UMINReduceInt512VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + int v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4320,8 +4418,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::UMINReduce, Int512VectorTests::UMINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMIN_IDENTITY; + + Assert.assertEquals((int) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static int UMINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.minUnsigned(res, a[i]); @@ -4331,7 +4452,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int UMINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4345,20 +4466,15 @@ public class Int512VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + int v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4367,7 +4483,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int UMAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.maxUnsigned(res, a[i]); } @@ -4376,7 +4492,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int UMAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4388,20 +4504,15 @@ public class Int512VectorTests extends AbstractVectorTest { static void UMAXReduceInt512VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + int v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4409,8 +4520,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::UMAXReduce, Int512VectorTests::UMAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMAX_IDENTITY; + + Assert.assertEquals((int) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static int UMAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.maxUnsigned(res, a[i]); @@ -4420,7 +4554,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int UMAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4434,20 +4568,15 @@ public class Int512VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + int v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4456,7 +4585,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduce(int[] a, int idx) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4465,7 +4594,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAll(int[] a) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4477,20 +4606,15 @@ public class Int512VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceInt512VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4498,8 +4622,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::FIRST_NONZEROReduce, Int512VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4509,7 +4656,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4523,20 +4670,15 @@ public class Int512VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4593,7 +4735,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int SUADDReduce(int[] a, int idx) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4602,7 +4744,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int SUADDReduceAll(int[] a) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4617,17 +4759,12 @@ public class Int512VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + int v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4635,8 +4772,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::SUADDReduce, Int512VectorTests::SUADDReduceAll); } + @Test(dataProvider = "intSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = SUADD_IDENTITY; + + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static int SUADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4646,7 +4806,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int SUADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4662,17 +4822,12 @@ public class Int512VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + int v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Int64VectorTests.java b/test/jdk/jdk/incubator/vector/Int64VectorTests.java index 3c00904a70e..d64db80b94d 100644 --- a/test/jdk/jdk/incubator/vector/Int64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -63,9 +63,21 @@ public class Int64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final int CONST_SHIFT = Integer.SIZE / 2; + // Identity values for reduction operations + private static final int ADD_IDENTITY = (int)0; + private static final int AND_IDENTITY = (int)-1; + private static final int FIRST_NONZERO_IDENTITY = (int)0; + private static final int MAX_IDENTITY = Integer.MIN_VALUE; + private static final int MIN_IDENTITY = Integer.MAX_VALUE; + private static final int MUL_IDENTITY = (int)1; + private static final int OR_IDENTITY = (int)0; + private static final int SUADD_IDENTITY = (int)0; + private static final int UMAX_IDENTITY = (int)0; // Minimum unsigned value + private static final int UMIN_IDENTITY = (int)-1; // Maximum unsigned value + private static final int XOR_IDENTITY = (int)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); static void assertArraysStrictlyEquals(int[] r, int[] a) { @@ -3655,7 +3667,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ANDReduce(int[] a, int idx) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3664,7 +3676,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ANDReduceAll(int[] a) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3676,20 +3688,15 @@ public class Int64VectorTests extends AbstractVectorTest { static void ANDReduceInt64VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + int v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3697,8 +3704,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::ANDReduce, Int64VectorTests::ANDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = AND_IDENTITY; + + Assert.assertEquals((int) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id & x), x); + Assert.assertEquals((int) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static int ANDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3708,7 +3738,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ANDReduceAllMasked(int[] a, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3722,20 +3752,15 @@ public class Int64VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + int v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3744,7 +3769,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ORReduce(int[] a, int idx) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3753,7 +3778,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ORReduceAll(int[] a) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3768,17 +3793,12 @@ public class Int64VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + int v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3786,8 +3806,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::ORReduce, Int64VectorTests::ORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = OR_IDENTITY; + + Assert.assertEquals((int) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id | x), x); + Assert.assertEquals((int) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static int ORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3797,7 +3840,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3814,17 +3857,12 @@ public class Int64VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + int v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3833,7 +3871,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int XORReduce(int[] a, int idx) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3842,7 +3880,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int XORReduceAll(int[] a) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3857,17 +3895,12 @@ public class Int64VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + int v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3875,8 +3908,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::XORReduce, Int64VectorTests::XORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = XOR_IDENTITY; + + Assert.assertEquals((int) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id ^ x), x); + Assert.assertEquals((int) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static int XORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3886,7 +3942,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int XORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3903,17 +3959,12 @@ public class Int64VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + int v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3922,7 +3973,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ADDReduce(int[] a, int idx) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3931,7 +3982,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ADDReduceAll(int[] a) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3946,17 +3997,12 @@ public class Int64VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + int v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3964,8 +4010,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::ADDReduce, Int64VectorTests::ADDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = ADD_IDENTITY; + + Assert.assertEquals((int) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id + x), x); + Assert.assertEquals((int) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static int ADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3975,7 +4044,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3992,17 +4061,12 @@ public class Int64VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + int v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4011,7 +4075,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MULReduce(int[] a, int idx) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4020,7 +4084,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MULReduceAll(int[] a) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4032,20 +4096,15 @@ public class Int64VectorTests extends AbstractVectorTest { static void MULReduceInt64VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + int v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4053,8 +4112,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::MULReduce, Int64VectorTests::MULReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MUL_IDENTITY; + + Assert.assertEquals((int) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id * x), x); + Assert.assertEquals((int) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static int MULReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4064,7 +4146,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MULReduceAllMasked(int[] a, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4078,20 +4160,15 @@ public class Int64VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + int v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4100,7 +4177,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.min(res, a[i]); } @@ -4109,7 +4186,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduce(a, i)); } @@ -4121,20 +4198,15 @@ public class Int64VectorTests extends AbstractVectorTest { static void MINReduceInt64VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + int v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4142,8 +4214,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::MINReduce, Int64VectorTests::MINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MIN_IDENTITY; + + Assert.assertEquals((int) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.min(id, x), x); + Assert.assertEquals((int) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static int MINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.min(res, a[i]); @@ -4153,7 +4248,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4167,20 +4262,15 @@ public class Int64VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + int v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4189,7 +4279,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.max(res, a[i]); } @@ -4198,7 +4288,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduce(a, i)); } @@ -4210,20 +4300,15 @@ public class Int64VectorTests extends AbstractVectorTest { static void MAXReduceInt64VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + int v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4231,8 +4316,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::MAXReduce, Int64VectorTests::MAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MAX_IDENTITY; + + Assert.assertEquals((int) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.max(id, x), x); + Assert.assertEquals((int) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.max(res, a[i]); @@ -4242,7 +4350,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4256,20 +4364,15 @@ public class Int64VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + int v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4278,7 +4381,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int UMINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.minUnsigned(res, a[i]); } @@ -4287,7 +4390,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int UMINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4299,20 +4402,15 @@ public class Int64VectorTests extends AbstractVectorTest { static void UMINReduceInt64VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + int v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4320,8 +4418,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::UMINReduce, Int64VectorTests::UMINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMIN_IDENTITY; + + Assert.assertEquals((int) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static int UMINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.minUnsigned(res, a[i]); @@ -4331,7 +4452,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int UMINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4345,20 +4466,15 @@ public class Int64VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + int v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4367,7 +4483,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int UMAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.maxUnsigned(res, a[i]); } @@ -4376,7 +4492,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int UMAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4388,20 +4504,15 @@ public class Int64VectorTests extends AbstractVectorTest { static void UMAXReduceInt64VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + int v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4409,8 +4520,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::UMAXReduce, Int64VectorTests::UMAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMAX_IDENTITY; + + Assert.assertEquals((int) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static int UMAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.maxUnsigned(res, a[i]); @@ -4420,7 +4554,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int UMAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4434,20 +4568,15 @@ public class Int64VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + int v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4456,7 +4585,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduce(int[] a, int idx) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4465,7 +4594,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAll(int[] a) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4477,20 +4606,15 @@ public class Int64VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceInt64VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4498,8 +4622,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::FIRST_NONZEROReduce, Int64VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4509,7 +4656,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4523,20 +4670,15 @@ public class Int64VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4593,7 +4735,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int SUADDReduce(int[] a, int idx) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4602,7 +4744,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int SUADDReduceAll(int[] a) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4617,17 +4759,12 @@ public class Int64VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + int v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4635,8 +4772,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::SUADDReduce, Int64VectorTests::SUADDReduceAll); } + @Test(dataProvider = "intSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = SUADD_IDENTITY; + + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static int SUADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4646,7 +4806,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int SUADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4662,17 +4822,12 @@ public class Int64VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + int v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java index 42659bfe44e..7bf4dc48171 100644 --- a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -71,6 +71,19 @@ public class IntMaxVectorTests extends AbstractVectorTest { private static final int CONST_SHIFT = Integer.SIZE / 2; + // Identity values for reduction operations + private static final int ADD_IDENTITY = (int)0; + private static final int AND_IDENTITY = (int)-1; + private static final int FIRST_NONZERO_IDENTITY = (int)0; + private static final int MAX_IDENTITY = Integer.MIN_VALUE; + private static final int MIN_IDENTITY = Integer.MAX_VALUE; + private static final int MUL_IDENTITY = (int)1; + private static final int OR_IDENTITY = (int)0; + private static final int SUADD_IDENTITY = (int)0; + private static final int UMAX_IDENTITY = (int)0; // Minimum unsigned value + private static final int UMIN_IDENTITY = (int)-1; // Maximum unsigned value + private static final int XOR_IDENTITY = (int)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); static void assertArraysStrictlyEquals(int[] r, int[] a) { @@ -3660,7 +3673,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ANDReduce(int[] a, int idx) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3669,7 +3682,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ANDReduceAll(int[] a) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3681,20 +3694,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { static void ANDReduceIntMaxVectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + int v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3702,8 +3710,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::ANDReduce, IntMaxVectorTests::ANDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = AND_IDENTITY; + + Assert.assertEquals((int) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id & x), x); + Assert.assertEquals((int) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static int ANDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3713,7 +3744,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ANDReduceAllMasked(int[] a, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3727,20 +3758,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + int v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3749,7 +3775,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ORReduce(int[] a, int idx) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3758,7 +3784,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ORReduceAll(int[] a) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3773,17 +3799,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + int v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3791,8 +3812,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::ORReduce, IntMaxVectorTests::ORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = OR_IDENTITY; + + Assert.assertEquals((int) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id | x), x); + Assert.assertEquals((int) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static int ORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3802,7 +3846,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3819,17 +3863,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + int v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3838,7 +3877,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int XORReduce(int[] a, int idx) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3847,7 +3886,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int XORReduceAll(int[] a) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3862,17 +3901,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + int v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3880,8 +3914,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::XORReduce, IntMaxVectorTests::XORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = XOR_IDENTITY; + + Assert.assertEquals((int) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id ^ x), x); + Assert.assertEquals((int) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static int XORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3891,7 +3948,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int XORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3908,17 +3965,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + int v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3927,7 +3979,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ADDReduce(int[] a, int idx) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3936,7 +3988,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ADDReduceAll(int[] a) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3951,17 +4003,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + int v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3969,8 +4016,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::ADDReduce, IntMaxVectorTests::ADDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = ADD_IDENTITY; + + Assert.assertEquals((int) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id + x), x); + Assert.assertEquals((int) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static int ADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3980,7 +4050,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3997,17 +4067,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + int v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4016,7 +4081,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MULReduce(int[] a, int idx) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4025,7 +4090,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MULReduceAll(int[] a) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4037,20 +4102,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { static void MULReduceIntMaxVectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + int v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4058,8 +4118,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::MULReduce, IntMaxVectorTests::MULReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MUL_IDENTITY; + + Assert.assertEquals((int) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id * x), x); + Assert.assertEquals((int) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static int MULReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4069,7 +4152,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MULReduceAllMasked(int[] a, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4083,20 +4166,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + int v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4105,7 +4183,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.min(res, a[i]); } @@ -4114,7 +4192,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduce(a, i)); } @@ -4126,20 +4204,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { static void MINReduceIntMaxVectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + int v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4147,8 +4220,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::MINReduce, IntMaxVectorTests::MINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MIN_IDENTITY; + + Assert.assertEquals((int) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.min(id, x), x); + Assert.assertEquals((int) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static int MINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.min(res, a[i]); @@ -4158,7 +4254,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4172,20 +4268,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + int v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4194,7 +4285,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.max(res, a[i]); } @@ -4203,7 +4294,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduce(a, i)); } @@ -4215,20 +4306,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { static void MAXReduceIntMaxVectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + int v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4236,8 +4322,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::MAXReduce, IntMaxVectorTests::MAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MAX_IDENTITY; + + Assert.assertEquals((int) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.max(id, x), x); + Assert.assertEquals((int) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.max(res, a[i]); @@ -4247,7 +4356,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4261,20 +4370,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + int v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4283,7 +4387,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int UMINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.minUnsigned(res, a[i]); } @@ -4292,7 +4396,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int UMINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4304,20 +4408,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { static void UMINReduceIntMaxVectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + int v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4325,8 +4424,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::UMINReduce, IntMaxVectorTests::UMINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMIN_IDENTITY; + + Assert.assertEquals((int) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static int UMINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.minUnsigned(res, a[i]); @@ -4336,7 +4458,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int UMINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4350,20 +4472,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + int v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4372,7 +4489,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int UMAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.maxUnsigned(res, a[i]); } @@ -4381,7 +4498,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int UMAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4393,20 +4510,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { static void UMAXReduceIntMaxVectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + int v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4414,8 +4526,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::UMAXReduce, IntMaxVectorTests::UMAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMAX_IDENTITY; + + Assert.assertEquals((int) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static int UMAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.maxUnsigned(res, a[i]); @@ -4425,7 +4560,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int UMAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4439,20 +4574,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + int v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4461,7 +4591,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduce(int[] a, int idx) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4470,7 +4600,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAll(int[] a) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4482,20 +4612,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceIntMaxVectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4503,8 +4628,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::FIRST_NONZEROReduce, IntMaxVectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4514,7 +4662,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4528,20 +4676,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4598,7 +4741,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int SUADDReduce(int[] a, int idx) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4607,7 +4750,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int SUADDReduceAll(int[] a) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4622,17 +4765,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + int v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4640,8 +4778,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::SUADDReduce, IntMaxVectorTests::SUADDReduceAll); } + @Test(dataProvider = "intSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = SUADD_IDENTITY; + + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static int SUADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4651,7 +4812,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int SUADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4667,17 +4828,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + int v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Long128VectorTests.java b/test/jdk/jdk/incubator/vector/Long128VectorTests.java index 6c305a5c2b4..227f196ffdf 100644 --- a/test/jdk/jdk/incubator/vector/Long128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -63,9 +63,21 @@ public class Long128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final long CONST_SHIFT = Long.SIZE / 2; + // Identity values for reduction operations + private static final long ADD_IDENTITY = (long)0; + private static final long AND_IDENTITY = (long)-1; + private static final long FIRST_NONZERO_IDENTITY = (long)0; + private static final long MAX_IDENTITY = Long.MIN_VALUE; + private static final long MIN_IDENTITY = Long.MAX_VALUE; + private static final long MUL_IDENTITY = (long)1; + private static final long OR_IDENTITY = (long)0; + private static final long SUADD_IDENTITY = (long)0; + private static final long UMAX_IDENTITY = (long)0; // Minimum unsigned value + private static final long UMIN_IDENTITY = (long)-1; // Maximum unsigned value + private static final long XOR_IDENTITY = (long)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); static void assertArraysStrictlyEquals(long[] r, long[] a) { @@ -3677,7 +3689,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ANDReduce(long[] a, int idx) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3686,7 +3698,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ANDReduceAll(long[] a) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3698,20 +3710,15 @@ public class Long128VectorTests extends AbstractVectorTest { static void ANDReduceLong128VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + long v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3719,8 +3726,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::ANDReduce, Long128VectorTests::ANDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = AND_IDENTITY; + + Assert.assertEquals((long) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id & x), x); + Assert.assertEquals((long) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static long ANDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3730,7 +3760,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ANDReduceAllMasked(long[] a, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3744,20 +3774,15 @@ public class Long128VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + long v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3766,7 +3791,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ORReduce(long[] a, int idx) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3775,7 +3800,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ORReduceAll(long[] a) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3790,17 +3815,12 @@ public class Long128VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + long v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3808,8 +3828,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::ORReduce, Long128VectorTests::ORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = OR_IDENTITY; + + Assert.assertEquals((long) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id | x), x); + Assert.assertEquals((long) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static long ORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3819,7 +3862,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3836,17 +3879,12 @@ public class Long128VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + long v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3855,7 +3893,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long XORReduce(long[] a, int idx) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3864,7 +3902,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long XORReduceAll(long[] a) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3879,17 +3917,12 @@ public class Long128VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + long v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3897,8 +3930,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::XORReduce, Long128VectorTests::XORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = XOR_IDENTITY; + + Assert.assertEquals((long) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id ^ x), x); + Assert.assertEquals((long) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static long XORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3908,7 +3964,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long XORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3925,17 +3981,12 @@ public class Long128VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + long v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3944,7 +3995,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ADDReduce(long[] a, int idx) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3953,7 +4004,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ADDReduceAll(long[] a) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3968,17 +4019,12 @@ public class Long128VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + long v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3986,8 +4032,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::ADDReduce, Long128VectorTests::ADDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = ADD_IDENTITY; + + Assert.assertEquals((long) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id + x), x); + Assert.assertEquals((long) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static long ADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3997,7 +4066,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -4014,17 +4083,12 @@ public class Long128VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + long v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4033,7 +4097,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MULReduce(long[] a, int idx) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4042,7 +4106,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MULReduceAll(long[] a) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4054,20 +4118,15 @@ public class Long128VectorTests extends AbstractVectorTest { static void MULReduceLong128VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + long v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4075,8 +4134,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::MULReduce, Long128VectorTests::MULReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MUL_IDENTITY; + + Assert.assertEquals((long) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id * x), x); + Assert.assertEquals((long) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static long MULReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4086,7 +4168,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MULReduceAllMasked(long[] a, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4100,20 +4182,15 @@ public class Long128VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + long v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4122,7 +4199,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.min(res, a[i]); } @@ -4131,7 +4208,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduce(a, i)); } @@ -4143,20 +4220,15 @@ public class Long128VectorTests extends AbstractVectorTest { static void MINReduceLong128VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + long v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4164,8 +4236,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::MINReduce, Long128VectorTests::MINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MIN_IDENTITY; + + Assert.assertEquals((long) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.min(id, x), x); + Assert.assertEquals((long) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static long MINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.min(res, a[i]); @@ -4175,7 +4270,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4189,20 +4284,15 @@ public class Long128VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + long v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4211,7 +4301,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.max(res, a[i]); } @@ -4220,7 +4310,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduce(a, i)); } @@ -4232,20 +4322,15 @@ public class Long128VectorTests extends AbstractVectorTest { static void MAXReduceLong128VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + long v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4253,8 +4338,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::MAXReduce, Long128VectorTests::MAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MAX_IDENTITY; + + Assert.assertEquals((long) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.max(id, x), x); + Assert.assertEquals((long) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.max(res, a[i]); @@ -4264,7 +4372,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4278,20 +4386,15 @@ public class Long128VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + long v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4300,7 +4403,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long UMINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.minUnsigned(res, a[i]); } @@ -4309,7 +4412,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long UMINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4321,20 +4424,15 @@ public class Long128VectorTests extends AbstractVectorTest { static void UMINReduceLong128VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + long v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4342,8 +4440,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::UMINReduce, Long128VectorTests::UMINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMIN_IDENTITY; + + Assert.assertEquals((long) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static long UMINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.minUnsigned(res, a[i]); @@ -4353,7 +4474,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long UMINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4367,20 +4488,15 @@ public class Long128VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + long v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4389,7 +4505,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long UMAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.maxUnsigned(res, a[i]); } @@ -4398,7 +4514,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long UMAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4410,20 +4526,15 @@ public class Long128VectorTests extends AbstractVectorTest { static void UMAXReduceLong128VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + long v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4431,8 +4542,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::UMAXReduce, Long128VectorTests::UMAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMAX_IDENTITY; + + Assert.assertEquals((long) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static long UMAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.maxUnsigned(res, a[i]); @@ -4442,7 +4576,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long UMAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4456,20 +4590,15 @@ public class Long128VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + long v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4478,7 +4607,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduce(long[] a, int idx) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4487,7 +4616,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAll(long[] a) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4499,20 +4628,15 @@ public class Long128VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceLong128VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4520,8 +4644,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::FIRST_NONZEROReduce, Long128VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4531,7 +4678,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4545,20 +4692,15 @@ public class Long128VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4615,7 +4757,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long SUADDReduce(long[] a, int idx) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4624,7 +4766,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long SUADDReduceAll(long[] a) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4639,17 +4781,12 @@ public class Long128VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + long v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4657,8 +4794,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::SUADDReduce, Long128VectorTests::SUADDReduceAll); } + @Test(dataProvider = "longSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = SUADD_IDENTITY; + + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static long SUADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4668,7 +4828,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long SUADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4684,17 +4844,12 @@ public class Long128VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + long v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Long256VectorTests.java b/test/jdk/jdk/incubator/vector/Long256VectorTests.java index 3b276391cb7..c37e68e3728 100644 --- a/test/jdk/jdk/incubator/vector/Long256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -63,9 +63,21 @@ public class Long256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final long CONST_SHIFT = Long.SIZE / 2; + // Identity values for reduction operations + private static final long ADD_IDENTITY = (long)0; + private static final long AND_IDENTITY = (long)-1; + private static final long FIRST_NONZERO_IDENTITY = (long)0; + private static final long MAX_IDENTITY = Long.MIN_VALUE; + private static final long MIN_IDENTITY = Long.MAX_VALUE; + private static final long MUL_IDENTITY = (long)1; + private static final long OR_IDENTITY = (long)0; + private static final long SUADD_IDENTITY = (long)0; + private static final long UMAX_IDENTITY = (long)0; // Minimum unsigned value + private static final long UMIN_IDENTITY = (long)-1; // Maximum unsigned value + private static final long XOR_IDENTITY = (long)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); static void assertArraysStrictlyEquals(long[] r, long[] a) { @@ -3677,7 +3689,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ANDReduce(long[] a, int idx) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3686,7 +3698,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ANDReduceAll(long[] a) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3698,20 +3710,15 @@ public class Long256VectorTests extends AbstractVectorTest { static void ANDReduceLong256VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + long v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3719,8 +3726,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::ANDReduce, Long256VectorTests::ANDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = AND_IDENTITY; + + Assert.assertEquals((long) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id & x), x); + Assert.assertEquals((long) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static long ANDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3730,7 +3760,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ANDReduceAllMasked(long[] a, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3744,20 +3774,15 @@ public class Long256VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + long v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3766,7 +3791,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ORReduce(long[] a, int idx) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3775,7 +3800,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ORReduceAll(long[] a) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3790,17 +3815,12 @@ public class Long256VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + long v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3808,8 +3828,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::ORReduce, Long256VectorTests::ORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = OR_IDENTITY; + + Assert.assertEquals((long) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id | x), x); + Assert.assertEquals((long) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static long ORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3819,7 +3862,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3836,17 +3879,12 @@ public class Long256VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + long v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3855,7 +3893,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long XORReduce(long[] a, int idx) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3864,7 +3902,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long XORReduceAll(long[] a) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3879,17 +3917,12 @@ public class Long256VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + long v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3897,8 +3930,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::XORReduce, Long256VectorTests::XORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = XOR_IDENTITY; + + Assert.assertEquals((long) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id ^ x), x); + Assert.assertEquals((long) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static long XORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3908,7 +3964,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long XORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3925,17 +3981,12 @@ public class Long256VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + long v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3944,7 +3995,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ADDReduce(long[] a, int idx) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3953,7 +4004,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ADDReduceAll(long[] a) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3968,17 +4019,12 @@ public class Long256VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + long v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3986,8 +4032,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::ADDReduce, Long256VectorTests::ADDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = ADD_IDENTITY; + + Assert.assertEquals((long) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id + x), x); + Assert.assertEquals((long) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static long ADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3997,7 +4066,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -4014,17 +4083,12 @@ public class Long256VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + long v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4033,7 +4097,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MULReduce(long[] a, int idx) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4042,7 +4106,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MULReduceAll(long[] a) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4054,20 +4118,15 @@ public class Long256VectorTests extends AbstractVectorTest { static void MULReduceLong256VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + long v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4075,8 +4134,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::MULReduce, Long256VectorTests::MULReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MUL_IDENTITY; + + Assert.assertEquals((long) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id * x), x); + Assert.assertEquals((long) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static long MULReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4086,7 +4168,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MULReduceAllMasked(long[] a, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4100,20 +4182,15 @@ public class Long256VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + long v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4122,7 +4199,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.min(res, a[i]); } @@ -4131,7 +4208,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduce(a, i)); } @@ -4143,20 +4220,15 @@ public class Long256VectorTests extends AbstractVectorTest { static void MINReduceLong256VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + long v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4164,8 +4236,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::MINReduce, Long256VectorTests::MINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MIN_IDENTITY; + + Assert.assertEquals((long) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.min(id, x), x); + Assert.assertEquals((long) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static long MINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.min(res, a[i]); @@ -4175,7 +4270,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4189,20 +4284,15 @@ public class Long256VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + long v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4211,7 +4301,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.max(res, a[i]); } @@ -4220,7 +4310,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduce(a, i)); } @@ -4232,20 +4322,15 @@ public class Long256VectorTests extends AbstractVectorTest { static void MAXReduceLong256VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + long v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4253,8 +4338,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::MAXReduce, Long256VectorTests::MAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MAX_IDENTITY; + + Assert.assertEquals((long) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.max(id, x), x); + Assert.assertEquals((long) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.max(res, a[i]); @@ -4264,7 +4372,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4278,20 +4386,15 @@ public class Long256VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + long v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4300,7 +4403,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long UMINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.minUnsigned(res, a[i]); } @@ -4309,7 +4412,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long UMINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4321,20 +4424,15 @@ public class Long256VectorTests extends AbstractVectorTest { static void UMINReduceLong256VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + long v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4342,8 +4440,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::UMINReduce, Long256VectorTests::UMINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMIN_IDENTITY; + + Assert.assertEquals((long) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static long UMINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.minUnsigned(res, a[i]); @@ -4353,7 +4474,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long UMINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4367,20 +4488,15 @@ public class Long256VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + long v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4389,7 +4505,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long UMAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.maxUnsigned(res, a[i]); } @@ -4398,7 +4514,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long UMAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4410,20 +4526,15 @@ public class Long256VectorTests extends AbstractVectorTest { static void UMAXReduceLong256VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + long v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4431,8 +4542,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::UMAXReduce, Long256VectorTests::UMAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMAX_IDENTITY; + + Assert.assertEquals((long) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static long UMAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.maxUnsigned(res, a[i]); @@ -4442,7 +4576,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long UMAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4456,20 +4590,15 @@ public class Long256VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + long v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4478,7 +4607,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduce(long[] a, int idx) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4487,7 +4616,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAll(long[] a) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4499,20 +4628,15 @@ public class Long256VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceLong256VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4520,8 +4644,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::FIRST_NONZEROReduce, Long256VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4531,7 +4678,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4545,20 +4692,15 @@ public class Long256VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4615,7 +4757,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long SUADDReduce(long[] a, int idx) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4624,7 +4766,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long SUADDReduceAll(long[] a) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4639,17 +4781,12 @@ public class Long256VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + long v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4657,8 +4794,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::SUADDReduce, Long256VectorTests::SUADDReduceAll); } + @Test(dataProvider = "longSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = SUADD_IDENTITY; + + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static long SUADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4668,7 +4828,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long SUADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4684,17 +4844,12 @@ public class Long256VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + long v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Long512VectorTests.java b/test/jdk/jdk/incubator/vector/Long512VectorTests.java index 181116cf399..5f8abb5bdd5 100644 --- a/test/jdk/jdk/incubator/vector/Long512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -63,9 +63,21 @@ public class Long512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final long CONST_SHIFT = Long.SIZE / 2; + // Identity values for reduction operations + private static final long ADD_IDENTITY = (long)0; + private static final long AND_IDENTITY = (long)-1; + private static final long FIRST_NONZERO_IDENTITY = (long)0; + private static final long MAX_IDENTITY = Long.MIN_VALUE; + private static final long MIN_IDENTITY = Long.MAX_VALUE; + private static final long MUL_IDENTITY = (long)1; + private static final long OR_IDENTITY = (long)0; + private static final long SUADD_IDENTITY = (long)0; + private static final long UMAX_IDENTITY = (long)0; // Minimum unsigned value + private static final long UMIN_IDENTITY = (long)-1; // Maximum unsigned value + private static final long XOR_IDENTITY = (long)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); static void assertArraysStrictlyEquals(long[] r, long[] a) { @@ -3677,7 +3689,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ANDReduce(long[] a, int idx) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3686,7 +3698,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ANDReduceAll(long[] a) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3698,20 +3710,15 @@ public class Long512VectorTests extends AbstractVectorTest { static void ANDReduceLong512VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + long v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3719,8 +3726,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::ANDReduce, Long512VectorTests::ANDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = AND_IDENTITY; + + Assert.assertEquals((long) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id & x), x); + Assert.assertEquals((long) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static long ANDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3730,7 +3760,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ANDReduceAllMasked(long[] a, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3744,20 +3774,15 @@ public class Long512VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + long v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3766,7 +3791,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ORReduce(long[] a, int idx) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3775,7 +3800,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ORReduceAll(long[] a) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3790,17 +3815,12 @@ public class Long512VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + long v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3808,8 +3828,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::ORReduce, Long512VectorTests::ORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = OR_IDENTITY; + + Assert.assertEquals((long) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id | x), x); + Assert.assertEquals((long) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static long ORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3819,7 +3862,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3836,17 +3879,12 @@ public class Long512VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + long v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3855,7 +3893,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long XORReduce(long[] a, int idx) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3864,7 +3902,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long XORReduceAll(long[] a) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3879,17 +3917,12 @@ public class Long512VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + long v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3897,8 +3930,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::XORReduce, Long512VectorTests::XORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = XOR_IDENTITY; + + Assert.assertEquals((long) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id ^ x), x); + Assert.assertEquals((long) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static long XORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3908,7 +3964,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long XORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3925,17 +3981,12 @@ public class Long512VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + long v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3944,7 +3995,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ADDReduce(long[] a, int idx) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3953,7 +4004,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ADDReduceAll(long[] a) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3968,17 +4019,12 @@ public class Long512VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + long v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3986,8 +4032,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::ADDReduce, Long512VectorTests::ADDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = ADD_IDENTITY; + + Assert.assertEquals((long) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id + x), x); + Assert.assertEquals((long) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static long ADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3997,7 +4066,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -4014,17 +4083,12 @@ public class Long512VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + long v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4033,7 +4097,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MULReduce(long[] a, int idx) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4042,7 +4106,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MULReduceAll(long[] a) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4054,20 +4118,15 @@ public class Long512VectorTests extends AbstractVectorTest { static void MULReduceLong512VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + long v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4075,8 +4134,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::MULReduce, Long512VectorTests::MULReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MUL_IDENTITY; + + Assert.assertEquals((long) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id * x), x); + Assert.assertEquals((long) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static long MULReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4086,7 +4168,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MULReduceAllMasked(long[] a, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4100,20 +4182,15 @@ public class Long512VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + long v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4122,7 +4199,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.min(res, a[i]); } @@ -4131,7 +4208,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduce(a, i)); } @@ -4143,20 +4220,15 @@ public class Long512VectorTests extends AbstractVectorTest { static void MINReduceLong512VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + long v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4164,8 +4236,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::MINReduce, Long512VectorTests::MINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MIN_IDENTITY; + + Assert.assertEquals((long) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.min(id, x), x); + Assert.assertEquals((long) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static long MINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.min(res, a[i]); @@ -4175,7 +4270,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4189,20 +4284,15 @@ public class Long512VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + long v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4211,7 +4301,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.max(res, a[i]); } @@ -4220,7 +4310,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduce(a, i)); } @@ -4232,20 +4322,15 @@ public class Long512VectorTests extends AbstractVectorTest { static void MAXReduceLong512VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + long v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4253,8 +4338,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::MAXReduce, Long512VectorTests::MAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MAX_IDENTITY; + + Assert.assertEquals((long) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.max(id, x), x); + Assert.assertEquals((long) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.max(res, a[i]); @@ -4264,7 +4372,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4278,20 +4386,15 @@ public class Long512VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + long v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4300,7 +4403,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long UMINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.minUnsigned(res, a[i]); } @@ -4309,7 +4412,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long UMINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4321,20 +4424,15 @@ public class Long512VectorTests extends AbstractVectorTest { static void UMINReduceLong512VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + long v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4342,8 +4440,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::UMINReduce, Long512VectorTests::UMINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMIN_IDENTITY; + + Assert.assertEquals((long) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static long UMINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.minUnsigned(res, a[i]); @@ -4353,7 +4474,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long UMINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4367,20 +4488,15 @@ public class Long512VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + long v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4389,7 +4505,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long UMAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.maxUnsigned(res, a[i]); } @@ -4398,7 +4514,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long UMAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4410,20 +4526,15 @@ public class Long512VectorTests extends AbstractVectorTest { static void UMAXReduceLong512VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + long v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4431,8 +4542,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::UMAXReduce, Long512VectorTests::UMAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMAX_IDENTITY; + + Assert.assertEquals((long) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static long UMAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.maxUnsigned(res, a[i]); @@ -4442,7 +4576,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long UMAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4456,20 +4590,15 @@ public class Long512VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + long v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4478,7 +4607,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduce(long[] a, int idx) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4487,7 +4616,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAll(long[] a) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4499,20 +4628,15 @@ public class Long512VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceLong512VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4520,8 +4644,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::FIRST_NONZEROReduce, Long512VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4531,7 +4678,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4545,20 +4692,15 @@ public class Long512VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4615,7 +4757,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long SUADDReduce(long[] a, int idx) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4624,7 +4766,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long SUADDReduceAll(long[] a) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4639,17 +4781,12 @@ public class Long512VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + long v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4657,8 +4794,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::SUADDReduce, Long512VectorTests::SUADDReduceAll); } + @Test(dataProvider = "longSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = SUADD_IDENTITY; + + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static long SUADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4668,7 +4828,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long SUADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4684,17 +4844,12 @@ public class Long512VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + long v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Long64VectorTests.java b/test/jdk/jdk/incubator/vector/Long64VectorTests.java index cb052925778..5f8a9018384 100644 --- a/test/jdk/jdk/incubator/vector/Long64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -63,9 +63,21 @@ public class Long64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final long CONST_SHIFT = Long.SIZE / 2; + // Identity values for reduction operations + private static final long ADD_IDENTITY = (long)0; + private static final long AND_IDENTITY = (long)-1; + private static final long FIRST_NONZERO_IDENTITY = (long)0; + private static final long MAX_IDENTITY = Long.MIN_VALUE; + private static final long MIN_IDENTITY = Long.MAX_VALUE; + private static final long MUL_IDENTITY = (long)1; + private static final long OR_IDENTITY = (long)0; + private static final long SUADD_IDENTITY = (long)0; + private static final long UMAX_IDENTITY = (long)0; // Minimum unsigned value + private static final long UMIN_IDENTITY = (long)-1; // Maximum unsigned value + private static final long XOR_IDENTITY = (long)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); static void assertArraysStrictlyEquals(long[] r, long[] a) { @@ -3677,7 +3689,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ANDReduce(long[] a, int idx) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3686,7 +3698,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ANDReduceAll(long[] a) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3698,20 +3710,15 @@ public class Long64VectorTests extends AbstractVectorTest { static void ANDReduceLong64VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + long v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3719,8 +3726,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::ANDReduce, Long64VectorTests::ANDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = AND_IDENTITY; + + Assert.assertEquals((long) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id & x), x); + Assert.assertEquals((long) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static long ANDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3730,7 +3760,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ANDReduceAllMasked(long[] a, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3744,20 +3774,15 @@ public class Long64VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + long v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3766,7 +3791,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ORReduce(long[] a, int idx) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3775,7 +3800,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ORReduceAll(long[] a) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3790,17 +3815,12 @@ public class Long64VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + long v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3808,8 +3828,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::ORReduce, Long64VectorTests::ORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = OR_IDENTITY; + + Assert.assertEquals((long) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id | x), x); + Assert.assertEquals((long) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static long ORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3819,7 +3862,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3836,17 +3879,12 @@ public class Long64VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + long v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3855,7 +3893,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long XORReduce(long[] a, int idx) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3864,7 +3902,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long XORReduceAll(long[] a) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3879,17 +3917,12 @@ public class Long64VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + long v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3897,8 +3930,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::XORReduce, Long64VectorTests::XORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = XOR_IDENTITY; + + Assert.assertEquals((long) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id ^ x), x); + Assert.assertEquals((long) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static long XORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3908,7 +3964,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long XORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3925,17 +3981,12 @@ public class Long64VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + long v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3944,7 +3995,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ADDReduce(long[] a, int idx) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3953,7 +4004,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ADDReduceAll(long[] a) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3968,17 +4019,12 @@ public class Long64VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + long v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3986,8 +4032,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::ADDReduce, Long64VectorTests::ADDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = ADD_IDENTITY; + + Assert.assertEquals((long) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id + x), x); + Assert.assertEquals((long) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static long ADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3997,7 +4066,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -4014,17 +4083,12 @@ public class Long64VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + long v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4033,7 +4097,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MULReduce(long[] a, int idx) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4042,7 +4106,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MULReduceAll(long[] a) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4054,20 +4118,15 @@ public class Long64VectorTests extends AbstractVectorTest { static void MULReduceLong64VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + long v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4075,8 +4134,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::MULReduce, Long64VectorTests::MULReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MUL_IDENTITY; + + Assert.assertEquals((long) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id * x), x); + Assert.assertEquals((long) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static long MULReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4086,7 +4168,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MULReduceAllMasked(long[] a, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4100,20 +4182,15 @@ public class Long64VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + long v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4122,7 +4199,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.min(res, a[i]); } @@ -4131,7 +4208,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduce(a, i)); } @@ -4143,20 +4220,15 @@ public class Long64VectorTests extends AbstractVectorTest { static void MINReduceLong64VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + long v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4164,8 +4236,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::MINReduce, Long64VectorTests::MINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MIN_IDENTITY; + + Assert.assertEquals((long) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.min(id, x), x); + Assert.assertEquals((long) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static long MINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.min(res, a[i]); @@ -4175,7 +4270,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4189,20 +4284,15 @@ public class Long64VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + long v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4211,7 +4301,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.max(res, a[i]); } @@ -4220,7 +4310,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduce(a, i)); } @@ -4232,20 +4322,15 @@ public class Long64VectorTests extends AbstractVectorTest { static void MAXReduceLong64VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + long v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4253,8 +4338,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::MAXReduce, Long64VectorTests::MAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MAX_IDENTITY; + + Assert.assertEquals((long) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.max(id, x), x); + Assert.assertEquals((long) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.max(res, a[i]); @@ -4264,7 +4372,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4278,20 +4386,15 @@ public class Long64VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + long v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4300,7 +4403,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long UMINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.minUnsigned(res, a[i]); } @@ -4309,7 +4412,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long UMINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4321,20 +4424,15 @@ public class Long64VectorTests extends AbstractVectorTest { static void UMINReduceLong64VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + long v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4342,8 +4440,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::UMINReduce, Long64VectorTests::UMINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMIN_IDENTITY; + + Assert.assertEquals((long) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static long UMINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.minUnsigned(res, a[i]); @@ -4353,7 +4474,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long UMINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4367,20 +4488,15 @@ public class Long64VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + long v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4389,7 +4505,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long UMAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.maxUnsigned(res, a[i]); } @@ -4398,7 +4514,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long UMAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4410,20 +4526,15 @@ public class Long64VectorTests extends AbstractVectorTest { static void UMAXReduceLong64VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + long v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4431,8 +4542,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::UMAXReduce, Long64VectorTests::UMAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMAX_IDENTITY; + + Assert.assertEquals((long) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static long UMAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.maxUnsigned(res, a[i]); @@ -4442,7 +4576,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long UMAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4456,20 +4590,15 @@ public class Long64VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + long v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4478,7 +4607,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduce(long[] a, int idx) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4487,7 +4616,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAll(long[] a) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4499,20 +4628,15 @@ public class Long64VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceLong64VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4520,8 +4644,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::FIRST_NONZEROReduce, Long64VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4531,7 +4678,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4545,20 +4692,15 @@ public class Long64VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4615,7 +4757,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long SUADDReduce(long[] a, int idx) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4624,7 +4766,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long SUADDReduceAll(long[] a) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4639,17 +4781,12 @@ public class Long64VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + long v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4657,8 +4794,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::SUADDReduce, Long64VectorTests::SUADDReduceAll); } + @Test(dataProvider = "longSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = SUADD_IDENTITY; + + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static long SUADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4668,7 +4828,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long SUADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4684,17 +4844,12 @@ public class Long64VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + long v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java index 6fe189867c2..17fee0a7765 100644 --- a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -71,6 +71,19 @@ public class LongMaxVectorTests extends AbstractVectorTest { private static final long CONST_SHIFT = Long.SIZE / 2; + // Identity values for reduction operations + private static final long ADD_IDENTITY = (long)0; + private static final long AND_IDENTITY = (long)-1; + private static final long FIRST_NONZERO_IDENTITY = (long)0; + private static final long MAX_IDENTITY = Long.MIN_VALUE; + private static final long MIN_IDENTITY = Long.MAX_VALUE; + private static final long MUL_IDENTITY = (long)1; + private static final long OR_IDENTITY = (long)0; + private static final long SUADD_IDENTITY = (long)0; + private static final long UMAX_IDENTITY = (long)0; // Minimum unsigned value + private static final long UMIN_IDENTITY = (long)-1; // Maximum unsigned value + private static final long XOR_IDENTITY = (long)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); static void assertArraysStrictlyEquals(long[] r, long[] a) { @@ -3682,7 +3695,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ANDReduce(long[] a, int idx) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3691,7 +3704,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ANDReduceAll(long[] a) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3703,20 +3716,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { static void ANDReduceLongMaxVectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + long v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3724,8 +3732,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::ANDReduce, LongMaxVectorTests::ANDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = AND_IDENTITY; + + Assert.assertEquals((long) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id & x), x); + Assert.assertEquals((long) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static long ANDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3735,7 +3766,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ANDReduceAllMasked(long[] a, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3749,20 +3780,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + long v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3771,7 +3797,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ORReduce(long[] a, int idx) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3780,7 +3806,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ORReduceAll(long[] a) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3795,17 +3821,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + long v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3813,8 +3834,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::ORReduce, LongMaxVectorTests::ORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = OR_IDENTITY; + + Assert.assertEquals((long) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id | x), x); + Assert.assertEquals((long) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static long ORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3824,7 +3868,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3841,17 +3885,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + long v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3860,7 +3899,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long XORReduce(long[] a, int idx) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3869,7 +3908,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long XORReduceAll(long[] a) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3884,17 +3923,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + long v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3902,8 +3936,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::XORReduce, LongMaxVectorTests::XORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = XOR_IDENTITY; + + Assert.assertEquals((long) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id ^ x), x); + Assert.assertEquals((long) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static long XORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3913,7 +3970,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long XORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3930,17 +3987,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + long v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3949,7 +4001,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ADDReduce(long[] a, int idx) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3958,7 +4010,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ADDReduceAll(long[] a) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3973,17 +4025,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + long v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3991,8 +4038,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::ADDReduce, LongMaxVectorTests::ADDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = ADD_IDENTITY; + + Assert.assertEquals((long) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id + x), x); + Assert.assertEquals((long) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static long ADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -4002,7 +4072,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -4019,17 +4089,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + long v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4038,7 +4103,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MULReduce(long[] a, int idx) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4047,7 +4112,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MULReduceAll(long[] a) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4059,20 +4124,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { static void MULReduceLongMaxVectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + long v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4080,8 +4140,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::MULReduce, LongMaxVectorTests::MULReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MUL_IDENTITY; + + Assert.assertEquals((long) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id * x), x); + Assert.assertEquals((long) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static long MULReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4091,7 +4174,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MULReduceAllMasked(long[] a, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4105,20 +4188,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + long v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4127,7 +4205,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.min(res, a[i]); } @@ -4136,7 +4214,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduce(a, i)); } @@ -4148,20 +4226,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { static void MINReduceLongMaxVectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + long v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4169,8 +4242,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::MINReduce, LongMaxVectorTests::MINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MIN_IDENTITY; + + Assert.assertEquals((long) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.min(id, x), x); + Assert.assertEquals((long) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static long MINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.min(res, a[i]); @@ -4180,7 +4276,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4194,20 +4290,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + long v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4216,7 +4307,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.max(res, a[i]); } @@ -4225,7 +4316,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduce(a, i)); } @@ -4237,20 +4328,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { static void MAXReduceLongMaxVectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + long v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4258,8 +4344,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::MAXReduce, LongMaxVectorTests::MAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MAX_IDENTITY; + + Assert.assertEquals((long) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.max(id, x), x); + Assert.assertEquals((long) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.max(res, a[i]); @@ -4269,7 +4378,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4283,20 +4392,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + long v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4305,7 +4409,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long UMINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.minUnsigned(res, a[i]); } @@ -4314,7 +4418,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long UMINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4326,20 +4430,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { static void UMINReduceLongMaxVectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + long v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4347,8 +4446,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::UMINReduce, LongMaxVectorTests::UMINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMIN_IDENTITY; + + Assert.assertEquals((long) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static long UMINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.minUnsigned(res, a[i]); @@ -4358,7 +4480,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long UMINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4372,20 +4494,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + long v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4394,7 +4511,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long UMAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.maxUnsigned(res, a[i]); } @@ -4403,7 +4520,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long UMAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4415,20 +4532,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { static void UMAXReduceLongMaxVectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + long v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4436,8 +4548,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::UMAXReduce, LongMaxVectorTests::UMAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMAX_IDENTITY; + + Assert.assertEquals((long) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static long UMAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.maxUnsigned(res, a[i]); @@ -4447,7 +4582,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long UMAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4461,20 +4596,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + long v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4483,7 +4613,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduce(long[] a, int idx) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4492,7 +4622,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAll(long[] a) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4504,20 +4634,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceLongMaxVectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4525,8 +4650,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::FIRST_NONZEROReduce, LongMaxVectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4536,7 +4684,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4550,20 +4698,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4620,7 +4763,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long SUADDReduce(long[] a, int idx) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4629,7 +4772,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long SUADDReduceAll(long[] a) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4644,17 +4787,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + long v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4662,8 +4800,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::SUADDReduce, LongMaxVectorTests::SUADDReduceAll); } + @Test(dataProvider = "longSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = SUADD_IDENTITY; + + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static long SUADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4673,7 +4834,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long SUADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4689,17 +4850,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + long v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Short128VectorTests.java b/test/jdk/jdk/incubator/vector/Short128VectorTests.java index be39a01a4e7..fb740fedfd4 100644 --- a/test/jdk/jdk/incubator/vector/Short128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -63,9 +63,21 @@ public class Short128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final short CONST_SHIFT = Short.SIZE / 2; + // Identity values for reduction operations + private static final short ADD_IDENTITY = (short)0; + private static final short AND_IDENTITY = (short)-1; + private static final short FIRST_NONZERO_IDENTITY = (short)0; + private static final short MAX_IDENTITY = Short.MIN_VALUE; + private static final short MIN_IDENTITY = Short.MAX_VALUE; + private static final short MUL_IDENTITY = (short)1; + private static final short OR_IDENTITY = (short)0; + private static final short SUADD_IDENTITY = (short)0; + private static final short UMAX_IDENTITY = (short)0; // Minimum unsigned value + private static final short UMIN_IDENTITY = (short)-1; // Maximum unsigned value + private static final short XOR_IDENTITY = (short)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); static void assertArraysStrictlyEquals(short[] r, short[] a) { @@ -3602,7 +3614,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ANDReduce(short[] a, int idx) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3611,7 +3623,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ANDReduceAll(short[] a) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3623,20 +3635,15 @@ public class Short128VectorTests extends AbstractVectorTest { static void ANDReduceShort128VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + short v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3644,8 +3651,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::ANDReduce, Short128VectorTests::ANDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = AND_IDENTITY; + + Assert.assertEquals((short) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id & x), x); + Assert.assertEquals((short) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static short ANDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3655,7 +3685,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ANDReduceAllMasked(short[] a, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3669,20 +3699,15 @@ public class Short128VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + short v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3691,7 +3716,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ORReduce(short[] a, int idx) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3700,7 +3725,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ORReduceAll(short[] a) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3715,17 +3740,12 @@ public class Short128VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + short v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3733,8 +3753,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::ORReduce, Short128VectorTests::ORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = OR_IDENTITY; + + Assert.assertEquals((short) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id | x), x); + Assert.assertEquals((short) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static short ORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3744,7 +3787,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3761,17 +3804,12 @@ public class Short128VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + short v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3780,7 +3818,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short XORReduce(short[] a, int idx) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3789,7 +3827,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short XORReduceAll(short[] a) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3804,17 +3842,12 @@ public class Short128VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + short v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3822,8 +3855,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::XORReduce, Short128VectorTests::XORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = XOR_IDENTITY; + + Assert.assertEquals((short) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id ^ x), x); + Assert.assertEquals((short) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static short XORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3833,7 +3889,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short XORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3850,17 +3906,12 @@ public class Short128VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + short v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3869,7 +3920,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ADDReduce(short[] a, int idx) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3878,7 +3929,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ADDReduceAll(short[] a) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3893,17 +3944,12 @@ public class Short128VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + short v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3911,8 +3957,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::ADDReduce, Short128VectorTests::ADDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = ADD_IDENTITY; + + Assert.assertEquals((short) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id + x), x); + Assert.assertEquals((short) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static short ADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3922,7 +3991,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3939,17 +4008,12 @@ public class Short128VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + short v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3958,7 +4022,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MULReduce(short[] a, int idx) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3967,7 +4031,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MULReduceAll(short[] a) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3979,20 +4043,15 @@ public class Short128VectorTests extends AbstractVectorTest { static void MULReduceShort128VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + short v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4000,8 +4059,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::MULReduce, Short128VectorTests::MULReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MUL_IDENTITY; + + Assert.assertEquals((short) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id * x), x); + Assert.assertEquals((short) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static short MULReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4011,7 +4093,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MULReduceAllMasked(short[] a, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4025,20 +4107,15 @@ public class Short128VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + short v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4047,7 +4124,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.min(res, a[i]); } @@ -4056,7 +4133,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduce(a, i)); } @@ -4068,20 +4145,15 @@ public class Short128VectorTests extends AbstractVectorTest { static void MINReduceShort128VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + short v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4089,8 +4161,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::MINReduce, Short128VectorTests::MINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MIN_IDENTITY; + + Assert.assertEquals((short) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.min(id, x), x); + Assert.assertEquals((short) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static short MINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.min(res, a[i]); @@ -4100,7 +4195,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4114,20 +4209,15 @@ public class Short128VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + short v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4136,7 +4226,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.max(res, a[i]); } @@ -4145,7 +4235,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduce(a, i)); } @@ -4157,20 +4247,15 @@ public class Short128VectorTests extends AbstractVectorTest { static void MAXReduceShort128VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + short v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4178,8 +4263,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::MAXReduce, Short128VectorTests::MAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MAX_IDENTITY; + + Assert.assertEquals((short) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.max(id, x), x); + Assert.assertEquals((short) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.max(res, a[i]); @@ -4189,7 +4297,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4203,20 +4311,15 @@ public class Short128VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + short v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4225,7 +4328,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short UMINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.minUnsigned(res, a[i]); } @@ -4234,7 +4337,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short UMINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4246,20 +4349,15 @@ public class Short128VectorTests extends AbstractVectorTest { static void UMINReduceShort128VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + short v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4267,8 +4365,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::UMINReduce, Short128VectorTests::UMINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMIN_IDENTITY; + + Assert.assertEquals((short) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static short UMINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.minUnsigned(res, a[i]); @@ -4278,7 +4399,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short UMINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4292,20 +4413,15 @@ public class Short128VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + short v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4314,7 +4430,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short UMAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.maxUnsigned(res, a[i]); } @@ -4323,7 +4439,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short UMAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4335,20 +4451,15 @@ public class Short128VectorTests extends AbstractVectorTest { static void UMAXReduceShort128VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + short v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4356,8 +4467,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::UMAXReduce, Short128VectorTests::UMAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMAX_IDENTITY; + + Assert.assertEquals((short) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static short UMAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.maxUnsigned(res, a[i]); @@ -4367,7 +4501,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short UMAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4381,20 +4515,15 @@ public class Short128VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + short v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4403,7 +4532,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduce(short[] a, int idx) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4412,7 +4541,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAll(short[] a) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4424,20 +4553,15 @@ public class Short128VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceShort128VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4445,8 +4569,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::FIRST_NONZEROReduce, Short128VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4456,7 +4603,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4470,20 +4617,15 @@ public class Short128VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4540,7 +4682,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short SUADDReduce(short[] a, int idx) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4549,7 +4691,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short SUADDReduceAll(short[] a) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4564,17 +4706,12 @@ public class Short128VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + short v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4582,8 +4719,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::SUADDReduce, Short128VectorTests::SUADDReduceAll); } + @Test(dataProvider = "shortSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = SUADD_IDENTITY; + + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static short SUADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4593,7 +4753,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short SUADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4609,17 +4769,12 @@ public class Short128VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + short v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Short256VectorTests.java b/test/jdk/jdk/incubator/vector/Short256VectorTests.java index 0b6ae53710e..cd6aa113b84 100644 --- a/test/jdk/jdk/incubator/vector/Short256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -63,9 +63,21 @@ public class Short256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final short CONST_SHIFT = Short.SIZE / 2; + // Identity values for reduction operations + private static final short ADD_IDENTITY = (short)0; + private static final short AND_IDENTITY = (short)-1; + private static final short FIRST_NONZERO_IDENTITY = (short)0; + private static final short MAX_IDENTITY = Short.MIN_VALUE; + private static final short MIN_IDENTITY = Short.MAX_VALUE; + private static final short MUL_IDENTITY = (short)1; + private static final short OR_IDENTITY = (short)0; + private static final short SUADD_IDENTITY = (short)0; + private static final short UMAX_IDENTITY = (short)0; // Minimum unsigned value + private static final short UMIN_IDENTITY = (short)-1; // Maximum unsigned value + private static final short XOR_IDENTITY = (short)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); static void assertArraysStrictlyEquals(short[] r, short[] a) { @@ -3602,7 +3614,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ANDReduce(short[] a, int idx) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3611,7 +3623,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ANDReduceAll(short[] a) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3623,20 +3635,15 @@ public class Short256VectorTests extends AbstractVectorTest { static void ANDReduceShort256VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + short v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3644,8 +3651,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::ANDReduce, Short256VectorTests::ANDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = AND_IDENTITY; + + Assert.assertEquals((short) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id & x), x); + Assert.assertEquals((short) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static short ANDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3655,7 +3685,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ANDReduceAllMasked(short[] a, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3669,20 +3699,15 @@ public class Short256VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + short v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3691,7 +3716,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ORReduce(short[] a, int idx) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3700,7 +3725,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ORReduceAll(short[] a) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3715,17 +3740,12 @@ public class Short256VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + short v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3733,8 +3753,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::ORReduce, Short256VectorTests::ORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = OR_IDENTITY; + + Assert.assertEquals((short) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id | x), x); + Assert.assertEquals((short) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static short ORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3744,7 +3787,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3761,17 +3804,12 @@ public class Short256VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + short v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3780,7 +3818,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short XORReduce(short[] a, int idx) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3789,7 +3827,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short XORReduceAll(short[] a) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3804,17 +3842,12 @@ public class Short256VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + short v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3822,8 +3855,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::XORReduce, Short256VectorTests::XORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = XOR_IDENTITY; + + Assert.assertEquals((short) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id ^ x), x); + Assert.assertEquals((short) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static short XORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3833,7 +3889,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short XORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3850,17 +3906,12 @@ public class Short256VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + short v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3869,7 +3920,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ADDReduce(short[] a, int idx) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3878,7 +3929,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ADDReduceAll(short[] a) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3893,17 +3944,12 @@ public class Short256VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + short v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3911,8 +3957,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::ADDReduce, Short256VectorTests::ADDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = ADD_IDENTITY; + + Assert.assertEquals((short) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id + x), x); + Assert.assertEquals((short) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static short ADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3922,7 +3991,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3939,17 +4008,12 @@ public class Short256VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + short v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3958,7 +4022,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MULReduce(short[] a, int idx) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3967,7 +4031,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MULReduceAll(short[] a) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3979,20 +4043,15 @@ public class Short256VectorTests extends AbstractVectorTest { static void MULReduceShort256VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + short v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4000,8 +4059,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::MULReduce, Short256VectorTests::MULReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MUL_IDENTITY; + + Assert.assertEquals((short) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id * x), x); + Assert.assertEquals((short) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static short MULReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4011,7 +4093,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MULReduceAllMasked(short[] a, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4025,20 +4107,15 @@ public class Short256VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + short v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4047,7 +4124,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.min(res, a[i]); } @@ -4056,7 +4133,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduce(a, i)); } @@ -4068,20 +4145,15 @@ public class Short256VectorTests extends AbstractVectorTest { static void MINReduceShort256VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + short v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4089,8 +4161,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::MINReduce, Short256VectorTests::MINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MIN_IDENTITY; + + Assert.assertEquals((short) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.min(id, x), x); + Assert.assertEquals((short) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static short MINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.min(res, a[i]); @@ -4100,7 +4195,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4114,20 +4209,15 @@ public class Short256VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + short v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4136,7 +4226,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.max(res, a[i]); } @@ -4145,7 +4235,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduce(a, i)); } @@ -4157,20 +4247,15 @@ public class Short256VectorTests extends AbstractVectorTest { static void MAXReduceShort256VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + short v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4178,8 +4263,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::MAXReduce, Short256VectorTests::MAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MAX_IDENTITY; + + Assert.assertEquals((short) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.max(id, x), x); + Assert.assertEquals((short) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.max(res, a[i]); @@ -4189,7 +4297,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4203,20 +4311,15 @@ public class Short256VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + short v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4225,7 +4328,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short UMINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.minUnsigned(res, a[i]); } @@ -4234,7 +4337,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short UMINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4246,20 +4349,15 @@ public class Short256VectorTests extends AbstractVectorTest { static void UMINReduceShort256VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + short v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4267,8 +4365,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::UMINReduce, Short256VectorTests::UMINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMIN_IDENTITY; + + Assert.assertEquals((short) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static short UMINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.minUnsigned(res, a[i]); @@ -4278,7 +4399,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short UMINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4292,20 +4413,15 @@ public class Short256VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + short v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4314,7 +4430,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short UMAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.maxUnsigned(res, a[i]); } @@ -4323,7 +4439,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short UMAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4335,20 +4451,15 @@ public class Short256VectorTests extends AbstractVectorTest { static void UMAXReduceShort256VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + short v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4356,8 +4467,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::UMAXReduce, Short256VectorTests::UMAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMAX_IDENTITY; + + Assert.assertEquals((short) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static short UMAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.maxUnsigned(res, a[i]); @@ -4367,7 +4501,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short UMAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4381,20 +4515,15 @@ public class Short256VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + short v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4403,7 +4532,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduce(short[] a, int idx) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4412,7 +4541,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAll(short[] a) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4424,20 +4553,15 @@ public class Short256VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceShort256VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4445,8 +4569,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::FIRST_NONZEROReduce, Short256VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4456,7 +4603,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4470,20 +4617,15 @@ public class Short256VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4540,7 +4682,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short SUADDReduce(short[] a, int idx) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4549,7 +4691,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short SUADDReduceAll(short[] a) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4564,17 +4706,12 @@ public class Short256VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + short v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4582,8 +4719,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::SUADDReduce, Short256VectorTests::SUADDReduceAll); } + @Test(dataProvider = "shortSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = SUADD_IDENTITY; + + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static short SUADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4593,7 +4753,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short SUADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4609,17 +4769,12 @@ public class Short256VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + short v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Short512VectorTests.java b/test/jdk/jdk/incubator/vector/Short512VectorTests.java index d4568068b6a..722f826f3e9 100644 --- a/test/jdk/jdk/incubator/vector/Short512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -63,9 +63,21 @@ public class Short512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final short CONST_SHIFT = Short.SIZE / 2; + // Identity values for reduction operations + private static final short ADD_IDENTITY = (short)0; + private static final short AND_IDENTITY = (short)-1; + private static final short FIRST_NONZERO_IDENTITY = (short)0; + private static final short MAX_IDENTITY = Short.MIN_VALUE; + private static final short MIN_IDENTITY = Short.MAX_VALUE; + private static final short MUL_IDENTITY = (short)1; + private static final short OR_IDENTITY = (short)0; + private static final short SUADD_IDENTITY = (short)0; + private static final short UMAX_IDENTITY = (short)0; // Minimum unsigned value + private static final short UMIN_IDENTITY = (short)-1; // Maximum unsigned value + private static final short XOR_IDENTITY = (short)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); static void assertArraysStrictlyEquals(short[] r, short[] a) { @@ -3602,7 +3614,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ANDReduce(short[] a, int idx) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3611,7 +3623,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ANDReduceAll(short[] a) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3623,20 +3635,15 @@ public class Short512VectorTests extends AbstractVectorTest { static void ANDReduceShort512VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + short v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3644,8 +3651,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::ANDReduce, Short512VectorTests::ANDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = AND_IDENTITY; + + Assert.assertEquals((short) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id & x), x); + Assert.assertEquals((short) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static short ANDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3655,7 +3685,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ANDReduceAllMasked(short[] a, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3669,20 +3699,15 @@ public class Short512VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + short v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3691,7 +3716,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ORReduce(short[] a, int idx) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3700,7 +3725,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ORReduceAll(short[] a) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3715,17 +3740,12 @@ public class Short512VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + short v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3733,8 +3753,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::ORReduce, Short512VectorTests::ORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = OR_IDENTITY; + + Assert.assertEquals((short) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id | x), x); + Assert.assertEquals((short) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static short ORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3744,7 +3787,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3761,17 +3804,12 @@ public class Short512VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + short v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3780,7 +3818,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short XORReduce(short[] a, int idx) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3789,7 +3827,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short XORReduceAll(short[] a) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3804,17 +3842,12 @@ public class Short512VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + short v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3822,8 +3855,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::XORReduce, Short512VectorTests::XORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = XOR_IDENTITY; + + Assert.assertEquals((short) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id ^ x), x); + Assert.assertEquals((short) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static short XORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3833,7 +3889,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short XORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3850,17 +3906,12 @@ public class Short512VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + short v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3869,7 +3920,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ADDReduce(short[] a, int idx) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3878,7 +3929,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ADDReduceAll(short[] a) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3893,17 +3944,12 @@ public class Short512VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + short v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3911,8 +3957,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::ADDReduce, Short512VectorTests::ADDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = ADD_IDENTITY; + + Assert.assertEquals((short) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id + x), x); + Assert.assertEquals((short) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static short ADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3922,7 +3991,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3939,17 +4008,12 @@ public class Short512VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + short v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3958,7 +4022,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MULReduce(short[] a, int idx) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3967,7 +4031,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MULReduceAll(short[] a) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3979,20 +4043,15 @@ public class Short512VectorTests extends AbstractVectorTest { static void MULReduceShort512VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + short v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4000,8 +4059,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::MULReduce, Short512VectorTests::MULReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MUL_IDENTITY; + + Assert.assertEquals((short) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id * x), x); + Assert.assertEquals((short) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static short MULReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4011,7 +4093,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MULReduceAllMasked(short[] a, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4025,20 +4107,15 @@ public class Short512VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + short v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4047,7 +4124,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.min(res, a[i]); } @@ -4056,7 +4133,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduce(a, i)); } @@ -4068,20 +4145,15 @@ public class Short512VectorTests extends AbstractVectorTest { static void MINReduceShort512VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + short v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4089,8 +4161,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::MINReduce, Short512VectorTests::MINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MIN_IDENTITY; + + Assert.assertEquals((short) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.min(id, x), x); + Assert.assertEquals((short) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static short MINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.min(res, a[i]); @@ -4100,7 +4195,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4114,20 +4209,15 @@ public class Short512VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + short v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4136,7 +4226,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.max(res, a[i]); } @@ -4145,7 +4235,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduce(a, i)); } @@ -4157,20 +4247,15 @@ public class Short512VectorTests extends AbstractVectorTest { static void MAXReduceShort512VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + short v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4178,8 +4263,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::MAXReduce, Short512VectorTests::MAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MAX_IDENTITY; + + Assert.assertEquals((short) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.max(id, x), x); + Assert.assertEquals((short) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.max(res, a[i]); @@ -4189,7 +4297,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4203,20 +4311,15 @@ public class Short512VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + short v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4225,7 +4328,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short UMINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.minUnsigned(res, a[i]); } @@ -4234,7 +4337,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short UMINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4246,20 +4349,15 @@ public class Short512VectorTests extends AbstractVectorTest { static void UMINReduceShort512VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + short v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4267,8 +4365,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::UMINReduce, Short512VectorTests::UMINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMIN_IDENTITY; + + Assert.assertEquals((short) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static short UMINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.minUnsigned(res, a[i]); @@ -4278,7 +4399,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short UMINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4292,20 +4413,15 @@ public class Short512VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + short v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4314,7 +4430,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short UMAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.maxUnsigned(res, a[i]); } @@ -4323,7 +4439,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short UMAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4335,20 +4451,15 @@ public class Short512VectorTests extends AbstractVectorTest { static void UMAXReduceShort512VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + short v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4356,8 +4467,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::UMAXReduce, Short512VectorTests::UMAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMAX_IDENTITY; + + Assert.assertEquals((short) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static short UMAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.maxUnsigned(res, a[i]); @@ -4367,7 +4501,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short UMAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4381,20 +4515,15 @@ public class Short512VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + short v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4403,7 +4532,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduce(short[] a, int idx) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4412,7 +4541,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAll(short[] a) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4424,20 +4553,15 @@ public class Short512VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceShort512VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4445,8 +4569,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::FIRST_NONZEROReduce, Short512VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4456,7 +4603,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4470,20 +4617,15 @@ public class Short512VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4540,7 +4682,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short SUADDReduce(short[] a, int idx) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4549,7 +4691,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short SUADDReduceAll(short[] a) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4564,17 +4706,12 @@ public class Short512VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + short v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4582,8 +4719,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::SUADDReduce, Short512VectorTests::SUADDReduceAll); } + @Test(dataProvider = "shortSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = SUADD_IDENTITY; + + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static short SUADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4593,7 +4753,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short SUADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4609,17 +4769,12 @@ public class Short512VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + short v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Short64VectorTests.java b/test/jdk/jdk/incubator/vector/Short64VectorTests.java index 83d5cfd18e8..9ec8ac08789 100644 --- a/test/jdk/jdk/incubator/vector/Short64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -63,9 +63,21 @@ public class Short64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final short CONST_SHIFT = Short.SIZE / 2; + // Identity values for reduction operations + private static final short ADD_IDENTITY = (short)0; + private static final short AND_IDENTITY = (short)-1; + private static final short FIRST_NONZERO_IDENTITY = (short)0; + private static final short MAX_IDENTITY = Short.MIN_VALUE; + private static final short MIN_IDENTITY = Short.MAX_VALUE; + private static final short MUL_IDENTITY = (short)1; + private static final short OR_IDENTITY = (short)0; + private static final short SUADD_IDENTITY = (short)0; + private static final short UMAX_IDENTITY = (short)0; // Minimum unsigned value + private static final short UMIN_IDENTITY = (short)-1; // Maximum unsigned value + private static final short XOR_IDENTITY = (short)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); static void assertArraysStrictlyEquals(short[] r, short[] a) { @@ -3602,7 +3614,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ANDReduce(short[] a, int idx) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3611,7 +3623,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ANDReduceAll(short[] a) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3623,20 +3635,15 @@ public class Short64VectorTests extends AbstractVectorTest { static void ANDReduceShort64VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + short v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3644,8 +3651,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::ANDReduce, Short64VectorTests::ANDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = AND_IDENTITY; + + Assert.assertEquals((short) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id & x), x); + Assert.assertEquals((short) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static short ANDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3655,7 +3685,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ANDReduceAllMasked(short[] a, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3669,20 +3699,15 @@ public class Short64VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + short v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3691,7 +3716,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ORReduce(short[] a, int idx) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3700,7 +3725,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ORReduceAll(short[] a) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3715,17 +3740,12 @@ public class Short64VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + short v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3733,8 +3753,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::ORReduce, Short64VectorTests::ORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = OR_IDENTITY; + + Assert.assertEquals((short) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id | x), x); + Assert.assertEquals((short) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static short ORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3744,7 +3787,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3761,17 +3804,12 @@ public class Short64VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + short v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3780,7 +3818,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short XORReduce(short[] a, int idx) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3789,7 +3827,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short XORReduceAll(short[] a) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3804,17 +3842,12 @@ public class Short64VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + short v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3822,8 +3855,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::XORReduce, Short64VectorTests::XORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = XOR_IDENTITY; + + Assert.assertEquals((short) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id ^ x), x); + Assert.assertEquals((short) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static short XORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3833,7 +3889,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short XORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3850,17 +3906,12 @@ public class Short64VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + short v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3869,7 +3920,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ADDReduce(short[] a, int idx) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3878,7 +3929,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ADDReduceAll(short[] a) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3893,17 +3944,12 @@ public class Short64VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + short v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3911,8 +3957,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::ADDReduce, Short64VectorTests::ADDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = ADD_IDENTITY; + + Assert.assertEquals((short) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id + x), x); + Assert.assertEquals((short) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static short ADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3922,7 +3991,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3939,17 +4008,12 @@ public class Short64VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + short v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3958,7 +4022,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MULReduce(short[] a, int idx) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3967,7 +4031,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MULReduceAll(short[] a) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3979,20 +4043,15 @@ public class Short64VectorTests extends AbstractVectorTest { static void MULReduceShort64VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + short v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4000,8 +4059,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::MULReduce, Short64VectorTests::MULReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MUL_IDENTITY; + + Assert.assertEquals((short) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id * x), x); + Assert.assertEquals((short) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static short MULReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4011,7 +4093,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MULReduceAllMasked(short[] a, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4025,20 +4107,15 @@ public class Short64VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + short v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4047,7 +4124,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.min(res, a[i]); } @@ -4056,7 +4133,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduce(a, i)); } @@ -4068,20 +4145,15 @@ public class Short64VectorTests extends AbstractVectorTest { static void MINReduceShort64VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + short v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4089,8 +4161,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::MINReduce, Short64VectorTests::MINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MIN_IDENTITY; + + Assert.assertEquals((short) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.min(id, x), x); + Assert.assertEquals((short) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static short MINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.min(res, a[i]); @@ -4100,7 +4195,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4114,20 +4209,15 @@ public class Short64VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + short v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4136,7 +4226,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.max(res, a[i]); } @@ -4145,7 +4235,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduce(a, i)); } @@ -4157,20 +4247,15 @@ public class Short64VectorTests extends AbstractVectorTest { static void MAXReduceShort64VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + short v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4178,8 +4263,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::MAXReduce, Short64VectorTests::MAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MAX_IDENTITY; + + Assert.assertEquals((short) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.max(id, x), x); + Assert.assertEquals((short) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.max(res, a[i]); @@ -4189,7 +4297,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4203,20 +4311,15 @@ public class Short64VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + short v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4225,7 +4328,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short UMINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.minUnsigned(res, a[i]); } @@ -4234,7 +4337,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short UMINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4246,20 +4349,15 @@ public class Short64VectorTests extends AbstractVectorTest { static void UMINReduceShort64VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + short v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4267,8 +4365,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::UMINReduce, Short64VectorTests::UMINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMIN_IDENTITY; + + Assert.assertEquals((short) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static short UMINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.minUnsigned(res, a[i]); @@ -4278,7 +4399,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short UMINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4292,20 +4413,15 @@ public class Short64VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + short v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4314,7 +4430,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short UMAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.maxUnsigned(res, a[i]); } @@ -4323,7 +4439,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short UMAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4335,20 +4451,15 @@ public class Short64VectorTests extends AbstractVectorTest { static void UMAXReduceShort64VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + short v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4356,8 +4467,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::UMAXReduce, Short64VectorTests::UMAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMAX_IDENTITY; + + Assert.assertEquals((short) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static short UMAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.maxUnsigned(res, a[i]); @@ -4367,7 +4501,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short UMAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4381,20 +4515,15 @@ public class Short64VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + short v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4403,7 +4532,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduce(short[] a, int idx) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4412,7 +4541,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAll(short[] a) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4424,20 +4553,15 @@ public class Short64VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceShort64VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4445,8 +4569,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::FIRST_NONZEROReduce, Short64VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4456,7 +4603,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4470,20 +4617,15 @@ public class Short64VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4540,7 +4682,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short SUADDReduce(short[] a, int idx) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4549,7 +4691,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short SUADDReduceAll(short[] a) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4564,17 +4706,12 @@ public class Short64VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + short v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4582,8 +4719,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::SUADDReduce, Short64VectorTests::SUADDReduceAll); } + @Test(dataProvider = "shortSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = SUADD_IDENTITY; + + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static short SUADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4593,7 +4753,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short SUADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4609,17 +4769,12 @@ public class Short64VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + short v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java index 45ba8db51c1..ad2efd3575d 100644 --- a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -71,6 +71,19 @@ public class ShortMaxVectorTests extends AbstractVectorTest { private static final short CONST_SHIFT = Short.SIZE / 2; + // Identity values for reduction operations + private static final short ADD_IDENTITY = (short)0; + private static final short AND_IDENTITY = (short)-1; + private static final short FIRST_NONZERO_IDENTITY = (short)0; + private static final short MAX_IDENTITY = Short.MIN_VALUE; + private static final short MIN_IDENTITY = Short.MAX_VALUE; + private static final short MUL_IDENTITY = (short)1; + private static final short OR_IDENTITY = (short)0; + private static final short SUADD_IDENTITY = (short)0; + private static final short UMAX_IDENTITY = (short)0; // Minimum unsigned value + private static final short UMIN_IDENTITY = (short)-1; // Maximum unsigned value + private static final short XOR_IDENTITY = (short)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); static void assertArraysStrictlyEquals(short[] r, short[] a) { @@ -3607,7 +3620,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ANDReduce(short[] a, int idx) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3616,7 +3629,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ANDReduceAll(short[] a) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3628,20 +3641,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static void ANDReduceShortMaxVectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + short v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3649,8 +3657,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::ANDReduce, ShortMaxVectorTests::ANDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = AND_IDENTITY; + + Assert.assertEquals((short) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id & x), x); + Assert.assertEquals((short) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static short ANDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3660,7 +3691,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ANDReduceAllMasked(short[] a, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3674,20 +3705,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + short v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3696,7 +3722,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ORReduce(short[] a, int idx) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3705,7 +3731,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ORReduceAll(short[] a) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3720,17 +3746,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + short v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3738,8 +3759,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::ORReduce, ShortMaxVectorTests::ORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = OR_IDENTITY; + + Assert.assertEquals((short) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id | x), x); + Assert.assertEquals((short) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static short ORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3749,7 +3793,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3766,17 +3810,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + short v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3785,7 +3824,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short XORReduce(short[] a, int idx) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3794,7 +3833,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short XORReduceAll(short[] a) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3809,17 +3848,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + short v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3827,8 +3861,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::XORReduce, ShortMaxVectorTests::XORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = XOR_IDENTITY; + + Assert.assertEquals((short) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id ^ x), x); + Assert.assertEquals((short) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static short XORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3838,7 +3895,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short XORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3855,17 +3912,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + short v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3874,7 +3926,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ADDReduce(short[] a, int idx) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3883,7 +3935,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ADDReduceAll(short[] a) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3898,17 +3950,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + short v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3916,8 +3963,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::ADDReduce, ShortMaxVectorTests::ADDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = ADD_IDENTITY; + + Assert.assertEquals((short) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id + x), x); + Assert.assertEquals((short) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static short ADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3927,7 +3997,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3944,17 +4014,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + short v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3963,7 +4028,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MULReduce(short[] a, int idx) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3972,7 +4037,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MULReduceAll(short[] a) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3984,20 +4049,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static void MULReduceShortMaxVectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + short v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4005,8 +4065,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::MULReduce, ShortMaxVectorTests::MULReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MUL_IDENTITY; + + Assert.assertEquals((short) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id * x), x); + Assert.assertEquals((short) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static short MULReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4016,7 +4099,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MULReduceAllMasked(short[] a, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4030,20 +4113,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + short v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4052,7 +4130,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.min(res, a[i]); } @@ -4061,7 +4139,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduce(a, i)); } @@ -4073,20 +4151,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static void MINReduceShortMaxVectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + short v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4094,8 +4167,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::MINReduce, ShortMaxVectorTests::MINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MIN_IDENTITY; + + Assert.assertEquals((short) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.min(id, x), x); + Assert.assertEquals((short) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static short MINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.min(res, a[i]); @@ -4105,7 +4201,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4119,20 +4215,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + short v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4141,7 +4232,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.max(res, a[i]); } @@ -4150,7 +4241,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduce(a, i)); } @@ -4162,20 +4253,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static void MAXReduceShortMaxVectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + short v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4183,8 +4269,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::MAXReduce, ShortMaxVectorTests::MAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MAX_IDENTITY; + + Assert.assertEquals((short) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.max(id, x), x); + Assert.assertEquals((short) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.max(res, a[i]); @@ -4194,7 +4303,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4208,20 +4317,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + short v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4230,7 +4334,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short UMINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.minUnsigned(res, a[i]); } @@ -4239,7 +4343,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short UMINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4251,20 +4355,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static void UMINReduceShortMaxVectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + short v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4272,8 +4371,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::UMINReduce, ShortMaxVectorTests::UMINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMIN_IDENTITY; + + Assert.assertEquals((short) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static short UMINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.minUnsigned(res, a[i]); @@ -4283,7 +4405,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short UMINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4297,20 +4419,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + short v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4319,7 +4436,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short UMAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.maxUnsigned(res, a[i]); } @@ -4328,7 +4445,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short UMAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4340,20 +4457,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static void UMAXReduceShortMaxVectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + short v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4361,8 +4473,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::UMAXReduce, ShortMaxVectorTests::UMAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMAX_IDENTITY; + + Assert.assertEquals((short) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static short UMAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.maxUnsigned(res, a[i]); @@ -4372,7 +4507,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short UMAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4386,20 +4521,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + short v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4408,7 +4538,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduce(short[] a, int idx) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4417,7 +4547,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAll(short[] a) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4429,20 +4559,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceShortMaxVectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4450,8 +4575,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::FIRST_NONZEROReduce, ShortMaxVectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4461,7 +4609,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4475,20 +4623,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4545,7 +4688,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short SUADDReduce(short[] a, int idx) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4554,7 +4697,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short SUADDReduceAll(short[] a) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4569,17 +4712,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + short v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4587,8 +4725,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::SUADDReduce, ShortMaxVectorTests::SUADDReduceAll); } + @Test(dataProvider = "shortSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = SUADD_IDENTITY; + + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static short SUADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4598,7 +4759,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short SUADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4614,17 +4775,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + short v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/gen-template.sh b/test/jdk/jdk/incubator/vector/gen-template.sh index d9bae116da2..d2528b13b78 100644 --- a/test/jdk/jdk/incubator/vector/gen-template.sh +++ b/test/jdk/jdk/incubator/vector/gen-template.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2026, 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 @@ -511,23 +511,23 @@ gen_binary_bcst_op_no_masked "MAX+max" "Math.max(a, b)" gen_saturating_binary_op_associative "SUADD" "VectorMath.addSaturatingUnsigned(a, b)" "BITWISE" # Reductions. -gen_reduction_op "AND" "\&" "BITWISE" "-1" -gen_reduction_op "OR" "|" "BITWISE" "0" -gen_reduction_op "XOR" "^" "BITWISE" "0" -gen_reduction_op "ADD" "+" "" "0" -gen_reduction_op "MUL" "*" "" "1" -gen_reduction_op_func "MIN" "(\$type\$) Math.min" "" "\$Wideboxtype\$.\$MaxValue\$" -gen_reduction_op_func "MAX" "(\$type\$) Math.max" "" "\$Wideboxtype\$.\$MinValue\$" -gen_reduction_op_func "UMIN" "(\$type\$) VectorMath.minUnsigned" "BITWISE" "\$Wideboxtype\$.\$MaxValue\$" -gen_reduction_op_func "UMAX" "(\$type\$) VectorMath.maxUnsigned" "BITWISE" "\$Wideboxtype\$.\$MinValue\$" -gen_reduction_op_func "FIRST_NONZERO" "firstNonZero" "" "(\$type\$) 0" +gen_reduction_op "AND" "\&" "BITWISE" "AND_IDENTITY" +gen_reduction_op "OR" "|" "BITWISE" "OR_IDENTITY" +gen_reduction_op "XOR" "^" "BITWISE" "XOR_IDENTITY" +gen_reduction_op "ADD" "+" "" "ADD_IDENTITY" +gen_reduction_op "MUL" "*" "" "MUL_IDENTITY" +gen_reduction_op_func "MIN" "(\$type\$) Math.min" "" "MIN_IDENTITY" +gen_reduction_op_func "MAX" "(\$type\$) Math.max" "" "MAX_IDENTITY" +gen_reduction_op_func "UMIN" "(\$type\$) VectorMath.minUnsigned" "BITWISE" "UMIN_IDENTITY" +gen_reduction_op_func "UMAX" "(\$type\$) VectorMath.maxUnsigned" "BITWISE" "UMAX_IDENTITY" +gen_reduction_op_func "FIRST_NONZERO" "firstNonZero" "" "FIRST_NONZERO_IDENTITY" # Boolean reductions. gen_bool_reduction_op "anyTrue" "|" "BITWISE" "false" gen_bool_reduction_op "allTrue" "\&" "BITWISE" "true" # Saturating reductions. -gen_saturating_reduction_op "SUADD" "(\$type\$) VectorMath.addSaturatingUnsigned" "BITWISE" "0" +gen_saturating_reduction_op "SUADD" "(\$type\$) VectorMath.addSaturatingUnsigned" "BITWISE" "SUADD_IDENTITY" #Insert gen_with_op "withLane" "" "" "" diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op-func.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op-func.template index bf03a4d0430..73e02bf68dd 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op-func.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op-func.template @@ -2,20 +2,15 @@ $type$[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<$Wideboxtype$> vmask = VectorMask.fromArray(SPECIES, mask, 0); - $type$ ra = [[TEST_INIT]]; - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.[[TEST]], vmask); - } - } + $type$ ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { ra = [[TEST_INIT]]; for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra = [[TEST_OP]](ra, av.reduceLanes(VectorOperators.[[TEST]], vmask)); + $type$ v = av.reduceLanes(VectorOperators.[[TEST]], vmask); + r[i] = v; + ra = [[TEST_OP]](ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op.template index f108491523e..82e20d594b6 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op.template @@ -2,20 +2,15 @@ $type$[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<$Wideboxtype$> vmask = VectorMask.fromArray(SPECIES, mask, 0); - $type$ ra = [[TEST_INIT]]; - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.[[TEST]], vmask); - } - } + $type$ ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { ra = [[TEST_INIT]]; for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra [[TEST_OP]]= av.reduceLanes(VectorOperators.[[TEST]], vmask); + $type$ v = av.reduceLanes(VectorOperators.[[TEST]], vmask); + r[i] = v; + ra [[TEST_OP]]= v; } } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op-func.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op-func.template index 7082ff0795e..94fae420cdd 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op-func.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op-func.template @@ -1,19 +1,14 @@ $type$[] a = fa.apply(SPECIES.length()); $type$[] r = fr.apply(SPECIES.length()); - $type$ ra = [[TEST_INIT]]; - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.[[TEST]]); - } - } + $type$ ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { ra = [[TEST_INIT]]; for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra = [[TEST_OP]](ra, av.reduceLanes(VectorOperators.[[TEST]])); + $type$ v = av.reduceLanes(VectorOperators.[[TEST]]); + r[i] = v; + ra = [[TEST_OP]](ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op.template index 66250c09213..3edc2b27e3e 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op.template @@ -1,19 +1,14 @@ $type$[] a = fa.apply(SPECIES.length()); $type$[] r = fr.apply(SPECIES.length()); - $type$ ra = [[TEST_INIT]]; - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.[[TEST]]); - } - } + $type$ ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { ra = [[TEST_INIT]]; for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra [[TEST_OP]]= av.reduceLanes(VectorOperators.[[TEST]]); + $type$ v = av.reduceLanes(VectorOperators.[[TEST]]); + r[i] = v; + ra [[TEST_OP]]= v; } } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingReduction-Masked-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingReduction-Masked-op.template index bf03a4d0430..73e02bf68dd 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingReduction-Masked-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingReduction-Masked-op.template @@ -2,20 +2,15 @@ $type$[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<$Wideboxtype$> vmask = VectorMask.fromArray(SPECIES, mask, 0); - $type$ ra = [[TEST_INIT]]; - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.[[TEST]], vmask); - } - } + $type$ ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { ra = [[TEST_INIT]]; for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra = [[TEST_OP]](ra, av.reduceLanes(VectorOperators.[[TEST]], vmask)); + $type$ v = av.reduceLanes(VectorOperators.[[TEST]], vmask); + r[i] = v; + ra = [[TEST_OP]](ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingReduction-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingReduction-op.template index 7082ff0795e..94fae420cdd 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingReduction-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingReduction-op.template @@ -1,19 +1,14 @@ $type$[] a = fa.apply(SPECIES.length()); $type$[] r = fr.apply(SPECIES.length()); - $type$ ra = [[TEST_INIT]]; - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.[[TEST]]); - } - } + $type$ ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { ra = [[TEST_INIT]]; for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra = [[TEST_OP]](ra, av.reduceLanes(VectorOperators.[[TEST]])); + $type$ v = av.reduceLanes(VectorOperators.[[TEST]]); + r[i] = v; + ra = [[TEST_OP]](ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op-func.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op-func.template index e6bcdb83c2e..c797ad907fb 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op-func.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op-func.template @@ -5,3 +5,26 @@ assertReductionArraysEquals(r, ra, a, $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll); } + + @Test(dataProvider = "$type$UnaryOpProvider") + static void [[TEST]]ReduceIdentityValueTests(IntFunction<$type$[]> fa) { + $type$[] a = fa.apply(SPECIES.length()); + $type$ id = [[TEST_INIT]]; + + Assert.assertEquals([[TEST_OP]](id, id), id, + "[[TEST]]([[TEST_INIT]], [[TEST_INIT]]) != [[TEST_INIT]]"); + + $type$ x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals([[TEST_OP]](id, x), x); + Assert.assertEquals([[TEST_OP]](x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals([[TEST_OP]](id, x), x, + "[[TEST]]([[TEST_INIT]], " + x + ") != " + x); + Assert.assertEquals([[TEST_OP]](x, id), x, + "[[TEST]](" + x + ", [[TEST_INIT]]) != " + x); + } + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template index 5638940045d..f8438fa58c8 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template @@ -9,3 +9,26 @@ $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll); #end[FP] } + + @Test(dataProvider = "$type$UnaryOpProvider") + static void [[TEST]]ReduceIdentityValueTests(IntFunction<$type$[]> fa) { + $type$[] a = fa.apply(SPECIES.length()); + $type$ id = [[TEST_INIT]]; + + Assert.assertEquals(($type$) (id [[TEST_OP]] id), id, + "[[TEST]]([[TEST_INIT]], [[TEST_INIT]]) != [[TEST_INIT]]"); + + $type$ x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(($type$) (id [[TEST_OP]] x), x); + Assert.assertEquals(($type$) (x [[TEST_OP]] id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(($type$) (id [[TEST_OP]] x), x, + "[[TEST]]([[TEST_INIT]], " + x + ") != " + x); + Assert.assertEquals(($type$) (x [[TEST_OP]] id), x, + "[[TEST]](" + x + ", [[TEST_INIT]]) != " + x); + } + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-SaturatingReduction-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-SaturatingReduction-op.template index fdd9e47167e..d961a29e5c8 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-SaturatingReduction-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-SaturatingReduction-op.template @@ -5,3 +5,26 @@ assertReductionArraysEquals(r, ra, a, $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll); } + + @Test(dataProvider = "$type$SaturatingUnaryOpProvider") + static void [[TEST]]ReduceIdentityValueTests(IntFunction<$type$[]> fa) { + $type$[] a = fa.apply(SPECIES.length()); + $type$ id = [[TEST_INIT]]; + + Assert.assertEquals([[TEST_OP]](id, id), id, + "[[TEST]]([[TEST_INIT]], [[TEST_INIT]]) != [[TEST_INIT]]"); + + $type$ x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals([[TEST_OP]](id, x), x); + Assert.assertEquals([[TEST_OP]](x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals([[TEST_OP]](id, x), x, + "[[TEST]]([[TEST_INIT]], " + x + ") != " + x); + Assert.assertEquals([[TEST_OP]](x, id), x, + "[[TEST]](" + x + ", [[TEST_INIT]]) != " + x); + } + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-header.template b/test/jdk/jdk/incubator/vector/templates/Unit-header.template index 7e00cb1678c..e1ec6624022 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-header.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-header.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -86,19 +86,37 @@ public class $vectorteststype$ extends AbstractVectorTest { #end[MaxBit] static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - #if[MaxBit] + static VectorShape getMaxBit() { return VectorShape.S_Max_BIT; } private static final int Max = 256; // juts so we can do N/$bits$ #end[MaxBit] - #if[BITWISE] + private static final $type$ CONST_SHIFT = $Boxtype$.SIZE / 2; #end[BITWISE] + + // Identity values for reduction operations + private static final $type$ ADD_IDENTITY = ($type$)0; +#if[BITWISE] + private static final $type$ AND_IDENTITY = ($type$)-1; +#end[BITWISE] + private static final $type$ FIRST_NONZERO_IDENTITY = ($type$)0; + private static final $type$ MAX_IDENTITY = $Wideboxtype$.$MinValue$; + private static final $type$ MIN_IDENTITY = $Wideboxtype$.$MaxValue$; + private static final $type$ MUL_IDENTITY = ($type$)1; +#if[BITWISE] + private static final $type$ OR_IDENTITY = ($type$)0; + private static final $type$ SUADD_IDENTITY = ($type$)0; + private static final $type$ UMAX_IDENTITY = ($type$)0; // Minimum unsigned value + private static final $type$ UMIN_IDENTITY = ($type$)-1; // Maximum unsigned value + private static final $type$ XOR_IDENTITY = ($type$)0; +#end[BITWISE] #if[FP] + // for floating point addition reduction ops that may introduce rounding errors private static final $type$ RELATIVE_ROUNDING_ERROR_FACTOR_ADD = ($type$)10.0; From 624d7144f757c39215ae3dfed1b78cdd3b3e4f8e Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Wed, 14 Jan 2026 07:09:38 +0000 Subject: [PATCH 028/328] 8374435: assert(addp->is_AddP()) failed: must be AddP during EA with -XX:-UseCompressedOops Reviewed-by: chagedorn, thartmann --- src/hotspot/share/opto/escape.cpp | 35 ++++++++++- .../TestSplitLoadThroughPhiDuringEA.java | 58 +++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/compiler/escapeAnalysis/TestSplitLoadThroughPhiDuringEA.java diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 7b5c3855a9e..792384b1ec1 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, 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 @@ -1058,6 +1058,39 @@ void ConnectionGraph::updates_after_load_split(Node* data_phi, Node* previous_lo // "new_load" might actually be a constant, parameter, etc. if (new_load->is_Load()) { Node* new_addp = new_load->in(MemNode::Address); + + // If new_load is a Load but not from an AddP, it means that the load is folded into another + // load. And since this load is not from a field, we cannot create a unique type for it. + // For example: + // + // if (b) { + // Holder h1 = new Holder(); + // Object o = ...; + // h.o = o.getClass(); + // } else { + // Holder h2 = ...; + // } + // Holder h = Phi(h1, h2); + // Object r = h.o; + // + // Then, splitting r through the merge point results in: + // + // if (b) { + // Holder h1 = new Holder(); + // Object o = ...; + // h.o = o.getClass(); + // Object o1 = h.o; + // } else { + // Holder h2 = ...; + // Object o2 = h2.o; + // } + // Object r = Phi(o1, o2); + // + // In this case, o1 is folded to o.getClass() which is a Load but not from an AddP, but from + // an OopHandle that is loaded from the Klass of o. + if (!new_addp->is_AddP()) { + continue; + } Node* base = get_addp_base(new_addp); // The base might not be something that we can create an unique diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestSplitLoadThroughPhiDuringEA.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestSplitLoadThroughPhiDuringEA.java new file mode 100644 index 00000000000..1221c1b8064 --- /dev/null +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestSplitLoadThroughPhiDuringEA.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2026, 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.escapeAnalysis; + +import java.util.Objects; + +/* + * @test + * @bug 8374435 + * @summary assert during escape analysis when splitting a Load through a Phi because the input of + * the result Phi is a Load not from an AddP + * @run main/othervm -XX:-UseOnStackReplacement -XX:-UseCompressedOops ${test.main.class} + */ +public class TestSplitLoadThroughPhiDuringEA { + static class Holder { + Object o; + } + + public static void main(String[] args) { + Object o = new Object(); + Holder h = new Holder(); + for (int i = 0; i < 20000; i++) { + test(true, h, o); + test(false, h, o); + } + } + + private static Object test(boolean b, Holder h, Object o) { + h = Objects.requireNonNull(h); + if (b) { + h = new Holder(); + // This access has the pattern LoadP -> LoadP, which upsets the compiler because the + // pointer input of a LoadP is not an AddP + h.o = o.getClass(); + } + return h.o; + } +} From 1b6c2bdd7b57891ed35e3c067871d2c0bf282824 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 14 Jan 2026 07:21:25 +0000 Subject: [PATCH 029/328] 8375055: C2: Better dead loop detection printout Reviewed-by: chagedorn, qamai --- src/hotspot/share/opto/phaseX.cpp | 46 +++++++++++++++++++------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 1e4cd42e09a..c4bdc5e8903 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -762,26 +762,36 @@ bool PhaseGVN::is_dominator_helper(Node *d, Node *n, bool linear_only) { //------------------------------dead_loop_check-------------------------------- // Check for a simple dead loop when a data node references itself directly // or through an other data node excluding cons and phis. -void PhaseGVN::dead_loop_check( Node *n ) { - // Phi may reference itself in a loop - if (n != nullptr && !n->is_dead_loop_safe() && !n->is_CFG()) { - // Do 2 levels check and only data inputs. - bool no_dead_loop = true; - uint cnt = n->req(); - for (uint i = 1; i < cnt && no_dead_loop; i++) { - Node *in = n->in(i); - if (in == n) { - no_dead_loop = false; - } else if (in != nullptr && !in->is_dead_loop_safe()) { - uint icnt = in->req(); - for (uint j = 1; j < icnt && no_dead_loop; j++) { - if (in->in(j) == n || in->in(j) == in) - no_dead_loop = false; - } +void PhaseGVN::dead_loop_check(Node* n) { + // Phi may reference itself in a loop. + if (n == nullptr || n->is_dead_loop_safe() || n->is_CFG()) { + return; + } + + // Do 2 levels check and only data inputs. + for (uint i = 1; i < n->req(); i++) { + Node* in = n->in(i); + if (in == n) { + n->dump_bfs(100, nullptr, ""); + fatal("Dead loop detected, node references itself: %s (%d)", + n->Name(), n->_idx); + } + + if (in == nullptr || in->is_dead_loop_safe()) { + continue; + } + for (uint j = 1; j < in->req(); j++) { + if (in->in(j) == n) { + n->dump_bfs(100, nullptr, ""); + fatal("Dead loop detected, node input references current node: %s (%d) -> %s (%d)", + in->Name(), in->_idx, n->Name(), n->_idx); + } + if (in->in(j) == in) { + n->dump_bfs(100, nullptr, ""); + fatal("Dead loop detected, node input references itself: %s (%d)", + in->Name(), in->_idx); } } - if (!no_dead_loop) { n->dump_bfs(100, nullptr, ""); } - assert(no_dead_loop, "dead loop detected"); } } From 703665c13f754f3ba7858c4bb2549c76cbc22a62 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 14 Jan 2026 13:46:40 +0000 Subject: [PATCH 030/328] 8356684: jpackage error messages are not helpful Reviewed-by: almatvee --- .../jdk/jpackage/internal/Executor.java | 16 +- .../jdk/jpackage/internal/cli/Main.java | 64 +++++-- .../jpackage/internal/cli/StandardOption.java | 3 + .../jdk/jpackage/internal/cli/Utils.java | 4 +- ...xecutableAttributesWithCapturedOutput.java | 53 ++++++ .../internal/model/JPackageException.java | 3 +- .../model/SelfContainedException.java | 42 ++++ .../resources/MainResources.properties | 5 + .../internal/util/CommandOutputControl.java | 83 ++++++-- .../helpers/jdk/jpackage/test/Executor.java | 15 +- .../test/mock/CommandActionSpecs.java | 7 + .../jdk/jpackage/internal/cli/MainTest.java | 180 +++++++++++++++++- .../util/CommandOutputControlTest.java | 39 +++- 13 files changed, 440 insertions(+), 74 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ExecutableAttributesWithCapturedOutput.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/SelfContainedException.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Executor.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Executor.java index ca7a630b6d1..53c587ab37c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Executor.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Executor.java @@ -41,6 +41,7 @@ import java.util.concurrent.TimeUnit; import java.util.function.UnaryOperator; import java.util.spi.ToolProvider; import java.util.stream.Stream; +import jdk.jpackage.internal.model.ExecutableAttributesWithCapturedOutput; import jdk.jpackage.internal.util.CommandLineFormat; import jdk.jpackage.internal.util.CommandOutputControl; import jdk.jpackage.internal.util.CommandOutputControl.ProcessAttributes; @@ -211,17 +212,11 @@ final class Executor { throw new IllegalStateException("No target to execute"); } - PrintableOutputBuilder printableOutputBuilder; - if (dumpOutput()) { - printableOutputBuilder = new PrintableOutputBuilder(coc); - } else { - printableOutputBuilder = null; - } - if (dumpOutput()) { Log.verbose(String.format("Running %s", CommandLineFormat.DEFAULT.apply(List.of(commandLine().getFirst())))); } + var printableOutputBuilder = new PrintableOutputBuilder(coc); Result result; try { if (timeout == null) { @@ -233,11 +228,12 @@ final class Executor { throw ExceptionBox.toUnchecked(ex); } + var printableOutput = printableOutputBuilder.create(); if (dumpOutput()) { - log(result, printableOutputBuilder.create()); + log(result, printableOutput); } - return result; + return ExecutableAttributesWithCapturedOutput.augmentResultWithOutput(result, printableOutput); } Result executeExpectSuccess() throws IOException { @@ -309,7 +305,7 @@ final class Executor { pid.ifPresent(p -> { sb.append(" [PID: ").append(p).append("]"); }); - sb.append(":\n ").append(result.execAttrs()); + sb.append(":\n ").append(result.execAttrs().printableCommandLine()); Log.verbose(sb.toString()); if (!printableOutput.isEmpty()) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java index 270ba0c927f..562a0d2d3c1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java @@ -29,10 +29,12 @@ import static jdk.jpackage.internal.cli.StandardOption.HELP; import static jdk.jpackage.internal.cli.StandardOption.VERBOSE; import static jdk.jpackage.internal.cli.StandardOption.VERSION; +import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; +import java.io.StringReader; import java.io.UncheckedIOException; import java.nio.file.NoSuchFileException; import java.util.Collection; @@ -48,7 +50,11 @@ import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.Globals; import jdk.jpackage.internal.Log; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.ExecutableAttributesWithCapturedOutput; import jdk.jpackage.internal.model.JPackageException; +import jdk.jpackage.internal.model.SelfContainedException; +import jdk.jpackage.internal.util.CommandOutputControl.UnexpectedExitCodeException; +import jdk.jpackage.internal.util.CommandOutputControl.UnexpectedResultException; import jdk.jpackage.internal.util.Slot; import jdk.jpackage.internal.util.function.ExceptionBox; @@ -239,44 +245,60 @@ public final class Main { reportError(ex.getCause()); } else if (t instanceof UncheckedIOException ex) { reportError(ex.getCause()); + } else if (t instanceof UnexpectedResultException ex) { + printExternalCommandError(ex); } else { printError(t, Optional.empty()); } } - private void printError(Throwable t, Optional advice) { - var isAlienException = isAlienExceptionType(t); + private void printExternalCommandError(UnexpectedResultException ex) { + var result = ex.getResult(); + var commandOutput = ((ExecutableAttributesWithCapturedOutput)result.execAttrs()).printableOutput(); + var printableCommandLine = result.execAttrs().printableCommandLine(); - if (isAlienException || verbose) { + if (verbose) { + stackTracePrinter.accept(ex); + } + + String msg; + if (ex instanceof UnexpectedExitCodeException) { + msg = I18N.format("error.command-failed-unexpected-exit-code", result.getExitCode(), printableCommandLine); + } else if (result.exitCode().isPresent()) { + msg = I18N.format("error.command-failed-unexpected-output", printableCommandLine); + } else { + msg = I18N.format("error.command-failed-timed-out", printableCommandLine); + } + + messagePrinter.accept(I18N.format("message.error-header", msg)); + if (!verbose) { + messagePrinter.accept(I18N.format("message.failed-command-output-header")); + try (var lines = new BufferedReader(new StringReader(commandOutput)).lines()) { + lines.forEach(messagePrinter); + } + } + } + + private void printError(Throwable t, Optional advice) { + var isSelfContained = isSelfContained(t); + + if (!isSelfContained || verbose) { stackTracePrinter.accept(t); } String msg; - if (isAlienException) { - msg = t.toString(); - } else { + if (isSelfContained) { msg = t.getMessage(); + } else { + msg = t.toString(); } messagePrinter.accept(I18N.format("message.error-header", msg)); advice.ifPresent(v -> messagePrinter.accept(I18N.format("message.advice-header", v))); } - private static boolean isAlienExceptionType(Throwable t) { - switch (t) { - case JPackageException _ -> { - return false; - } - case Utils.ParseException _ -> { - return false; - } - case StandardOption.AddLauncherIllegalArgumentException _ -> { - return false; - } - default -> { - return true; - } - } + private static boolean isSelfContained(Throwable t) { + return t.getClass().getAnnotation(SelfContainedException.class) != null; } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java index 9c828705a4d..fadd9bacb1c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java @@ -61,6 +61,8 @@ import jdk.jpackage.internal.model.BundlingOperationDescriptor; import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.LauncherShortcut; import jdk.jpackage.internal.model.LauncherShortcutStartupDirectory; +import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.SelfContainedException; import jdk.jpackage.internal.util.SetBuilder; /** @@ -701,6 +703,7 @@ public final class StandardOption { } + @SelfContainedException static class AddLauncherIllegalArgumentException extends IllegalArgumentException { AddLauncherIllegalArgumentException(String message) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Utils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Utils.java index 0565a8f1235..a94de355284 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Utils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import java.util.function.IntPredicate; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.model.BundlingEnvironment; +import jdk.jpackage.internal.model.SelfContainedException; final class Utils { @@ -98,6 +99,7 @@ final class Utils { }); } + @SelfContainedException static final class ParseException extends RuntimeException { ParseException(String msg) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ExecutableAttributesWithCapturedOutput.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ExecutableAttributesWithCapturedOutput.java new file mode 100644 index 00000000000..faed9d24d01 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ExecutableAttributesWithCapturedOutput.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.model; + +import java.util.List; +import java.util.Objects; +import jdk.jpackage.internal.util.CommandOutputControl.ExecutableAttributes; +import jdk.jpackage.internal.util.CommandOutputControl.Result; + +/** + * {@link ExecutableAttributes} augmented with printable command output. + */ +public record ExecutableAttributesWithCapturedOutput(ExecutableAttributes execAttrs, String printableOutput) + implements ExecutableAttributes { + + public ExecutableAttributesWithCapturedOutput { + Objects.requireNonNull(execAttrs); + Objects.requireNonNull(printableOutput); + } + + @Override + public List commandLine() { + return execAttrs.commandLine(); + } + + public static Result augmentResultWithOutput(Result result, String output) { + var execAttrs = new ExecutableAttributesWithCapturedOutput(result.execAttrs(), output); + return result.copyWithExecutableAttributes(execAttrs); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/JPackageException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/JPackageException.java index 9727f21d2d7..3d24d293f18 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/JPackageException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/JPackageException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.util.Objects; /** * Generic jpackage exception with non-null message. */ +@SelfContainedException public class JPackageException extends RuntimeException { public JPackageException(String msg) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/SelfContainedException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/SelfContainedException.java new file mode 100644 index 00000000000..c7d1b3016ac --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/SelfContainedException.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.model; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for exceptions with self-contained error messages that don't + * require an additional context, like exception class name or a stack trace. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +public @interface SelfContainedException { +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index 588a3702839..07460a18fe8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -55,6 +55,11 @@ message.module-version=Using version "{0}" from module "{1}" as application vers message.error-header=Error: {0} message.advice-header=Advice to fix: {0} +message.failed-command-output-header=Command output: + +error.command-failed-unexpected-output=Unexpected output from executing the command {0} +error.command-failed-unexpected-exit-code=Unexpected exit code {0} from executing the command {1} +error.command-failed-timed-out=Timed-out command {0} error.version-string-empty=Version may not be empty string error.version-string-zero-length-component=Version [{0}] contains a zero length component diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CommandOutputControl.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CommandOutputControl.java index e35439815b1..00fbdd71919 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CommandOutputControl.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CommandOutputControl.java @@ -796,6 +796,10 @@ public final class CommandOutputControl { public interface ExecutableAttributes { List commandLine(); + + default String printableCommandLine() { + return CommandLineFormat.DEFAULT.apply(commandLine()); + } } public sealed interface Executable { @@ -812,11 +816,6 @@ public final class CommandOutputControl { Objects.requireNonNull(pid); commandLine.forEach(Objects::requireNonNull); } - - @Override - public String toString() { - return CommandLineFormat.DEFAULT.apply(commandLine()); - } } public record ToolProviderAttributes(String name, List args) implements ExecutableAttributes { @@ -825,11 +824,6 @@ public final class CommandOutputControl { args.forEach(Objects::requireNonNull); } - @Override - public String toString() { - return CommandLineFormat.DEFAULT.apply(commandLine()); - } - @Override public List commandLine() { return Stream.concat(Stream.of(name), args.stream()).toList(); @@ -837,14 +831,9 @@ public final class CommandOutputControl { } public static ExecutableAttributes EMPTY_EXECUTABLE_ATTRIBUTES = new ExecutableAttributes() { - @Override - public String toString() { - return ""; - } - @Override public List commandLine() { - return List.of(); + return List.of(""); } }; @@ -869,6 +858,51 @@ public final class CommandOutputControl { Objects.requireNonNull(execAttrs); } + public static Builder build() { + return new Builder(); + } + + public static final class Builder { + + public Result create() { + return new Result( + exitCode, + Optional.ofNullable(content).map(List::copyOf).map(StringListContent::new).map(c -> { + return new CommandOutput>(Optional.of(c), c.size(), true); + }), + Optional.empty(), + Optional.ofNullable(execAttrs).orElse(EMPTY_EXECUTABLE_ATTRIBUTES)); + } + + public Builder exitCode(int v) { + exitCode = Optional.of(v); + return this; + } + + public Builder noExitCode() { + exitCode = Optional.empty(); + return this; + } + + public Builder execAttrs(ExecutableAttributes v) { + execAttrs = v; + return this; + } + + public Builder content(List v) { + content = v; + return this; + } + + public Builder content(String... v) { + return content(List.of(v)); + } + + private ExecutableAttributes execAttrs; + private List content; + private Optional exitCode = Optional.empty(); + } + public Result(int exitCode) { this(Optional.of(exitCode), Optional.empty(), Optional.empty(), EMPTY_EXECUTABLE_ATTRIBUTES); } @@ -1019,7 +1053,8 @@ public final class CommandOutputControl { } private UnexpectedResultException(Result value) { - this(value, String.format("Unexpected result from executing the command %s", value.execAttrs())); + this(value, String.format("Unexpected result from executing the command %s", + value.execAttrs().printableCommandLine())); } public Result getResult() { @@ -1034,11 +1069,21 @@ public final class CommandOutputControl { public static final class UnexpectedExitCodeException extends UnexpectedResultException { public UnexpectedExitCodeException(Result value, String message) { - super(value, message); + super(requireExitCode(value), message); } public UnexpectedExitCodeException(Result value) { - this(value, String.format("Unexpected exit code %d from executing the command %s", value.getExitCode(), value.execAttrs())); + this(value, String.format("Unexpected exit code %d from executing the command %s", + requireExitCode(value).getExitCode(), value.execAttrs().printableCommandLine())); + } + + private static Result requireExitCode(Result v) { + Objects.requireNonNull(v); + if (v.exitCode().isPresent()) { + return v; + } else { + throw new IllegalArgumentException(); + } } private static final long serialVersionUID = 1L; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java index d4833eb9736..b508d4f5ffe 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -283,11 +283,11 @@ public final class Executor extends CommandArguments { long expectedExitCode = expectedExitCodes.getFirst(); TKit.assertEquals(expectedExitCode, getExitCode(), String.format( "Check command %s exited with %d code", - base.execAttrs(), expectedExitCode)); + base.execAttrs().printableCommandLine(), expectedExitCode)); } default -> { TKit.assertTrue(expectedExitCodes.contains(getExitCode()), String.format( "Check command %s exited with one of %s codes", - base.execAttrs(), expectedExitCodes.stream().sorted().toList())); + base.execAttrs().printableCommandLine(), expectedExitCodes.stream().sorted().toList())); } } return this; @@ -302,7 +302,7 @@ public final class Executor extends CommandArguments { } public String getPrintableCommandLine() { - return base.execAttrs().toString(); + return base.execAttrs().printableCommandLine(); } } @@ -515,21 +515,16 @@ public final class Executor extends CommandArguments { return String.format(format, CommandLineFormat.DEFAULT.apply(cmdline), cmdline.size()); } - private record ExecutableAttributes(CommandOutputControl.ExecutableAttributes base, String toStringValue) + private record ExecutableAttributes(CommandOutputControl.ExecutableAttributes base, String printableCommandLine) implements CommandOutputControl.ExecutableAttributes { ExecutableAttributes { Objects.requireNonNull(base); - if (toStringValue.isBlank()) { + if (printableCommandLine.isBlank()) { throw new IllegalArgumentException(); } } - @Override - public String toString() { - return toStringValue; - } - @Override public List commandLine() { return base.commandLine(); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/CommandActionSpecs.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/CommandActionSpecs.java index e89e458c02d..ce3aa6f80e1 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/CommandActionSpecs.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/CommandActionSpecs.java @@ -115,6 +115,13 @@ public record CommandActionSpecs(List specs) { return printToStderr(List.of(str)); } + public Builder argsListener(Consumer> listener) { + Objects.requireNonNull(listener); + return action(CommandActionSpec.create("args-listener", context -> { + listener.accept(context.args()); + })); + } + public Builder exit(int exitCode) { return action(CommandActionSpec.create(String.format("exit(%d)", exitCode), () -> { return exitCode; diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java index 365a8a50b33..79648260274 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ */ package jdk.jpackage.internal.cli; +import static jdk.jpackage.internal.model.ExecutableAttributesWithCapturedOutput.augmentResultWithOutput; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -43,19 +44,31 @@ import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.UnaryOperator; +import java.util.spi.ToolProvider; import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.Globals; +import jdk.jpackage.internal.MockUtils; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.ExecutableAttributesWithCapturedOutput; import jdk.jpackage.internal.model.JPackageException; +import jdk.jpackage.internal.util.CommandOutputControl; +import jdk.jpackage.internal.util.CommandOutputControl.UnexpectedExitCodeException; +import jdk.jpackage.internal.util.CommandOutputControl.UnexpectedResultException; import jdk.jpackage.internal.util.function.ExceptionBox; +import jdk.jpackage.test.Annotations; +import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JUnitAdapter; import jdk.jpackage.test.TKit; +import jdk.jpackage.test.mock.CommandActionSpecs; +import jdk.jpackage.test.mock.Script; +import jdk.jpackage.test.mock.VerbatimCommandMock; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; -public class MainTest extends JUnitAdapter.TestSrcInitializer { +public class MainTest extends JUnitAdapter { @ParameterizedTest @MethodSource @@ -78,6 +91,71 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { assertNotEquals(str, msg); } + /** + * Run app image packaging and simulate jlink failure. + *

+ * The test verifies that jpackage prints an error message with jlink exit code, + * command line, and output. + */ + @Annotations.Test + public void testFailedCommandOutput() { + + var jlinkMockExitCode = 17; + + var jlinkArgs = new ArrayList(); + + var jlinkMock = CommandActionSpecs.build() + .stdout("It").stderr("fell").stdout("apart") + .argsListener(jlinkArgs::addAll) + .exit(jlinkMockExitCode).create().toCommandMockBuilder().name("jlink-mock").create(); + + var script = Script.build() + // Replace jlink with the mock. + .map(Script.cmdlineStartsWith("jlink"), jlinkMock) + // Don't mock other external commands. + .map(_ -> true, VerbatimCommandMock.INSTANCE) + .createLoop(); + + var jpackageExitCode = 1; + + var jpackageToolProviderMock = new ToolProvider() { + @Override + public int run(PrintWriter out, PrintWriter err, String... args) { + var globalsMutator = MockUtils.buildJPackage().script(script).createGlobalsMutator(); + return Globals.main(() -> { + globalsMutator.accept(Globals.instance()); + + var result = ExecutionResult.create(args); + + var jlinkMockAttrs = new CommandOutputControl.ToolProviderAttributes(jlinkMock.name(), jlinkArgs); + + result.stdout().forEach(out::println); + result.stderr().forEach(err::println); + + assertEquals(jpackageExitCode, result.exitCode()); + assertEquals(List.of(), result.stdout()); + assertEquals(List.of( + I18N.format("message.error-header", I18N.format("error.command-failed-unexpected-exit-code", + jlinkMockExitCode, jlinkMockAttrs.printableCommandLine())), + I18N.format("message.failed-command-output-header"), + "It", "fell", "apart"), result.stderr()); + + return jpackageExitCode; + }); + } + + @Override + public String name() { + return "jpackage-mock"; + } + }; + + JPackageCommand.helloAppImage() + .ignoreDefaultVerbose(true) + .useToolProvider(jpackageToolProviderMock) + .execute(jpackageExitCode); + } + private static Collection testOutput() { return Stream.of( // Print the tool version @@ -165,6 +243,49 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { data.add(new ErrorReporterTestSpec(cause, expect.getKey(), verbose, expectedOutput)); } } + + var execAttrs = new CommandOutputControl.ProcessAttributes(Optional.of(12345L), List.of("foo", "--bar")); + for (var makeCause : List.>of( + ex -> ex, + ExceptionBox::toUnchecked + )) { + + for (var expect : List.of( + Map.entry( + augmentResultWithOutput( + CommandOutputControl.Result.build().exitCode(135).execAttrs(execAttrs).create(), + "The quick brown fox\njumps over the lazy dog" + ).unexpected("Kaput!"), + ExceptionFormatter.FAILED_COMMAND_UNEXPECTED_OUTPUT_MESSAGE + ), + Map.entry( + new UnexpectedExitCodeException(augmentResultWithOutput( + CommandOutputControl.Result.build().exitCode(135).create(), + "The quick brown fox\njumps" + )), + ExceptionFormatter.FAILED_COMMAND_UNEXPECTED_EXIT_CODE_MESSAGE + ), + Map.entry( + augmentResultWithOutput( + CommandOutputControl.Result.build().create(), + "The quick brown fox\njumps" + ).unexpected("Timed out!"), + ExceptionFormatter.FAILED_COMMAND_TIMEDOUT_MESSAGE + ) + )) { + var cause = makeCause.apply(expect.getKey()); + var expectedOutput = new ArrayList(); + if (verbose) { + expectedOutput.add(ExceptionFormatter.STACK_TRACE); + } + expectedOutput.add(expect.getValue()); + if (!verbose) { + expectedOutput.add(ExceptionFormatter.FAILED_COMMAND_OUTPUT); + } + data.add(new ErrorReporterTestSpec(cause, expect.getKey(), verbose, expectedOutput)); + } + } + } return data; @@ -350,7 +471,24 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { ex.printStackTrace(pw); } return sink.toString(); - }) + }), + FAILED_COMMAND_OUTPUT(ex -> { + var result = failedCommandResult(ex); + var commandOutput = ((ExecutableAttributesWithCapturedOutput)result.execAttrs()).printableOutput(); + + var sink = new StringWriter(); + var pw = new PrintWriter(sink); + + pw.println(I18N.format("message.failed-command-output-header")); + try (var lines = new BufferedReader(new StringReader(commandOutput)).lines()) { + lines.forEach(pw::println); + } + + return sink.toString(); + }), + FAILED_COMMAND_UNEXPECTED_OUTPUT_MESSAGE(errorMessage(CommandFailureType.UNEXPECTED_OUTPUT::getMessage)), + FAILED_COMMAND_UNEXPECTED_EXIT_CODE_MESSAGE(errorMessage(CommandFailureType.UNEXPECTED_EXIT_CODE::getMessage)), + FAILED_COMMAND_TIMEDOUT_MESSAGE(errorMessage(CommandFailureType.TIMEDOUT::getMessage)), ; ExceptionFormatter(Function formatter) { @@ -369,6 +507,42 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { }; } + private static CommandOutputControl.Result failedCommandResult(Exception ex) { + Objects.requireNonNull(ex); + if (ex instanceof UnexpectedResultException urex) { + return urex.getResult(); + } else { + throw new IllegalArgumentException(); + } + } + + private enum CommandFailureType { + UNEXPECTED_OUTPUT, + UNEXPECTED_EXIT_CODE, + TIMEDOUT, + ; + + String getMessage(Exception ex) { + var result = failedCommandResult(ex); + var printableCommandLine = result.execAttrs().printableCommandLine(); + switch (this) { + case TIMEDOUT -> { + return I18N.format("error.command-failed-timed-out", printableCommandLine); + } + case UNEXPECTED_EXIT_CODE -> { + return I18N.format("error.command-failed-unexpected-exit-code", result.getExitCode(), printableCommandLine); + } + case UNEXPECTED_OUTPUT -> { + return I18N.format("error.command-failed-unexpected-output", printableCommandLine); + } + default -> { + // Unreachable + throw ExceptionBox.reachedUnreachable(); + } + } + } + } + private final Function formatter; } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CommandOutputControlTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CommandOutputControlTest.java index f1d8c142eb9..d71cf7c4d41 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CommandOutputControlTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CommandOutputControlTest.java @@ -203,11 +203,11 @@ public class CommandOutputControlTest { exec = coc.createExecutable(new ProcessBuilder("runme", "--foo", "--baz=10")); } - assertEquals("runme --foo --baz=10", exec.attributes().toString()); + assertEquals("runme --foo --baz=10", exec.attributes().printableCommandLine()); } @Test - public void test_Result_no_args_ctor() { + public void test_Result_single_arg_ctor() { var result = new CommandOutputControl.Result(7); assertFalse(result.findContent().isPresent()); assertFalse(result.findStdout().isPresent()); @@ -216,6 +216,18 @@ public class CommandOutputControlTest { assertSame(Objects.requireNonNull(CommandOutputControl.EMPTY_EXECUTABLE_ATTRIBUTES), result.execAttrs()); } + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_Result_unexpected(boolean customMessage) throws IOException { + var result = new CommandOutputControl.Result(7); + + if (customMessage) { + assertEquals("Kaput!", result.unexpected("Kaput!").getMessage()); + } else { + assertEquals("Unexpected result from executing the command ", result.unexpected().getMessage()); + } + } + @Test public void test_Result_expectExitCode() throws IOException { var result = new CommandOutputControl.Result(7); @@ -276,14 +288,9 @@ public class CommandOutputControlTest { var empty = new CommandOutputControl.Result(0); var execAttrs = new CommandOutputControl.ExecutableAttributes() { - @Override - public String toString() { - return "foo"; - } - @Override public List commandLine() { - return List.of(); + return List.of("foo"); } }; @@ -295,6 +302,20 @@ public class CommandOutputControlTest { assertSame(execAttrs, copy.execAttrs()); } + @Test + public void test_UnexpectedExitCodeException_no_exit_code() { + + var resultWithoutExitCode = CommandOutputControl.Result.build().create(); + + assertThrowsExactly(IllegalArgumentException.class, () -> { + new CommandOutputControl.UnexpectedExitCodeException(resultWithoutExitCode); + }); + + assertThrowsExactly(IllegalArgumentException.class, () -> { + new CommandOutputControl.UnexpectedExitCodeException(resultWithoutExitCode, "Kaput!"); + }); + } + @ParameterizedTest @EnumSource(ExecutableType.class) public void test_timeout_expires(ExecutableType mode) throws InterruptedException, IOException { @@ -1781,7 +1802,7 @@ public class CommandOutputControlTest { } } - private final static class InterruptibleToolProvider implements ToolProvider { + private static final class InterruptibleToolProvider implements ToolProvider { InterruptibleToolProvider(ToolProvider impl) { this.impl = impl; From 20bd178b997b8bbf895877774d55d1a9e87c3038 Mon Sep 17 00:00:00 2001 From: Roger Calnan Date: Wed, 14 Jan 2026 14:08:21 +0000 Subject: [PATCH 031/328] 8373836: add anchors to the java options in the java man page Reviewed-by: jwilhelm, iris --- src/java.base/share/man/java.md | 494 ++++++++++++++++---------------- 1 file changed, 247 insertions(+), 247 deletions(-) diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 30661a3f387..4343df663e6 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -1,5 +1,5 @@ --- -# Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1994, 2026, 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 @@ To launch a source-file program: : Specifies the name of the class to be launched. Command-line entries following `classname` are the arguments for the main method. -`-jar` *jarfile* +[`-jar`]{#-jar} *jarfile* : Executes a program encapsulated in a JAR file. The *jarfile* argument is the name of a JAR file with a manifest that contains a line in the form `Main-Class:`*classname* that defines the class with the @@ -70,7 +70,7 @@ To launch a source-file program: is the source of all user classes, and other class path settings are ignored. If you're using JAR files, then see [jar](jar.html). -`-m` or `--module` *module*\[`/`*mainclass*\] +[`-m`]{#-m} or `--module` *module*\[`/`*mainclass*\] : Executes the main class in a module specified by *mainclass* if it is given, or, if it is not given, the value in the *module*. In other words, *mainclass* can be used when it is not specified by the module, or to @@ -370,7 +370,7 @@ the JVM. > **Note:** To specify an argument for a long option, you can use either `--`*name*`=`*value* or `--`*name* *value*. -`-agentlib:`*libname*\[`=`*options*\] +[`-agentlib:`]{#-agentlib}*libname*\[`=`*options*\] : Loads the specified native agent library. After the library name, a comma-separated list of options specific to the library can be used. If the option `-agentlib:foo` is specified, then the JVM attempts to @@ -393,12 +393,12 @@ the JVM. > `-agentlib:jdwp=transport=dt_socket,server=y,address=8000` -`-agentpath:`*pathname*\[`=`*options*\] +[`-agentpath:`]{#-agentpath}*pathname*\[`=`*options*\] : Loads the native agent library specified by the absolute path name. This option is equivalent to `-agentlib` but uses the full path and file name of the library. -`--class-path` *classpath*, `-classpath` *classpath*, or `-cp` *classpath* +[`--class-path`]{#--class-path} *classpath*, `-classpath` *classpath*, or `-cp` *classpath* : Specifies a list of directories, JAR files, and ZIP archives to search for class files. @@ -424,15 +424,15 @@ the JVM. expanded except by querying the environment, such as by calling `System.getenv("CLASSPATH")`. -`--disable-@files` +[`--disable-@files`]{#--disable-@files} : Can be used anywhere on the command line, including in an argument file, to prevent further `@filename` expansion. This option stops expanding `@`-argfiles after the option. -`--enable-preview` +[`--enable-preview`]{#--enable-preview} : Allows classes to depend on [preview features](https://docs.oracle.com/en/java/javase/12/language/index.html#JSLAN-GUID-5A82FE0E-0CA4-4F1F-B075-564874FE2823) of the release. -`--enable-native-access` *module*\[`,`*module*...\] +[`--enable-native-access`]{#--enable-native-access} *module*\[`,`*module*...\] : Native access involves access to code or data outside the Java runtime. This is generally unsafe and, if done incorrectly, might crash the JVM or result in memory corruption. Native access can occur as a result of calling a method that @@ -465,7 +465,7 @@ the JVM. run it with `--illegal-native-access=deny` along with any necessary `--enable-native-access` options. -`--enable-final-field-mutation` *module*\[,*module*...\] +[`--enable-final-field-mutation`]{#--enable-final-field-mutation} *module*\[,*module*...\] : Mutation of final fields is possible with the reflection API of the Java Platform. However, it compromises safety and performance in all programs. This option allows code in the specified modules to mutate final fields by reflection. @@ -498,13 +498,13 @@ the JVM. run it with `--illegal-final-field-mutation=deny` along with any necessary `--enable-final-field-mutation` options. -`--finalization=`*value* +[`--finalization=`]{#--finalization}*value* : Controls whether the JVM performs finalization of objects. Valid values are "enabled" and "disabled". Finalization is enabled by default, so the value "enabled" does nothing. The value "disabled" disables finalization, so that no finalizers are invoked. -`--module-path` *modulepath*... or `-p` *modulepath* +[`--module-path`]{#--module-path} *modulepath*... or `-p` *modulepath* : Specifies where to find application modules with a list of path elements. The elements of a module path can be a file path to a module or a directory containing modules. Each module is either a modular JAR or an @@ -513,7 +513,7 @@ the JVM. On Windows, semicolons (`;`) separate path elements in this list; on other platforms it is a colon (`:`). -`--upgrade-module-path` *modulepath*... +[`--upgrade-module-path`]{#--upgrade-module-path} *modulepath*... : Specifies where to find module replacements of upgradeable modules in the runtime image with a list of path elements. The elements of a module path can be a file path to a module or a directory @@ -523,33 +523,33 @@ the JVM. On Windows, semicolons (`;`) separate path elements in this list; on other platforms it is a colon (`:`). -`--add-modules` *module*\[`,`*module*...\] +[`--add-modules`]{#--add-modules} *module*\[`,`*module*...\] : Specifies the root modules to resolve in addition to the initial module. *module* can also be `ALL-DEFAULT`, `ALL-SYSTEM`, and `ALL-MODULE-PATH`. -`--list-modules` +[`--list-modules`]{#--list-modules} : Lists the observable modules and then exits. -`-d` *module\_name* or `--describe-module` *module\_name* +[`-d`]{#-d} *module\_name* or `--describe-module` *module\_name* : Describes a specified module and then exits. -`--dry-run` +[`--dry-run`]{#--dry-run} : Creates the VM but doesn't execute the main method. This `--dry-run` option might be useful for validating the command-line options such as the module system configuration. -`--validate-modules` +[`--validate-modules`]{#--validate-modules} : Validates all modules and exit. This option is helpful for finding conflicts and other errors with modules on the module path. -`-D`*property*`=`*value* +[`-D`]{#-D}*property*`=`*value* : Sets a system property value. The *property* variable is a string with no spaces that represents the name of the property. The *value* variable is a string that represents the value of the property. If *value* is a string with spaces, then enclose it in quotation marks (for example `-Dfoo="foo bar"`). -`-disableassertions`\[`:`\[*packagename*\]...\|`:`*classname*\] or `-da`\[`:`\[*packagename*\]...\|`:`*classname*\] +[`-disableassertions`]{#-disableassertions}\[`:`\[*packagename*\]...\|`:`*classname*\] or `-da`\[`:`\[*packagename*\]...\|`:`*classname*\] : Disables assertions. By default, assertions are disabled in all packages and classes. With no arguments, `-disableassertions` (`-da`) disables assertions in all packages and classes. With the *packagename* argument @@ -574,10 +574,10 @@ the JVM. > `java -ea:com.wombat.fruitbat... -da:com.wombat.fruitbat.Brickbat MyClass` -`-disablesystemassertions` or `-dsa` +[`-disablesystemassertions`]{#-disablesystemassertions} or `-dsa` : Disables assertions in all system classes. -`-enableassertions`\[`:`\[*packagename*\]...\|`:`*classname*\] or `-ea`\[`:`\[*packagename*\]...\|`:`*classname*\] +[`-enableassertions`]{#-enableassertions}\[`:`\[*packagename*\]...\|`:`*classname*\] or `-ea`\[`:`\[*packagename*\]...\|`:`*classname*\] : Enables assertions. By default, assertions are disabled in all packages and classes. With no arguments, `-enableassertions` (`-ea`) enables assertions in all packages and classes. With the *packagename* argument ending in @@ -604,28 +604,28 @@ the JVM. > `java -ea:com.wombat.fruitbat... -da:com.wombat.fruitbat.Brickbat MyClass` -`-enablesystemassertions` or `-esa` +[`-enablesystemassertions`]{#-enablesystemassertions} or `-esa` : Enables assertions in all system classes. -`-help`, `-h`, or `-?` +[`-help`]{#-help}, `-h`, or `-?` : Prints the help message to the error stream. -`--help` +[`--help`]{#--help} : Prints the help message to the output stream. -`-javaagent:`*jarpath*\[`=`*options*\] +[`-javaagent:`]{#-javaagent_}*jarpath*\[`=`*options*\] : Loads the specified Java programming language agent. See `java.lang.instrument`. -`--show-version` +[`--show-version`]{#--show-version} : Prints the product version to the output stream and continues. -`-showversion` +[`-showversion`]{#-showversion} : Prints the product version to the error stream and continues. -`--show-module-resolution` +[`--show-module-resolution`]{#--show-module-resolution} : Shows module resolution output during startup. -`-splash:`*imagepath* +[`-splash:`]{#-splash_}*imagepath* : Shows the splash screen with the image specified by *imagepath*. HiDPI scaled images are automatically supported and used if available. The unscaled image file name, such as `image.ext`, should always be passed as @@ -639,29 +639,29 @@ the JVM. See the SplashScreen API documentation for more information. -`-verbose:class` +[`-verbose:class`]{#-verbose_class} : Displays information about each loaded class. -`-verbose:gc` +[`-verbose:gc`]{#-verbose_gc} : Displays information about each garbage collection (GC) event. -`-verbose:jni` +[`-verbose:jni`]{#-verbose_jni} : Displays information about the use of native methods and other Java Native Interface (JNI) activity. -`-verbose:module` +[`-verbose:module`]{#-verbose_module} : Displays information about the modules in use. -`--version` +[`--version`]{#--version} : Prints product version to the output stream and exits. -`-version` +[`-version`]{#-version} : Prints product version to the error stream and exits. -`-X` +[`-X`]{#-X} : Prints the help on extra options to the error stream. -`--help-extra` +[`--help-extra`]{#--help-extra} : Prints the help on extra options to the output stream. `@`*argfile* @@ -688,7 +688,7 @@ the JVM. The following `java` options are general purpose options that are specific to the Java HotSpot Virtual Machine. -`-Xbatch` +[`-Xbatch`]{#-Xbatch} : Disables background compilation. By default, the JVM compiles the method as a background task, running the method in interpreter mode until the background compilation is finished. The `-Xbatch` flag disables background @@ -696,14 +696,14 @@ the Java HotSpot Virtual Machine. task until completed. This option is equivalent to `-XX:-BackgroundCompilation`. -`-Xbootclasspath/a:`*directories*\|*zip*\|*JAR-files* +[`-Xbootclasspath/a:`]{#-Xbootclasspath}*directories*\|*zip*\|*JAR-files* : Specifies a list of directories, JAR files, and ZIP archives to append to the end of the default bootstrap class path. On Windows, semicolons (`;`) separate entities in this list; on other platforms it is a colon (`:`). -`-Xcheck:jni` +[`-Xcheck:jni`]{#-Xcheck_jni} : Performs additional checks for Java Native Interface (JNI) functions. The following checks are considered indicative of significant problems @@ -739,22 +739,22 @@ the Java HotSpot Virtual Machine. Expect a performance degradation when this option is used. -`-Xcomp` +[`-Xcomp`]{#-Xcomp} : Testing mode to exercise JIT compilers. This option should not be used in production environments. -`-Xdebug` +[`-Xdebug`]{#-Xdebug} : Does nothing; deprecated for removal in a future release. -`-Xdiag` +[`-Xdiag`]{#-Xdiag} : Shows additional diagnostic messages. -`-Xint` +[`-Xint`]{#-Xint} : Runs the application in interpreted-only mode. Compilation to native code is disabled, and all bytecode is executed by the interpreter. The performance benefits offered by the just-in-time (JIT) compiler aren't present in this mode. -`-Xinternalversion` +[`-Xinternalversion`]{#-Xinternalversion} : Displays more detailed JVM version information than the `-version` option, and then exits. @@ -763,11 +763,11 @@ the Java HotSpot Virtual Machine. logging framework. See [Enable Logging with the JVM Unified Logging Framework]. -`-Xmixed` +[`-Xmixed`]{#-Xmixed} : Executes all bytecode by the interpreter except for hot methods, which are compiled to native code. On by default. Use `-Xint` to switch off. -`-Xmn` *size* +[`-Xmn`]{#-Xmn} *size* : Sets the initial and maximum size (in bytes) of the heap for the young generation (nursery) in the generational collectors. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or @@ -793,7 +793,7 @@ the Java HotSpot Virtual Machine. the heap for the young generation, you can use `-XX:NewSize` to set the initial size and `-XX:MaxNewSize` to set the maximum size. -`-Xms` *size* +[`-Xms`]{#-Xms} *size* : Sets the minimum and the initial size (in bytes) of the heap. This value must be a multiple of 1024 and greater than 1 MB. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or `g` or `G` @@ -815,7 +815,7 @@ the Java HotSpot Virtual Machine. initial heap size. If it appears after `-Xms` on the command line, then the initial heap size gets set to the value specified with `-XX:InitialHeapSize`. -`-Xmx` *size* +[`-Xmx`]{#-Xmx} *size* : Specifies the maximum size (in bytes) of the heap. This value must be a multiple of 1024 and greater than 2 MB. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or `g` or `G` @@ -832,7 +832,7 @@ the Java HotSpot Virtual Machine. The `-Xmx` option is equivalent to `-XX:MaxHeapSize`. -`-Xnoclassgc` +[`-Xnoclassgc`]{#-Xnoclassgc} : Disables garbage collection (GC) of classes. This can save some GC time, which shortens interruptions during the application run. When you specify `-Xnoclassgc` at startup, the class objects in the application are left @@ -840,7 +840,7 @@ the Java HotSpot Virtual Machine. more memory being permanently occupied which, if not used carefully, throws an out-of-memory exception. -`-Xrs` +[`-Xrs`]{#-Xrs} : Reduces the use of operating system signals by the JVM. Shutdown hooks enable the orderly shutdown of a Java application by running user cleanup code (such as closing database connections) at shutdown, even if the JVM @@ -890,7 +890,7 @@ the Java HotSpot Virtual Machine. User code is responsible for causing shutdown hooks to run, for example, by calling `System.exit()` when the JVM is to be terminated. -`-Xshare:`*mode* +[`-Xshare:`]{#-Xshare_}*mode* : Sets the class data sharing (CDS) mode. Possible *mode* arguments for this option include the following: @@ -910,10 +910,10 @@ the Java HotSpot Virtual Machine. `off` : Do not attempt to use shared class data. -`-XshowSettings` +[`-XshowSettings`]{#-XshowSettings} : Shows all settings and then continues. -`-XshowSettings:`*category* +[`-XshowSettings:`]{#-XshowSettings_}*category* : Shows settings and continues. Possible *category* arguments for this option include the following: @@ -942,7 +942,7 @@ the Java HotSpot Virtual Machine. `system` : **Linux only:** Shows host system or container configuration and continues. -`-Xss` *size* +[`-Xss`]{#-Xss} *size* : Sets the thread stack size (in bytes). Append the letter `k` or `K` to indicate KB, `m` or `M` to indicate MB, or `g` or `G` to indicate GB. The actual size may be rounded up to a multiple of the system page size as @@ -970,32 +970,32 @@ the Java HotSpot Virtual Machine. This option is similar to `-XX:ThreadStackSize`. -`--add-reads` *module*`=`*target-module*(`,`*target-module*)\* +[`--add-reads`]{#--add-reads} *module*`=`*target-module*(`,`*target-module*)\* : Updates *module* to read the *target-module*, regardless of the module declaration. *target-module* can be `ALL-UNNAMED` to read all unnamed modules. -`--add-exports` *module*`/`*package*`=`*target-module*(`,`*target-module*)\* +[`--add-exports`]{#--add-exports} *module*`/`*package*`=`*target-module*(`,`*target-module*)\* : Updates *module* to export *package* to *target-module*, regardless of module declaration. *target-module* can be `ALL-UNNAMED` to export to all unnamed modules. -`--add-opens` *module*`/`*package*`=`*target-module*(`,`*target-module*)\* +[`--add-opens`]{#--add-opens} *module*`/`*package*`=`*target-module*(`,`*target-module*)\* : Updates *module* to open *package* to *target-module*, regardless of module declaration. -`--limit-modules` *module*\[`,`*module*...\] +[`--limit-modules`]{#--limit-modules} *module*\[`,`*module*...\] : Specifies the limit of the universe of observable modules. -`--patch-module` *module*`=`*file*(`;`*file*)\* +[`--patch-module`]{#--patch-module} *module*`=`*file*(`;`*file*)\* : Overrides or augments a module with classes and resources in JAR files or directories. -`--source` *version* +[`--source`]{#--source} *version* : Sets the version of the source in source-file mode. -`--sun-misc-unsafe-memory-access=` *value* +[`--sun-misc-unsafe-memory-access=`]{#--sun-misc-unsafe-memory-access} *value* : Allow or deny usage of unsupported API `sun.misc.Unsafe`. *value* is one of: `allow` @@ -1021,20 +1021,20 @@ the Java HotSpot Virtual Machine. The following extra options are macOS specific. -`-XstartOnFirstThread` +[`-XstartOnFirstThread`]{#-XstartOnFirstThread} : Runs the `main()` method on the first (AppKit) thread. -`-Xdock:name=`*application\_name* +[`-Xdock:name=`]{#-Xdock_name}*application\_name* : Overrides the default application name displayed in dock. -`-Xdock:icon=`*path\_to\_icon\_file* +[`-Xdock:icon=`]{#-Xdock_icon}*path\_to\_icon\_file* : Overrides the default icon displayed in dock. ## Advanced Options for Java These `java` options can be used to enable other advanced options. -`-XX:+UnlockDiagnosticVMOptions` +[`-XX:+UnlockDiagnosticVMOptions`]{#-XX__UnlockDiagnosticVMOptions} : Unlocks the options intended for diagnosing the JVM. By default, this option is disabled and diagnostic options aren't available. @@ -1046,7 +1046,7 @@ These `java` options can be used to enable other advanced options. of these options may be removed or their behavior changed without any warning. -`-XX:+UnlockExperimentalVMOptions` +[`-XX:+UnlockExperimentalVMOptions`]{#-XX__UnlockExperimentalVMOptions} : Unlocks the options that provide experimental features in the JVM. By default, this option is disabled and experimental features aren't available. @@ -1054,7 +1054,7 @@ These `java` options can be used to enable other advanced options. These `java` options control the runtime behavior of the Java HotSpot VM. -`-XX:ActiveProcessorCount=`*x* +[`-XX:ActiveProcessorCount=`]{#-XX_ActiveProcessorCount}*x* : Overrides the number of CPUs that the VM will use to calculate the size of thread pools it will use for various operations such as Garbage Collection and ForkJoinPool. @@ -1066,7 +1066,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. `-XX:-UseContainerSupport` for a description of enabling and disabling container support. -`-XX:AllocateHeapAt=`*path* +[`-XX:AllocateHeapAt=`]{#-XX_AllocateHeapAt}*path* : Takes a path to the file system and uses memory mapping to allocate the object heap on the memory device. Using this option enables the HotSpot VM to allocate the Java object heap on an alternative memory device, such as @@ -1084,7 +1084,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. The existing heap related flags (such as `-Xmx` and `-Xms`) and garbage-collection related flags continue to work as before. -`-XX:-CompactStrings` +[`-XX:-CompactStrings`]{#-XX__CompactStrings} : Disables the Compact Strings feature. By default, this option is enabled. When this option is enabled, Java Strings containing only single-byte characters are internally represented and stored as @@ -1107,7 +1107,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. In both of these scenarios, disabling Compact Strings makes sense. -`-XX:ErrorFile=`*filename* +[`-XX:ErrorFile=`]{#-XX_ErrorFile}*filename* : Specifies the path and file name to which error data is written when an irrecoverable error occurs. By default, this file is created in the current working directory and named `hs_err_pid`*pid*`.log` where *pid* is the @@ -1139,7 +1139,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. `TMP` environment variable; if that environment variable isn't defined, then the value of the `TEMP` environment variable is used. -`-XX:+ExtensiveErrorReports` +[`-XX:+ExtensiveErrorReports`]{#-XX__ExtensiveErrorReports} : Enables the reporting of more extensive error information in the `ErrorFile`. This option can be turned on in environments where maximal information is desired - even if the resulting logs may be quite large and/or contain @@ -1147,7 +1147,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. from release to release, and across different platforms. By default this option is disabled. -`-XX:FlightRecorderOptions=`*parameter*`=`*value* (or) `-XX:FlightRecorderOptions:`*parameter*`=`*value* +[`-XX:FlightRecorderOptions=`]{#-XX_FlightRecorderOptions}*parameter*`=`*value* (or) `-XX:FlightRecorderOptions:`*parameter*`=`*value* : Sets the parameters that control the behavior of JFR. Multiple parameters can be specified by separating them with a comma. @@ -1207,7 +1207,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. 4 kilobytes. Overriding this parameter could reduce performance and is not recommended. -`-XX:LargePageSizeInBytes=`*size* +[`-XX:LargePageSizeInBytes=`]{#-XX_LargePageSizeInBytes}*size* : Sets the maximum large page size (in bytes) used by the JVM. The *size* argument must be a valid page size supported by the environment to have any effect. Append the letter `k` or `K` to indicate kilobytes, @@ -1221,7 +1221,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. > `-XX:LargePageSizeInBytes=1g` -`-XX:MaxDirectMemorySize=`*size* +[`-XX:MaxDirectMemorySize=`]{#-XX_MaxDirectMemorySize}*size* : Sets the maximum total size (in bytes) of the `java.nio` package, direct-buffer allocations. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or `g` or `G` to indicate @@ -1237,14 +1237,14 @@ These `java` options control the runtime behavior of the Java HotSpot VM. -XX:MaxDirectMemorySize=1048576 ``` -`-XX:-MaxFDLimit` +[`-XX:-MaxFDLimit`]{#-XX__MaxFDLimit} : Disables the attempt to set the soft limit for the number of open file descriptors to the hard limit. By default, this option is enabled on all platforms, but is ignored on Windows. The only time that you may need to disable this is on macOS, where its use imposes a maximum of 10240, which is lower than the actual system maximum. -`-XX:NativeMemoryTracking=`*mode* +[`-XX:NativeMemoryTracking=`]{#-XX_NativeMemoryTracking}*mode* : Specifies the mode for tracking JVM native memory usage. Possible *mode* arguments for this option include the following: @@ -1261,7 +1261,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. usage by individual `CallSite`, individual virtual memory region and its committed regions. -`-XX:TrimNativeHeapInterval=`*millis* +[`-XX:TrimNativeHeapInterval=`]{#-XX_TrimNativeHeapInterval}*millis* : Interval, in ms, at which the JVM will trim the native heap. Lower values will reclaim memory more eagerly at the cost of higher overhead. A value of 0 (default) disables native heap trimming. @@ -1269,7 +1269,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. This option is only supported on Linux with GNU C Library (glibc). -`-XX:ObjectAlignmentInBytes=`*alignment* +[`-XX:ObjectAlignmentInBytes=`]{#-XX_ObjectAlignmentInBytes}*alignment* : Sets the memory alignment of Java objects (in bytes). By default, the value is set to 8 bytes. The specified value should be a power of 2, and must be within the range of 8 and 256 (inclusive). This option makes it possible to @@ -1283,7 +1283,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. increases. As a result, you may not realize any benefits from using compressed pointers with large Java heap sizes. -`-XX:OnError=`*string* +[`-XX:OnError=`]{#-XX_OnError}*string* : Sets a custom command or a series of semicolon-separated commands to run when an irrecoverable error occurs. If the string contains spaces, then it must be enclosed in quotation marks. @@ -1304,7 +1304,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. > `-XX:OnError="userdump.exe %p"` -`-XX:OnOutOfMemoryError=`*string* +[`-XX:OnOutOfMemoryError=`]{#-XX_OnOutOfMemoryError}*string* : Sets a custom command or a series of semicolon-separated commands to run when an `OutOfMemoryError` exception is first thrown by the JVM. If the string @@ -1316,31 +1316,31 @@ These `java` options control the runtime behavior of the Java HotSpot VM. directly from Java code, nor by the JVM for other types of resource exhaustion (such as native thread creation errors). -`-XX:+PrintCommandLineFlags` +[`-XX:+PrintCommandLineFlags`]{#-XX__PrintCommandLineFlags} : Enables printing of ergonomically selected JVM flags that appeared on the command line. It can be useful to know the ergonomic values set by the JVM, such as the heap space size and the selected garbage collector. By default, this option is disabled and flags aren't printed. -`-XX:+PreserveFramePointer` +[`-XX:+PreserveFramePointer`]{#-XX__PreserveFramePointer} : Selects between using the RBP register as a general purpose register (`-XX:-PreserveFramePointer`) and using the RBP register to hold the frame pointer of the currently executing method (`-XX:+PreserveFramePointer`). If the frame pointer is available, then external profiling tools (for example, Linux perf) can construct more accurate stack traces. -`-XX:+PrintNMTStatistics` +[`-XX:+PrintNMTStatistics`]{#-XX__PrintNMTStatistics} : Enables printing of collected native memory tracking data at JVM exit when native memory tracking is enabled (see `-XX:NativeMemoryTracking`). By default, this option is disabled and native memory tracking data isn't printed. -`-XX:SharedArchiveFile=`*path* +[`-XX:SharedArchiveFile=`]{#-XX_SharedArchiveFile}*path* : Specifies the path and name of the class data sharing (CDS) archive file See [Application Class Data Sharing]. -`-XX:+VerifySharedSpaces` +[`-XX:+VerifySharedSpaces`]{#-XX__VerifySharedSpaces} : If this option is specified, the JVM will load a CDS archive file only if it passes an integrity check based on CRC32 checksums. The purpose of this flag is to check for unintentional damage to CDS archive files in transmission or storage. @@ -1348,10 +1348,10 @@ These `java` options control the runtime behavior of the Java HotSpot VM. ensure that the CDS archive files used by Java applications cannot be modified without proper authorization. -`-XX:SharedArchiveConfigFile=`*shared\_config\_file* +[`-XX:SharedArchiveConfigFile=`]{#-XX_SharedArchiveConfigFile}*shared\_config\_file* : Specifies additional shared data added to the archive file. -`-XX:SharedClassListFile=`*file\_name* +[`-XX:SharedClassListFile=`]{#-XX_SharedClassListFile}*file\_name* : Specifies the text file that contains the names of the classes to store in the class data sharing (CDS) archive. This file contains the full name of one class per line, except slashes (`/`) replace dots (`.`). For example, @@ -1369,7 +1369,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. See [Application Class Data Sharing]. -`-XX:+ShowCodeDetailsInExceptionMessages` +[`-XX:+ShowCodeDetailsInExceptionMessages`]{#-XX__ShowCodeDetailsInExceptionMessages} : Enables printing of improved `NullPointerException` messages. When an application throws a `NullPointerException`, the option enables the JVM to analyze the program's bytecode instructions to determine precisely which reference is `null`, @@ -1378,13 +1378,13 @@ These `java` options control the runtime behavior of the Java HotSpot VM. and will be printed as the exception message along with the method, filename, and line number. By default, this option is enabled. -`-XX:+ShowMessageBoxOnError` +[`-XX:+ShowMessageBoxOnError`]{#-XX__ShowMessageBoxOnError} : Enables the display of a dialog box when the JVM experiences an irrecoverable error. This prevents the JVM from exiting and keeps the process active so that you can attach a debugger to it to investigate the cause of the error. By default, this option is disabled. -`-XX:StartFlightRecording:`*parameter*`=`*value* +[`-XX:StartFlightRecording:`]{#-XX_StartFlightRecording_}*parameter*`=`*value* : Starts a JFR recording for the Java application. This option is equivalent to the `JFR.start` diagnostic command that starts a recording during runtime. `-XX:StartFlightRecording:help` prints available options and @@ -1503,7 +1503,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. To only see warnings and errors from JFR during startup set -Xlog:jfr+startup=warning. -`-XX:ThreadStackSize=`*size* +[`-XX:ThreadStackSize=`]{#-XX_ThreadStackSize}*size* : Sets the Java thread stack size (in kilobytes). Use of a scaling suffix, such as `k`, results in the scaling of the kilobytes value so that `-XX:ThreadStackSize=1k` sets the Java thread stack size to 1024\*1024 @@ -1529,7 +1529,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. This option is similar to `-Xss`. -`-XX:+UseCompactObjectHeaders` +[`-XX:+UseCompactObjectHeaders`]{#-XX__UseCompactObjectHeaders} : Enables compact object headers. By default, this option is disabled. Enabling this option reduces memory footprint in the Java heap by 4 bytes per object (on average) and often improves performance. @@ -1538,7 +1538,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. In a future release it is expected to be enabled by default, and eventually will be the only mode of operation. -`-XX:-UseCompressedOops` +[`-XX:-UseCompressedOops`]{#-XX__UseCompressedOops} : Disables the use of compressed pointers. By default, this option is enabled, and compressed pointers are used. This will automatically limit the maximum ergonomically determined Java heap size to the maximum amount @@ -1553,7 +1553,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. It's possible to use compressed pointers with Java heap sizes greater than 32 GB. See the `-XX:ObjectAlignmentInBytes` option. -`-XX:-UseContainerSupport` +[`-XX:-UseContainerSupport`]{#-XX__UseContainerSupport} : **Linux only:** The VM now provides automatic container detection support, which allows the VM to determine the amount of memory and number of processors that are available to a Java process running in docker containers. It uses this @@ -1568,28 +1568,28 @@ These `java` options control the runtime behavior of the Java HotSpot VM. information. See [Enable Logging with the JVM Unified Logging Framework] for a description of using Unified Logging. -`-XX:+UseLargePages` +[`-XX:+UseLargePages`]{#-XX__UseLargePages} : Enables the use of large page memory. By default, this option is disabled and large page memory isn't used. See [Large Pages]. -`-XX:+UseTransparentHugePages` +[`-XX:+UseTransparentHugePages`]{#-XX__UseTransparentHugePages} : **Linux only:** Enables the use of large pages that can dynamically grow or shrink. This option is disabled by default. You may encounter performance problems with transparent huge pages as the OS moves other pages around to create huge pages; this option is made available for experimentation. -`-XX:+AllowUserSignalHandlers` +[`-XX:+AllowUserSignalHandlers`]{#-XX__AllowUserSignalHandlers} : **Non-Windows:** Enables installation of signal handlers by the application. By default, this option is disabled and the application isn't allowed to install signal handlers. -`-XX:VMOptionsFile=`*filename* +[`-XX:VMOptionsFile=`]{#-XX_VMOptionsFile}*filename* : Allows user to specify VM options in a file, for example, `java -XX:VMOptionsFile=/var/my_vm_options HelloWorld`. -`-XX:UseBranchProtection=`*mode* +[`-XX:UseBranchProtection=`]{#-XX_UseBranchProtection}*mode* : **Linux AArch64 only:** Specifies the branch protection mode. All options other than `none` require the VM to have been built with branch protection @@ -1613,14 +1613,14 @@ These `java` options control the runtime behavior of the Java HotSpot VM. These `java` options control the dynamic just-in-time (JIT) compilation performed by the Java HotSpot VM. -`-XX:AllocateInstancePrefetchLines=`*lines* +[`-XX:AllocateInstancePrefetchLines=`]{#-XX_AllocateInstancePrefetchLines}*lines* : Sets the number of lines to prefetch ahead of the instance allocation pointer. By default, the number of lines to prefetch is set to 1: > `-XX:AllocateInstancePrefetchLines=1` -`-XX:AllocatePrefetchDistance=`*size* +[`-XX:AllocatePrefetchDistance=`]{#-XX_AllocatePrefetchDistance}*size* : Sets the size (in bytes) of the prefetch distance for object allocation. Memory about to be written with the value of new objects is prefetched up to this distance starting from the address of the last allocated object. @@ -1636,7 +1636,7 @@ performed by the Java HotSpot VM. > `-XX:AllocatePrefetchDistance=1024` -`-XX:AllocatePrefetchInstr=`*instruction* +[`-XX:AllocatePrefetchInstr=`]{#-XX_AllocatePrefetchInstr}*instruction* : Sets the prefetch instruction to prefetch ahead of the allocation pointer. Possible values are from 0 to 3. The actual instructions behind the values depend on the platform. By default, the prefetch instruction is set to 0: @@ -1644,7 +1644,7 @@ performed by the Java HotSpot VM. > `-XX:AllocatePrefetchInstr=0` -`-XX:AllocatePrefetchLines=`*lines* +[`-XX:AllocatePrefetchLines=`]{#-XX_AllocatePrefetchLines}*lines* : Sets the number of cache lines to load after the last object allocation by using the prefetch instructions generated in compiled code. The default value is 1 if the last allocated object was an instance, and 3 if it was an @@ -1656,7 +1656,7 @@ performed by the Java HotSpot VM. > `-XX:AllocatePrefetchLines=5` -`-XX:AllocatePrefetchStepSize=`*size* +[`-XX:AllocatePrefetchStepSize=`]{#-XX_AllocatePrefetchStepSize}*size* : Sets the step size (in bytes) for sequential prefetch instructions. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, `g` or `G` to indicate gigabytes. By default, the step size is @@ -1665,7 +1665,7 @@ performed by the Java HotSpot VM. > `-XX:AllocatePrefetchStepSize=16` -`-XX:AllocatePrefetchStyle=`*style* +[`-XX:AllocatePrefetchStyle=`]{#-XX_AllocatePrefetchStyle}*style* : Sets the generated code style for prefetch instructions. The *style* argument is an integer from 0 to 3: @@ -1684,12 +1684,12 @@ performed by the Java HotSpot VM. : Generate one prefetch instruction per cache line. -`-XX:+BackgroundCompilation` +[`-XX:+BackgroundCompilation`]{#-XX__BackgroundCompilation} : Enables background compilation. This option is enabled by default. To disable background compilation, specify `-XX:-BackgroundCompilation` (this is equivalent to specifying `-Xbatch`). -`-XX:CICompilerCount=`*threads* +[`-XX:CICompilerCount=`]{#-XX_CICompilerCount}*threads* : Sets the number of compiler threads to use for compilation. By default, the number of compiler threads is selected automatically depending on the number of CPUs and memory available for compiled code. @@ -1697,11 +1697,11 @@ performed by the Java HotSpot VM. > `-XX:CICompilerCount=2` -`-XX:+UseDynamicNumberOfCompilerThreads` +[`-XX:+UseDynamicNumberOfCompilerThreads`]{#-XX__UseDynamicNumberOfCompilerThreads} : Dynamically create compiler thread up to the limit specified by `-XX:CICompilerCount`. This option is enabled by default. -`-XX:CompileCommand=`*command*`,`*method*\[`,`*option*\] +[`-XX:CompileCommand=`]{#-XX_CompileCommand}*command*`,`*method*\[`,`*option*\] : Specifies a *command* to perform on a *method*. For example, to exclude the `indexOf()` method of the `String` class from being compiled, use the following: @@ -1800,7 +1800,7 @@ performed by the Java HotSpot VM. You can suppress this by specifying the `-XX:CompileCommand=quiet` option before other `-XX:CompileCommand` options. -`-XX:CompileCommandFile=`*filename* +[`-XX:CompileCommandFile=`]{#-XX_CompileCommandFile}*filename* : Sets the file from which JIT compiler commands are read. By default, the `.hotspot_compiler` file is used to store commands performed by the JIT compiler. @@ -1814,7 +1814,7 @@ performed by the Java HotSpot VM. If you're using commands for the JIT compiler to perform on methods, then see the `-XX:CompileCommand` option. -`-XX:CompilerDirectivesFile=`*file* +[`-XX:CompilerDirectivesFile=`]{#-XX_CompilerDirectivesFile}*file* : Adds directives from a file to the directives stack when a program starts. See [Compiler Control](https://docs.oracle.com/en/java/javase/12/vm/compiler-control1.html#GUID-94AD8194-786A-4F19-BFFF-278F8E237F3A). @@ -1822,14 +1822,14 @@ performed by the Java HotSpot VM. `-XX:UnlockDiagnosticVMOptions` option that unlocks diagnostic JVM options. -`-XX:+CompilerDirectivesPrint` +[`-XX:+CompilerDirectivesPrint`]{#-XX__CompilerDirectivesPrint} : Prints the directives stack when the program starts or when a new directive is added. The `-XX:+CompilerDirectivesPrint` option has to be used together with the `-XX:UnlockDiagnosticVMOptions` option that unlocks diagnostic JVM options. -`-XX:CompileOnly=`*methods* +[`-XX:CompileOnly=`]{#-XX_CompileOnly}*methods* : Sets the list of methods (separated by commas) to which compilation should be restricted. Only the specified methods are compiled. @@ -1841,7 +1841,7 @@ performed by the Java HotSpot VM. -XX:CompileCommand=compileonly,methodN ``` -`-XX:CompileThresholdScaling=`*scale* +[`-XX:CompileThresholdScaling=`]{#-XX_CompileThresholdScaling}*scale* : Provides unified control of first compilation. This option controls when methods are first compiled for both the tiered and the nontiered modes of operation. The `CompileThresholdScaling` option has a floating point value @@ -1851,11 +1851,11 @@ performed by the Java HotSpot VM. compilation while values greater than 1.0 delay compilation. Setting `CompileThresholdScaling` to 0 is equivalent to disabling compilation. -`-XX:+DoEscapeAnalysis` +[`-XX:+DoEscapeAnalysis`]{#-XX__DoEscapeAnalysis} : Enables the use of escape analysis. This option is enabled by default. To disable the use of escape analysis, specify `-XX:-DoEscapeAnalysis`. -`-XX:InitialCodeCacheSize=`*size* +[`-XX:InitialCodeCacheSize=`]{#-XX_InitialCodeCacheSize}*size* : Sets the initial code cache size (in bytes). Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or `g` or `G` to indicate gigabytes. The default value depends on the platform. The initial code @@ -1865,11 +1865,11 @@ performed by the Java HotSpot VM. > `-XX:InitialCodeCacheSize=32k` -`-XX:+Inline` +[`-XX:+Inline`]{#-XX__Inline} : Enables method inlining. This option is enabled by default to increase performance. To disable method inlining, specify `-XX:-Inline`. -`-XX:InlineSmallCode=`*size* +[`-XX:InlineSmallCode=`]{#-XX_InlineSmallCode}*size* : Sets the maximum code size (in bytes) for already compiled methods that may be inlined. This flag only applies to the C2 compiler. Append the letter `k` or `K` to indicate kilobytes, @@ -1879,7 +1879,7 @@ performed by the Java HotSpot VM. > `-XX:InlineSmallCode=1000` -`-XX:+LogCompilation` +[`-XX:+LogCompilation`]{#-XX__LogCompilation} : Enables logging of compilation activity to a file named `hotspot.log` in the current working directory. You can specify a different log file path and name using the `-XX:LogFile` option. @@ -1893,7 +1893,7 @@ performed by the Java HotSpot VM. `-XX:+PrintCompilation` option. -`-XX:FreqInlineSize=`*size* +[`-XX:FreqInlineSize=`]{#-XX_FreqInlineSize}*size* : Sets the maximum bytecode size (in bytes) of a hot method to be inlined. This flag only applies to the C2 compiler. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate @@ -1903,7 +1903,7 @@ performed by the Java HotSpot VM. > `-XX:FreqInlineSize=325` -`-XX:MaxInlineSize=`*size* +[`-XX:MaxInlineSize=`]{#-XX_MaxInlineSize}*size* : Sets the maximum bytecode size (in bytes) of a cold method to be inlined. This flag only applies to the C2 compiler. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate @@ -1912,7 +1912,7 @@ performed by the Java HotSpot VM. > `-XX:MaxInlineSize=35` -`-XX:C1MaxInlineSize=`*size* +[`-XX:C1MaxInlineSize=`]{#-XX_C1MaxInlineSize}*size* : Sets the maximum bytecode size (in bytes) of a cold method to be inlined. This flag only applies to the C1 compiler. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate @@ -1921,7 +1921,7 @@ performed by the Java HotSpot VM. > `-XX:MaxInlineSize=35` -`-XX:MaxTrivialSize=`*size* +[`-XX:MaxTrivialSize=`]{#-XX_MaxTrivialSize}*size* : Sets the maximum bytecode size (in bytes) of a trivial method to be inlined. This flag only applies to the C2 compiler. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to @@ -1930,7 +1930,7 @@ performed by the Java HotSpot VM. > `-XX:MaxTrivialSize=6` -`-XX:C1MaxTrivialSize=`*size* +[`-XX:C1MaxTrivialSize=`]{#-XX_C1MaxTrivialSize}*size* : Sets the maximum bytecode size (in bytes) of a trivial method to be inlined. This flag only applies to the C1 compiler. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to @@ -1939,14 +1939,14 @@ performed by the Java HotSpot VM. > `-XX:MaxTrivialSize=6` -`-XX:MaxNodeLimit=`*nodes* +[`-XX:MaxNodeLimit=`]{#-XX_MaxNodeLimit}*nodes* : Sets the maximum number of nodes to be used during single method compilation. By default the value depends on the features enabled. In the following example the maximum number of nodes is set to 100,000: > `-XX:MaxNodeLimit=100000` -`-XX:NonNMethodCodeHeapSize=`*size* +[`-XX:NonNMethodCodeHeapSize=`]{#-XX_NonNMethodCodeHeapSize}*size* : Sets the size in bytes of the code segment containing nonmethod code. A nonmethod code segment containing nonmethod code, such as compiler @@ -1954,16 +1954,16 @@ performed by the Java HotSpot VM. cache forever. This flag is used only if `-XX:SegmentedCodeCache` is enabled. -`-XX:NonProfiledCodeHeapSize=`*size* +[`-XX:NonProfiledCodeHeapSize=`]{#-XX_NonProfiledCodeHeapSize}*size* : Sets the size in bytes of the code segment containing nonprofiled methods. This flag is used only if `-XX:SegmentedCodeCache` is enabled. -`-XX:+OptimizeStringConcat` +[`-XX:+OptimizeStringConcat`]{#-XX__OptimizeStringConcat} : Enables the optimization of `String` concatenation operations. This option is enabled by default. To disable the optimization of `String` concatenation operations, specify `-XX:-OptimizeStringConcat`. -`-XX:+PrintAssembly` +[`-XX:+PrintAssembly`]{#-XX__PrintAssembly} : Enables printing of assembly code for bytecoded and native methods by using the external `hsdis-.so` or `.dll` library. For 64-bit VM on Windows, it's `hsdis-amd64.dll`. This lets you to see the generated code, which may @@ -1973,11 +1973,11 @@ performed by the Java HotSpot VM. `-XX:+PrintAssembly` option has to be used together with the `-XX:UnlockDiagnosticVMOptions` option that unlocks diagnostic JVM options. -`-XX:ProfiledCodeHeapSize=`*size* +[`-XX:ProfiledCodeHeapSize=`]{#-XX_ProfiledCodeHeapSize}*size* : Sets the size in bytes of the code segment containing profiled methods. This flag is used only if `-XX:SegmentedCodeCache` is enabled. -`-XX:+PrintCompilation` +[`-XX:+PrintCompilation`]{#-XX__PrintCompilation} : Enables verbose diagnostic output from the JVM by printing a message to the console every time a method is compiled. This lets you to see which methods actually get compiled. By default, this option is disabled and diagnostic @@ -1986,7 +1986,7 @@ performed by the Java HotSpot VM. You can also log compilation activity to a file by using the `-XX:+LogCompilation` option. -`-XX:+PrintInlining` +[`-XX:+PrintInlining`]{#-XX__PrintInlining} : Enables printing of inlining decisions. This let's you see which methods are getting inlined. @@ -1995,7 +1995,7 @@ performed by the Java HotSpot VM. `-XX:+UnlockDiagnosticVMOptions` option that unlocks diagnostic JVM options. -`-XX:ReservedCodeCacheSize=`*size* +[`-XX:ReservedCodeCacheSize=`]{#-XX_ReservedCodeCacheSize}*size* : Sets the maximum code cache size (in bytes) for JIT-compiled code. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or `g` or `G` to indicate gigabytes. The default maximum code @@ -2005,7 +2005,7 @@ performed by the Java HotSpot VM. size shouldn't be less than the initial code cache size; see the option `-XX:InitialCodeCacheSize`. -`-XX:+SegmentedCodeCache` +[`-XX:+SegmentedCodeCache`]{#-XX__SegmentedCodeCache} : Enables segmentation of the code cache, without which the code cache consists of one large segment. With `-XX:+SegmentedCodeCache`, separate segments will be used for non-method, profiled method, and non-profiled @@ -2018,29 +2018,29 @@ performed by the Java HotSpot VM. (`-XX:+TieredCompilation` ) and the reserved code cache size (`-XX:ReservedCodeCacheSize`) is at least 240 MB. -`-XX:StartAggressiveSweepingAt=`*percent* +[`-XX:StartAggressiveSweepingAt=`]{#-XX_StartAggressiveSweepingAt}*percent* : Forces stack scanning of active methods to aggressively remove unused code when only the given percentage of the code cache is free. The default value is 10%. -`-XX:-TieredCompilation` +[`-XX:-TieredCompilation`]{#-XX__TieredCompilation} : Disables the use of tiered compilation. By default, this option is enabled. -`-XX:UseSSE=`*version* +[`-XX:UseSSE=`]{#-XX_UseSSE}*version* : Enables the use of SSE instruction set of a specified version. Is set by default to the highest supported version available (x86 only). -`-XX:UseAVX=`*version* +[`-XX:UseAVX=`]{#-XX_UseAVX}*version* : Enables the use of AVX instruction set of a specified version. Is set by default to the highest supported version available (x86 only). -`-XX:+UseAES` +[`-XX:+UseAES`]{#-XX__UseAES} : Enables hardware-based AES intrinsics for hardware that supports it. This option is on by default on hardware that has the necessary instructions. The `-XX:+UseAES` is used in conjunction with `UseAESIntrinsics`. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseAESIntrinsics` +[`-XX:+UseAESIntrinsics`]{#-XX__UseAESIntrinsics} : Enables AES intrinsics. Specifying `-XX:+UseAESIntrinsics` is equivalent to also enabling `-XX:+UseAES`. To disable hardware-based AES intrinsics, specify `-XX:-UseAES -XX:-UseAESIntrinsics`. For example, to enable hardware @@ -2051,47 +2051,47 @@ performed by the Java HotSpot VM. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseAESCTRIntrinsics` +[`-XX:+UseAESCTRIntrinsics`]{#-XX__UseAESCTRIntrinsics} : Analogous to `-XX:+UseAESIntrinsics` enables AES/CTR intrinsics. -`-XX:+UseGHASHIntrinsics` +[`-XX:+UseGHASHIntrinsics`]{#-XX__UseGHASHIntrinsics} : Controls the use of GHASH intrinsics. Enabled by default on platforms that support the corresponding instructions. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseChaCha20Intrinsics` +[`-XX:+UseChaCha20Intrinsics`]{#-XX__UseChaCha20Intrinsics} : Enable ChaCha20 intrinsics. This option is on by default for supported platforms. To disable ChaCha20 intrinsics, specify `-XX:-UseChaCha20Intrinsics`. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UsePoly1305Intrinsics` +[`-XX:+UsePoly1305Intrinsics`]{#-XX__UsePoly1305Intrinsics} : Enable Poly1305 intrinsics. This option is on by default for supported platforms. To disable Poly1305 intrinsics, specify `-XX:-UsePoly1305Intrinsics`. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseBASE64Intrinsics` +[`-XX:+UseBASE64Intrinsics`]{#-XX__UseBASE64Intrinsics} : Controls the use of accelerated BASE64 encoding routines for `java.util.Base64`. Enabled by default on platforms that support it. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseAdler32Intrinsics` +[`-XX:+UseAdler32Intrinsics`]{#-XX__UseAdler32Intrinsics} : Controls the use of Adler32 checksum algorithm intrinsic for `java.util.zip.Adler32`. Enabled by default on platforms that support it. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseCRC32Intrinsics` +[`-XX:+UseCRC32Intrinsics`]{#-XX__UseCRC32Intrinsics} : Controls the use of CRC32 intrinsics for `java.util.zip.CRC32`. Enabled by default on platforms that support it. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseCRC32CIntrinsics` +[`-XX:+UseCRC32CIntrinsics`]{#-XX__UseCRC32CIntrinsics} : Controls the use of CRC32C intrinsics for `java.util.zip.CRC32C`. Enabled by default on platforms that support it. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseSHA` +[`-XX:+UseSHA`]{#-XX__UseSHA} : Enables hardware-based intrinsics for SHA crypto hash functions for some hardware. The `UseSHA` option is used in conjunction with the `UseSHA1Intrinsics`, `UseSHA256Intrinsics`, and `UseSHA512Intrinsics` @@ -2108,26 +2108,26 @@ performed by the Java HotSpot VM. disable only a particular SHA intrinsic, use the appropriate corresponding option. For example: `-XX:-UseSHA256Intrinsics`. -`-XX:+UseSHA1Intrinsics` +[`-XX:+UseSHA1Intrinsics`]{#-XX__UseSHA1Intrinsics} : Enables intrinsics for SHA-1 crypto hash function. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseSHA256Intrinsics` +[`-XX:+UseSHA256Intrinsics`]{#-XX__UseSHA256Intrinsics} : Enables intrinsics for SHA-224 and SHA-256 crypto hash functions. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseSHA512Intrinsics` +[`-XX:+UseSHA512Intrinsics`]{#-XX__UseSHA512Intrinsics} : Enables intrinsics for SHA-384 and SHA-512 crypto hash functions. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseMathExactIntrinsics` +[`-XX:+UseMathExactIntrinsics`]{#-XX__UseMathExactIntrinsics} : Enables intrinsification of various `java.lang.Math.*Exact()` functions. Enabled by default. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseMultiplyToLenIntrinsic` +[`-XX:+UseMultiplyToLenIntrinsic`]{#-XX__UseMultiplyToLenIntrinsic} : Enables intrinsification of `BigInteger.multiplyToLen()`. Enabled by default on platforms that support it. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. @@ -2152,44 +2152,44 @@ performed by the Java HotSpot VM. Enabled by default on platforms that support it. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseCMoveUnconditionally` +[`-XX:+UseCMoveUnconditionally`]{#-XX__UseCMoveUnconditionally} : Generates CMove (scalar and vector) instructions regardless of profitability analysis. -`-XX:+UseCodeCacheFlushing` +[`-XX:+UseCodeCacheFlushing`]{#-XX__UseCodeCacheFlushing} : Enables flushing of the code cache before shutting down the compiler. This option is enabled by default. To disable flushing of the code cache before shutting down the compiler, specify `-XX:-UseCodeCacheFlushing`. -`-XX:+UseCondCardMark` +[`-XX:+UseCondCardMark`]{#-XX__UseCondCardMark} : Enables checking if the card is already marked before updating the card table. This option is disabled by default. It should be used only on machines with multiple sockets, where it increases the performance of Java applications that rely on concurrent operations. -`-XX:+UseCountedLoopSafepoints` +[`-XX:+UseCountedLoopSafepoints`]{#-XX__UseCountedLoopSafepoints} : Keeps safepoints in counted loops. Its default value depends on whether the selected garbage collector requires low latency safepoints. -`-XX:LoopStripMiningIter=`*number_of_iterations* +[`-XX:LoopStripMiningIter=`]{#-XX_LoopStripMiningIter}*number_of_iterations* : Controls the number of iterations in the inner strip mined loop. Strip mining transforms counted loops into two level nested loops. Safepoints are kept in the outer loop while the inner loop can execute at full speed. This option controls the maximum number of iterations in the inner loop. The default value is 1,000. -`-XX:LoopStripMiningIterShortLoop=`*number_of_iterations* +[`-XX:LoopStripMiningIterShortLoop=`]{#-XX_LoopStripMiningIterShortLoop}*number_of_iterations* : Controls loop strip mining optimization. Loops with the number of iterations less than specified will not have safepoints in them. Default value is 1/10th of `-XX:LoopStripMiningIter`. -`-XX:+UseFMA` +[`-XX:+UseFMA`]{#-XX__UseFMA} : Enables hardware-based FMA intrinsics for hardware where FMA instructions are available (such as, Intel and ARM64). FMA intrinsics are generated for the `java.lang.Math.fma(`*a*`,` *b*`,` *c*`)` methods that calculate the value of `(` *a* `*` *b* `+` *c* `)` expressions. -`-XX:+UseSuperWord` +[`-XX:+UseSuperWord`]{#-XX__UseSuperWord} : Enables the transformation of scalar operations into superword operations. Superword is a vectorization optimization. This option is enabled by default. To disable the transformation of scalar operations into superword @@ -2200,7 +2200,7 @@ performed by the Java HotSpot VM. These `java` options provide the ability to gather system information and perform extensive debugging. -`-XX:+DisableAttachMechanism` +[`-XX:+DisableAttachMechanism`]{#-XX__DisableAttachMechanism} : Disables the mechanism that lets tools attach to the JVM. By default, this option is disabled, meaning that the attach mechanism is enabled and you can use diagnostics and troubleshooting tools such as `jcmd`, `jstack`, @@ -2211,17 +2211,17 @@ perform extensive debugging. supported when using the tools from one JDK version to troubleshoot a different JDK version. -`-XX:+DTraceAllocProbes` +[`-XX:+DTraceAllocProbes`]{#-XX__DTraceAllocProbes} : **Linux and macOS:** Enable `dtrace` tool probes for object allocation. -`-XX:+DTraceMethodProbes` +[`-XX:+DTraceMethodProbes`]{#-XX__DTraceMethodProbes} : **Linux and macOS:** Enable `dtrace` tool probes for method-entry and method-exit. -`-XX:+DTraceMonitorProbes` +[`-XX:+DTraceMonitorProbes`]{#-XX__DTraceMonitorProbes} : **Linux and macOS:** Enable `dtrace` tool probes for monitor events. -`-XX:+HeapDumpOnOutOfMemoryError` +[`-XX:+HeapDumpOnOutOfMemoryError`]{#-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 by the JVM. You can explicitly set the heap dump file path and @@ -2233,7 +2233,7 @@ perform extensive debugging. directly from Java code, nor by the JVM for other types of resource exhaustion (such as native thread creation errors). -`-XX:HeapDumpPath=`*path* +[`-XX:HeapDumpPath=`]{#-XX_HeapDumpPath}*path* : Sets the path and file name for writing the heap dump provided by the heap profiler (HPROF) when the `-XX:+HeapDumpOnOutOfMemoryError` option is set. By default, the file is created in the current working directory, and it's @@ -2253,7 +2253,7 @@ perform extensive debugging. > `-XX:HeapDumpPath=C:/log/java/java_heapdump.log` -`-XX:LogFile=`*path* +[`-XX:LogFile=`]{#-XX_LogFile}*path* : Sets the path and file name to where log data is written. By default, the file is created in the current working directory, and it's named `hotspot.log`. @@ -2268,7 +2268,7 @@ perform extensive debugging. > `-XX:LogFile=C:/log/java/hotspot.log` -`-XX:+PrintClassHistogram` +[`-XX:+PrintClassHistogram`]{#-XX__PrintClassHistogram} : Enables printing of a class instance histogram after one of the following events: @@ -2282,7 +2282,7 @@ perform extensive debugging. the `jcmd` *pid* `GC.class_histogram` command, where *pid* is the current Java process identifier. -`-XX:+PrintConcurrentLocks` +[`-XX:+PrintConcurrentLocks`]{#-XX__PrintConcurrentLocks} : Enables printing of `java.util.concurrent` locks after one of the following events: @@ -2296,12 +2296,12 @@ perform extensive debugging. `jcmd` *pid* `Thread.print -l` command, where *pid* is the current Java process identifier. -`-XX:+PrintFlagsRanges` +[`-XX:+PrintFlagsRanges`]{#-XX__PrintFlagsRanges} : Prints the range specified and allows automatic testing of the values. See [Validate Java Virtual Machine Flag Arguments]. -`-XX:+PerfDataSaveToFile` +[`-XX:+PerfDataSaveToFile`]{#-XX__PerfDataSaveToFile} : If enabled, saves [jstat](jstat.html) binary data when the Java application exits. This binary data is saved in a file named `hsperfdata_`*pid*, where *pid* is the process identifier of the Java application that you ran. Use @@ -2312,7 +2312,7 @@ perform extensive debugging. > `jstat -gc file:///`*path*`/hsperfdata_`*pid* -`-XX:+UsePerfData` +[`-XX:+UsePerfData`]{#-XX__UsePerfData} : Enables the `perfdata` feature. This option is enabled by default to allow JVM monitoring and performance testing. Disabling it suppresses the creation of the `hsperfdata_userid` directories. To disable the `perfdata` @@ -2323,13 +2323,13 @@ perform extensive debugging. These `java` options control how garbage collection (GC) is performed by the Java HotSpot VM. -`-XX:+AlwaysPreTouch` +[`-XX:+AlwaysPreTouch`]{#-XX__AlwaysPreTouch} : Requests the VM to touch every page on the Java heap after requesting it from the operating system and before handing memory out to the application. By default, this option is disabled and all pages are committed as the application uses the heap space. -`-XX:ConcGCThreads=`*threads* +[`-XX:ConcGCThreads=`]{#-XX_ConcGCThreads}*threads* : Sets the number of threads used for concurrent GC. Sets *`threads`* to approximately 1/4 of the number of parallel garbage collection threads. The default value depends on the number of CPUs available to the JVM. @@ -2339,24 +2339,24 @@ Java HotSpot VM. > `-XX:ConcGCThreads=2` -`-XX:+DisableExplicitGC` +[`-XX:+DisableExplicitGC`]{#-XX__DisableExplicitGC} : Enables the option that disables processing of calls to the `System.gc()` method. This option is disabled by default, meaning that calls to `System.gc()` are processed. If processing of calls to `System.gc()` is disabled, then the JVM still performs GC when necessary. -`-XX:+ExplicitGCInvokesConcurrent` +[`-XX:+ExplicitGCInvokesConcurrent`]{#-XX__ExplicitGCInvokesConcurrent} : Enables invoking of concurrent GC by using the `System.gc()` request. This option is disabled by default and can be enabled only with the `-XX:+UseG1GC` option. -`-XX:G1AdaptiveIHOPNumInitialSamples=`*number* +[`-XX:G1AdaptiveIHOPNumInitialSamples=`]{#-XX_G1AdaptiveIHOPNumInitialSamples}*number* : When `-XX:UseAdaptiveIHOP` is enabled, this option sets the number of completed marking cycles used to gather samples until G1 adaptively determines the optimum value of `-XX:InitiatingHeapOccupancyPercent`. Before, G1 uses the value of `-XX:InitiatingHeapOccupancyPercent` directly for this purpose. The default value is 3. -`-XX:G1HeapRegionSize=`*size* +[`-XX:G1HeapRegionSize=`]{#-XX_G1HeapRegionSize}*size* : Sets the size of the regions into which the Java heap is subdivided when using the garbage-first (G1) collector. The value is a power of 2 and can range from 1 MB to 32 MB. The default region size is determined @@ -2367,44 +2367,44 @@ Java HotSpot VM. > `-XX:G1HeapRegionSize=16m` -`-XX:G1HeapWastePercent=`*percent* +[`-XX:G1HeapWastePercent=`]{#-XX_G1HeapWastePercent}*percent* : Sets the percentage of heap that you're willing to waste. The Java HotSpot VM doesn't initiate the mixed garbage collection cycle when the reclaimable percentage is less than the heap waste percentage. The default is 5 percent. -`-XX:G1MaxNewSizePercent=`*percent* +[`-XX:G1MaxNewSizePercent=`]{#-XX_G1MaxNewSizePercent}*percent* : Sets the percentage of the heap size to use as the maximum for the young generation size. The default value is 60 percent of your Java heap. This is an experimental flag. This setting replaces the `-XX:DefaultMaxNewGenPercent` setting. -`-XX:G1MixedGCCountTarget=`*number* +[`-XX:G1MixedGCCountTarget=`]{#-XX_G1MixedGCCountTarget}*number* : Sets the target number of mixed garbage collections after a marking cycle to collect old regions with at most `G1MixedGCLIveThresholdPercent` live data. The default is 8 mixed garbage collections. The goal for mixed collections is to be within this target number. -`-XX:G1MixedGCLiveThresholdPercent=`*percent* +[`-XX:G1MixedGCLiveThresholdPercent=`]{#-XX_G1MixedGCLiveThresholdPercent}*percent* : Sets the occupancy threshold for an old region to be included in a mixed garbage collection cycle. The default occupancy is 85 percent. This is an experimental flag. This setting replaces the `-XX:G1OldCSetRegionLiveThresholdPercent` setting. -`-XX:G1NewSizePercent=`*percent* +[`-XX:G1NewSizePercent=`]{#-XX_G1NewSizePercent}*percent* : Sets the percentage of the heap to use as the minimum for the young generation size. The default value is 5 percent of your Java heap. This is an experimental flag. This setting replaces the `-XX:DefaultMinNewGenPercent` setting. -`-XX:G1OldCSetRegionThresholdPercent=`*percent* +[`-XX:G1OldCSetRegionThresholdPercent=`]{#-XX_G1OldCSetRegionThresholdPercent}*percent* : Sets an upper limit on the number of old regions to be collected during a mixed garbage collection cycle. The default is 10 percent of the Java heap. -`-XX:G1ReservePercent=`*percent* +[`-XX:G1ReservePercent=`]{#-XX_G1ReservePercent}*percent* : Sets the percentage of the heap (0 to 50) that's reserved as a false ceiling to reduce the possibility of promotion failure for the G1 collector. When you increase or decrease the percentage, ensure that you @@ -2415,7 +2415,7 @@ Java HotSpot VM. > `-XX:G1ReservePercent=20` -`-XX:+G1UseAdaptiveIHOP` +[`-XX:+G1UseAdaptiveIHOP`]{#-XX__G1UseAdaptiveIHOP} : Controls adaptive calculation of the old generation occupancy to start background work preparing for an old generation collection. If enabled, G1 uses `-XX:InitiatingHeapOccupancyPercent` for the first few times as @@ -2428,7 +2428,7 @@ Java HotSpot VM. The default is enabled. -`-XX:InitialHeapSize=`*size* +[`-XX:InitialHeapSize=`]{#-XX_InitialHeapSize}*size* : Sets the initial size (in bytes) of the memory allocation pool. This value must be either 0, or a multiple of 1024 and greater than 1 MB. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, @@ -2452,7 +2452,7 @@ Java HotSpot VM. command line, then the initial heap size gets set to the value specified with `-Xms`. -`-XX:InitialRAMPercentage=`*percent* +[`-XX:InitialRAMPercentage=`]{#-XX_InitialRAMPercentage}*percent* : Sets the initial amount of memory that the JVM will use for the Java heap before applying ergonomics heuristics as a percentage of the maximum amount determined as described in the `-XX:MaxRAM` option. @@ -2462,7 +2462,7 @@ Java HotSpot VM. > `-XX:InitialRAMPercentage=5` -`-XX:InitialSurvivorRatio=`*ratio* +[`-XX:InitialSurvivorRatio=`]{#-XX_InitialSurvivorRatio}*ratio* : Sets the initial survivor space ratio used by the throughput garbage collector (which is enabled by the `-XX:+UseParallelGC` option). Adaptive sizing is enabled by default with the throughput garbage collector by @@ -2491,7 +2491,7 @@ Java HotSpot VM. > `-XX:InitialSurvivorRatio=4` -`-XX:InitiatingHeapOccupancyPercent=`*percent* +[`-XX:InitiatingHeapOccupancyPercent=`]{#-XX_InitiatingHeapOccupancyPercent}*percent* : Sets the percentage of the old generation occupancy (0 to 100) at which to start the first few concurrent marking cycles for the G1 garbage collector. @@ -2506,7 +2506,7 @@ Java HotSpot VM. > `-XX:InitiatingHeapOccupancyPercent=75` -`-XX:MaxGCPauseMillis=`*time* +[`-XX:MaxGCPauseMillis=`]{#-XX_MaxGCPauseMillis}*time* : Sets a target for the maximum GC pause time (in milliseconds). This is a soft goal, and the JVM will make its best effort to achieve it. Only G1 and Parallel support a maximum GC pause time target. For G1, the default @@ -2517,7 +2517,7 @@ Java HotSpot VM. > `-XX:MaxGCPauseMillis=500` -`-XX:MaxHeapSize=`*size* +[`-XX:MaxHeapSize=`]{#-XX_MaxHeapSize}*size* : Sets the maximum size (in byes) of the memory allocation pool. This value must be a multiple of 1024 and greater than 2 MB. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or `g` or `G` @@ -2537,7 +2537,7 @@ Java HotSpot VM. The `-XX:MaxHeapSize` option is equivalent to `-Xmx`. -`-XX:MaxHeapFreeRatio=`*percent* +[`-XX:MaxHeapFreeRatio=`]{#-XX_MaxHeapFreeRatio}*percent* : Sets the maximum allowed percentage of free heap space (0 to 100) after a GC event. If free heap space expands above this value, then the heap is shrunk. By default, this value is set to 70%. @@ -2558,7 +2558,7 @@ Java HotSpot VM. description of using this option to keep the Java heap small by reducing the dynamic footprint for embedded applications. -`-XX:MaxMetaspaceSize=`*size* +[`-XX:MaxMetaspaceSize=`]{#-XX_MaxMetaspaceSize}*size* : Sets the maximum amount of native memory that can be allocated for class metadata. By default, the size isn't limited. The amount of metadata for an application depends on the application itself, other running applications, @@ -2569,11 +2569,11 @@ Java HotSpot VM. > `-XX:MaxMetaspaceSize=256m` -`-XX:MaxNewSize=`*size* +[`-XX:MaxNewSize=`]{#-XX_MaxNewSize}*size* : Sets the maximum size (in bytes) of the heap for the young generation (nursery). The default value is set ergonomically. -`-XX:MaxRAMPercentage=`*percent* +[`-XX:MaxRAMPercentage=`]{#-XX_MaxRAMPercentage}*percent* : Sets the maximum amount of memory that the JVM may use for the Java heap before applying ergonomics heuristics as a percentage of the maximum amount determined as described in the `-XX:MaxRAM` option. The default value is 25 @@ -2589,7 +2589,7 @@ Java HotSpot VM. > `-XX:MaxRAMPercentage=75` -`-XX:MinRAMPercentage=`*percent* +[`-XX:MinRAMPercentage=`]{#-XX_MinRAMPercentage}*percent* : Sets the maximum amount of memory that the JVM may use for the Java heap before applying ergonomics heuristics as a percentage of the maximum amount determined as described in the `-XX:MaxRAM` option for small heaps. A small @@ -2600,7 +2600,7 @@ Java HotSpot VM. > `-XX:MinRAMPercentage=75` -`-XX:MaxTenuringThreshold=`*threshold* +[`-XX:MaxTenuringThreshold=`]{#-XX_MaxTenuringThreshold}*threshold* : Sets the maximum tenuring threshold for use in adaptive GC sizing. The largest value is 15. The default value is 15 for the parallel (throughput) collector. @@ -2610,13 +2610,13 @@ Java HotSpot VM. > `-XX:MaxTenuringThreshold=10` -`-XX:MetaspaceSize=`*size* +[`-XX:MetaspaceSize=`]{#-XX_MetaspaceSize}*size* : Sets the size of the allocated class metadata space that triggers a garbage collection the first time it's exceeded. This threshold for a garbage collection is increased or decreased depending on the amount of metadata used. The default size depends on the platform. -`-XX:MinHeapFreeRatio=`*percent* +[`-XX:MinHeapFreeRatio=`]{#-XX_MinHeapFreeRatio}*percent* : Sets the minimum allowed percentage of free heap space (0 to 100) after a GC event. If free heap space falls below this value, then the heap is expanded. By default, this value is set to 40%. @@ -2637,7 +2637,7 @@ Java HotSpot VM. description of using this option to keep the Java heap small by reducing the dynamic footprint for embedded applications. -`-XX:MinHeapSize=`*size* +[`-XX:MinHeapSize=`]{#-XX_MinHeapSize}*size* : Sets the minimum size (in bytes) of the memory allocation pool. This value must be either 0, or a multiple of 1024 and greater than 1 MB. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, @@ -2656,14 +2656,14 @@ Java HotSpot VM. If you set this option to 0, then the minimum size is set to the same value as the initial size. -`-XX:NewRatio=`*ratio* +[`-XX:NewRatio=`]{#-XX_NewRatio}*ratio* : Sets the ratio between young and old generation sizes. By default, this option is set to 2. The following example shows how to set the young-to-old ratio to 1: > `-XX:NewRatio=1` -`-XX:NewSize=`*size* +[`-XX:NewSize=`]{#-XX_NewSize}*size* : Sets the initial size (in bytes) of the heap for the young generation (nursery). Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or `g` or `G` to indicate gigabytes. @@ -2687,7 +2687,7 @@ Java HotSpot VM. The `-XX:NewSize` option is equivalent to `-Xmn`. -`-XX:ParallelGCThreads=`*threads* +[`-XX:ParallelGCThreads=`]{#-XX_ParallelGCThreads}*threads* : Sets the number of the stop-the-world (STW) worker threads. The default value depends on the number of CPUs available to the JVM and the garbage collector selected. @@ -2697,11 +2697,11 @@ Java HotSpot VM. > `-XX:ParallelGCThreads=2` -`-XX:+PrintAdaptiveSizePolicy` +[`-XX:+PrintAdaptiveSizePolicy`]{#-XX__PrintAdaptiveSizePolicy} : Enables printing of information about adaptive-generation sizing. By default, this option is disabled. -`-XX:SoftRefLRUPolicyMSPerMB=`*time* +[`-XX:SoftRefLRUPolicyMSPerMB=`]{#-XX_SoftRefLRUPolicyMSPerMB}*time* : Sets the amount of time (in milliseconds) a softly reachable object is kept active on the heap after the last time it was referenced. The default value is one second of lifetime per free megabyte in the heap. The @@ -2718,7 +2718,7 @@ Java HotSpot VM. `-XX:SoftRefLRUPolicyMSPerMB=2500` -`-XX:-ShrinkHeapInSteps` +[`-XX:-ShrinkHeapInSteps`]{#-XX__ShrinkHeapInSteps} : Incrementally reduces the Java heap to the target size, specified by the option `-XX:MaxHeapFreeRatio`. This option is enabled by default. If disabled, then it immediately reduces the Java heap to the target size @@ -2730,7 +2730,7 @@ Java HotSpot VM. `MaxHeapFreeRatio` option to keep the Java heap small by reducing the dynamic footprint for embedded applications. -`-XX:StringDeduplicationAgeThreshold=`*threshold* +[`-XX:StringDeduplicationAgeThreshold=`]{#-XX_StringDeduplicationAgeThreshold}*threshold* : Identifies `String` objects reaching the specified age that are considered candidates for deduplication. An object's age is a measure of how many times it has survived garbage collection. This is sometimes referred to as @@ -2741,14 +2741,14 @@ Java HotSpot VM. default value for this option is `3`. See the `-XX:+UseStringDeduplication` option. -`-XX:SurvivorRatio=`*ratio* +[`-XX:SurvivorRatio=`]{#-XX_SurvivorRatio}*ratio* : Sets the ratio between eden space size and survivor space size. By default, this option is set to 8. The following example shows how to set the eden/survivor space ratio to 4: > `-XX:SurvivorRatio=4` -`-XX:TargetSurvivorRatio=`*percent* +[`-XX:TargetSurvivorRatio=`]{#-XX_TargetSurvivorRatio}*percent* : Sets the desired percentage of survivor space (0 to 100) used after young garbage collection. By default, this option is set to 50%. @@ -2757,7 +2757,7 @@ Java HotSpot VM. > `-XX:TargetSurvivorRatio=30` -`-XX:TLABSize=`*size* +[`-XX:TLABSize=`]{#-XX_TLABSize}*size* : Sets the initial size (in bytes) of a thread-local allocation buffer (TLAB). Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or `g` or `G` to indicate gigabytes. If this option is @@ -2767,13 +2767,13 @@ Java HotSpot VM. > `-XX:TLABSize=512k` -`-XX:+UseAdaptiveSizePolicy` +[`-XX:+UseAdaptiveSizePolicy`]{#-XX__UseAdaptiveSizePolicy} : Enables the use of adaptive generation sizing. This option is enabled by default. To disable adaptive generation sizing, specify `-XX:-UseAdaptiveSizePolicy` and set the size of the memory allocation pool explicitly. See the `-XX:SurvivorRatio` option. -`-XX:+UseG1GC` +[`-XX:+UseG1GC`]{#-XX__UseG1GC} : Enables the use of the garbage-first (G1) garbage collector. It's a server-style garbage collector, targeted for multiprocessor machines with a large amount of RAM. This option meets GC pause time goals with high @@ -2783,7 +2783,7 @@ Java HotSpot VM. pause time below 0.5 seconds). By default, this option is enabled and G1 is used as the default garbage collector. -`-XX:+UseGCOverheadLimit` +[`-XX:+UseGCOverheadLimit`]{#-XX__UseGCOverheadLimit} : Enables the use of a policy that limits the proportion of time spent by the JVM on GC before an `OutOfMemoryError` exception is thrown. This option is enabled, by default, and the parallel GC will throw an `OutOfMemoryError` @@ -2793,26 +2793,26 @@ Java HotSpot VM. little or no progress. To disable this option, specify the option `-XX:-UseGCOverheadLimit`. -`-XX:+UseNUMA` +[`-XX:+UseNUMA`]{#-XX__UseNUMA} : Enables performance optimization of an application on a machine with nonuniform memory architecture (NUMA) by increasing the application's use of lower latency memory. The default value for this option depends on the garbage collector. -`-XX:+UseParallelGC` +[`-XX:+UseParallelGC`]{#-XX__UseParallelGC} : Enables the use of the parallel scavenge garbage collector (also known as the throughput collector) to improve the performance of your application by leveraging multiple processors. By default, this option is disabled and the default collector is used. -`-XX:+UseSerialGC` +[`-XX:+UseSerialGC`]{#-XX__UseSerialGC} : Enables the use of the serial garbage collector. This is generally the best choice for small and simple applications that don't require any special functionality from garbage collection. By default, this option is disabled and the default collector is used. -`-XX:+UseStringDeduplication` +[`-XX:+UseStringDeduplication`]{#-XX__UseStringDeduplication} : Enables string deduplication. By default, this option is disabled. To use this option, you must enable the garbage-first (G1) garbage collector. @@ -2822,34 +2822,34 @@ Java HotSpot VM. character array, identical `String` objects can point to and share the same character array. -`-XX:+UseTLAB` +[`-XX:+UseTLAB`]{#-XX__UseTLAB} : Enables the use of thread-local allocation blocks (TLABs) in the young generation space. This option is enabled by default. To disable the use of TLABs, specify the option `-XX:-UseTLAB`. -`-XX:+UseZGC` +[`-XX:+UseZGC`]{#-XX__UseZGC} : Enables the use of the Z garbage collector (ZGC). This is a low latency garbage collector, providing max pause times of a few milliseconds, at some throughput cost. Pause times are independent of what heap size is used. Supports heap sizes from 8MB to 16TB. -`-XX:ZAllocationSpikeTolerance=`*factor* +[`-XX:ZAllocationSpikeTolerance=`]{#-XX_ZAllocationSpikeTolerance}*factor* : Sets the allocation spike tolerance for ZGC. By default, this option is set to 2.0. This factor describes the level of allocation spikes to expect. For example, using a factor of 3.0 means the current allocation rate can be expected to triple at any time. -`-XX:ZCollectionInterval=`*seconds* +[`-XX:ZCollectionInterval=`]{#-XX_ZCollectionInterval}*seconds* : Sets the maximum interval (in seconds) between two GC cycles when using ZGC. By default, this option is set to 0 (disabled). -`-XX:ZFragmentationLimit=`*percent* +[`-XX:ZFragmentationLimit=`]{#-XX_ZFragmentationLimit}*percent* : Sets the maximum acceptable heap fragmentation (in percent) for ZGC. By default, this option is set to 25. Using a lower value will cause the heap to be compacted more aggressively, to reclaim more memory at the cost of using more CPU time. -`-XX:+ZProactive` +[`-XX:+ZProactive`]{#-XX__ZProactive} : Enables proactive GC cycles when using ZGC. By default, this option is enabled. ZGC will start a proactive GC cycle if doing so is expected to have minimal impact on the running application. This is useful if the @@ -2857,27 +2857,27 @@ Java HotSpot VM. want to keep the heap size down and allow reference processing to happen even when there are a lot of free space on the heap. -`-XX:+ZUncommit` +[`-XX:+ZUncommit`]{#-XX__ZUncommit} : Enables uncommitting of unused heap memory when using ZGC. By default, this option is enabled. Uncommitting unused heap memory will lower the memory footprint of the JVM, and make that memory available for other processes to use. -`-XX:ZUncommitDelay=`*seconds* +[`-XX:ZUncommitDelay=`]{#-XX_ZUncommitDelay}*seconds* : Sets the amount of time (in seconds) that heap memory must have been unused before being uncommitted. By default, this option is set to 300 (5 minutes). Committing and uncommitting memory are relatively expensive operations. Using a lower value will cause heap memory to be uncommitted earlier, at the risk of soon having to commit it again. -`-XX:+UseShenandoahGC` +[`-XX:+UseShenandoahGC`]{#-XX__UseShenandoahGC} : Enables the use of the Shenandoah garbage collector. This is a low pause time, concurrent garbage collector. Its pause times are not proportional to the size of the heap. Shenandoah garbage collector can work with compressed pointers. See `-XX:UseCompressedOops` for further information about compressed pointers. -`-XX:ShenandoahGCMode=`*mode* +[`-XX:ShenandoahGCMode=`]{#-XX_ShenandoahGCMode}*mode* : Sets the GC mode for Shenandoah GC to use. By default, this option is set to `satb`. Among other things, this defines which barriers are in use. Possible mode values include the following: @@ -2891,7 +2891,7 @@ Java HotSpot VM. generational. Please see [JEP 404](https://openjdk.org/jeps/404) and [JEP 521](https://openjdk.org/jeps/521) for its advantages and risks. -`-XX:ShenandoahGCHeuristics=`*heuristics* +[`-XX:ShenandoahGCHeuristics=`]{#-XX_ShenandoahGCHeuristics}*heuristics* : Sets the heuristics for Shenandoah GC to use. By default, this option is set to `adaptive`. This fine-tunes the GC mode selected, by choosing when to start the GC, how much to process on each cycle, and what other features @@ -2916,7 +2916,7 @@ These `java` options are deprecated and might be removed in a future JDK release. They're still accepted and acted upon, but a warning is issued when they're used. -`-Xloggc:`*filename* +[`-Xloggc:`]{#-Xloggc_}*filename* : Sets the file to which verbose GC events information should be redirected for logging. The `-Xloggc` option overrides `-verbose:gc` if both are given with the same java command. `-Xloggc:`*filename* is replaced by @@ -2927,11 +2927,11 @@ they're used. `-Xlog:gc:garbage-collection.log` -`-XX:+FlightRecorder` +[`-XX:+FlightRecorder`]{#-XX__FlightRecorder} : Enables the use of Java Flight Recorder (JFR) during the runtime of the application. Since JDK 8u40 this option has not been required to use JFR. -`-XX:+ParallelRefProcEnabled` +[`-XX:+ParallelRefProcEnabled`]{#-XX__ParallelRefProcEnabled} : Enables parallel reference processing. By default, collectors employing multiple threads perform parallel reference processing if the number of parallel threads to use is larger than one. @@ -2939,7 +2939,7 @@ they're used. (`-XX:+UseParallelGC` or `-XX:+UseG1GC`). Other collectors employing multiple threads always perform reference processing in parallel. -`-XX:MaxRAM=`*size* +[`-XX:MaxRAM=`]{#-XX_MaxRAM}*size* : Sets the maximum amount of memory that the JVM may use for the Java heap before applying ergonomics heuristics. The default value is the amount of available memory to the JVM process. @@ -2958,13 +2958,13 @@ they're used. > `-XX:MaxRAM=2G` -`-XX:+AggressiveHeap` +[`-XX:+AggressiveHeap`]{#-XX__AggressiveHeap} : Enables Java heap optimization. This sets various parameters to be optimal for long-running jobs with intensive memory allocation, based on the configuration of the computer (RAM and CPU). By default, the option is disabled and the heap sizes are configured less aggressively. -`-XX:+NeverActAsServerClassMachine` +[`-XX:+NeverActAsServerClassMachine`]{#-XX__NeverActAsServerClassMachine} : Enable the "Client VM emulation" mode which only uses the C1 JIT compiler, a 32Mb CodeCache and the Serial GC. The maximum amount of memory that the JVM may use (controlled by the `-XX:MaxRAM=n` flag) is set to 1GB by default. @@ -2989,7 +2989,7 @@ they're used. These `java` options are still accepted but ignored, and a warning is issued when they're used. -`--illegal-access=`*parameter* +[`--illegal-access=`]{#--illegal-access}*parameter* : Controlled _relaxed strong encapsulation_, as defined in [JEP 261](https://openjdk.org/jeps/261#Relaxed-strong-encapsulation). This option was deprecated in JDK 16 by [JEP @@ -3283,7 +3283,7 @@ Flags to Xlog]. The following provides quick reference to the `-Xlog` command and syntax for options: -`-Xlog` +[`-Xlog`]{#-Xlog} : Enables JVM logging on an `info` level. `-Xlog:help` @@ -3570,7 +3570,7 @@ Legacy Runtime Flag Xlog Configuration Comment The following are `-Xlog` examples. -`-Xlog` +[`-Xlog`]{#-Xlog} : Logs all messages by using the `info` level to `stdout` with `uptime`, `levels`, and `tags` decorations. This is equivalent to using: @@ -4075,7 +4075,7 @@ The deployment of the AOT cache is divided into three phases: The AOT cache can be used with the following command-line options: -`-XX:AOTCache=`*cachefile* +[`-XX:AOTCache=`]{#-XX_AOTCache}*cachefile* : Specifies the location of the AOT cache. The standard extension for *cachefile* is `.aot`. This option cannot be used together with `-XX:AOTCacheOutput`. @@ -4084,13 +4084,13 @@ The AOT cache can be used with the following command-line options: The *cachefile* is written by AOT mode `create`. In that case, this option is equivalent to `-XX:AOTCacheOutput=`*cachefile*. -`-XX:AOTCacheOutput=`*cachefile* +[`-XX:AOTCacheOutput=`]{#-XX_AOTCacheOutput}*cachefile* : Specifies the location of the AOT cache to write. The standard extension for *cachefile* is `.aot`. This option cannot be used together with `-XX:AOTCache`. This option is compatible with `AOTMode` settings of `record`, `create`, or `auto` (the default). -`-XX:AOTConfiguration=`*configfile* +[`-XX:AOTConfiguration=`]{#-XX_AOTConfiguration}*configfile* : Specifies the AOT Configuration file for the JVM to write to or read from. The standard extension for *configfile* is `.aotconfig`. @@ -4098,7 +4098,7 @@ The AOT cache can be used with the following command-line options: The *configfile* is read by AOT mode `create`, and written by the other applicable modes. If the AOT mode is `auto`, then `AOTCacheOutput` must also be present. -`-XX:AOTMode=`*mode* +[`-XX:AOTMode=`]{#-XX_AOTMode}*mode* : Specifies the AOT Mode for this run. *mode* must be one of the following: `auto`, `off`, `record`, `create`, or `on`. @@ -4170,7 +4170,7 @@ The AOT cache can be used with the following command-line options: options are compatible with the AOT cache. An alternative is to run your application with `-XX:AOTMode=auto -Xlog:aot` to see if the AOT cache can be used or not. -`-XX:+AOTClassLinking` +[`-XX:+AOTClassLinking`]{#-XX__AOTClassLinking} : If this option is enabled, the JVM will perform more advanced optimizations (such as ahead-of-time resolution of invokedynamic instructions) when creating the AOT cache. As a result, the application will see further improvements From 56545328f849c3ebf062e3ff601224084fa3b46e Mon Sep 17 00:00:00 2001 From: Jonas Norlinder Date: Wed, 14 Jan 2026 16:54:24 +0000 Subject: [PATCH 032/328] 8375297: ZGC: Remove obsolete O_CLOEXEC definition Reviewed-by: tschatzl, eosterlund --- src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp index 25ffd0b8078..28159ae4801 100644 --- a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp +++ b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp @@ -66,9 +66,6 @@ #endif // open(2) flags -#ifndef O_CLOEXEC -#define O_CLOEXEC 02000000 -#endif #ifndef O_TMPFILE #define O_TMPFILE (020000000 | O_DIRECTORY) #endif From 60fbaf5b26d7d359b1258898d4c4dfd86010b8a5 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 14 Jan 2026 18:53:10 +0000 Subject: [PATCH 033/328] 8374828: Save load_barrier_on_oop_field_preloaded in aot CodeCache Reviewed-by: adinn, iklam, shade --- src/hotspot/share/code/aotCodeCache.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index 0314c5227d2..f51c068f1e7 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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 @@ -1371,6 +1371,7 @@ void AOTCodeAddressTable::init_extrs() { SET_ADDRESS(_extrs, ShenandoahRuntime::load_reference_barrier_phantom_narrow); #endif #if INCLUDE_ZGC + SET_ADDRESS(_extrs, ZBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr()); SET_ADDRESS(_extrs, ZBarrierSetRuntime::load_barrier_on_phantom_oop_field_preloaded_addr()); #if defined(AMD64) SET_ADDRESS(_extrs, &ZPointerLoadShift); From a7507ffa1dda403110a61c4b61143b76e8a7911e Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Wed, 14 Jan 2026 19:26:45 +0000 Subject: [PATCH 034/328] 8375237: Document existing exceptional behavior of divideUnsigned and remainderUnsigned Reviewed-by: rgiulietti --- src/java.base/share/classes/java/lang/Integer.java | 4 +++- src/java.base/share/classes/java/lang/Long.java | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index a9da1c32490..85ca80735f8 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2026, 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 @@ -1448,6 +1448,7 @@ public final class Integer extends Number * @param divisor the value doing the dividing * @return the unsigned quotient of the first argument divided by * the second argument + * @throws ArithmeticException if the divisor is zero * @see #remainderUnsigned * @since 1.8 */ @@ -1466,6 +1467,7 @@ public final class Integer extends Number * @param divisor the value doing the dividing * @return the unsigned remainder of the first argument divided by * the second argument + * @throws ArithmeticException if the divisor is zero * @see #divideUnsigned * @since 1.8 */ diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index c5cd9650f2d..5fa1b8fc2ea 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2026, 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 @@ -1411,6 +1411,7 @@ public final class Long extends Number * @param divisor the value doing the dividing * @return the unsigned quotient of the first argument divided by * the second argument + * @throws ArithmeticException if the divisor is zero * @see #remainderUnsigned * @since 1.8 */ @@ -1434,6 +1435,7 @@ public final class Long extends Number * @param divisor the value doing the dividing * @return the unsigned remainder of the first argument divided by * the second argument + * @throws ArithmeticException if the divisor is zero * @see #divideUnsigned * @since 1.8 */ From 3007365b73d400ee6a5ea9a9041899bb81cf357a Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Wed, 14 Jan 2026 19:27:10 +0000 Subject: [PATCH 035/328] 8373913: Refactor serialization tests to use JUnit Reviewed-by: jlu, naoto --- .../Serializable/GetField/ReadFieldsCNF.java | 34 ++-- .../class/NonSerializableTest.java | 75 +++++---- .../Serializable/records/RecordClassTest.java | 10 +- .../records/SerialVersionUIDTest.java | 12 +- .../serialFilter/CheckArrayTest.java | 28 ++-- .../serialFilter/CheckInputOrderTest.java | 23 +-- .../serialFilter/GlobalFilterTest.java | 71 ++++---- .../serialFilter/InvalidGlobalFilterTest.java | 40 ++--- .../serialFilter/MixedFiltersTest.java | 52 +++--- .../serialFilter/SerialFactoryExample.java | 33 ++-- .../serialFilter/SerialFactoryFaults.java | 52 +++--- .../serialFilter/SerialFilterFactoryTest.java | 76 +++++---- .../SerialFilterFunctionTest.java | 51 +++--- .../serialFilter/SerialFilterTest.java | 151 ++++++++---------- 14 files changed, 355 insertions(+), 353 deletions(-) diff --git a/test/jdk/java/io/Serializable/GetField/ReadFieldsCNF.java b/test/jdk/java/io/Serializable/GetField/ReadFieldsCNF.java index 7b91222d737..2b3f1c6aa45 100644 --- a/test/jdk/java/io/Serializable/GetField/ReadFieldsCNF.java +++ b/test/jdk/java/io/Serializable/GetField/ReadFieldsCNF.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,8 +27,8 @@ * @summary Verify that ObjectInputStream ReadFields correctly reports ClassNotFoundException * while getting the field value. The test uses Vector that calls ReadFields from its readObject. * @library /test/lib - * @run testng ReadFieldsCNF - * @run testng/othervm -Djdk.serialGetFieldCnfeReturnsNull=true ReadFieldsCNF + * @run junit ReadFieldsCNF + * @run junit/othervm -Djdk.serialGetFieldCnfeReturnsNull=true ReadFieldsCNF */ import java.io.ByteArrayInputStream; @@ -41,12 +41,12 @@ import java.io.StreamCorruptedException; import java.nio.charset.StandardCharsets; import java.util.Vector; -import org.testng.annotations.Test; -import org.testng.Assert; - import jdk.test.lib.hexdump.HexPrinter; import jdk.test.lib.hexdump.ObjectStreamPrinter; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + public class ReadFieldsCNF { private static final boolean GETFIELD_CNFE_RETURNS_NULL = @@ -58,7 +58,7 @@ public class ReadFieldsCNF { * @throws IOException If any other exception occurs */ @Test - private static void testVectorWithRole() throws IOException { + void testVectorWithRole() throws IOException { System.out.println("Property GETFIELD_CNFE_RETURNS_NULL: " + GETFIELD_CNFE_RETURNS_NULL); Role role = new Role(); @@ -75,7 +75,7 @@ public class ReadFieldsCNF { System.out.printf("Role offset: %d (0x%x) : %s%n", off, off, Role.class.getName()); if (off < 0) { HexPrinter.simple().formatter(ObjectStreamPrinter.formatter()).format(bytes); - Assert.fail("classname not found"); + Assertions.fail("classname not found"); } bytes[off] = (byte) 'X'; // replace R with X -> Class not found @@ -85,18 +85,18 @@ public class ReadFieldsCNF { try { Object obj = in.readObject(); System.out.println("Read: " + obj); - Assert.fail("Should not reach here, an exception should always occur"); + Assertions.fail("Should not reach here, an exception should always occur"); } catch (ClassNotFoundException cnfe) { // Expected ClassNotFoundException String expected = "XeadFieldsCNF$Role"; - Assert.assertEquals(expected, cnfe.getMessage(), "Wrong classname"); + Assertions.assertEquals(expected, cnfe.getMessage(), "Wrong classname"); if (GETFIELD_CNFE_RETURNS_NULL) { - Assert.fail("Expected IOException got ClassNotFoundException", cnfe); + Assertions.fail("Expected IOException got ClassNotFoundException", cnfe); } System.out.println("Normal: OIS.readObject: " + cnfe); } catch (StreamCorruptedException ioe) { if (!GETFIELD_CNFE_RETURNS_NULL) { - Assert.fail("Expected ClassNotFoundException got StreamCorruptedException ", ioe); + Assertions.fail("Expected ClassNotFoundException got StreamCorruptedException ", ioe); } System.out.println("Normal: " + ioe); } @@ -108,7 +108,7 @@ public class ReadFieldsCNF { * @throws IOException If any other exception occurs */ @Test - private static void testHolderWithRole() throws IOException { + void testHolderWithRole() throws IOException { System.out.println("Property GETFIELD_CNFE_RETURNS_NULL: " + GETFIELD_CNFE_RETURNS_NULL); Role role = new Role(); Holder holder = new Holder(role); @@ -123,7 +123,7 @@ public class ReadFieldsCNF { System.out.printf("Role offset: %d (0x%x)%n", off, off); if (off < 0) { HexPrinter.simple().formatter(ObjectStreamPrinter.formatter()).format(bytes); - Assert.fail("classname found at index: " + off + " (0x" + Integer.toHexString(off) + ")"); + Assertions.fail("classname found at index: " + off + " (0x" + Integer.toHexString(off) + ")"); } bytes[off] = (byte) 'X'; // replace R with X -> Class not found @@ -133,15 +133,15 @@ public class ReadFieldsCNF { try { Holder obj = (Holder)in.readObject(); System.out.println("Read: " + obj); - Assert.fail("Should not reach here, an exception should always occur"); + Assertions.fail("Should not reach here, an exception should always occur"); } catch (ClassNotFoundException cnfe) { // Expected ClassNotFoundException String expected = "XeadFieldsCNF$Role"; - Assert.assertEquals(expected, cnfe.getMessage(), "Wrong classname"); + Assertions.assertEquals(expected, cnfe.getMessage(), "Wrong classname"); System.out.println("Normal: OIS.readObject: " + cnfe); } catch (StreamCorruptedException ioe) { if (!GETFIELD_CNFE_RETURNS_NULL) { - Assert.fail("Expected ClassNotFoundException got StreamCorruptedException ", ioe); + Assertions.fail("Expected ClassNotFoundException got StreamCorruptedException ", ioe); } System.out.println("Normal: " + ioe); } diff --git a/test/jdk/java/io/Serializable/class/NonSerializableTest.java b/test/jdk/java/io/Serializable/class/NonSerializableTest.java index fa81b3e3ce7..2a36380aae7 100644 --- a/test/jdk/java/io/Serializable/class/NonSerializableTest.java +++ b/test/jdk/java/io/Serializable/class/NonSerializableTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,79 +32,84 @@ * jdk.test.lib.JDKToolLauncher * jdk.test.lib.Platform * jdk.test.lib.process.* - * @run testng/timeout=300 NonSerializableTest + * @run junit/timeout=300 NonSerializableTest * @summary Enable serialize of nonSerializable Class descriptor. */ import java.nio.file.Paths; import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; -import org.testng.annotations.DataProvider; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.process.ProcessTools; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + public class NonSerializableTest { - @BeforeClass - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { boolean b = CompilerUtils.compile( Paths.get(System.getProperty("test.src"), "TestEntry.java"), Paths.get(System.getProperty("user.dir"))); assertTrue(b, "Compilation failed"); } - @DataProvider - public Object[][] provider() { - return new String[][][] { + // Test cases to compile and run + public static Stream> provider() { + return Stream.of( // Write NonSerial1, Read NonSerial1 - {{"NonSerialA_1", "-cp", ".", "TestEntry", "-s", "A"}}, - {{"NonSerialA_1", "-cp", ".", "TestEntry", "-d"}}, + List.of("NonSerialA_1", "-cp", ".", "TestEntry", "-s", "A"), + List.of("NonSerialA_1", "-cp", ".", "TestEntry", "-d"), // Write NonSerial1, Read NonSerial2 - {{"NonSerialA_1", "-cp", ".", "TestEntry", "-s", "A"}}, - {{"NonSerialA_2", "-cp", ".", "TestEntry", "-d"}}, + List.of("NonSerialA_1", "-cp", ".", "TestEntry", "-s", "A"), + List.of("NonSerialA_2", "-cp", ".", "TestEntry", "-d"), // Write NonSerial1, Read Serial1 - {{"NonSerialA_1", "-cp", ".", "TestEntry", "-s", "A"}}, - {{"SerialA_1", "-cp", ".", "TestEntry", "-d"}}, + List.of("NonSerialA_1", "-cp", ".", "TestEntry", "-s", "A"), + List.of("SerialA_1", "-cp", ".", "TestEntry", "-d"), // Write Serial1, Read NonSerial1 - {{"SerialA_1", "-cp", ".", "TestEntry", "-s", "A"}}, - {{"NonSerialA_1", "-cp", ".", "TestEntry", "-doe"}}, + List.of("SerialA_1", "-cp", ".", "TestEntry", "-s", "A"), + List.of("NonSerialA_1", "-cp", ".", "TestEntry", "-doe"), // Write Serial1, Read Serial2 - {{"SerialA_1", "-cp", ".", "TestEntry", "-s", "A"}}, - {{"SerialA_2", "-cp", ".", "TestEntry", "-d"}}, + List.of("SerialA_1", "-cp", ".", "TestEntry", "-s", "A"), + List.of("SerialA_2", "-cp", ".", "TestEntry", "-d"), // Write Serial2, Read Serial1 - {{"SerialA_2", "-cp", ".", "TestEntry", "-s", "A"}}, - {{"SerialA_1", "-cp", ".", "TestEntry", "-d"}}, + List.of("SerialA_2", "-cp", ".", "TestEntry", "-s", "A"), + List.of("SerialA_1", "-cp", ".", "TestEntry", "-d"), // Write Serial1, Read Serial3 - {{"SerialA_1", "-cp", ".", "TestEntry", "-s", "A"}}, - {{"SerialA_3", "-cp", ".", "TestEntry", "-de"}}, + List.of("SerialA_1", "-cp", ".", "TestEntry", "-s", "A"), + List.of("SerialA_3", "-cp", ".", "TestEntry", "-de"), // Write Serial3, Read Serial1 - {{"SerialA_3", "-cp", ".", "TestEntry", "-s", "A"}}, - {{"SerialA_1", "-cp", ".", "TestEntry", "-de"}}, - }; + List.of("SerialA_3", "-cp", ".", "TestEntry", "-s", "A"), + List.of("SerialA_1", "-cp", ".", "TestEntry", "-de")); } - @Test(dataProvider="provider") - public void test(String[] args) throws Exception { + @ParameterizedTest + @MethodSource("provider") + public void test(List argList) throws Exception { + String[] args = argList.toArray(new String[0]); boolean b = CompilerUtils.compile(Paths.get(System.getProperty("test.src"), args[0]), Paths.get(System.getProperty("user.dir"))); assertTrue(b, "Compilation failed"); - String params[] = Arrays.copyOfRange(args, 1, args.length); + String[] params = Arrays.copyOfRange(args, 1, args.length); ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(params); - Process p = ProcessTools.startProcess("Serializable Test", pb); - int exitValue = p.waitFor(); - assertEquals(exitValue, 0, "Test failed"); + try (Process p = ProcessTools.startProcess("Serializable Test", pb)) { + int exitValue = p.waitFor(); + assertEquals(0, exitValue, "Test failed"); + } } } diff --git a/test/jdk/java/io/Serializable/records/RecordClassTest.java b/test/jdk/java/io/Serializable/records/RecordClassTest.java index ba920ce92e5..951dd2f44dc 100644 --- a/test/jdk/java/io/Serializable/records/RecordClassTest.java +++ b/test/jdk/java/io/Serializable/records/RecordClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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,6 +37,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; +import java.io.Serial; import java.io.Serializable; import static java.lang.System.out; @@ -49,12 +50,12 @@ import org.junit.jupiter.params.provider.MethodSource; /** * Serializes and deserializes record classes. Ensures that the SUID is 0. */ -@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class RecordClassTest { record Foo () implements Serializable { } record Bar (int x) implements Serializable { + @Serial private static final long serialVersionUID = 987654321L; } @@ -70,6 +71,7 @@ public class RecordClassTest { } record Wibble () implements ThrowingExternalizable { + @Serial private static final long serialVersionUID = 12345678L; } @@ -77,7 +79,7 @@ public class RecordClassTest { record Wubble (Wobble wobble, Wibble wibble, String s) implements ThrowingExternalizable { } - public Object[][] recordClasses() { + public static Object[][] recordClasses() { return new Object[][] { new Object[] { Foo.class , 0L }, new Object[] { Bar.class , 987654321L }, @@ -124,7 +126,7 @@ public class RecordClassTest { record NotSerializable3(T t) { } - public Object[][] notSerRecordClasses() { + public static Object[][] notSerRecordClasses() { return new Object[][] { new Object[] { NotSerializable1.class }, new Object[] { NotSerializable2.class }, diff --git a/test/jdk/java/io/Serializable/records/SerialVersionUIDTest.java b/test/jdk/java/io/Serializable/records/SerialVersionUIDTest.java index 2c133392dcb..f313e8a44a3 100644 --- a/test/jdk/java/io/Serializable/records/SerialVersionUIDTest.java +++ b/test/jdk/java/io/Serializable/records/SerialVersionUIDTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.Serial; import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -44,18 +45,18 @@ import static java.lang.System.out; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class SerialVersionUIDTest { record R1 () implements Serializable { + @Serial private static final long serialVersionUID = 1L; } record R2 (int x, int y) implements Serializable { + @Serial private static final long serialVersionUID = 0L; } @@ -64,10 +65,11 @@ public class SerialVersionUIDTest { record R4 (String s) implements Serializable { } record R5 (long l) implements Serializable { + @Serial private static final long serialVersionUID = 5678L; } - public Object[][] recordObjects() { + public static Object[][] recordObjects() { return new Object[][] { new Object[] { new R1(), 1L }, new Object[] { new R2(1, 2), 0L }, @@ -103,7 +105,7 @@ public class SerialVersionUIDTest { assertEquals(expectedUID, dis.readLong()); } - public Object[][] recordClasses() { + public static Object[][] recordClasses() { List list = new ArrayList<>(); List> recordClasses = List.of(R1.class, R2.class, R3.class, R4.class, R5.class); LongStream.of(0L, 1L, 100L, 10_000L, 1_000_000L).forEach(suid -> diff --git a/test/jdk/java/io/Serializable/serialFilter/CheckArrayTest.java b/test/jdk/java/io/Serializable/serialFilter/CheckArrayTest.java index d00c670bd15..2081375ca59 100644 --- a/test/jdk/java/io/Serializable/serialFilter/CheckArrayTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/CheckArrayTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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,15 +30,15 @@ import java.io.InvalidClassException; import jdk.internal.access.SharedSecrets; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import org.testng.Assert; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /* @test * @build CheckArrayTest SerialFilterTest * @bug 8203368 * @modules java.base/jdk.internal.access - * @run testng CheckArrayTest + * @run junit CheckArrayTest * * @summary Test the SharedSecret access to ObjectInputStream.checkArray works * with overridden subclasses. @@ -53,8 +53,8 @@ import org.testng.Assert; */ public class CheckArrayTest { - @DataProvider(name = "Patterns") - Object[][] patterns() { + // Test patterns for arrays + private static Object[][] patterns() { return new Object[][]{ new Object[]{"maxarray=10", 10, new String[10]}, // successful new Object[]{"maxarray=10", 11, new String[11]}, // exception expected @@ -64,7 +64,8 @@ public class CheckArrayTest { /** * Test SharedSecrets checkArray with unmodified ObjectInputStream. */ - @Test(dataProvider = "Patterns") + @ParameterizedTest + @MethodSource("patterns") public void normalOIS(String pattern, int arraySize, Object[] array) throws IOException { ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern); byte[] bytes = SerialFilterTest.writeObjects(array); @@ -75,10 +76,10 @@ public class CheckArrayTest { ois.setObjectInputFilter(filter); SharedSecrets.getJavaObjectInputStreamAccess() .checkArray(ois, array.getClass(), arraySize); - Assert.assertTrue(array.length >= arraySize, + Assertions.assertTrue(array.length >= arraySize, "Should have thrown InvalidClassException due to array size"); } catch (InvalidClassException ice) { - Assert.assertFalse(array.length > arraySize, + Assertions.assertFalse(array.length > arraySize, "Should NOT have thrown InvalidClassException due to array size"); } } @@ -88,7 +89,8 @@ public class CheckArrayTest { * Test SharedSecrets checkArray with an ObjectInputStream subclassed to * handle all input stream functions. */ - @Test(dataProvider = "Patterns") + @ParameterizedTest + @MethodSource("patterns") public void subclassedOIS(String pattern, int arraySize, Object[] array) throws IOException { byte[] bytes = SerialFilterTest.writeObjects(array); try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes); @@ -98,10 +100,10 @@ public class CheckArrayTest { ois.setObjectInputFilter(filter); SharedSecrets.getJavaObjectInputStreamAccess() .checkArray(ois, array.getClass(), arraySize); - Assert.assertTrue(array.length >= arraySize, + Assertions.assertTrue(array.length >= arraySize, "Should have thrown InvalidClassException due to array size"); } catch (InvalidClassException ice) { - Assert.assertFalse(array.length > arraySize, + Assertions.assertFalse(array.length > arraySize, "Should NOT have thrown InvalidClassException due to array size"); } } diff --git a/test/jdk/java/io/Serializable/serialFilter/CheckInputOrderTest.java b/test/jdk/java/io/Serializable/serialFilter/CheckInputOrderTest.java index 0230eb653ce..d824c947ece 100644 --- a/test/jdk/java/io/Serializable/serialFilter/CheckInputOrderTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/CheckInputOrderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,28 +25,28 @@ import java.io.ByteArrayInputStream; import java.io.InvalidClassException; import java.io.ObjectInputFilter; import java.io.ObjectInputStream; +import java.io.Serial; import java.io.Serializable; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /* @test * @build CheckInputOrderTest SerialFilterTest - * @run testng/othervm CheckInputOrderTest + * @run junit/othervm CheckInputOrderTest * * @summary Test that when both global filter and specific filter are set, * global filter will not affect specific filter. */ public class CheckInputOrderTest implements Serializable { + @Serial private static final long serialVersionUID = 12345678901L; - @DataProvider(name="Patterns") - Object[][] patterns() { + // Test cases for serial filter strings + static Object[][] patterns() { return new Object[][] { new Object[] { SerialFilterTest.genTestObject("maxarray=1", true), "java.**;java.lang.*;java.lang.Long;maxarray=0", false }, new Object[] { SerialFilterTest.genTestObject("maxarray=1", true), "java.**;java.lang.*;java.lang.Long", true }, @@ -75,7 +75,8 @@ public class CheckInputOrderTest implements Serializable { * "global filter reject" + "specific ObjectInputStream filter is empty" => should reject * "global filter reject" + "specific ObjectInputStream filter allow" => should allow */ - @Test(dataProvider="Patterns") + @ParameterizedTest + @MethodSource("patterns") public void testRejectedInGlobal(Object toDeserialized, String pattern, boolean allowed) throws Exception { byte[] bytes = SerialFilterTest.writeObjects(toDeserialized); ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern); diff --git a/test/jdk/java/io/Serializable/serialFilter/GlobalFilterTest.java b/test/jdk/java/io/Serializable/serialFilter/GlobalFilterTest.java index 9e38d6c499d..18bbf265e43 100644 --- a/test/jdk/java/io/Serializable/serialFilter/GlobalFilterTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/GlobalFilterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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,9 +21,8 @@ * questions. */ -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertSame; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.EOFException; @@ -35,39 +34,40 @@ import java.io.ObjectInputStream; import java.security.Security; import java.util.Objects; -import org.testng.Assert; -import org.testng.annotations.Test; -import org.testng.annotations.DataProvider; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIf; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /* @test * @bug 8231422 * @build GlobalFilterTest SerialFilterTest - * @run testng/othervm GlobalFilterTest - * @run testng/othervm -Djdk.serialFilter=java.** + * @run junit/othervm GlobalFilterTest + * @run junit/othervm -Djdk.serialFilter=java.** * -Dexpected-jdk.serialFilter=java.** GlobalFilterTest * @summary Test Global Filters */ -@Test public class GlobalFilterTest { private static final String serialPropName = "jdk.serialFilter"; private static final String badSerialFilter = "java.lang.StringBuffer;!*"; private static final String origSerialFilterProperty = System.setProperty(serialPropName, badSerialFilter); + private static final String EXPECTED_GLOBAL_FILTER = System.getProperty("expected-" + serialPropName, + Security.getProperty(serialPropName)); + + static boolean hasGlobalFilter() { + return EXPECTED_GLOBAL_FILTER != null && !EXPECTED_GLOBAL_FILTER.isEmpty(); + } + /** * DataProvider of patterns and objects derived from the configured process-wide filter. * @return Array of arrays of pattern, object, allowed boolean, and API factory */ - @DataProvider(name="globalPatternElements") - Object[][] globalPatternElements() { - String globalFilter = - System.getProperty("expected-" + serialPropName, - Security.getProperty(serialPropName)); - if (globalFilter == null) { - return new Object[0][]; - } + static Object[][] globalPatternElements() { - String[] patterns = globalFilter.split(";"); + String[] patterns = EXPECTED_GLOBAL_FILTER.split(";"); Object[][] objects = new Object[patterns.length][]; for (int i = 0; i < patterns.length; i++) { @@ -83,7 +83,7 @@ public class GlobalFilterTest { ? SerialFilterTest.genTestObject(pattern, true) : SerialFilterTest.genTestObject(pattern.substring(1), false); - Assert.assertNotNull(o, "fail generation failed"); + Assertions.assertNotNull(o, "fail generation failed"); } objects[i] = new Object[3]; objects[i][0] = pattern; @@ -98,13 +98,13 @@ public class GlobalFilterTest { * and has the toString matching the configured pattern. */ @Test() - static void globalFilter() { + void globalFilter() { ObjectInputFilter filter = ObjectInputFilter.Config.getSerialFilter(); // Check that the System.setProperty(jdk.serialFilter) DOES NOT affect the filter. String asSetSystemProp = System.getProperty(serialPropName, Security.getProperty(serialPropName)); - Assert.assertNotEquals(Objects.toString(filter, null), asSetSystemProp, + Assertions.assertNotEquals(asSetSystemProp, Objects.toString(filter, null), "System.setProperty(\"jdk.serialfilter\", ...) should not change filter: " + asSetSystemProp); @@ -112,7 +112,7 @@ public class GlobalFilterTest { System.getProperty("expected-" + serialPropName, Security.getProperty(serialPropName)); System.out.printf("global pattern: %s, filter: %s%n", pattern, filter); - Assert.assertEquals(Objects.toString(filter, null), pattern, + assertEquals(pattern, Objects.toString(filter, null), "process-wide filter pattern does not match"); } @@ -120,16 +120,15 @@ public class GlobalFilterTest { * If the Global filter is already set, it should always refuse to be * set again. */ - @Test() - @SuppressWarnings("removal") - static void setGlobalFilter() { + @Test + void setGlobalFilter() { ObjectInputFilter filter = new SerialFilterTest.Validator(); ObjectInputFilter global = ObjectInputFilter.Config.getSerialFilter(); if (global != null) { // once set, can never be re-set try { ObjectInputFilter.Config.setSerialFilter(filter); - Assert.fail("set only once process-wide filter"); + Assertions.fail("set only once process-wide filter"); } catch (IllegalStateException ise) { // Normal, once set can never be re-set } @@ -141,7 +140,7 @@ public class GlobalFilterTest { try { // Try to set it again, expecting it to throw ObjectInputFilter.Config.setSerialFilter(filter); - Assert.fail("set only once process-wide filter"); + Assertions.fail("set only once process-wide filter"); } catch (IllegalStateException ise) { // Normal case } @@ -154,8 +153,10 @@ public class GlobalFilterTest { * * @param pattern a pattern extracted from the configured global pattern */ - @Test(dataProvider = "globalPatternElements") - static void globalFilterElements(String pattern, boolean allowed,Object obj) { + @ParameterizedTest + @EnabledIf("hasGlobalFilter") + @MethodSource("globalPatternElements") + void globalFilterElements(String pattern, boolean allowed,Object obj) { testGlobalPattern(pattern, obj, allowed); } @@ -177,15 +178,15 @@ public class GlobalFilterTest { } catch (EOFException eof) { // normal completion } catch (ClassNotFoundException cnf) { - Assert.fail("Deserializing", cnf); + Assertions.fail("Deserializing", cnf); } - Assert.assertTrue(allowed, "filter should have thrown an exception"); + assertTrue(allowed, "filter should have thrown an exception"); } catch (IllegalArgumentException iae) { - Assert.fail("bad format pattern", iae); + Assertions.fail("bad format pattern", iae); } catch (InvalidClassException ice) { - Assert.assertFalse(allowed, "filter should not have thrown an exception: " + ice); + Assertions.assertFalse(allowed, "filter should not have thrown an exception: " + ice); } catch (IOException ioe) { - Assert.fail("Unexpected IOException", ioe); + Assertions.fail("Unexpected IOException", ioe); } } } diff --git a/test/jdk/java/io/Serializable/serialFilter/InvalidGlobalFilterTest.java b/test/jdk/java/io/Serializable/serialFilter/InvalidGlobalFilterTest.java index a017354b103..b924a96c86c 100644 --- a/test/jdk/java/io/Serializable/serialFilter/InvalidGlobalFilterTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/InvalidGlobalFilterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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,9 +21,6 @@ * questions. */ -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -31,18 +28,22 @@ import java.io.ObjectInputFilter; import java.io.ObjectInputStream; import java.util.Map; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.function.Executable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + /* * @test * @bug 8278087 * @summary Test that an invalid pattern value for the jdk.serialFilter system property causes an * exception to be thrown when an attempt is made to use the filter or deserialize. * A subset of invalid filter patterns is tested. - * @run testng/othervm -Djdk.serialFilter=.* InvalidGlobalFilterTest - * @run testng/othervm -Djdk.serialFilter=! InvalidGlobalFilterTest - * @run testng/othervm -Djdk.serialFilter=/ InvalidGlobalFilterTest + * @run junit/othervm -Djdk.serialFilter=.* InvalidGlobalFilterTest + * @run junit/othervm -Djdk.serialFilter=! InvalidGlobalFilterTest + * @run junit/othervm -Djdk.serialFilter=/ InvalidGlobalFilterTest * */ -@Test public class InvalidGlobalFilterTest { private static final String serialPropName = "jdk.serialFilter"; private static final String serialFilter = System.getProperty(serialPropName); @@ -64,13 +65,13 @@ public class InvalidGlobalFilterTest { "java.base/", "Invalid jdk.serialFilter: class or package missing in: \"java.base/\"", "/", "Invalid jdk.serialFilter: module name is missing in: \"/\""); - @DataProvider(name = "MethodsToCall") - private Object[][] cases() { + // Test cases for exceptions + private static Object[][] cases() { return new Object[][] { - {serialFilter, "getSerialFilter", (Assert.ThrowingRunnable) () -> ObjectInputFilter.Config.getSerialFilter()}, - {serialFilter, "setSerialFilter", (Assert.ThrowingRunnable) () -> ObjectInputFilter.Config.setSerialFilter(new NoopFilter())}, - {serialFilter, "new ObjectInputStream(is)", (Assert.ThrowingRunnable) () -> new ObjectInputStream(new ByteArrayInputStream(new byte[0]))}, - {serialFilter, "new OISSubclass()", (Assert.ThrowingRunnable) () -> new OISSubclass()}, + {serialFilter, "getSerialFilter", (Executable) () -> ObjectInputFilter.Config.getSerialFilter()}, + {serialFilter, "setSerialFilter", (Executable) () -> ObjectInputFilter.Config.setSerialFilter(new NoopFilter())}, + {serialFilter, "new ObjectInputStream(is)", (Executable) () -> new ObjectInputStream(new ByteArrayInputStream(new byte[0]))}, + {serialFilter, "new OISSubclass()", (Executable) () -> new OISSubclass()}, }; } @@ -78,18 +79,19 @@ public class InvalidGlobalFilterTest { * Test each method that should throw IllegalStateException based on * the invalid arguments it was launched with. */ - @Test(dataProvider = "MethodsToCall") - public void initFaultTest(String pattern, String method, Assert.ThrowingRunnable runnable) { + @ParameterizedTest + @MethodSource("cases") + public void initFaultTest(String pattern, String method, Executable runnable) { - IllegalStateException ex = Assert.expectThrows(IllegalStateException.class, + IllegalStateException ex = Assertions.assertThrows(IllegalStateException.class, runnable); String expected = invalidMessages.get(serialFilter); if (expected == null) { - Assert.fail("No expected message for filter: " + serialFilter); + Assertions.fail("No expected message for filter: " + serialFilter); } System.out.println(ex.getMessage()); - Assert.assertEquals(ex.getMessage(), expected, "wrong message"); + Assertions.assertEquals(expected, ex.getMessage(), "wrong message"); } private static class NoopFilter implements ObjectInputFilter { diff --git a/test/jdk/java/io/Serializable/serialFilter/MixedFiltersTest.java b/test/jdk/java/io/Serializable/serialFilter/MixedFiltersTest.java index 8e24f27f598..5af5f4d15ed 100644 --- a/test/jdk/java/io/Serializable/serialFilter/MixedFiltersTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/MixedFiltersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,21 @@ import java.io.ByteArrayInputStream; import java.io.InvalidClassException; import java.io.ObjectInputFilter; import java.io.ObjectInputStream; +import java.io.Serial; import java.io.Serializable; import java.security.Security; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.condition.DisabledIf; +import org.junit.jupiter.api.condition.EnabledIf; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /* @test * @build MixedFiltersTest SerialFilterTest - * @run testng/othervm -Djdk.serialFilter=!java.**;!java.lang.Long;maxdepth=5;maxarray=5;maxbytes=90;maxrefs=5 MixedFiltersTest - * @run testng/othervm -Djdk.serialFilter=java.**;java.lang.Long;maxdepth=1000;maxarray=1000;maxbytes=1000;maxrefs=1000 MixedFiltersTest + * @run junit/othervm -Djdk.serialFilter=!java.**;!java.lang.Long;maxdepth=5;maxarray=5;maxbytes=90;maxrefs=5 MixedFiltersTest + * @run junit/othervm -Djdk.serialFilter=java.**;java.lang.Long;maxdepth=1000;maxarray=1000;maxbytes=1000;maxrefs=1000 MixedFiltersTest * * @summary Test that when both global filter and specific filter are set, * global filter will not affect specific filter. @@ -46,23 +47,17 @@ import static org.testng.Assert.fail; public class MixedFiltersTest implements Serializable { + @Serial private static final long serialVersionUID = 1234567890L; + private static final String JDK_SERIAL_FILTER = System.getProperty("jdk.serialFilter", + Security.getProperty("jdk.serialFilter")); - boolean globalRejected; - - @BeforeClass - public void setup() { - String pattern = System.getProperty("jdk.serialFilter", - Security.getProperty("jdk.serialFilter")); - globalRejected = pattern.startsWith("!"); + private static boolean globalRejected() { + return JDK_SERIAL_FILTER.startsWith("!"); } - @DataProvider(name="RejectedInGlobal") - Object[][] rejectedInGlobal() { - if (!globalRejected) { - return new Object[0][]; - } + static Object[][] rejectedInGlobal() { return new Object[][] { new Object[] { Long.MAX_VALUE, "java.**" }, new Object[] { Long.MAX_VALUE, "java.lang.Long" }, @@ -79,7 +74,9 @@ public class MixedFiltersTest implements Serializable { * "global filter reject" + "specific ObjectInputStream filter is empty" => should reject * "global filter reject" + "specific ObjectInputStream filter allow" => should allow */ - @Test(dataProvider="RejectedInGlobal") + @ParameterizedTest + @EnabledIf("globalRejected") + @MethodSource("rejectedInGlobal") public void testRejectedInGlobal(Object toDeserialized, String pattern) throws Exception { byte[] bytes = SerialFilterTest.writeObjects(toDeserialized); try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes); @@ -96,12 +93,7 @@ public class MixedFiltersTest implements Serializable { } } - @DataProvider(name="AllowedInGlobal") - Object[][] allowedInGlobal() { - if (globalRejected) { - return new Object[0][]; - } - + static Object[][] allowedInGlobal() { return new Object[][] { new Object[] { Long.MAX_VALUE, "!java.**" }, new Object[] { Long.MAX_VALUE, "!java.lang.Long" }, @@ -118,7 +110,9 @@ public class MixedFiltersTest implements Serializable { * "global filter allow" + "specific ObjectInputStream filter is empty" => should allow * "global filter allow" + "specific ObjectInputStream filter reject" => should reject */ - @Test(dataProvider="AllowedInGlobal") + @ParameterizedTest + @DisabledIf("globalRejected") + @MethodSource("allowedInGlobal") public void testAllowedInGlobal(Object toDeserialized, String pattern) throws Exception { byte[] bytes = SerialFilterTest.writeObjects(toDeserialized); try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes); diff --git a/test/jdk/java/io/Serializable/serialFilter/SerialFactoryExample.java b/test/jdk/java/io/Serializable/serialFilter/SerialFactoryExample.java index 45b1872bae0..271c22b917c 100644 --- a/test/jdk/java/io/Serializable/serialFilter/SerialFactoryExample.java +++ b/test/jdk/java/io/Serializable/serialFilter/SerialFactoryExample.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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,10 +21,6 @@ * questions. */ -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -46,9 +42,13 @@ import static java.io.ObjectInputFilter.Status.ALLOWED; import static java.io.ObjectInputFilter.Status.REJECTED; import static java.io.ObjectInputFilter.Status.UNDECIDED; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + /* @test - * @run testng/othervm SerialFactoryExample - * @run testng/othervm -Djdk.serialFilterFactory=SerialFactoryExample$FilterInThread SerialFactoryExample + * @run junit/othervm SerialFactoryExample + * @run junit/othervm -Djdk.serialFilterFactory=SerialFactoryExample$FilterInThread SerialFactoryExample * @summary Test SerialFactoryExample */ @@ -76,10 +76,9 @@ import static java.io.ObjectInputFilter.Status.UNDECIDED; * * The `doWithSerialFilter` calls can be nested. When nested, the filters are concatenated. */ -@Test public class SerialFactoryExample { - @DataProvider(name = "Examples") + // Test cases for filters static Object[][] examples() { return new Object[][]{ {new Point(1, 2), null, @@ -108,7 +107,8 @@ public class SerialFactoryExample { } - @Test(dataProvider = "Examples") + @ParameterizedTest + @MethodSource("examples") void examples(Serializable obj, ObjectInputFilter filter, Status expected) { // Establish FilterInThread as the application-wide filter factory FilterInThread filterInThread; @@ -128,11 +128,11 @@ public class SerialFactoryExample { Object o = deserializeObject(bytes); }); if (expected.equals(REJECTED)) - Assert.fail("IllegalClassException should have occurred"); + Assertions.fail("IllegalClassException should have occurred"); } catch (UncheckedIOException uioe) { IOException ioe = uioe.getCause(); - Assert.assertEquals(ioe.getClass(), InvalidClassException.class, "Wrong exception"); - Assert.assertEquals(REJECTED, expected, "Exception should not have occurred"); + Assertions.assertEquals(InvalidClassException.class, ioe.getClass(), "Wrong exception"); + Assertions.assertEquals(expected, REJECTED, "Exception should not have occurred"); } } @@ -142,7 +142,8 @@ public class SerialFactoryExample { * @param filter a filter * @param expected status */ - @Test(dataProvider = "Examples") + @ParameterizedTest + @MethodSource("examples") void checkStatus(Serializable obj, ObjectInputFilter filter, Status expected) { // Establish FilterInThread as the application-wide filter factory FilterInThread filterInThread; @@ -166,12 +167,12 @@ public class SerialFactoryExample { System.out.println(" filter in effect: " + filterInThread.currFilter); if (compositeFilter != null) { Status actualStatus = compositeFilter.checkInput(info); - Assert.assertEquals(actualStatus, expected, "Wrong Status"); + Assertions.assertEquals(expected, actualStatus, "Wrong Status"); } }); } catch (Exception ex) { - Assert.fail("unexpected exception", ex); + Assertions.fail("unexpected exception", ex); } } diff --git a/test/jdk/java/io/Serializable/serialFilter/SerialFactoryFaults.java b/test/jdk/java/io/Serializable/serialFilter/SerialFactoryFaults.java index 1d35306a426..add9f3557da 100644 --- a/test/jdk/java/io/Serializable/serialFilter/SerialFactoryFaults.java +++ b/test/jdk/java/io/Serializable/serialFilter/SerialFactoryFaults.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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,9 +21,6 @@ * questions. */ -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -32,15 +29,19 @@ import java.io.ObjectInputFilter.Config; import java.io.ObjectInputStream; import java.util.function.BinaryOperator; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.function.Executable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + /* @test - * @run testng/othervm -Djdk.serialFilterFactory=ForcedError_NoSuchClass SerialFactoryFaults - * @run testng/othervm -Djdk.serialFilterFactory=SerialFactoryFaults$NoPublicConstructor SerialFactoryFaults - * @run testng/othervm -Djdk.serialFilterFactory=SerialFactoryFaults$ConstructorThrows SerialFactoryFaults - * @run testng/othervm -Djdk.serialFilterFactory=SerialFactoryFaults$FactorySetsFactory SerialFactoryFaults + * @run junit/othervm -Djdk.serialFilterFactory=ForcedError_NoSuchClass SerialFactoryFaults + * @run junit/othervm -Djdk.serialFilterFactory=SerialFactoryFaults$NoPublicConstructor SerialFactoryFaults + * @run junit/othervm -Djdk.serialFilterFactory=SerialFactoryFaults$ConstructorThrows SerialFactoryFaults + * @run junit/othervm -Djdk.serialFilterFactory=SerialFactoryFaults$FactorySetsFactory SerialFactoryFaults * @summary Check cases where the Filter Factory initialization from properties fails */ -@Test public class SerialFactoryFaults { // Sample the serial factory class name @@ -52,13 +53,13 @@ public class SerialFactoryFaults { System.getProperty("test.src", ".") + "/logging.properties"); } - @DataProvider(name = "MethodsToCall") - private Object[][] cases() { + // Test cases of faults + private static Object[][] cases() { return new Object[][] { - {"getSerialFilterFactory", (Assert.ThrowingRunnable) () -> Config.getSerialFilterFactory()}, - {"setSerialFilterFactory", (Assert.ThrowingRunnable) () -> Config.setSerialFilterFactory(new NoopFactory())}, - {"new ObjectInputStream(is)", (Assert.ThrowingRunnable) () -> new ObjectInputStream(new ByteArrayInputStream(new byte[0]))}, - {"new OISSubclass()", (Assert.ThrowingRunnable) () -> new OISSubclass()}, + {"getSerialFilterFactory", (Executable) () -> Config.getSerialFilterFactory()}, + {"setSerialFilterFactory", (Executable) () -> Config.setSerialFilterFactory(new NoopFactory())}, + {"new ObjectInputStream(is)", (Executable) () -> new ObjectInputStream(new ByteArrayInputStream(new byte[0]))}, + {"new OISSubclass()", (Executable) () -> new OISSubclass()}, }; } @@ -66,26 +67,23 @@ public class SerialFactoryFaults { * Test each method that should throw IllegalStateException based on * the invalid arguments it was launched with. */ - @Test(dataProvider = "MethodsToCall") - public void initFaultTest(String name, Assert.ThrowingRunnable runnable) { - IllegalStateException ex = Assert.expectThrows(IllegalStateException.class, + @ParameterizedTest + @MethodSource("cases") + public void initFaultTest(String name, Executable runnable) { + IllegalStateException ex = Assertions.assertThrows(IllegalStateException.class, runnable); final String msg = ex.getMessage(); if (factoryName.equals("ForcedError_NoSuchClass")) { - Assert.assertEquals(msg, - "invalid jdk.serialFilterFactory: ForcedError_NoSuchClass: java.lang.ClassNotFoundException: ForcedError_NoSuchClass", "wrong exception"); + Assertions.assertEquals("invalid jdk.serialFilterFactory: ForcedError_NoSuchClass: java.lang.ClassNotFoundException: ForcedError_NoSuchClass", msg, "wrong exception"); } else if (factoryName.equals("SerialFactoryFaults$NoPublicConstructor")) { - Assert.assertEquals(msg, - "invalid jdk.serialFilterFactory: SerialFactoryFaults$NoPublicConstructor: java.lang.NoSuchMethodException: SerialFactoryFaults$NoPublicConstructor.()", "wrong exception"); + Assertions.assertEquals("invalid jdk.serialFilterFactory: SerialFactoryFaults$NoPublicConstructor: java.lang.NoSuchMethodException: SerialFactoryFaults$NoPublicConstructor.()", msg, "wrong exception"); } else if (factoryName.equals("SerialFactoryFaults$ConstructorThrows")) { - Assert.assertEquals(msg, - "invalid jdk.serialFilterFactory: SerialFactoryFaults$ConstructorThrows: java.lang.RuntimeException: constructor throwing a runtime exception", "wrong exception"); + Assertions.assertEquals("invalid jdk.serialFilterFactory: SerialFactoryFaults$ConstructorThrows: java.lang.RuntimeException: constructor throwing a runtime exception", msg, "wrong exception"); } else if (factoryName.equals("SerialFactoryFaults$FactorySetsFactory")) { - Assert.assertEquals(msg, - "invalid jdk.serialFilterFactory: SerialFactoryFaults$FactorySetsFactory: java.lang.IllegalStateException: Serial filter factory initialization incomplete", "wrong exception"); + Assertions.assertEquals("invalid jdk.serialFilterFactory: SerialFactoryFaults$FactorySetsFactory: java.lang.IllegalStateException: Serial filter factory initialization incomplete", msg, "wrong exception"); } else { - Assert.fail("No test for filter factory: " + factoryName); + Assertions.fail("No test for filter factory: " + factoryName); } } diff --git a/test/jdk/java/io/Serializable/serialFilter/SerialFilterFactoryTest.java b/test/jdk/java/io/Serializable/serialFilter/SerialFilterFactoryTest.java index 6842eabe9b0..f34f95a72b3 100644 --- a/test/jdk/java/io/Serializable/serialFilter/SerialFilterFactoryTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/SerialFilterFactoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,6 @@ */ -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -38,17 +35,26 @@ import java.io.Serial; import java.io.Serializable; import java.util.function.BinaryOperator; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.condition.EnabledIf; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + /* @test * @build SerialFilterFactoryTest - * @run testng/othervm SerialFilterFactoryTest - * @run testng/othervm -Djdk.serialFilterFactory=SerialFilterFactoryTest$PropertyFilterFactory + * @run junit/othervm SerialFilterFactoryTest + * @run junit/othervm -Djdk.serialFilterFactory=SerialFilterFactoryTest$PropertyFilterFactory * -Djava.util.logging.config.file=${test.src}/logging.properties SerialFilterFactoryTest - * @run testng/othervm -Djdk.serialFilterFactory=SerialFilterFactoryTest$NotMyFilterFactory + * @run junit/othervm -Djdk.serialFilterFactory=SerialFilterFactoryTest$NotMyFilterFactory * -Djava.util.logging.config.file=${test.src}/logging.properties SerialFilterFactoryTest * * @summary Test Context-specific Deserialization Filters */ -@Test +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class SerialFilterFactoryTest { // A stream with just the header, enough to create a OIS @@ -70,7 +76,7 @@ public class SerialFilterFactoryTest { ois.writeObject(new Dummy("Here")); return boas.toByteArray(); } catch (IOException ioe) { - Assert.fail("unexpected IOE", ioe); + Assertions.fail("unexpected IOE", ioe); } throw new RuntimeException("should not reach here"); } @@ -109,7 +115,7 @@ public class SerialFilterFactoryTest { return !(ObjectInputFilter.Config.getSerialFilterFactory() instanceof NotMyFilterFactory); } - @DataProvider(name="FilterCases") + // Test cases for filter factory static Object[][] filterCases() { if (isValidFilterFactory()) { return new Object[][]{ @@ -124,9 +130,11 @@ public class SerialFilterFactoryTest { } // Setting the filter factory to null is not allowed. - @Test(expectedExceptions=NullPointerException.class) + @Test void testNull() { - Config.setSerialFilterFactory(null); + Assertions.assertThrows(NullPointerException.class, () -> { + Config.setSerialFilterFactory(null); + }); } /** @@ -136,7 +144,6 @@ public class SerialFilterFactoryTest { * Try to set it again, the second should throw. */ @Test - @SuppressWarnings("removal") void testSecondSetShouldThrow() { var currFF = Config.getSerialFilterFactory(); if (currFF.getClass().getClassLoader() == null) { @@ -145,14 +152,14 @@ public class SerialFilterFactoryTest { Config.setSerialFilterFactory(contextFilterFactory); currFF = contextFilterFactory; } catch (IllegalStateException ise) { - Assert.fail("First setSerialFilterFactory should not throw"); + Assertions.fail("First setSerialFilterFactory should not throw"); } } // Setting it again will throw - Assert.expectThrows(IllegalStateException.class, + Assertions.assertThrows(IllegalStateException.class, () -> Config.setSerialFilterFactory(new MyFilterFactory("f11"))); var resetFF = Config.getSerialFilterFactory(); - Assert.assertEquals(resetFF, currFF, "Setting again should not change filter factory"); + Assertions.assertEquals(currFF, resetFF, "Setting again should not change filter factory"); } /** @@ -167,8 +174,10 @@ public class SerialFilterFactoryTest { * @throws IOException if an I/O error occurs (should not occur) * @throws ClassNotFoundException for class not found (should not occur) */ - @Test(dataProvider="FilterCases") - @SuppressWarnings("removal") + @ParameterizedTest + @EnabledIf("isValidFilterFactory") + @MethodSource("filterCases") + @Order(1) void testCase(MyFilterFactory dynFilterFactory, Validator dynFilter, Validator streamFilter) throws IOException, ClassNotFoundException { @@ -182,32 +191,32 @@ public class SerialFilterFactoryTest { InputStream is = new ByteArrayInputStream(simpleStream); ObjectInputStream ois = new ObjectInputStream(is); - Assert.assertNull(factory.current(), "initially current should be null"); - Assert.assertEquals(factory.next(), configFilter, "initially next should be the configured filter"); + Assertions.assertNull(factory.current(), "initially current should be null"); + Assertions.assertEquals(configFilter, factory.next(), "initially next should be the configured filter"); var currFilter = ois.getObjectInputFilter(); if (currFilter != null && currFilter.getClass().getClassLoader() == null) { // Builtin loader; defaults to configured filter - Assert.assertEquals(currFilter, configFilter, "getObjectInputFilter should be configured filter"); + Assertions.assertEquals(configFilter, currFilter, "getObjectInputFilter should be configured filter"); } else { - Assert.assertEquals(currFilter, configFilter, "getObjectInputFilter should be null"); + Assertions.assertEquals(configFilter, currFilter, "getObjectInputFilter should be null"); } if (streamFilter != null) { ois.setObjectInputFilter(streamFilter); // MyFilterFactory is called when the stream filter is changed; verify values passed it - Assert.assertEquals(factory.current(), currFilter, "when setObjectInputFilter, current should be current filter"); - Assert.assertEquals(factory.next(), streamFilter, "next should be stream specific filter"); + Assertions.assertEquals(currFilter, factory.current(), "when setObjectInputFilter, current should be current filter"); + Assertions.assertEquals(streamFilter, factory.next(), "next should be stream specific filter"); // Check the OIS filter after the factory has updated it. currFilter = ois.getObjectInputFilter(); - Assert.assertEquals(currFilter, streamFilter, "getObjectInputFilter should be set"); + Assertions.assertEquals(streamFilter, currFilter, "getObjectInputFilter should be set"); // Verify that it can not be set again - Assert.assertThrows(IllegalStateException.class, () -> ois.setObjectInputFilter(streamFilter)); + Assertions.assertThrows(IllegalStateException.class, () -> ois.setObjectInputFilter(streamFilter)); } if (currFilter instanceof Validator validator) { validator.reset(); Object o = ois.readObject(); // Invoke only for the side effect of calling the Filter - Assert.assertEquals(validator.count, 1, "Wrong number of calls to the stream filter"); + Assertions.assertEquals(1, validator.count, "Wrong number of calls to the stream filter"); } else { Object o = ois.readObject(); // Invoke only for the side effect of calling the filter } @@ -217,18 +226,19 @@ public class SerialFilterFactoryTest { @Test void testPropertyFilterFactory() { if (jdkSerialFilterFactoryProp != null) { - Assert.assertEquals(jdkSerialFilterFactory.getClass().getName(), jdkSerialFilterFactoryProp, + Assertions.assertEquals(jdkSerialFilterFactoryProp, jdkSerialFilterFactory.getClass().getName(), "jdk.serialFilterFactory property classname mismatch"); } } // Test that setting the filter factory after any deserialization (any testCase) // throws IllegalStateException with the specific message - @Test(dependsOnMethods="testCase") + @Test + @Order(99) void testSetFactoryAfterDeserialization() { BinaryOperator factory = Config.getSerialFilterFactory(); - IllegalStateException ise = Assert.expectThrows(IllegalStateException.class, () -> Config.setSerialFilterFactory(factory)); - Assert.assertTrue(ise.getMessage().startsWith("Cannot replace filter factory: ")); + IllegalStateException ise = Assertions.assertThrows(IllegalStateException.class, () -> Config.setSerialFilterFactory(factory)); + Assertions.assertTrue(ise.getMessage().startsWith("Cannot replace filter factory: ")); } @@ -243,11 +253,11 @@ public class SerialFilterFactoryTest { // Try to set the filter to null ois.setObjectInputFilter(null); if (curr != null) { - Assert.fail("setting filter to null after a non-null filter should throw"); + Assertions.fail("setting filter to null after a non-null filter should throw"); } } catch (IllegalStateException ise) { if (curr == null) { - Assert.fail("setting filter to null after a null filter should not throw"); + Assertions.fail("setting filter to null after a null filter should not throw"); } } } diff --git a/test/jdk/java/io/Serializable/serialFilter/SerialFilterFunctionTest.java b/test/jdk/java/io/Serializable/serialFilter/SerialFilterFunctionTest.java index 41832d583c2..8930c2dfa9d 100644 --- a/test/jdk/java/io/Serializable/serialFilter/SerialFilterFunctionTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/SerialFilterFunctionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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,11 +21,6 @@ * questions. */ - -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.io.ObjectInputFilter; import java.io.ObjectInputFilter.FilterInfo; import java.util.function.Predicate; @@ -35,12 +30,16 @@ import static java.io.ObjectInputFilter.Status.ALLOWED; import static java.io.ObjectInputFilter.Status.REJECTED; import static java.io.ObjectInputFilter.Status.UNDECIDED; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + /* @test - * @run testng/othervm -Djava.util.logging.config.file=${test.src}/logging.properties + * @run junit/othervm -Djava.util.logging.config.file=${test.src}/logging.properties * SerialFilterFunctionTest * @summary ObjectInputFilter.Config Function Tests */ -@Test public class SerialFilterFunctionTest { @Test @@ -53,10 +52,10 @@ public class SerialFilterFunctionTest { ObjectInputFilter filter2 = getFilter(st2); ObjectInputFilter f = ObjectInputFilter.merge(filter1, filter2); Status r = f.checkInput(info); - Assert.assertEquals(merge(st1, st2), r, "merge"); + Assertions.assertEquals(r, merge(st1, st2), "merge"); } - Assert.assertSame(ObjectInputFilter.merge(filter1, null), filter1, "merge with null fail"); - Assert.assertThrows(NullPointerException.class, () -> ObjectInputFilter.merge(null, filter1)); + Assertions.assertSame(ObjectInputFilter.merge(filter1, null), filter1, "merge with null fail"); + Assertions.assertThrows(NullPointerException.class, () -> ObjectInputFilter.merge(null, filter1)); } } @@ -84,7 +83,7 @@ public class SerialFilterFunctionTest { return (cl) -> cl.equals(Integer.class); } - @DataProvider(name = "AllowPredicateCases") + // Test cases of filter strings static Object[][] allowPredicateCases() { return new Object[][]{ { Integer.class, isInteger(), REJECTED, ALLOWED}, @@ -95,18 +94,17 @@ public class SerialFilterFunctionTest { }; } - @Test(dataProvider = "AllowPredicateCases") + @ParameterizedTest + @MethodSource("allowPredicateCases") void testAllowPredicates(Class clazz, Predicate> predicate, Status otherStatus, Status expected) { ObjectInputFilter.FilterInfo info = new SerialInfo(clazz); if (predicate == null || expected == null) { - Assert.assertThrows(NullPointerException.class, () -> ObjectInputFilter.allowFilter(predicate, expected)); + Assertions.assertThrows(NullPointerException.class, () -> ObjectInputFilter.allowFilter(predicate, expected)); } else { - Assert.assertEquals(ObjectInputFilter.allowFilter(predicate, otherStatus).checkInput(info), - expected, "Predicate result"); + Assertions.assertEquals( expected, ObjectInputFilter.allowFilter(predicate, otherStatus).checkInput(info), "Predicate result"); } } - @DataProvider(name = "RejectPredicateCases") static Object[][] rejectPredicateCases() { return new Object[][]{ { Integer.class, isInteger(), REJECTED, REJECTED}, @@ -117,14 +115,15 @@ public class SerialFilterFunctionTest { }; } - @Test(dataProvider = "RejectPredicateCases") + @ParameterizedTest + @MethodSource("rejectPredicateCases") void testRejectPredicates(Class clazz, Predicate> predicate, Status otherStatus, Status expected) { ObjectInputFilter.FilterInfo info = new SerialInfo(clazz); if (predicate == null || expected == null) { - Assert.assertThrows(NullPointerException.class, () -> ObjectInputFilter.allowFilter(predicate, expected)); + Assertions.assertThrows(NullPointerException.class, () -> ObjectInputFilter.allowFilter(predicate, expected)); } else { - Assert.assertEquals(ObjectInputFilter.rejectFilter(predicate, otherStatus) - .checkInput(info), expected, "Predicate result"); + Assertions.assertEquals(expected, ObjectInputFilter.rejectFilter(predicate, otherStatus) + .checkInput(info), "Predicate result"); } } @@ -133,11 +132,11 @@ public class SerialFilterFunctionTest { FilterInfo info = new SerialInfo(Object.class); // an info structure, unused ObjectInputFilter undecided = getFilter(UNDECIDED); - Assert.assertEquals(ObjectInputFilter.rejectUndecidedClass(undecided).checkInput(info), REJECTED, "undecided -> rejected"); + Assertions.assertEquals(REJECTED, ObjectInputFilter.rejectUndecidedClass(undecided).checkInput(info), "undecided -> rejected"); ObjectInputFilter allowed = getFilter(ALLOWED); - Assert.assertEquals(ObjectInputFilter.rejectUndecidedClass(allowed).checkInput(info), ALLOWED, "allowed -> rejected"); + Assertions.assertEquals(ALLOWED, ObjectInputFilter.rejectUndecidedClass(allowed).checkInput(info), "allowed -> rejected"); ObjectInputFilter rejected = getFilter(REJECTED); - Assert.assertEquals(ObjectInputFilter.rejectUndecidedClass(rejected).checkInput(info), REJECTED, "rejected -> rejected"); + Assertions.assertEquals(REJECTED, ObjectInputFilter.rejectUndecidedClass(rejected).checkInput(info), "rejected -> rejected"); // Specific cases of Classes the result in allowed, rejected, and undecided status ObjectInputFilter numberFilter = ObjectInputFilter.Config.createFilter("java.lang.Integer;!java.lang.Double"); @@ -164,9 +163,9 @@ public class SerialFilterFunctionTest { while (clazz.isArray()) clazz = clazz.getComponentType(); Status expected = (clazz.isPrimitive()) ? UNDECIDED : REJECTED; - Assert.assertEquals(st, expected, "Wrong status for class: " + obj.getClass()); + Assertions.assertEquals(expected, st, "Wrong status for class: " + obj.getClass()); } else { - Assert.assertEquals(rawSt, st, "raw filter and rejectUndecided filter disagree"); + Assertions.assertEquals(st, rawSt, "raw filter and rejectUndecided filter disagree"); } } } diff --git a/test/jdk/java/io/Serializable/serialFilter/SerialFilterTest.java b/test/jdk/java/io/Serializable/serialFilter/SerialFilterTest.java index fb02cd02268..3b2ecc3d1b1 100644 --- a/test/jdk/java/io/Serializable/serialFilter/SerialFilterTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/SerialFilterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,20 +46,20 @@ import java.util.concurrent.atomic.LongAdder; import javax.net.ssl.SSLEngineResult; -import org.testng.Assert; -import org.testng.annotations.Test; -import org.testng.annotations.DataProvider; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /* @test * @bug 8234836 * @build SerialFilterTest - * @run testng/othervm -Djava.util.logging.config.file=${test.src}/logging.properties + * @run junit/othervm -Djava.util.logging.config.file=${test.src}/logging.properties * SerialFilterTest - * @run testng/othervm -Djdk.serialSetFilterAfterRead=true SerialFilterTest + * @run junit/othervm -Djdk.serialSetFilterAfterRead=true SerialFilterTest * * @summary Test ObjectInputFilters using Builtin Filter Factory */ -@Test public class SerialFilterTest implements Serializable { @Serial @@ -89,9 +89,8 @@ public class SerialFilterTest implements Serializable { * Expand the patterns into cases for each of the Std and Compatibility APIs. * @return an array of arrays of the parameters including factories */ - @DataProvider(name="Patterns") static Object[][] patterns() { - Object[][] patterns = new Object[][]{ + return new Object[][]{ {"java.util.Hashtable"}, {"java.util.Hash*"}, {"javax.net.ssl.*"}, @@ -105,10 +104,8 @@ public class SerialFilterTest implements Serializable { {"maxbytes=+1024"}, {"java.base/java.util.Hashtable"}, }; - return patterns; } - @DataProvider(name="InvalidPatterns") static Object[][] invalidPatterns() { return new Object [][] { {".*"}, @@ -120,7 +117,6 @@ public class SerialFilterTest implements Serializable { }; } - @DataProvider(name="Limits") static Object[][] limits() { // The numbers are arbitrary > 1 return new Object[][] { @@ -133,7 +129,6 @@ public class SerialFilterTest implements Serializable { }; } - @DataProvider(name="InvalidLimits") static Object[][] invalidLimits() { return new Object[][] { {"maxrefs=-1"}, @@ -157,7 +152,6 @@ public class SerialFilterTest implements Serializable { * available to the filter. * @return Arrays of parameters with objects */ - @DataProvider(name="Objects") static Object[][] objects() { byte[] byteArray = new byte[0]; Object[] objArray = new Object[7]; @@ -168,7 +162,7 @@ public class SerialFilterTest implements Serializable { try { serClass = Class.forName(className); } catch (Exception e) { - Assert.fail("missing class: " + className, e); + Assertions.fail("missing class: " + className, e); } Class[] interfaces = {Runnable.class}; @@ -213,7 +207,6 @@ public class SerialFilterTest implements Serializable { return objects; } - @DataProvider(name="Arrays") static Object[][] arrays() { return new Object[][]{ {new Object[16], 16}, @@ -244,21 +237,22 @@ public class SerialFilterTest implements Serializable { * @param classes the expected (unique) classes * @throws IOException */ - @Test(dataProvider="Objects") + @ParameterizedTest + @MethodSource("objects") void t1(Object object, long count, long maxArray, long maxRefs, long maxDepth, long maxBytes, List> classes) throws IOException { byte[] bytes = writeObjects(object); Validator validator = new Validator(); validate(bytes, validator); - System.out.printf("v: %s%n", validator); + System.err.printf("v: %s%n", validator); - Assert.assertEquals(validator.count, count, "callback count wrong"); - Assert.assertEquals(validator.classes, classes, "classes mismatch"); - Assert.assertEquals(validator.maxArray, maxArray, "maxArray mismatch"); - Assert.assertEquals(validator.maxRefs, maxRefs, "maxRefs wrong"); - Assert.assertEquals(validator.maxDepth, maxDepth, "depth wrong"); - Assert.assertEquals(validator.maxBytes, maxBytes, "maxBytes wrong"); + Assertions.assertEquals(count, validator.count, "callback count wrong"); + Assertions.assertEquals(classes, validator.classes, "classes mismatch"); + Assertions.assertEquals(maxArray, validator.maxArray, "maxArray mismatch"); + Assertions.assertEquals(maxRefs, validator.maxRefs, "maxRefs wrong"); + Assertions.assertEquals(maxDepth, validator.maxDepth, "depth wrong"); + Assertions.assertEquals(maxBytes, validator.maxBytes, "maxBytes wrong"); } /** @@ -269,7 +263,8 @@ public class SerialFilterTest implements Serializable { * * @param pattern a pattern */ - @Test(dataProvider="Patterns") + @ParameterizedTest + @MethodSource("patterns") void testPatterns(String pattern) { evalPattern(pattern, (p, o, neg) -> testPatterns(p, o, neg)); } @@ -297,23 +292,23 @@ public class SerialFilterTest implements Serializable { // Check the initial filter is the global filter; may be null ObjectInputFilter global = ObjectInputFilter.Config.getSerialFilter(); ObjectInputFilter initial = ois.getObjectInputFilter(); - Assert.assertEquals(global, initial, "initial filter should be the global filter"); + Assertions.assertEquals(initial, global, "initial filter should be the global filter"); ois.setObjectInputFilter(validator); Object o = ois.readObject(); try { ois.setObjectInputFilter(validator2); - Assert.fail("Should not be able to set filter twice"); + Assertions.fail("Should not be able to set filter twice"); } catch (IllegalStateException ise) { // success, the exception was expected } } catch (EOFException eof) { - Assert.fail("Should not reach end-of-file", eof); + Assertions.fail("Should not reach end-of-file", eof); } catch (ClassNotFoundException cnf) { - Assert.fail("Deserializing", cnf); + Assertions.fail("Deserializing", cnf); } } catch (IOException ex) { - Assert.fail("Unexpected IOException", ex); + Assertions.fail("Unexpected IOException", ex); } } } @@ -336,7 +331,7 @@ public class SerialFilterTest implements Serializable { try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(bais)) { Object actual1 = toggle ? ois.readObject() : ois.readUnshared(); - Assert.assertEquals(actual1, expected1, "unexpected string"); + Assertions.assertEquals(expected1, actual1, "unexpected string"); // Attempt to set filter ois.setObjectInputFilter(new ObjectInputFilter() { @Override @@ -345,14 +340,14 @@ public class SerialFilterTest implements Serializable { } }); if (!SET_FILTER_AFTER_READ) - Assert.fail("Should not be able to set filter after readObject has been called"); + Assertions.fail("Should not be able to set filter after readObject has been called"); } catch (IllegalStateException ise) { // success, the exception was expected if (SET_FILTER_AFTER_READ) - Assert.fail("With jdk.serialSetFilterAfterRead property set = true; " + + Assertions.fail("With jdk.serialSetFilterAfterRead property set = true; " + "should be able to set the filter after a read"); } catch (EOFException eof) { - Assert.fail("Should not reach end-of-file", eof); + Assertions.fail("Should not reach end-of-file", eof); } } } @@ -362,12 +357,13 @@ public class SerialFilterTest implements Serializable { * that the callback to the filter includes the proper array length. * @throws IOException if an error occurs */ - @Test(dataProvider="Arrays") + @ParameterizedTest + @MethodSource("arrays") void testReadResolveToArray(Object array, int length) throws IOException { ReadResolveToArray object = new ReadResolveToArray(array, length); byte[] bytes = writeObjects(object); Object o = validate(bytes, object); // the object is its own filter - Assert.assertEquals(o.getClass(), array.getClass(), "Filter not called with the array"); + Assertions.assertEquals(array.getClass(), o.getClass(), "Filter not called with the array"); } @@ -379,18 +375,17 @@ public class SerialFilterTest implements Serializable { * @param name the name of the limit to test * @param value a test value */ - @Test(dataProvider="Limits") + @ParameterizedTest + @MethodSource("limits") void testLimits(String name, long value) { Class arrayClass = new int[0].getClass(); String pattern = String.format("%s=%d;%s=%d", name, value, name, value - 1); ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern); - Assert.assertEquals( + Assertions.assertEquals(ObjectInputFilter.Status.REJECTED, filter.checkInput(new FilterValues(arrayClass, value, value, value, value)), - ObjectInputFilter.Status.REJECTED, "last limit value not used: " + filter); - Assert.assertEquals( + Assertions.assertEquals(ObjectInputFilter.Status.UNDECIDED, filter.checkInput(new FilterValues(arrayClass, value-1, value-1, value-1, value-1)), - ObjectInputFilter.Status.UNDECIDED, "last limit value not used: " + filter); } @@ -399,46 +394,36 @@ public class SerialFilterTest implements Serializable { * Construct a filter with the limit, it should throw IllegalArgumentException. * @param pattern a pattern to test */ - @Test(dataProvider="InvalidLimits", expectedExceptions=java.lang.IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("invalidLimits") void testInvalidLimits(String pattern) { - try { - ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern); - } catch (IllegalArgumentException iae) { - System.out.printf(" success exception: %s%n", iae); - throw iae; - } + var iae = Assertions.assertThrows(IllegalArgumentException.class, + () -> ObjectInputFilter.Config.createFilter(pattern)); + System.err.printf(" success exception: %s%n", iae); } /** * Test that returning null from a filter causes deserialization to fail. */ - @Test(expectedExceptions=InvalidClassException.class) + @Test void testNullStatus() throws IOException { - byte[] bytes = writeObjects(0); // an Integer - try { - Object o = validate(bytes, new ObjectInputFilter() { - public ObjectInputFilter.Status checkInput(ObjectInputFilter.FilterInfo f) { - return null; - } - }); - } catch (InvalidClassException ice) { - System.out.printf(" success exception: %s%n", ice); - throw ice; - } + var ice = Assertions.assertThrows(InvalidClassException.class, () -> { + byte[] bytes = writeObjects(0); // an Integer + validate(bytes, f -> null); + }); + System.err.printf(" success exception: %s%n", ice); } /** * Verify that malformed patterns throw IAE. * @param pattern pattern from the data source */ - @Test(dataProvider="InvalidPatterns", expectedExceptions=IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("invalidPatterns") void testInvalidPatterns(String pattern) { - try { - ObjectInputFilter.Config.createFilter(pattern); - } catch (IllegalArgumentException iae) { - System.out.printf(" success exception: %s%n", iae); - throw iae; - } + var iae = Assertions.assertThrows(IllegalArgumentException.class, + () -> ObjectInputFilter.Config.createFilter(pattern)); + System.err.printf(" success exception: %s%n", iae); } /** @@ -447,10 +432,10 @@ public class SerialFilterTest implements Serializable { @Test() void testEmptyPattern() { ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(""); - Assert.assertNull(filter, "empty pattern did not return null"); + Assertions.assertNull(filter, "empty pattern did not return null"); filter = ObjectInputFilter.Config.createFilter(";;;;"); - Assert.assertNull(filter, "pattern with only delimiters did not return null"); + Assertions.assertNull(filter, "pattern with only delimiters did not return null"); } /** @@ -472,7 +457,7 @@ public class SerialFilterTest implements Serializable { } catch (EOFException eof) { // normal completion } catch (ClassNotFoundException cnf) { - Assert.fail("Deserializing", cnf); + Assertions.fail("Deserializing", cnf); } return null; } @@ -514,7 +499,7 @@ public class SerialFilterTest implements Serializable { @Override public ObjectInputFilter.Status checkInput(FilterInfo filter) { Class serialClass = filter.serialClass(); - System.out.printf(" checkInput: class: %s, arrayLen: %d, refs: %d, depth: %d, bytes; %d%n", + System.err.printf(" checkInput: class: %s, arrayLen: %d, refs: %d, depth: %d, bytes; %d%n", serialClass, filter.arrayLength(), filter.references(), filter.depth(), filter.streamBytes()); count++; @@ -561,13 +546,13 @@ public class SerialFilterTest implements Serializable { byte[] bytes = SerialFilterTest.writeObjects(object); ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern); validate(bytes, filter); - Assert.assertTrue(allowed, "filter should have thrown an exception"); + Assertions.assertTrue(allowed, "filter should have thrown an exception"); } catch (IllegalArgumentException iae) { - Assert.fail("bad format pattern", iae); + Assertions.fail("bad format pattern", iae); } catch (InvalidClassException ice) { - Assert.assertFalse(allowed, "filter should not have thrown an exception: " + ice); + Assertions.assertFalse(allowed, "filter should not have thrown an exception: " + ice); } catch (IOException ioe) { - Assert.fail("Unexpected IOException", ioe); + Assertions.fail("Unexpected IOException", ioe); } } @@ -578,12 +563,12 @@ public class SerialFilterTest implements Serializable { */ static void evalPattern(String pattern, TriConsumer action) { Object o = genTestObject(pattern, true); - Assert.assertNotNull(o, "success generation failed"); + Assertions.assertNotNull(o, "success generation failed"); action.accept(pattern, o, true); // Test the negative pattern o = genTestObject(pattern, false); - Assert.assertNotNull(o, "fail generation failed"); + Assertions.assertNotNull(o, "fail generation failed"); String negPattern = pattern.contains("=") ? pattern : "!" + pattern; action.accept(negPattern, o, false); } @@ -616,12 +601,12 @@ public class SerialFilterTest implements Serializable { Constructor cons = clazz.getConstructor(); return cons.newInstance(); } catch (ClassNotFoundException ex) { - Assert.fail("no such class available: " + pattern); + Assertions.fail("no such class available: " + pattern); } catch (InvocationTargetException | NoSuchMethodException | InstantiationException | IllegalAccessException ex1) { - Assert.fail("newInstance: " + ex1); + Assertions.fail("newInstance: " + ex1); } } return null; @@ -661,7 +646,7 @@ public class SerialFilterTest implements Serializable { return new Hashtable(); } } - Assert.fail("Object could not be generated for pattern: " + Assertions.fail("Object could not be generated for pattern: " + pattern + ", allowed: " + allowed); return null; @@ -677,7 +662,7 @@ public class SerialFilterTest implements Serializable { */ static Object genTestLimit(String pattern, boolean allowed) { int ndx = pattern.indexOf('='); - Assert.assertNotEquals(ndx, -1, "missing value in limit"); + Assertions.assertNotEquals(-1, ndx, "missing value in limit"); long value = Long.parseUnsignedLong(pattern.substring(ndx+1)); if (pattern.startsWith("maxdepth=")) { // Return an object with the requested depth (or 1 greater) @@ -703,7 +688,7 @@ public class SerialFilterTest implements Serializable { } else if (pattern.startsWith("maxarray=")) { return allowed ? new int[(int)value] : new int[(int)value+1]; } - Assert.fail("Object could not be generated for pattern: " + Assertions.fail("Object could not be generated for pattern: " + pattern + ", allowed: " + allowed); return null; @@ -736,7 +721,7 @@ public class SerialFilterTest implements Serializable { os.flush(); actualSize = baos.size(); } catch (IOException ie) { - Assert.fail("exception generating stream", ie); + Assertions.fail("exception generating stream", ie); } } while (actualSize != desiredSize); return holder; From 6ad9f4ef6826bb031db7840ba3f689b0bde47775 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Wed, 14 Jan 2026 21:27:34 +0000 Subject: [PATCH 036/328] 8374493: Add missing @Override annotations in "com.sun.java.swing.plaf.motif" package Reviewed-by: tr, prr, aivanov --- .../java/swing/plaf/motif/MotifBorders.java | 21 ++++++++- .../swing/plaf/motif/MotifButtonListener.java | 3 +- .../java/swing/plaf/motif/MotifButtonUI.java | 9 +++- .../plaf/motif/MotifCheckBoxMenuItemUI.java | 13 +++++- .../swing/plaf/motif/MotifCheckBoxUI.java | 5 ++- .../swing/plaf/motif/MotifComboBoxUI.java | 20 ++++++++- .../swing/plaf/motif/MotifDesktopIconUI.java | 32 ++++++++++++- .../swing/plaf/motif/MotifDesktopPaneUI.java | 12 ++++- .../swing/plaf/motif/MotifEditorPaneUI.java | 3 +- .../swing/plaf/motif/MotifFileChooserUI.java | 45 ++++++++++++++++++- .../swing/plaf/motif/MotifIconFactory.java | 17 ++++++- .../motif/MotifInternalFrameTitlePane.java | 38 +++++++++++++++- .../plaf/motif/MotifInternalFrameUI.java | 19 +++++++- .../swing/plaf/motif/MotifLookAndFeel.java | 22 ++++++++- .../swing/plaf/motif/MotifMenuItemUI.java | 13 +++++- .../plaf/motif/MotifMenuMouseListener.java | 6 ++- .../motif/MotifMenuMouseMotionListener.java | 4 +- .../java/swing/plaf/motif/MotifMenuUI.java | 12 ++++- .../swing/plaf/motif/MotifOptionPaneUI.java | 8 +++- .../plaf/motif/MotifPasswordFieldUI.java | 3 +- .../plaf/motif/MotifPopupMenuSeparatorUI.java | 4 +- .../swing/plaf/motif/MotifPopupMenuUI.java | 5 ++- .../motif/MotifRadioButtonMenuItemUI.java | 13 +++++- .../swing/plaf/motif/MotifRadioButtonUI.java | 5 ++- .../plaf/motif/MotifScrollBarButton.java | 7 ++- .../swing/plaf/motif/MotifScrollBarUI.java | 7 ++- .../java/swing/plaf/motif/MotifSliderUI.java | 10 ++++- .../plaf/motif/MotifSplitPaneDivider.java | 8 +++- .../swing/plaf/motif/MotifSplitPaneUI.java | 3 +- .../swing/plaf/motif/MotifTabbedPaneUI.java | 12 ++++- .../swing/plaf/motif/MotifTextAreaUI.java | 3 +- .../swing/plaf/motif/MotifTextFieldUI.java | 3 +- .../swing/plaf/motif/MotifTextPaneUI.java | 3 +- .../java/swing/plaf/motif/MotifTextUI.java | 6 ++- .../swing/plaf/motif/MotifToggleButtonUI.java | 5 ++- .../plaf/motif/MotifTreeCellRenderer.java | 5 ++- .../java/swing/plaf/motif/MotifTreeUI.java | 10 ++++- 37 files changed, 377 insertions(+), 37 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifBorders.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifBorders.java index c61b1258894..6a97dd22d75 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifBorders.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifBorders.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -67,6 +67,7 @@ public class MotifBorders { this.lightShadow = lightShadow; } + @Override public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { g.setColor((isRaised) ? lightShadow : darkShadow); g.drawLine(x, y, x+w-1, y); // top @@ -77,6 +78,7 @@ public class MotifBorders { g.drawLine(x+w-1, y+h-1, x+w-1, y+1); // right } + @Override public Insets getBorderInsets(Component c, Insets insets) { insets.set(1, 1, 1, 1); return insets; @@ -99,6 +101,7 @@ public class MotifBorders { this.focus = focus; } + @Override public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { if (c.hasFocus()) { g.setColor(focus); @@ -109,6 +112,7 @@ public class MotifBorders { } } + @Override public Insets getBorderInsets(Component c, Insets insets) { insets.set(1, 1, 1, 1); return insets; @@ -130,6 +134,7 @@ public class MotifBorders { this.focus = focus; } + @Override public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { boolean isPressed = false; boolean hasFocus = false; @@ -187,6 +192,7 @@ public class MotifBorders { g.drawLine(bx1+1, by2, bx2, by2); } + @Override public Insets getBorderInsets(Component c, Insets insets) { int thickness = (c instanceof JButton && ((JButton)c).isDefaultCapable())? 8 : 2; insets.set(thickness, thickness, thickness, thickness); @@ -202,6 +208,7 @@ public class MotifBorders { super(shadow, highlight, darkShadow, focus); } + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { if (c instanceof AbstractButton) { @@ -223,6 +230,7 @@ public class MotifBorders { } } + @Override public Insets getBorderInsets(Component c, Insets insets) { insets.set(2, 2, 3, 3); return insets; @@ -236,6 +244,7 @@ public class MotifBorders { super(shadow, highlight, darkShadow, focus); } + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { if (!(c instanceof JMenuBar)) { return; @@ -249,6 +258,7 @@ public class MotifBorders { } } + @Override public Insets getBorderInsets(Component c, Insets insets) { insets.set(6, 6, 6, 6); return insets; @@ -297,6 +307,7 @@ public class MotifBorders { return frameShadow; } + @Override public Insets getBorderInsets(Component c, Insets newInsets) { newInsets.set(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE); return newInsets; @@ -424,6 +435,7 @@ public class MotifBorders { * drawTitleBar, drawLeftBorder, drawRightBorder and * drawBottomBorder. */ + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { if (isActiveFrame()) { @@ -487,6 +499,7 @@ public class MotifBorders { /** Draws the InternalFrameBorder's top border. */ + @Override protected boolean drawTopBorder(Component c, Graphics g, int x, int y, int width, int height) { if (super.drawTopBorder(c, g, x, y, width, height) && @@ -506,6 +519,7 @@ public class MotifBorders { /** Draws the InternalFrameBorder's left border. */ + @Override protected boolean drawLeftBorder(Component c, Graphics g, int x, int y, int width, int height) { if (super.drawLeftBorder(c, g, x, y, width, height) && @@ -525,6 +539,7 @@ public class MotifBorders { /** Draws the InternalFrameBorder's right border. */ + @Override protected boolean drawRightBorder(Component c, Graphics g, int x, int y, int width, int height) { if (super.drawRightBorder(c, g, x, y, width, height) && @@ -545,6 +560,7 @@ public class MotifBorders { /** Draws the InternalFrameBorder's bottom border. */ + @Override protected boolean drawBottomBorder(Component c, Graphics g, int x, int y, int width, int height) { if (super.drawBottomBorder(c, g, x, y, width, height) && @@ -567,6 +583,7 @@ public class MotifBorders { } // Returns true if the associated internal frame has focus. + @Override protected boolean isActiveFrame() { return frame.isSelected(); } @@ -667,6 +684,7 @@ public class MotifBorders { * @param width the width of the painted border * @param height the height of the painted border */ + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { if (!(c instanceof JPopupMenu)) { return; @@ -713,6 +731,7 @@ public class MotifBorders { * @param c the component for which this border insets value applies * @param insets the object to be reinitialized */ + @Override public Insets getBorderInsets(Component c, Insets insets) { if (!(c instanceof JPopupMenu)) { return insets; diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonListener.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonListener.java index a1a74f1230f..65754efed0d 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonListener.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -42,6 +42,7 @@ public class MotifButtonListener extends BasicButtonListener { super(b); } + @Override protected void checkOpacity(AbstractButton b) { b.setOpaque( false ); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java index 08017a0b2c8..0e4c2e526ac 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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,6 +74,7 @@ public class MotifButtonUI extends BasicButtonUI { // ******************************** // Create Listeners // ******************************** + @Override protected BasicButtonListener createButtonListener(AbstractButton b){ return new MotifButtonListener(b); } @@ -81,6 +82,7 @@ public class MotifButtonUI extends BasicButtonUI { // ******************************** // Install Defaults // ******************************** + @Override public void installDefaults(AbstractButton b) { super.installDefaults(b); if(!defaults_initialized) { @@ -90,6 +92,7 @@ public class MotifButtonUI extends BasicButtonUI { LookAndFeel.installProperty(b, "opaque", Boolean.FALSE); } + @Override protected void uninstallDefaults(AbstractButton b) { super.uninstallDefaults(b); defaults_initialized = false; @@ -106,12 +109,14 @@ public class MotifButtonUI extends BasicButtonUI { // ******************************** // Paint Methods // ******************************** + @Override public void paint(Graphics g, JComponent c) { fillContentArea( g, (AbstractButton)c , c.getBackground() ); super.paint(g,c); } // Overridden to ensure we don't paint icon over button borders. + @Override protected void paintIcon(Graphics g, JComponent c, Rectangle iconRect) { Shape oldClip = g.getClip(); Rectangle newClip = @@ -127,10 +132,12 @@ public class MotifButtonUI extends BasicButtonUI { g.setClip(oldClip); } + @Override protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, Rectangle textRect, Rectangle iconRect){ // focus painting is handled by the border } + @Override protected void paintButtonPressed(Graphics g, AbstractButton b) { fillContentArea( g, b , selectColor ); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxMenuItemUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxMenuItemUI.java index bcaf72cbe26..17d66a74bad 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxMenuItemUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -50,12 +50,14 @@ public class MotifCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI return new MotifCheckBoxMenuItemUI(); } + @Override protected void installListeners() { super.installListeners(); changeListener = createChangeListener(menuItem); menuItem.addChangeListener(changeListener); } + @Override protected void uninstallListeners() { super.uninstallListeners(); menuItem.removeChangeListener(changeListener); @@ -66,23 +68,28 @@ public class MotifCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI } protected class ChangeHandler implements ChangeListener { + @Override public void stateChanged(ChangeEvent e) { JMenuItem c = (JMenuItem)e.getSource(); LookAndFeel.installProperty(c, "borderPainted", c.isArmed()); } } + @Override protected MouseInputListener createMouseInputListener(JComponent c) { return new MouseInputHandler(); } protected class MouseInputHandler implements MouseInputListener { + @Override public void mouseClicked(MouseEvent e) {} + @Override public void mousePressed(MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); manager.setSelectedPath(getPath()); } + @Override public void mouseReleased(MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); @@ -99,11 +106,15 @@ public class MotifCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI manager.processMouseEvent(e); } } + @Override public void mouseEntered(MouseEvent e) {} + @Override public void mouseExited(MouseEvent e) {} + @Override public void mouseDragged(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } + @Override public void mouseMoved(MouseEvent e) { } } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java index fa06aa6bd02..9e9f0008b07 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -60,6 +60,7 @@ public class MotifCheckBoxUI extends MotifRadioButtonUI { return motifCheckBoxUI; } + @Override public String getPropertyPrefix() { return propertyPrefix; } @@ -67,6 +68,7 @@ public class MotifCheckBoxUI extends MotifRadioButtonUI { // ******************************** // Defaults // ******************************** + @Override public void installDefaults(AbstractButton b) { super.installDefaults(b); if(!defaults_initialized) { @@ -75,6 +77,7 @@ public class MotifCheckBoxUI extends MotifRadioButtonUI { } } + @Override protected void uninstallDefaults(AbstractButton b) { super.uninstallDefaults(b); defaults_initialized = false; diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java index d0cea2ec35b..8a6cb918ae4 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,6 +65,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { return new MotifComboBoxUI(); } + @Override public void installUI(JComponent c) { super.installUI(c); arrowIcon = new MotifComboBoxArrowIcon(UIManager.getColor("controlHighlight"), @@ -72,6 +73,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { UIManager.getColor("control")); } + @Override public Dimension getMinimumSize( JComponent c ) { if ( !isMinimumSizeDirty ) { return new Dimension( cachedMinimumSize ); @@ -89,6 +91,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { return size; } + @Override protected ComboPopup createPopup() { return new MotifComboPopup( comboBox ); } @@ -106,10 +109,12 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { /** * Motif combo popup should not track the mouse in the list. */ + @Override public MouseMotionListener createListMouseMotionListener() { return new MouseMotionAdapter() {}; } + @Override public KeyListener createKeyListener() { return super.createKeyListener(); } @@ -121,6 +126,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { } } + @Override protected void installComponents() { if ( comboBox.isEditable() ) { addEditor(); @@ -129,11 +135,13 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { comboBox.add( currentValuePane ); } + @Override protected void uninstallComponents() { removeEditor(); comboBox.removeAll(); } + @Override public void paint(Graphics g, JComponent c) { boolean hasFocus = comboBox.hasFocus(); Rectangle r; @@ -180,6 +188,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { currentValuePane.removeAll(); } + @Override public void paintCurrentValue(Graphics g,Rectangle bounds,boolean hasFocus) { ListCellRenderer renderer = comboBox.getRenderer(); Component c; @@ -226,6 +235,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { return b; } + @Override protected Rectangle rectangleForCurrentValue() { int width = comboBox.getWidth(); int height = comboBox.getHeight(); @@ -251,11 +261,13 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { return arrowIcon.getIconWidth() + (3 * HORIZ_MARGIN) + 2; } + @Override public void configureEditor() { super.configureEditor(); editor.setBackground( UIManager.getColor( "text" ) ); } + @Override protected LayoutManager createLayoutManager() { return new ComboBoxLayoutManager(); } @@ -273,6 +285,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { public ComboBoxLayoutManager() { MotifComboBoxUI.this.super(); } + @Override public void layoutContainer(Container parent) { if ( motifGetEditor() != null ) { Rectangle cvb = rectangleForCurrentValue(); @@ -298,6 +311,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { } + @Override public void paintIcon(Component c, Graphics g, int xo, int yo) { int w = getIconWidth(); int h = getIconHeight(); @@ -322,10 +336,12 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { } + @Override public int getIconWidth() { return 11; } + @Override public int getIconHeight() { return 11; } @@ -336,6 +352,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { * * @since 1.6 */ + @Override protected PropertyChangeListener createPropertyChangeListener() { return new MotifPropertyChangeListener(); } @@ -345,6 +362,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { */ private class MotifPropertyChangeListener extends BasicComboBoxUI.PropertyChangeHandler { + @Override public void propertyChange(PropertyChangeEvent e) { super.propertyChange(e); String propertyName = e.getPropertyName(); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopIconUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopIconUI.java index b71363d1c0e..872d4992d91 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopIconUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopIconUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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,6 +74,7 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI public MotifDesktopIconUI() { } + @Override protected void installDefaults(){ super.installDefaults(); setDefaultIcon(UIManager.getIcon("DesktopIcon.icon")); @@ -94,12 +95,15 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI JLayeredPane.putLayer(desktopIcon, JLayeredPane.getLayer(frame)); } + @Override protected void installComponents(){ } + @Override protected void uninstallComponents(){ } + @Override protected void installListeners(){ super.installListeners(); desktopIconActionListener = createDesktopIconActionListener(); @@ -149,6 +153,7 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI return new DesktopIconMouseListener(); } + @Override protected void uninstallDefaults(){ super.uninstallDefaults(); desktopIcon.setLayout(null); @@ -156,6 +161,7 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI desktopIcon.remove(iconLabel); } + @Override protected void uninstallListeners(){ super.uninstallListeners(); iconButton.removeActionListener(desktopIconActionListener); @@ -163,6 +169,7 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI sysMenuTitlePane.uninstallListeners(); } + @Override public Dimension getMinimumSize(JComponent c) { JInternalFrame iframe = desktopIcon.getInternalFrame(); @@ -180,10 +187,12 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI return new Dimension(w, h); } + @Override public Dimension getPreferredSize(JComponent c) { return getMinimumSize(c); } + @Override public Dimension getMaximumSize(JComponent c){ return getMinimumSize(c); } @@ -213,26 +222,33 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI // Forward mouse events to titlebar for moves. addMouseMotionListener(new MouseMotionListener() { + @Override public void mouseDragged(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseMoved(MouseEvent e) { forwardEventToParent(e); } }); addMouseListener(new MouseListener() { + @Override public void mouseClicked(MouseEvent e) { forwardEventToParent(e); } + @Override public void mousePressed(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseReleased(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseEntered(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseExited(MouseEvent e) { forwardEventToParent(e); } @@ -251,16 +267,19 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI getParent().dispatchEvent(newEvent); } + @Override @SuppressWarnings("deprecation") public boolean isFocusTraversable() { return false; } + @Override public Dimension getMinimumSize() { return new Dimension(defaultIcon.getIconWidth() + 1, LABEL_HEIGHT + LABEL_DIVIDER); } + @Override public Dimension getPreferredSize() { String title = frame.getTitle(); FontMetrics fm = frame.getFontMetrics(defaultTitleFont); @@ -271,6 +290,7 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI return new Dimension(w, LABEL_HEIGHT + LABEL_DIVIDER); } + @Override public void paint(Graphics g) { super.paint(g); @@ -308,28 +328,35 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI this.icon = icon; // Forward mouse events to titlebar for moves. addMouseMotionListener(new MouseMotionListener() { + @Override public void mouseDragged(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseMoved(MouseEvent e) { forwardEventToParent(e); } }); addMouseListener(new MouseListener() { + @Override public void mouseClicked(MouseEvent e) { forwardEventToParent(e); } + @Override public void mousePressed(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseReleased(MouseEvent e) { if (!systemMenu.isShowing()) { forwardEventToParent(e); } } + @Override public void mouseEntered(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseExited(MouseEvent e) { forwardEventToParent(e); } @@ -347,6 +374,7 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI getParent().dispatchEvent(newEvent); } + @Override @SuppressWarnings("deprecation") public boolean isFocusTraversable() { return false; @@ -355,6 +383,7 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI protected class DesktopIconActionListener implements ActionListener { + @Override public void actionPerformed(ActionEvent e){ systemMenu.show(iconButton, 0, getDesktopIcon().getHeight()); } @@ -362,6 +391,7 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI protected class DesktopIconMouseListener extends MouseAdapter { // if we drag or move we should deengage the popup + @Override public void mousePressed(MouseEvent e){ if (e.getClickCount() > 1) { try { diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java index 50563a971da..66f253be8c1 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,6 +59,7 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU public MotifDesktopPaneUI() { } + @Override protected void installDesktopManager() { desktopManager = desktop.getDesktopManager(); if(desktopManager == null) { @@ -75,6 +76,7 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU //////////////////////////////////////////////////////////////////////////////////// @SuppressWarnings("serial") // Superclass is not serializable across versions private static class DragPane extends JComponent { + @Override public void paint(Graphics g) { g.setColor(Color.darkGray); g.drawRect(0, 0, getWidth()-1, getHeight()-1); @@ -92,6 +94,7 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU int iconWidth, iconHeight; // PENDING(klobad) this should be optimized + @Override public void setBoundsForFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) { if(!usingDragPane) { @@ -112,6 +115,7 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU } } + @Override public void beginDraggingFrame(JComponent f) { usingDragPane = false; if(f.getParent() instanceof JLayeredPane) { @@ -125,10 +129,12 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU } } + @Override public void dragFrame(JComponent f, int newX, int newY) { setBoundsForFrame(f, newX, newY, f.getWidth(), f.getHeight()); } + @Override public void endDraggingFrame(JComponent f) { if(usingDragPane) { layeredPaneForDragPane.remove(dragPane); @@ -143,6 +149,7 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU } } + @Override public void beginResizingFrame(JComponent f, int direction) { usingDragPane = false; if(f.getParent() instanceof JLayeredPane) { @@ -157,11 +164,13 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU } } + @Override public void resizeFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) { setBoundsForFrame(f, newX, newY, newWidth, newHeight); } + @Override public void endResizingFrame(JComponent f) { if(usingDragPane) { JLayeredPane p = (JLayeredPane)f.getParent(); @@ -172,6 +181,7 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU } } + @Override public void iconifyFrame(JInternalFrame f) { JInternalFrame.JDesktopIcon icon = f.getDesktopIcon(); Point p = icon.getLocation(); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifEditorPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifEditorPaneUI.java index 3367b36f0fd..e0be55c9be7 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifEditorPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifEditorPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,7 @@ public class MotifEditorPaneUI extends BasicEditorPaneUI { * * @return the caret object */ + @Override protected Caret createCaret() { return MotifTextUI.createCaret(); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java index 7d820930415..10a193b1271 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -141,6 +141,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { super(filechooser); } + @Override public String getFileName() { if(filenameTextField != null) { return filenameTextField.getText(); @@ -149,30 +150,37 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } } + @Override public void setFileName(String filename) { if(filenameTextField != null) { filenameTextField.setText(filename); } } + @Override public String getDirectoryName() { return pathField.getText(); } + @Override public void setDirectoryName(String dirname) { pathField.setText(dirname); } + @Override public void ensureFileIsVisible(JFileChooser fc, File f) { // PENDING(jeff) } + @Override public void rescanCurrentDirectory(JFileChooser fc) { getModel().validateFileCache(); } + @Override public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) { return new PropertyChangeListener() { + @Override public void propertyChange(PropertyChangeEvent e) { String prop = e.getPropertyName(); if(prop.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) { @@ -266,10 +274,12 @@ public class MotifFileChooserUI extends BasicFileChooserUI { return new MotifFileChooserUI((JFileChooser)c); } + @Override public void installUI(JComponent c) { super.installUI(c); } + @Override public void uninstallUI(JComponent c) { c.removePropertyChangeListener(filterComboBoxModel); approveButton.removeActionListener(getApproveSelectionAction()); @@ -277,11 +287,13 @@ public class MotifFileChooserUI extends BasicFileChooserUI { super.uninstallUI(c); } + @Override public void installComponents(JFileChooser fc) { fc.setLayout(new BorderLayout(10, 10)); fc.setAlignmentX(JComponent.CENTER_ALIGNMENT); JPanel interior = new JPanel() { + @Override public Insets getInsets() { return insets; } @@ -305,6 +317,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } JTextField tmp1 = new JTextField(curDirName, 35) { + @Override public Dimension getMaximumSize() { Dimension d = super.getMaximumSize(); d.height = getPreferredSize().height; @@ -340,6 +353,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { leftPanel.add(l); JComboBox tmp2 = new JComboBox() { + @Override public Dimension getMaximumSize() { Dimension d = super.getMaximumSize(); d.height = getPreferredSize().height; @@ -417,6 +431,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { interior.add(fileNameLabel); JTextField tmp3 = new JTextField(35) { + @Override public Dimension getMaximumSize() { Dimension d = super.getMaximumSize(); d.height = getPreferredSize().height; @@ -441,6 +456,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { buttonPanel.add(Box.createGlue()); JButton tmp4 = new JButton(getApproveButtonText(fc)) { + @Override public Dimension getMaximumSize() { return new Dimension(MAX_SIZE.width, this.getPreferredSize().height); } @@ -456,6 +472,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { buttonPanel.add(Box.createGlue()); JButton updateButton = new JButton(updateButtonText) { + @Override public Dimension getMaximumSize() { return new Dimension(MAX_SIZE.width, this.getPreferredSize().height); } @@ -470,6 +487,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { buttonPanel.add(Box.createGlue()); JButton cancelButton = new JButton(cancelButtonText) { + @Override public Dimension getMaximumSize() { return new Dimension(MAX_SIZE.width, this.getPreferredSize().height); } @@ -484,6 +502,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { buttonPanel.add(Box.createGlue()); JButton helpButton = new JButton(helpButtonText) { + @Override public Dimension getMaximumSize() { return new Dimension(MAX_SIZE.width, this.getPreferredSize().height); } @@ -520,6 +539,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } } + @Override public void uninstallComponents(JFileChooser fc) { fc.removeAll(); bottomPanel = null; @@ -528,6 +548,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } } + @Override protected void installStrings(JFileChooser fc) { super.installStrings(fc); @@ -555,11 +576,13 @@ public class MotifFileChooserUI extends BasicFileChooserUI { return SwingUtilities2.getUIDefaultsInt(key, l); } + @Override protected void installIcons(JFileChooser fc) { // Since motif doesn't have button icons, leave this empty // which overrides the supertype icon loading } + @Override protected void uninstallIcons(JFileChooser fc) { // Since motif doesn't have button icons, leave this empty // which overrides the supertype icon loading @@ -580,6 +603,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { fileList.addListSelectionListener(createListSelectionListener(getFileChooser())); fileList.addMouseListener(createDoubleClickListener(getFileChooser(), fileList)); fileList.addMouseListener(new MouseAdapter() { + @Override public void mouseClicked(MouseEvent e) { JFileChooser chooser = getFileChooser(); if (SwingUtilities.isLeftMouseButton(e) && !chooser.isMultiSelectionEnabled()) { @@ -650,6 +674,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { @SuppressWarnings("serial") // Superclass is not serializable across versions protected class FileCellRenderer extends DefaultListCellRenderer { + @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { @@ -665,6 +690,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { @SuppressWarnings("serial") // Superclass is not serializable across versions protected class DirectoryCellRenderer extends DefaultListCellRenderer { + @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { @@ -684,18 +710,22 @@ public class MotifFileChooserUI extends BasicFileChooserUI { getModel().addListDataListener(this); } + @Override public int getSize() { return getModel().getDirectories().size(); } + @Override public File getElementAt(int index) { return getModel().getDirectories().elementAt(index); } + @Override public void intervalAdded(ListDataEvent e) { fireIntervalAdded(this, e.getIndex0(), e.getIndex1()); } + @Override public void intervalRemoved(ListDataEvent e) { fireIntervalRemoved(this, e.getIndex0(), e.getIndex1()); } @@ -709,6 +739,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { // PENDING(jeff) - fire the correct interval changed - currently sending // out that everything has changed + @Override public void contentsChanged(ListDataEvent e) { fireContentsChanged(); } @@ -721,6 +752,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { getModel().addListDataListener(this); } + @Override public int getSize() { return getModel().getFiles().size(); } @@ -733,14 +765,17 @@ public class MotifFileChooserUI extends BasicFileChooserUI { return getModel().getFiles().indexOf(o); } + @Override public File getElementAt(int index) { return getModel().getFiles().elementAt(index); } + @Override public void intervalAdded(ListDataEvent e) { fireIntervalAdded(this, e.getIndex0(), e.getIndex1()); } + @Override public void intervalRemoved(ListDataEvent e) { fireIntervalRemoved(this, e.getIndex0(), e.getIndex1()); } @@ -753,6 +788,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } // PENDING(jeff) - fire the interval changed + @Override public void contentsChanged(ListDataEvent e) { fireContentsChanged(); } @@ -779,6 +815,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { */ @SuppressWarnings("serial") // Superclass is not serializable across versions public class FilterComboBoxRenderer extends DefaultListCellRenderer { + @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { @@ -805,6 +842,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { filters = getFileChooser().getChoosableFileFilters(); } + @Override public void propertyChange(PropertyChangeEvent e) { String prop = e.getPropertyName(); if(prop.equals(JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY)) { @@ -815,6 +853,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } } + @Override public void setSelectedItem(Object filter) { if(filter != null) { getFileChooser().setFileFilter((FileFilter) filter); @@ -822,6 +861,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } } + @Override public Object getSelectedItem() { // Ensure that the current filter is in the list. // NOTE: we shouldn't have to do this, since JFileChooser adds @@ -843,6 +883,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { return getFileChooser().getFileFilter(); } + @Override public int getSize() { if(filters != null) { return filters.length; @@ -851,6 +892,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } } + @Override public FileFilter getElementAt(int index) { if(index > getSize() - 1) { // This shouldn't happen. Try to recover gracefully. @@ -864,6 +906,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } } + @Override protected JButton getApproveButton(JFileChooser fc) { return approveButton; } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java index dac6514f0c4..748c4dc6155 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -93,6 +93,7 @@ public class MotifIconFactory implements Serializable private Color highlight = UIManager.getColor("controlHighlight"); private Color lightShadow = UIManager.getColor("controlLightShadow"); + @Override public void paintIcon(Component c, Graphics g, int x, int y) { AbstractButton b = (AbstractButton) c; ButtonModel model = b.getModel(); @@ -158,10 +159,12 @@ public class MotifIconFactory implements Serializable } } + @Override public int getIconWidth() { return csize; } + @Override public int getIconHeight() { return csize; } @@ -258,6 +261,7 @@ public class MotifIconFactory implements Serializable private Color highlight = UIManager.getColor("controlHighlight"); private Color shadow = UIManager.getColor("controlShadow"); + @Override public void paintIcon(Component c, Graphics g, int x, int y) { // fill interior AbstractButton b = (AbstractButton) c; @@ -303,10 +307,12 @@ public class MotifIconFactory implements Serializable } } + @Override public int getIconWidth() { return 14; } + @Override public int getIconHeight() { return 14; } @@ -315,10 +321,13 @@ public class MotifIconFactory implements Serializable @SuppressWarnings("serial") // Same-version serialization only private static class MenuItemCheckIcon implements Icon, UIResource, Serializable { + @Override public void paintIcon(Component c,Graphics g, int x, int y) { } + @Override public int getIconWidth() { return 0; } + @Override public int getIconHeight() { return 0; } } // end class MenuItemCheckIcon @@ -326,10 +335,13 @@ public class MotifIconFactory implements Serializable @SuppressWarnings("serial") // Same-version serialization only private static class MenuItemArrowIcon implements Icon, UIResource, Serializable { + @Override public void paintIcon(Component c,Graphics g, int x, int y) { } + @Override public int getIconWidth() { return 0; } + @Override public int getIconHeight() { return 0; } } // end class MenuItemArrowIcon @@ -340,6 +352,7 @@ public class MotifIconFactory implements Serializable private Color shadow = UIManager.getColor("controlShadow"); private Color highlight = UIManager.getColor("controlHighlight"); + @Override public void paintIcon(Component c, Graphics g, int x, int y) { AbstractButton b = (AbstractButton) c; ButtonModel model = b.getModel(); @@ -414,7 +427,9 @@ public class MotifIconFactory implements Serializable } } + @Override public int getIconWidth() { return 10; } + @Override public int getIconHeight() { return 10; } } // End class MenuArrowIcon } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameTitlePane.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameTitlePane.java index b68200c1924..474bd707ce4 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameTitlePane.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameTitlePane.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -66,20 +66,24 @@ public class MotifInternalFrameTitlePane super(frame); } + @Override protected void installDefaults() { setFont(UIManager.getFont("InternalFrame.titleFont")); setPreferredSize(new Dimension(100, BUTTON_SIZE)); } + @Override protected void uninstallListeners() { // Get around protected method in superclass super.uninstallListeners(); } + @Override protected PropertyChangeListener createPropertyChangeListener() { return this; } + @Override protected LayoutManager createLayout() { return this; } @@ -88,6 +92,7 @@ public class MotifInternalFrameTitlePane return systemMenu; } + @Override protected void assembleSystemMenu() { systemMenu = new JPopupMenu(); JMenuItem mi = systemMenu.add(restoreAction); @@ -106,12 +111,14 @@ public class MotifInternalFrameTitlePane systemButton = new SystemButton(); systemButton.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { systemMenu.show(systemButton, 0, BUTTON_SIZE); } }); systemButton.addMouseListener(new MouseAdapter() { + @Override public void mousePressed(MouseEvent evt) { try { frame.setSelected(true); @@ -137,6 +144,7 @@ public class MotifInternalFrameTitlePane } } + @Override protected void createButtons() { minimizeButton = new MinimizeButton(); minimizeButton.addActionListener(iconifyAction); @@ -146,6 +154,7 @@ public class MotifInternalFrameTitlePane } + @Override protected void addSubComponents() { title = new Title(frame.getTitle()); title.setFont(getFont()); @@ -156,6 +165,7 @@ public class MotifInternalFrameTitlePane add(maximizeButton); } + @Override public void paintComponent(Graphics g) { } @@ -165,9 +175,11 @@ public class MotifInternalFrameTitlePane shadow = s; } + @Override public void actionPerformed(ActionEvent e) { } + @Override public void propertyChange(PropertyChangeEvent evt) { String prop = evt.getPropertyName(); JInternalFrame f = (JInternalFrame)evt.getSource(); @@ -194,16 +206,21 @@ public class MotifInternalFrameTitlePane enableActions(); } + @Override public void addLayoutComponent(String name, Component c) {} + @Override public void removeLayoutComponent(Component c) {} + @Override public Dimension preferredLayoutSize(Container c) { return minimumLayoutSize(c); } + @Override public Dimension minimumLayoutSize(Container c) { return new Dimension(100, BUTTON_SIZE); } + @Override public void layoutContainer(Container c) { int w = getWidth(); systemButton.setBounds(0, 0, BUTTON_SIZE, BUTTON_SIZE); @@ -226,6 +243,7 @@ public class MotifInternalFrameTitlePane title.setBounds(BUTTON_SIZE, 0, x, BUTTON_SIZE); } + @Override protected void showSystemMenu(){ systemMenu.show(systemButton, 0, BUTTON_SIZE); } @@ -245,23 +263,28 @@ public class MotifInternalFrameTitlePane setBorderPainted(false); } + @Override @SuppressWarnings("deprecation") public boolean isFocusTraversable() { return false; } + @Override public void requestFocus() { // ignore request. } + @Override public Dimension getMinimumSize() { return buttonDimension; } + @Override public Dimension getPreferredSize() { return buttonDimension; } + @Override public void paintComponent(Graphics g) { Dimension d = getSize(); int maxX = d.width - 1; @@ -284,6 +307,7 @@ public class MotifInternalFrameTitlePane @SuppressWarnings("serial") // Superclass is not serializable across versions private class MinimizeButton extends FrameButton { + @Override public void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(highlight); @@ -297,6 +321,7 @@ public class MotifInternalFrameTitlePane @SuppressWarnings("serial") // Superclass is not serializable across versions private class MaximizeButton extends FrameButton { + @Override public void paintComponent(Graphics g) { super.paintComponent(g); int max = BUTTON_SIZE - 5; @@ -312,9 +337,12 @@ public class MotifInternalFrameTitlePane @SuppressWarnings("serial") // Superclass is not serializable across versions private class SystemButton extends FrameButton { + @Override public boolean isFocusTraversable() { return false; } + @Override public void requestFocus() {} + @Override public void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(highlight); @@ -339,26 +367,33 @@ public class MotifInternalFrameTitlePane // Forward mouse events to titlebar for moves. addMouseMotionListener(new MouseMotionListener() { + @Override public void mouseDragged(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseMoved(MouseEvent e) { forwardEventToParent(e); } }); addMouseListener(new MouseListener() { + @Override public void mouseClicked(MouseEvent e) { forwardEventToParent(e); } + @Override public void mousePressed(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseReleased(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseEntered(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseExited(MouseEvent e) { forwardEventToParent(e); } @@ -377,6 +412,7 @@ public class MotifInternalFrameTitlePane getParent().dispatchEvent(newEvent); } + @Override public void paintComponent(Graphics g) { super.paintComponent(g); if (frame.isSelected()) { diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameUI.java index 1179df181ab..678686a9b17 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -81,11 +81,13 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { super(w); } + @Override public void installUI(JComponent c) { super.installUI(c); setColors((JInternalFrame)c); } + @Override protected void installDefaults() { Border frameBorder = frame.getBorder(); frame.setLayout(internalFrameLayout = createLayoutManager()); @@ -95,6 +97,7 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { } + @Override protected void installKeyboardActions(){ super.installKeyboardActions(); // We replace the @@ -103,6 +106,7 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { } + @Override protected void uninstallDefaults() { LookAndFeel.uninstallBorder(frame); frame.setLayout(null); @@ -113,15 +117,18 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { return frame; } + @Override public JComponent createNorthPane(JInternalFrame w) { titlePane = new MotifInternalFrameTitlePane(w); return titlePane; } + @Override public Dimension getMaximumSize(JComponent x) { return Toolkit.getDefaultToolkit().getScreenSize(); } + @Override protected void uninstallKeyboardActions(){ super.uninstallKeyboardActions(); if (isKeyBindingRegistered()){ @@ -132,6 +139,7 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { } } + @Override protected void setupMenuOpenKey(){ super.setupMenuOpenKey(); ActionMap map = SwingUtilities.getUIActionMap(frame); @@ -141,9 +149,11 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { // titlePane ivar in BasicInternalFrameUI, making supers action throw // an NPE for us. map.put("showSystemMenu", new AbstractAction(){ + @Override public void actionPerformed(ActionEvent e){ titlePane.showSystemMenu(); } + @Override public boolean isEnabled(){ return isKeyBindingActive(); } @@ -151,13 +161,16 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { } } + @Override protected void setupMenuCloseKey(){ ActionMap map = SwingUtilities.getUIActionMap(frame); if (map != null) { map.put("hideSystemMenu", new AbstractAction(){ + @Override public void actionPerformed(ActionEvent e){ titlePane.hideSystemMenu(); } + @Override public boolean isEnabled(){ return isKeyBindingActive(); } @@ -184,6 +197,7 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { if (diActionMap == null) { diActionMap = new ActionMapUIResource(); diActionMap.put("hideSystemMenu", new AbstractAction(){ + @Override public void actionPerformed(ActionEvent e){ JInternalFrame.JDesktopIcon icon = getFrame(). getDesktopIcon(); @@ -191,6 +205,7 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { getUI(); micon.hideSystemMenu(); } + @Override public boolean isEnabled(){ return isKeyBindingActive(); } @@ -201,12 +216,14 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { /** This method is called when the frame becomes selected. */ + @Override protected void activateFrame(JInternalFrame f) { super.activateFrame(f); setColors(f); } /** This method is called when the frame is no longer selected. */ + @Override protected void deactivateFrame(JInternalFrame f) { setColors(f); super.deactivateFrame(f); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java index aaeb0243ce7..d254443b8d1 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -56,24 +56,29 @@ import sun.swing.SwingUtilities2; @Deprecated(since="13", forRemoval=true) public class MotifLookAndFeel extends BasicLookAndFeel { + @Override public String getName() { return "CDE/Motif"; } + @Override public String getID() { return "Motif"; } + @Override public String getDescription() { return "The CDE/Motif Look and Feel"; } + @Override public boolean isNativeLookAndFeel() { return false; } + @Override public boolean isSupportedLookAndFeel() { return true; } @@ -87,6 +92,7 @@ public class MotifLookAndFeel extends BasicLookAndFeel * values, otherwise we create color objects whose values match * the default CDE/Motif colors. */ + @Override protected void initSystemColorDefaults(UIDefaults table) { String[] defaultSystemColors = { @@ -123,6 +129,7 @@ public class MotifLookAndFeel extends BasicLookAndFeel } + @Override protected void initClassDefaults(UIDefaults table) { super.initClassDefaults(table); @@ -178,6 +185,7 @@ public class MotifLookAndFeel extends BasicLookAndFeel } + @Override protected void initComponentDefaults(UIDefaults table) { super.initComponentDefaults(table); @@ -255,36 +263,42 @@ public class MotifLookAndFeel extends BasicLookAndFeel )); Object menuItemCheckIcon = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return MotifIconFactory.getMenuItemCheckIcon(); } }; Object menuItemArrowIcon = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return MotifIconFactory.getMenuItemArrowIcon(); } }; Object menuArrowIcon = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return MotifIconFactory.getMenuArrowIcon(); } }; Object checkBoxIcon = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return MotifIconFactory.getCheckBoxIcon(); } }; Object radioButtonIcon = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return MotifIconFactory.getRadioButtonIcon(); } }; Object unselectedTabBackground = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { Color c = table.getColor("control"); return new ColorUIResource(Math.max((int)(c.getRed()*.85),0), @@ -294,6 +308,7 @@ public class MotifLookAndFeel extends BasicLookAndFeel }; Object unselectedTabForeground = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { Color c = table.getColor("controlText"); return new ColorUIResource(Math.max((int)(c.getRed()*.85),0), @@ -303,6 +318,7 @@ public class MotifLookAndFeel extends BasicLookAndFeel }; Object unselectedTabShadow = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { Color c = table.getColor("control"); Color base = new Color(Math.max((int)(c.getRed()*.85),0), @@ -313,6 +329,7 @@ public class MotifLookAndFeel extends BasicLookAndFeel }; Object unselectedTabHighlight = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { Color c = table.getColor("control"); Color base = new Color(Math.max((int)(c.getRed()*.85),0), @@ -462,18 +479,21 @@ public class MotifLookAndFeel extends BasicLookAndFeel "icons/TreeClosed.gif"); Object treeLeafIcon = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return MotifTreeCellRenderer.loadLeafIcon(); } }; Object treeExpandedIcon = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return MotifTreeUI.MotifExpandedIcon.createExpandedIcon(); } }; Object treeCollapsedIcon = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return MotifTreeUI.MotifCollapsedIcon.createCollapsedIcon(); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuItemUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuItemUI.java index 52116aaf588..50ea704c73a 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuItemUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -50,12 +50,14 @@ public class MotifMenuItemUI extends BasicMenuItemUI return new MotifMenuItemUI(); } + @Override protected void installListeners() { super.installListeners(); changeListener = createChangeListener(menuItem); menuItem.addChangeListener(changeListener); } + @Override protected void uninstallListeners() { super.uninstallListeners(); menuItem.removeChangeListener(changeListener); @@ -65,12 +67,14 @@ public class MotifMenuItemUI extends BasicMenuItemUI return new ChangeHandler(); } + @Override protected MouseInputListener createMouseInputListener(JComponent c) { return new MouseInputHandler(); } protected class ChangeHandler implements ChangeListener { + @Override public void stateChanged(ChangeEvent e) { JMenuItem c = (JMenuItem)e.getSource(); LookAndFeel.installProperty(c, "borderPainted", @@ -79,11 +83,14 @@ public class MotifMenuItemUI extends BasicMenuItemUI } protected class MouseInputHandler implements MouseInputListener { + @Override public void mouseClicked(MouseEvent e) {} + @Override public void mousePressed(MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); manager.setSelectedPath(getPath()); } + @Override public void mouseReleased(MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); @@ -97,11 +104,15 @@ public class MotifMenuItemUI extends BasicMenuItemUI manager.processMouseEvent(e); } } + @Override public void mouseEntered(MouseEvent e) {} + @Override public void mouseExited(MouseEvent e) {} + @Override public void mouseDragged(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } + @Override public void mouseMoved(MouseEvent e) { } } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuMouseListener.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuMouseListener.java index 93f4d2c731c..c3f8e7c9ece 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuMouseListener.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuMouseListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -33,15 +33,19 @@ import javax.swing.MenuSelectionManager; * @author Arnaud Weber */ class MotifMenuMouseListener extends MouseAdapter { + @Override public void mousePressed(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } + @Override public void mouseReleased(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } + @Override public void mouseEntered(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } + @Override public void mouseExited(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuMouseMotionListener.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuMouseMotionListener.java index 22fcd908a11..8171ad8934d 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuMouseMotionListener.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuMouseMotionListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -33,10 +33,12 @@ import javax.swing.MenuSelectionManager; * @author Arnaud Weber */ class MotifMenuMouseMotionListener implements MouseMotionListener { + @Override public void mouseDragged(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } + @Override public void mouseMoved(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuUI.java index bcee2e666fa..5bf2b1e0503 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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,6 +61,7 @@ public class MotifMenuUI extends BasicMenuUI // menuItem.removeChangeListener(changeListener); // } + @Override protected ChangeListener createChangeListener(JComponent c) { return new MotifChangeHandler((JMenu)c, this); } @@ -76,6 +77,7 @@ public class MotifMenuUI extends BasicMenuUI return false; } + @Override protected MouseInputListener createMouseInputListener(JComponent c) { return new MouseInputHandler(); } @@ -86,6 +88,7 @@ public class MotifMenuUI extends BasicMenuUI } + @Override public void stateChanged(ChangeEvent e) { JMenuItem c = (JMenuItem)e.getSource(); if (c.isArmed() || c.isSelected()) { @@ -100,7 +103,9 @@ public class MotifMenuUI extends BasicMenuUI } protected class MouseInputHandler implements MouseInputListener { + @Override public void mouseClicked(MouseEvent e) {} + @Override public void mousePressed(MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); JMenu menu = (JMenu)e.getComponent(); @@ -129,6 +134,7 @@ public class MotifMenuUI extends BasicMenuUI } } + @Override public void mouseReleased(MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); @@ -139,11 +145,15 @@ public class MotifMenuUI extends BasicMenuUI manager.processMouseEvent(e); } } + @Override public void mouseEntered(MouseEvent e) {} + @Override public void mouseExited(MouseEvent e) {} + @Override public void mouseDragged(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } + @Override public void mouseMoved(MouseEvent e) { } } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifOptionPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifOptionPaneUI.java index 21e8c0f6747..641d5ec1b99 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifOptionPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifOptionPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -57,6 +57,7 @@ public class MotifOptionPaneUI extends BasicOptionPaneUI * Creates and returns a Container containing the buttons. The buttons * are created by calling getButtons. */ + @Override protected Container createButtonArea() { Container b = super.createButtonArea(); @@ -69,17 +70,21 @@ public class MotifOptionPaneUI extends BasicOptionPaneUI /** * Returns null, CDE/Motif does not impose a minimum size. */ + @Override public Dimension getMinimumOptionPaneSize() { return null; } + @Override protected Container createSeparator() { return new JPanel() { + @Override public Dimension getPreferredSize() { return new Dimension(10, 2); } + @Override public void paint(Graphics g) { int width = getWidth(); g.setColor(Color.darkGray); @@ -95,6 +100,7 @@ public class MotifOptionPaneUI extends BasicOptionPaneUI * getIcon to top. This is messaged from * createMessageArea */ + @Override protected void addIcon(Container top) { /* Create the icon. */ Icon sideIcon = getIcon(); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPasswordFieldUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPasswordFieldUI.java index 8e1369d7e96..b906329d353 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPasswordFieldUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPasswordFieldUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,7 @@ public class MotifPasswordFieldUI extends BasicPasswordFieldUI { * * @return the caret object */ + @Override protected Caret createCaret() { return MotifTextUI.createCaret(); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuSeparatorUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuSeparatorUI.java index 164b3227034..5556695429e 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuSeparatorUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuSeparatorUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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,6 +47,7 @@ public class MotifPopupMenuSeparatorUI extends MotifSeparatorUI return new MotifPopupMenuSeparatorUI(); } + @Override public void paint( Graphics g, JComponent c ) { Dimension s = c.getSize(); @@ -58,6 +59,7 @@ public class MotifPopupMenuSeparatorUI extends MotifSeparatorUI g.drawLine( 0, 1, s.width, 1 ); } + @Override public Dimension getPreferredSize( JComponent c ) { return new Dimension( 0, 2 ); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuUI.java index 0986f81f0ff..6012152905a 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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,6 +61,7 @@ public class MotifPopupMenuUI extends BasicPopupMenuUI { /* This has to deal with the fact that the title may be wider than the widest child component. */ + @Override public Dimension getPreferredSize(JComponent c) { LayoutManager layout = c.getLayout(); Dimension d = layout.preferredLayoutSize(c); @@ -94,10 +95,12 @@ public class MotifPopupMenuUI extends BasicPopupMenuUI { protected ChangeListener createChangeListener(JPopupMenu m) { return new ChangeListener() { + @Override public void stateChanged(ChangeEvent e) {} }; } + @Override @SuppressWarnings("deprecation") public boolean isPopupTrigger(MouseEvent e) { return ((e.getID()==MouseEvent.MOUSE_PRESSED) diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonMenuItemUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonMenuItemUI.java index 1a9d7fa1e91..914c305fa08 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonMenuItemUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,12 +55,14 @@ public class MotifRadioButtonMenuItemUI extends BasicRadioButtonMenuItemUI return new MotifRadioButtonMenuItemUI(); } + @Override protected void installListeners() { super.installListeners(); changeListener = createChangeListener(menuItem); menuItem.addChangeListener(changeListener); } + @Override protected void uninstallListeners() { super.uninstallListeners(); menuItem.removeChangeListener(changeListener); @@ -72,23 +74,28 @@ public class MotifRadioButtonMenuItemUI extends BasicRadioButtonMenuItemUI @SuppressWarnings("serial") // Same-version serialization only protected class ChangeHandler implements ChangeListener, Serializable { + @Override public void stateChanged(ChangeEvent e) { JMenuItem c = (JMenuItem)e.getSource(); LookAndFeel.installProperty(c, "borderPainted", c.isArmed()); } } + @Override protected MouseInputListener createMouseInputListener(JComponent c) { return new MouseInputHandler(); } protected class MouseInputHandler implements MouseInputListener { + @Override public void mouseClicked(MouseEvent e) {} + @Override public void mousePressed(MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); manager.setSelectedPath(getPath()); } + @Override public void mouseReleased(MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); @@ -105,11 +112,15 @@ public class MotifRadioButtonMenuItemUI extends BasicRadioButtonMenuItemUI manager.processMouseEvent(e); } } + @Override public void mouseEntered(MouseEvent e) {} + @Override public void mouseExited(MouseEvent e) {} + @Override public void mouseDragged(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } + @Override public void mouseMoved(MouseEvent e) { } } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java index 58619280493..f9a1dd7bb50 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -68,6 +68,7 @@ public class MotifRadioButtonUI extends BasicRadioButtonUI { // ******************************** // Install Defaults // ******************************** + @Override public void installDefaults(AbstractButton b) { super.installDefaults(b); if(!defaults_initialized) { @@ -76,6 +77,7 @@ public class MotifRadioButtonUI extends BasicRadioButtonUI { } } + @Override protected void uninstallDefaults(AbstractButton b) { super.uninstallDefaults(b); defaults_initialized = false; @@ -92,6 +94,7 @@ public class MotifRadioButtonUI extends BasicRadioButtonUI { // ******************************** // Paint Methods // ******************************** + @Override protected void paintFocus(Graphics g, Rectangle t, Dimension d){ g.setColor(getFocusColor()); g.drawRect(0,0,d.width-1,d.height-1); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java index 5b812ca4c8c..2f5eb9708b3 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -64,6 +64,7 @@ public class MotifScrollBarButton extends BasicArrowButton } + @Override public Dimension getPreferredSize() { switch (direction) { case NORTH: @@ -76,18 +77,22 @@ public class MotifScrollBarButton extends BasicArrowButton } } + @Override public Dimension getMinimumSize() { return getPreferredSize(); } + @Override public Dimension getMaximumSize() { return getPreferredSize(); } + @Override public boolean isFocusTraversable() { return false; } + @Override public void paint(Graphics g) { int w = getWidth(); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarUI.java index 08a283f5e52..48cee86636b 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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,6 +52,7 @@ public class MotifScrollBarUI extends BasicScrollBarUI return new MotifScrollBarUI(); } + @Override public Dimension getPreferredSize(JComponent c) { Insets insets = c.getInsets(); int dx = insets.left + insets.right; @@ -61,19 +62,23 @@ public class MotifScrollBarUI extends BasicScrollBarUI : new Dimension(dx + 33, dy + 11); } + @Override protected JButton createDecreaseButton(int orientation) { return new MotifScrollBarButton(orientation); } + @Override protected JButton createIncreaseButton(int orientation) { return new MotifScrollBarButton(orientation); } + @Override public void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) { g.setColor(trackColor); g.fillRect(trackBounds.x, trackBounds.y, trackBounds.width, trackBounds.height); } + @Override public void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) { if (thumbBounds.isEmpty() || !scrollbar.isEnabled()) { return; diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSliderUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSliderUI.java index c8820de17c4..c6afd5ce953 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSliderUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSliderUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -64,22 +64,27 @@ public class MotifSliderUI extends BasicSliderUI { return new MotifSliderUI((JSlider)b); } + @Override public Dimension getPreferredHorizontalSize() { return PREFERRED_HORIZONTAL_SIZE; } + @Override public Dimension getPreferredVerticalSize() { return PREFERRED_VERTICAL_SIZE; } + @Override public Dimension getMinimumHorizontalSize() { return MINIMUM_HORIZONTAL_SIZE; } + @Override public Dimension getMinimumVerticalSize() { return MINIMUM_VERTICAL_SIZE; } + @Override protected Dimension getThumbSize() { if ( slider.getOrientation() == JSlider.HORIZONTAL ) { return new Dimension( 30, 15 ); @@ -89,12 +94,15 @@ public class MotifSliderUI extends BasicSliderUI { } } + @Override public void paintFocus(Graphics g) { } + @Override public void paintTrack(Graphics g) { } + @Override public void paintThumb(Graphics g) { Rectangle knobBounds = thumbRect; diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneDivider.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneDivider.java index ba8f0efde4d..21cc1f7c38b 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneDivider.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneDivider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -84,6 +84,7 @@ public class MotifSplitPaneDivider extends BasicSplitPaneDivider * overrides to hardcode the size of the divider * PENDING(jeff) - rewrite JSplitPane so that this isn't needed */ + @Override public void setDividerSize(int newSize) { Insets insets = getInsets(); int borderSize = 0; @@ -109,6 +110,7 @@ public class MotifSplitPaneDivider extends BasicSplitPaneDivider */ // PENDING(jeff) - the thumb's location and size is currently hard coded. // It should be dynamic. + @Override public void paint(Graphics g) { Color bgColor = getBackground(); Dimension size = getSize(); @@ -179,6 +181,7 @@ public class MotifSplitPaneDivider extends BasicSplitPaneDivider /** * The minimums size is the same as the preferredSize */ + @Override public Dimension getMinimumSize() { return getPreferredSize(); } @@ -187,6 +190,7 @@ public class MotifSplitPaneDivider extends BasicSplitPaneDivider * Sets the SplitPaneUI that is using the receiver. This is completely * overridden from super to create a different MouseHandler. */ + @Override public void setBasicSplitPaneUI(BasicSplitPaneUI newUI) { if (splitPane != null) { splitPane.removePropertyChangeListener(this); @@ -268,6 +272,7 @@ public class MotifSplitPaneDivider extends BasicSplitPaneDivider * in. */ private class MotifMouseHandler extends MouseHandler { + @Override public void mousePressed(MouseEvent e) { // Constrain the mouse pressed to the thumb. if (e.getSource() == MotifSplitPaneDivider.this && @@ -277,6 +282,7 @@ public class MotifSplitPaneDivider extends BasicSplitPaneDivider } } + @Override public void mouseMoved(MouseEvent e) { if (getDragger() != null) { return; diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneUI.java index c61a1713c9b..90ce672f5c9 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -51,6 +51,7 @@ public class MotifSplitPaneUI extends BasicSplitPaneUI /** * Creates the default divider. */ + @Override public BasicSplitPaneDivider createDefaultDivider() { return new MotifSplitPaneDivider(this); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTabbedPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTabbedPaneUI.java index 1c53fc4a179..2b1e9482f9d 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTabbedPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTabbedPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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,6 +61,7 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI // UI Installation/De-installation + @Override protected void installDefaults() { super.installDefaults(); @@ -70,6 +71,7 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI unselectedTabHighlight = UIManager.getColor("TabbedPane.unselectedTabHighlight"); } + @Override protected void uninstallDefaults() { super.uninstallDefaults(); @@ -81,6 +83,7 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI // UI Rendering + @Override protected void paintContentBorderTopEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { @@ -104,6 +107,7 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI } } + @Override protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { @@ -126,6 +130,7 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI } } + @Override protected void paintContentBorderRightEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { @@ -148,6 +153,7 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI } } + @Override protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, @@ -174,6 +180,7 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI } + @Override protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, @@ -225,6 +232,7 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI } + @Override protected void paintFocusIndicator(Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex, Rectangle iconRect, Rectangle textRect, @@ -263,10 +271,12 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI } } + @Override protected int getTabRunIndent(int tabPlacement, int run) { return run*3; } + @Override protected int getTabRunOverlay(int tabPlacement) { tabRunOverlay = (tabPlacement == LEFT || tabPlacement == RIGHT)? (int)Math.round((float)maxTabWidth * .10) : diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextAreaUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextAreaUI.java index baddbf3a75d..f71dfe3c30d 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextAreaUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextAreaUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -57,6 +57,7 @@ public class MotifTextAreaUI extends BasicTextAreaUI { * * @return the caret object */ + @Override protected Caret createCaret() { return MotifTextUI.createCaret(); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextFieldUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextFieldUI.java index 08437687ebc..8e64aa02a63 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextFieldUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextFieldUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,7 @@ public class MotifTextFieldUI extends BasicTextFieldUI { * * @return the caret object */ + @Override protected Caret createCaret() { return MotifTextUI.createCaret(); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextPaneUI.java index e47ad4c60bf..fabbbb204d0 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,7 @@ public class MotifTextPaneUI extends BasicTextPaneUI { * * @return the caret object */ + @Override protected Caret createCaret() { return MotifTextUI.createCaret(); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextUI.java index b79ef19df8e..6e2e1059176 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,6 +75,7 @@ public class MotifTextUI { * @param e the focus event * @see FocusListener#focusGained */ + @Override public void focusGained(FocusEvent e) { super.focusGained(e); getComponent().repaint(); @@ -88,6 +89,7 @@ public class MotifTextUI { * @param e the focus event * @see FocusListener#focusLost */ + @Override public void focusLost(FocusEvent e) { super.focusLost(e); getComponent().repaint(); @@ -101,6 +103,7 @@ public class MotifTextUI { * @param r the current location of the caret, does nothing if null * @see #paint */ + @Override protected void damage(Rectangle r) { if (r != null) { x = r.x - IBeamOverhang - 1; @@ -121,6 +124,7 @@ public class MotifTextUI { * @param g the graphics context * @see #damage */ + @Override @SuppressWarnings("deprecation") public void paint(Graphics g) { if(isVisible()) { diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java index eef60ade9c9..7997145e648 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -71,6 +71,7 @@ public class MotifToggleButtonUI extends BasicToggleButtonUI // ******************************** // Install Defaults // ******************************** + @Override public void installDefaults(AbstractButton b) { super.installDefaults(b); if(!defaults_initialized) { @@ -80,6 +81,7 @@ public class MotifToggleButtonUI extends BasicToggleButtonUI LookAndFeel.installProperty(b, "opaque", Boolean.FALSE); } + @Override protected void uninstallDefaults(AbstractButton b) { super.uninstallDefaults(b); defaults_initialized = false; @@ -96,6 +98,7 @@ public class MotifToggleButtonUI extends BasicToggleButtonUI // ******************************** // Paint Methods // ******************************** + @Override protected void paintButtonPressed(Graphics g, AbstractButton b) { if (b.isContentAreaFilled()) { Color oldColor = g.getColor(); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeCellRenderer.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeCellRenderer.java index 78ec251f05d..b060c62f24b 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeCellRenderer.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeCellRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -70,6 +70,7 @@ public class MotifTreeCellRenderer extends DefaultTreeCellRenderer highlight = UIManager.getColor("Tree.iconHighlight"); } + @Override public void paintIcon(Component c, Graphics g, int x, int y) { g.setColor(bg); @@ -90,10 +91,12 @@ public class MotifTreeCellRenderer extends DefaultTreeCellRenderer g.drawLine(x + 9, y + 8, x + 7, y + 6); } + @Override public int getIconWidth() { return LEAF_SIZE; } + @Override public int getIconHeight() { return LEAF_SIZE; } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeUI.java index 468ef4eb565..11313b9ad12 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -54,12 +54,14 @@ public class MotifTreeUI extends BasicTreeUI super(); } + @Override public void installUI(JComponent c) { super.installUI(c); } // BasicTreeUI overrides + @Override protected void paintVerticalLine( Graphics g, JComponent c, int x, int top, int bottom ) { if (tree.getComponentOrientation().isLeftToRight()) { @@ -69,6 +71,7 @@ public class MotifTreeUI extends BasicTreeUI } } + @Override protected void paintHorizontalLine( Graphics g, JComponent c, int y, int left, int right ) { g.fillRect( left, y, right - left + 1, 2 ); @@ -96,6 +99,7 @@ public class MotifTreeUI extends BasicTreeUI return new MotifExpandedIcon(); } + @Override public void paintIcon(Component c, Graphics g, int x, int y) { g.setColor(highlight); g.drawLine(x, y, x+SIZE-1, y); @@ -113,7 +117,9 @@ public class MotifTreeUI extends BasicTreeUI g.drawLine(x+3, y+HALF_SIZE, x+SIZE-4, y+HALF_SIZE); } + @Override public int getIconWidth() { return SIZE; } + @Override public int getIconHeight() { return SIZE; } } @@ -126,6 +132,7 @@ public class MotifTreeUI extends BasicTreeUI return new MotifCollapsedIcon(); } + @Override public void paintIcon(Component c, Graphics g, int x, int y) { super.paintIcon(c, g, x, y); g.drawLine(x + HALF_SIZE-1, y + 3, x + HALF_SIZE-1, y + (SIZE - 4)); @@ -141,6 +148,7 @@ public class MotifTreeUI extends BasicTreeUI * Returns the default cell renderer that is used to do the * stamping of each node. */ + @Override public TreeCellRenderer createDefaultCellRenderer() { return new MotifTreeCellRenderer(); } From fb526c8f45de6ca9a57608f728ac223cbca118be Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 14 Jan 2026 21:37:44 +0000 Subject: [PATCH 037/328] 8373001: LauncherFromOptions.create() not properly handling FileAssociationNoExtensionsException Reviewed-by: almatvee --- .../classes/jdk/jpackage/internal/LauncherFromOptions.java | 6 +++--- .../jpackage/internal/resources/MainResources.properties | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java index ed030a4a726..9e81d144a1e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -51,6 +51,7 @@ import jdk.jpackage.internal.FileAssociationGroup.FileAssociationNoMimesExceptio import jdk.jpackage.internal.cli.Options; import jdk.jpackage.internal.cli.StandardFaOption; import jdk.jpackage.internal.model.CustomLauncherIcon; +import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.DefaultLauncherIcon; import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.model.Launcher; @@ -130,8 +131,7 @@ final class LauncherFromOptions { .advice("error.no-content-types-for-file-association.advice", faID) .create(); } catch (FileAssociationNoExtensionsException ex) { - // TODO: Must do something about this condition! - throw new AssertionError(); + throw new JPackageException(I18N.format("error.no-extensions-for-file-association", faID)); } catch (FileAssociationException ex) { // Should never happen throw new UnsupportedOperationException(ex); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index 07460a18fe8..e1f41e3ff48 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -93,6 +93,7 @@ error.properties-parameter-not-path=The value "{0}" provided for property "{1}" error.properties-parameter-not-file=The value "{0}" provided for property "{1}" in "{2}" file is not a file error.properties-parameter-not-launcher-shortcut-dir=The value "{0}" provided for property "{1}" in "{2}" file is not a valid shortcut startup directory +error.no-extensions-for-file-association=No extensions were specified for File Association number {0} error.no-content-types-for-file-association=No MIME types were specified for File Association number {0} error.no-content-types-for-file-association.advice=Specify MIME type for File Association number {0} error.too-many-content-types-for-file-association=More than one MIME types was specified for File Association number {0} From d8f45faf5849e66b8f0e35e1d18ed0331a0cb1c2 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 15 Jan 2026 02:40:36 +0000 Subject: [PATCH 038/328] 8374432: TimeoutResponseBodyTest.java#retriesEnabledForResponseFailure fails run with -Xcomp Reviewed-by: vyazici, dfuchs --- .../java/net/httpclient/TimeoutResponseTestSupport.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java b/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java index 67b993eef0b..2d8ff05dbd2 100644 --- a/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java +++ b/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,8 @@ public class TimeoutResponseTestSupport { private static final SSLContext SSL_CONTEXT = SimpleSSLContext.findSSLContext(); protected static final Duration REQUEST_TIMEOUT = - Duration.ofMillis(Long.parseLong(System.getProperty("test.requestTimeoutMillis"))); + Duration.ofMillis(jdk.test.lib.Utils.adjustTimeout( + Long.parseLong(System.getProperty("test.requestTimeoutMillis")))); static { assertTrue( @@ -87,7 +88,8 @@ public class TimeoutResponseTestSupport { Integer.parseInt(System.getProperty("jdk.httpclient.redirects.retrylimit", "0")); private static final long RESPONSE_FAILURE_WAIT_DURATION_MILLIS = - Long.parseLong(System.getProperty("test.responseFailureWaitDurationMillis", "0")); + jdk.test.lib.Utils.adjustTimeout( + Long.parseLong(System.getProperty("test.responseFailureWaitDurationMillis", "0"))); static { if (RETRY_LIMIT > 0) { From ce5e0d8a48296b51c9c2eff4867e2a9a70194091 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 15 Jan 2026 02:44:16 +0000 Subject: [PATCH 039/328] 8373945: Use WB.fullGC() in ClassUnloader.unloadClass to force GC for vmTestbase tests Reviewed-by: cjplummer, lmesnik --- .../LargeObjects/large001/large001.java | 26 ++++------ .../large002/TestDescription.java | 10 ++-- .../large003/TestDescription.java | 10 ++-- .../large004/TestDescription.java | 10 ++-- .../large005/TestDescription.java | 10 ++-- .../reflectype002/TestDescription.java | 9 ++-- .../classname001/TestDescription.java | 10 ++-- .../signature001/TestDescription.java | 10 ++-- .../exclfilter001/TestDescription.java | 9 ++-- .../filter001/TestDescription.java | 9 ++-- .../allfields003/TestDescription.java | 9 ++-- .../allmethods003/TestDescription.java | 9 ++-- .../classobj002/TestDescription.java | 9 ++-- .../equals/equals002/TestDescription.java | 9 ++-- .../failedtoinit002/TestDescription.java | 9 ++-- .../fieldbyname003/TestDescription.java | 9 ++-- .../fields/fields003/TestDescription.java | 9 ++-- .../hashCode/hashcode002/TestDescription.java | 9 ++-- .../isabstract002/TestDescription.java | 9 ++-- .../isinit002/TestDescription.java | 9 ++-- .../isprepared002/TestDescription.java | 9 ++-- .../isverified002/TestDescription.java | 9 ++-- .../methods/methods003/TestDescription.java | 10 ++-- .../methbyname_s003/TestDescription.java | 9 ++-- .../methbyname_ss003/TestDescription.java | 9 ++-- .../name/name002/TestDescription.java | 9 ++-- .../sourcename002/TestDescription.java | 9 ++-- .../visibfield003/TestDescription.java | 9 ++-- .../visibmethod003/TestDescription.java | 9 ++-- .../instancecounts003/instancecounts003.java | 8 ++- .../compmethunload001.java | 16 +++--- .../compmethunload001/TestDescription.java | 6 ++- .../objfree001/TestDescription.java | 5 +- .../events/EM02/em02t003/TestDescription.java | 6 ++- .../events/EM02/em02t005/TestDescription.java | 6 ++- .../events/EM07/em07t002/TestDescription.java | 6 ++- .../EX03/ex03t001/TestDescription.java | 6 ++- .../classload/load001/TestDescription.java | 6 ++- .../classload/load002/TestDescription.java | 6 ++- .../classload/load003/TestDescription.java | 6 ++- .../classload/load004/TestDescription.java | 6 ++- .../classload/load005/TestDescription.java | 6 ++- .../classload/load006/TestDescription.java | 6 ++- .../classload/load007/TestDescription.java | 6 ++- .../classload/load008/TestDescription.java | 6 ++- .../classload/load009/TestDescription.java | 6 ++- .../classload/load010/TestDescription.java | 6 ++- .../classload/load011/TestDescription.java | 6 ++- .../classload/load012/TestDescription.java | 6 ++- .../classload/unload001/TestDescription.java | 6 ++- .../classload/unload002/TestDescription.java | 6 ++- .../classload/unload003/TestDescription.java | 6 ++- .../classload/unload004/TestDescription.java | 6 ++- .../classload/unload005/TestDescription.java | 6 ++- .../classload/unload006/TestDescription.java | 6 ++- .../classload/unload007/TestDescription.java | 6 ++- .../classload/unload008/TestDescription.java | 6 ++- .../classload/unload009/TestDescription.java | 6 ++- .../classload/unload010/TestDescription.java | 6 ++- .../classload/unload011/TestDescription.java | 6 ++- .../classload/unload012/TestDescription.java | 6 ++- .../vmTestbase/nsk/share/ClassUnloader.java | 51 ++++--------------- 62 files changed, 324 insertions(+), 215 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java index 8f8cfdcd541..1fd550d3571 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,8 @@ * generated by nsk.share.gc.Generator (see its javadoc for more details). * Each class has a huge number of fields, but this number is less than the JVM * limitation. - * The test loads the classes with nsk.share.gc.GCClassUnloader class that - * extends nsk.share.ClassUnloader and has a bit different algorith of eating - * heap. As soon as a class is loaded, the test creates an instance of + * The test loads the classes with nsk.share.gc.GCClassUnloader class. + * As soon as a class is loaded, the test creates an instance of * it - allocates an object of that type. Then it drops references to the * class and to the instance and tries to unload the class. The test does not * expect any exceptions to be thrown. @@ -57,10 +56,13 @@ * /test/lib * * @comment generate and compile nsk.share.gc.newclass.* classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.gc.GenClassesBuilder * * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xlog:gc* * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes @@ -79,6 +81,7 @@ import nsk.share.TestFailure; import nsk.share.gc.*; import nsk.share.*; +import jdk.test.whitebox.WhiteBox; public class large001 extends ThreadedGCTest { @@ -146,8 +149,8 @@ public class large001 extends ThreadedGCTest { List refs = new ArrayList(depth); addObjRef(loadedClassInstance, loadedClass, depth, refs); - // Drop all references to the class and try to unload it - Algorithms.eatMemory(getExecutionController()); + // Keep all references to the class and try to unload it + WhiteBox.getWhiteBox().fullGC(); log.debug(id + ": Testing non-null after GC force for: " + name); if (loadedClass == null || loadedClassInstance == null) { throw new Exception("Null class"); @@ -158,21 +161,14 @@ public class large001 extends ThreadedGCTest { throw new Exception("Unexpected null reference"); } } + // Drop all references to the class and try to unload it refs = null; loadedClass = null; loadedClassInstance = null; log.debug(id + ": Unloading class: " + name); - boolean result = unloader.unloadClass(getExecutionController()); - log.debug(id + ": Result of uloading " - + "class " + name + ": " + result); - } - } catch (OutOfMemoryError oome) { - // just skip if we eat memory in several threads... - // rethrow in the case of one thread - if (runParams.getNumberOfThreads() == 1) { - throw oome; + WhiteBox.getWhiteBox().fullGC(); } } catch (Throwable t) { throw new TestFailure("Unexpected exception: ", t); diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java index c207b80c059..834a5d71822 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 +47,8 @@ * generated by nsk.share.gc.Generator (see its javadoc for more details). * Each class has a huge number of fields, and the number of fields is more than * the JVM limitation. - * The test loads the classes with nsk.share.gc.GCClassUnloader class that - * extends nsk.share.ClassUnloader and has a bit different algorith of eating - * heap. As soon as a class is loaded, the test creates an instance of + * The test loads the classes with nsk.share.gc.GCClassUnloader class. + * As soon as a class is loaded, the test creates an instance of * it - allocates an object of that type. Then it drops references to the * class and to the instance and tries to unload the class. The test does not * expect any exceptions to be thrown. @@ -58,10 +57,13 @@ * /test/lib * * @comment generate and compile nsk.share.gc.newclass.* classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.gc.GenClassesBuilder * * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes * -isOverLimitFields true diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java index fd7e1e5e8dd..d094776cb5d 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 +47,8 @@ * generated by nsk.share.gc.Generator (see its javadoc for more details). * Each class has a huge number of fields, but this number is less than the JVM * limitation. - * The test loads the classes with nsk.share.gc.GCClassUnloader class that - * extends nsk.share.ClassUnloader and has a bit different algorith of eating - * heap. As soon as a class is loaded, the test creates an instance of + * The test loads the classes with nsk.share.gc.GCClassUnloader class. + * As soon as a class is loaded, the test creates an instance of * it - allocates an object of that type. Then it drops references to the * class and to the instance and tries to unload the class. The test does not * expect any exceptions to be thrown. @@ -62,10 +61,13 @@ * /test/lib * * @comment generate and compile nsk.share.gc.newclass.* classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.gc.GenClassesBuilder * * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes * -isOverLimitFields false diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java index 2301daba8d3..021170d7d7a 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 +47,8 @@ * generated by nsk.share.gc.Generator (see its javadoc for more details). * Each class has a huge number of fields, but this number is less than the JVM * limitation. - * The test loads the classes with nsk.share.gc.GCClassUnloader class that - * extends nsk.share.ClassUnloader and has a bit different algorith of eating - * heap. As soon as a class is loaded, the test creates an instance of + * The test loads the classes with nsk.share.gc.GCClassUnloader class. + * As soon as a class is loaded, the test creates an instance of * it - allocates an object of that type. Then it drops references to the * class and to the instance and tries to unload the class. The test does not * expect any exceptions to be thrown. @@ -62,10 +61,13 @@ * /test/lib * * @comment generate and compile nsk.share.gc.newclass.* classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.gc.GenClassesBuilder * * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes * -isOverLimitFields true diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java index abf91f48dea..6ad629aa84e 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 +47,8 @@ * generated by nsk.share.gc.Generator (see its javadoc for more details). * Each class has a huge number of fields, but this number is less than the JVM * limitation. - * The test loads the classes with nsk.share.gc.GCClassUnloader class that - * extends nsk.share.ClassUnloader and has a bit different algorith of eating - * heap. As soon as a class is loaded, the test creates an instance of + * The test loads the classes with nsk.share.gc.GCClassUnloader class. + * As soon as a class is loaded, the test creates an instance of * it - allocates an object of that type. Then it drops references to the * class and to the instance and tries to unload the class. The test does not * expect any exceptions to be thrown. @@ -62,10 +61,13 @@ * /test/lib * * @comment generate and compile nsk.share.gc.newclass.* classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.gc.GenClassesBuilder * * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes * -isOverLimitFields true diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002/TestDescription.java index 20584002f6e..efec917716a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ClassObjectReference.reflectedType.reflectype002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadEvent/className/classname001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadEvent/className/classname001/TestDescription.java index c967382ccfd..8f906d4d6b2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadEvent/className/classname001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadEvent/className/classname001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -42,7 +42,7 @@ * debugger and debugee communicates with special commands. * The debugger forces debuggee to load checked class, creates and * enables ClassUnloadRequest. Next, debugger forces debuggee to - * unload class, using memory stressing techique, and waits for + * unload class, using whitebox full GC techique, and waits for * ClassUnloadEvent. * If expected ClassUnloadEvent occurs, debugger tests method * ClassUnloadEvent.className() and verifies that this event @@ -81,6 +81,8 @@ * nsk.jdi.ClassUnloadEvent.className.classname001a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -92,6 +94,6 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadEvent/classSignature/signature001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadEvent/classSignature/signature001/TestDescription.java index c83d6cdf0f3..6974e7077df 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadEvent/classSignature/signature001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadEvent/classSignature/signature001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -44,7 +44,7 @@ * debugger and debugee communicates with special commands. * The debugger forces debugge to load checked classes, creates and * enables ClassUnloadRequest. Next, debugger forces debuggee to - * unload classes, using memory stressing techique, and waits for + * unload classes, using whitebox full GC techique, and waits for * ClassUnloadEvent. * If each expected ClassUnloadEvent occurs, debugger tests method * ClassUnloadEvent.classSignature() and verifies that this event @@ -87,6 +87,8 @@ * nsk.jdi.ClassUnloadEvent.classSignature.signature001a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -98,6 +100,6 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadRequest/addClassExclusionFilter/exclfilter001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadRequest/addClassExclusionFilter/exclfilter001/TestDescription.java index ad14def18dc..d449ed04f91 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadRequest/addClassExclusionFilter/exclfilter001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadRequest/addClassExclusionFilter/exclfilter001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -67,6 +67,8 @@ * nsk.jdi.ClassUnloadRequest.addClassExclusionFilter.exclfilter001a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -77,6 +79,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadRequest/addClassFilter/filter001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadRequest/addClassFilter/filter001/TestDescription.java index 6a388fbaea9..1783e44fa43 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadRequest/addClassFilter/filter001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadRequest/addClassFilter/filter001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,6 +65,8 @@ * nsk.jdi.ClassUnloadRequest.addClassFilter.filter001a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -75,6 +77,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields003/TestDescription.java index 25196c3ae9b..053a6ff34c5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ReferenceType.allFields.allfields003a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods003/TestDescription.java index 149de042248..a0e8bd2b7f1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ReferenceType.allMethods.allmethods003a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj002/TestDescription.java index a639fe76ad8..ab751a1f29c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ReferenceType.classObject.classobj002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002/TestDescription.java index 1ccd1358c1c..e1c25e9dbdd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ReferenceType.equals.equals002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002/TestDescription.java index af68db9d869..703bb6c54aa 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ReferenceType.failedToInitialize.failedtoinit002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname003/TestDescription.java index bbd8998d3a1..fa5104cad55 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ReferenceType.fieldByName.fieldbyname003a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003/TestDescription.java index d6379dfbdbf..ab6af3a98e1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ReferenceType.fields.fields003a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002/TestDescription.java index f7a960746d9..693171c9dfe 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ReferenceType.hashCode.hashcode002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002/TestDescription.java index 6f9c0d5b18e..b61c14d3d4b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ReferenceType.isAbstract.isabstract002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002/TestDescription.java index c484851c178..c2b1eac7c1e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ReferenceType.isInitialized.isinit002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002/TestDescription.java index 867b7c45e81..9030c57a727 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ReferenceType.isPrepared.isprepared002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002/TestDescription.java index 5f638386da8..a766e7476f6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -57,6 +57,8 @@ * nsk.jdi.ReferenceType.isVerified.isverified002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -67,6 +69,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003/TestDescription.java index df70528ffd9..5a37d7e66a4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -57,7 +57,8 @@ * @comment compile loadclassXX to bin/loadclassXX * @run driver nsk.share.ExtraClassesBuilder * loadclass - * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver * nsk.jdi.ReferenceType.methods.methods003 * -verbose @@ -65,6 +66,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s003/TestDescription.java index fae4c67e986..6f70f225a14 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ReferenceType.methodsByName_s.methbyname_s003a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003/TestDescription.java index 5d21a5c868f..baf8931a636 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -57,6 +57,8 @@ * @comment compile loadclassXX to bin/loadclassXX * @run driver nsk.share.ExtraClassesBuilder * loadclass + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * * @run driver * nsk.jdi.ReferenceType.methodsByName_ss.methbyname_ss003 @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002/TestDescription.java index 91c37d75710..927e07929b4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ReferenceType.name.name002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002/TestDescription.java index 74427e9a8bc..543272a52f0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ReferenceType.sourceName.sourcename002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield003/TestDescription.java index db4ba02e457..f349deaad85 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ReferenceType.visibleFields.visibfield003a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod003/TestDescription.java index 11c4c3566bb..c6de37e2939 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ * nsk.jdi.ReferenceType.visibleMethods.visibmethod003a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/instanceCounts/instancecounts003/instancecounts003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/instanceCounts/instancecounts003/instancecounts003.java index f2150775916..4f4e83188b4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/instanceCounts/instancecounts003/instancecounts003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/instanceCounts/instancecounts003/instancecounts003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,8 @@ * @build nsk.jdi.VirtualMachine.instanceCounts.instancecounts003.instancecounts003 * nsk.share.jdi.TestClass1 * nsk.share.jdi.TestInterfaceImplementer1 + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver * nsk.jdi.VirtualMachine.instanceCounts.instancecounts003.instancecounts003 * -verbose @@ -55,7 +57,9 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="-Xmx256M ${test.vm.opts} ${test.java.opts}" + * -debugee.vmkeys="-Xmx256M ${test.vm.opts} ${test.java.opts} + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI" * -testClassPath ${test.class.path} */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/CompiledMethodUnload/compmethunload001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/CompiledMethodUnload/compmethunload001.java index e03c4ff4be2..09fdb1ae3f7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/CompiledMethodUnload/compmethunload001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/CompiledMethodUnload/compmethunload001.java @@ -47,7 +47,7 @@ public class compmethunload001 { private final static String CLS_TO_BE_UNLOADED = "nsk.jvmti.CompiledMethodUnload.compmethunload001u"; - private final static int MAX_ITERATIONS = 5; + private final static int MAX_ITERATIONS = 10; static { try { @@ -95,7 +95,6 @@ public class compmethunload001 { boolean clsUnloaded = clsUnLoader.unloadClass(); clsUnLoader = null; - System.gc(); } private int runThis(String argv[], PrintStream out) throws Exception { @@ -110,12 +109,13 @@ public class compmethunload001 { int num = unloaded(); int iter = 0; while (num == 0) { - System.gc(); - num = unloaded(); - iter++; - if (iter > MAX_ITERATIONS) { - throw new Failure("PRODUCT BUG: class was not unloaded in " + MAX_ITERATIONS); - } + // The unload is delayed because it happens async + Thread.sleep(1000); + num = unloaded(); + iter++; + if (iter > MAX_ITERATIONS) { + throw new Failure("PRODUCT BUG: class was not unloaded in " + MAX_ITERATIONS); + } } System.out.println("Number of unloaded events " + num + " number of iterations " + iter); return check(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/CompiledMethodUnload/compmethunload001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/CompiledMethodUnload/compmethunload001/TestDescription.java index 975f0fdee28..b3e43bf7d03 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/CompiledMethodUnload/compmethunload001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/CompiledMethodUnload/compmethunload001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,12 +46,14 @@ * @build nsk.jvmti.CompiledMethodUnload.compmethunload001 * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * * @run main/othervm/native * -agentlib:compmethunload001=-waittime=5 + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.jvmti.CompiledMethodUnload.compmethunload001 * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ObjectFree/objfree001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ObjectFree/objfree001/TestDescription.java index 8da18b646c7..c7f5376e53c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ObjectFree/objfree001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ObjectFree/objfree001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -51,12 +51,15 @@ * @build nsk.jvmti.ObjectFree.objfree001 * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * * @run main/othervm/native * -agentlib:objfree001=-waittime=5 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.jvmti.ObjectFree.objfree001 * ./bin 5 ./bin */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003/TestDescription.java index d3179b3c2c0..c32abdb635b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -71,13 +71,15 @@ * @build nsk.jvmti.scenarios.events.EM02.em02t003 * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * * @run main/othervm/native * -agentlib:em02t003=-waittime=5 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.jvmti.scenarios.events.EM02.em02t003 * ./bin/loadclass */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t005/TestDescription.java index 5e8b186fe9d..35fc4ceacdb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t005/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -64,13 +64,15 @@ * @build nsk.jvmti.scenarios.events.EM02.em02t005 * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * * @run main/othervm/native * -agentlib:em02t005=-waittime=5 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.jvmti.scenarios.events.EM02.em02t005 * ./bin/loadclass */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM07/em07t002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM07/em07t002/TestDescription.java index aacc48a1e94..dea19222973 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM07/em07t002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM07/em07t002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -57,13 +57,15 @@ * @build nsk.jvmti.scenarios.events.EM07.em07t002 * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * * @run main/othervm/native * -agentlib:em07t002=attempts=2,-waittime=5 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.jvmti.scenarios.events.EM07.em07t002 * ./bin/loadclass */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/extension/EX03/ex03t001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/extension/EX03/ex03t001/TestDescription.java index 0e63411b94b..76798c229f3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/extension/EX03/ex03t001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/extension/EX03/ex03t001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,13 +55,15 @@ * @build nsk.jvmti.scenarios.extension.EX03.ex03t001 * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * * @run main/othervm/native * -agentlib:ex03t001=-waittime=5 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.jvmti.scenarios.extension.EX03.ex03t001 * ./bin/loadclass */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load001/TestDescription.java index e93d0052423..979f51007a2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -43,12 +43,14 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load002/TestDescription.java index 563eb7500a0..e1dcaaf6946 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,13 +46,15 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -testMode=server * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load003/TestDescription.java index d972a74492c..41ffed813d1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -testMode=server @@ -56,4 +59,3 @@ * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load004/TestDescription.java index 7789d6b70ce..b0470cca572 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load004/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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,13 +47,15 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -singleClassloaderClass * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load005/TestDescription.java index b6eba9ca652..d5be1a61e8a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load005/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -44,9 +44,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -testMode=server @@ -54,4 +57,3 @@ * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load006/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load006/TestDescription.java index af8f67362bf..eff574f05a2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load006/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load006/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -44,9 +44,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -testMode=server @@ -55,4 +58,3 @@ * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load007/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load007/TestDescription.java index f8674cdbd21..ecd7e495fb9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load007/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load007/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,12 +46,14 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=360 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -loadableClassCount=100 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load008/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load008/TestDescription.java index f306fda9e02..9ebc7be7a72 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load008/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load008/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -44,13 +44,15 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=420 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -testMode=server * -loadableClassCount=100 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load009/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load009/TestDescription.java index 50f8116f7c9..5355064e57a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load009/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load009/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -44,9 +44,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=420 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -testMode=server @@ -54,4 +57,3 @@ * -loadableClassCount=100 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load010/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load010/TestDescription.java index 4f477035cd2..fe0ec8c9b62 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load010/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load010/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,13 +46,15 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=300 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -singleClassloaderClass * -loadableClassCount=100 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load011/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load011/TestDescription.java index 110f270daff..a5a1a5ae2a8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load011/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load011/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -44,9 +44,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=360 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -testMode=server @@ -54,4 +57,3 @@ * -loadableClassCount=100 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load012/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load012/TestDescription.java index 52c9d3e8ae7..ac3f8217a0d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load012/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load012/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -44,9 +44,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=300 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -testMode=server @@ -55,4 +58,3 @@ * -loadableClassCount=100 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload001/TestDescription.java index cab8b333848..9690240caa5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,11 +46,13 @@ * /test/lib * @comment generate and compile LoadableClassXXX classes * @run driver nsk.monitoring.stress.classload.GenClassesBuilder + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload002/TestDescription.java index cf611e5eb05..52395f92b0c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,13 +46,15 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -testMode=server * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload003/TestDescription.java index 6c8d9f61e36..7e24f92dafd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -testMode=server @@ -56,4 +59,3 @@ * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload004/TestDescription.java index 8f8e46e40be..8dedf5c1f61 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload004/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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,13 +47,15 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -singleClassloaderClass * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload005/TestDescription.java index 73aa31b3ff3..e4236d40e58 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload005/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -44,9 +44,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -testMode=server @@ -54,4 +57,3 @@ * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload006/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload006/TestDescription.java index 1b3d309a7fd..ef6e3d996d9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload006/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload006/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -44,9 +44,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -testMode=server @@ -55,4 +58,3 @@ * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload007/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload007/TestDescription.java index 62eaaa6c40a..cbe155bc77e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload007/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload007/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,12 +48,14 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -loadableClassCount=100 * -loadersCount=12 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload008/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload008/TestDescription.java index f87f913b769..41894adaed7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload008/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload008/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,13 +46,15 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -testMode=server * -loadableClassCount=100 * -loadersCount=12 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload009/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload009/TestDescription.java index 27c19980411..5999a8c7f7c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload009/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload009/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -testMode=server @@ -56,4 +59,3 @@ * -loadableClassCount=100 * -loadersCount=12 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload010/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload010/TestDescription.java index afc3cbb026c..683bca7ab93 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload010/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload010/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,13 +48,15 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -singleClassloaderClass * -loadableClassCount=100 * -loadersCount=12 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload011/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload011/TestDescription.java index 037d4c2affe..26227644431 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload011/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload011/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -testMode=server @@ -56,4 +59,3 @@ * -loadableClassCount=100 * -loadersCount=12 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload012/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload012/TestDescription.java index 256b0f91d1f..446db1d6e28 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload012/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload012/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -testMode=server @@ -57,4 +60,3 @@ * -loadableClassCount=100 * -loadersCount=12 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java b/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java index e3b6693657c..94b086f5757 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -33,13 +33,14 @@ import java.util.*; import nsk.share.gc.gp.*; import nsk.share.test.ExecutionController; import nsk.share.test.Stresser; +import jdk.test.whitebox.WhiteBox; /** * The ClassUnloader class allows to force VM to unload class(es) - * using memory stressing technique. + * using WhiteBox.fullGC technique. * - *

The method unloadClass() is provided which eats memory - * to enforce GC to cleanup the heap. So, if all references to a class + *

The method unloadClass() is provided which calls + * WhiteBox.fullGC to cleanup the heap. So, if all references to a class * and its loader are canceled, this may result in unloading the class. * *

ClassUnloader mainly intends to unload a class which was loaded @@ -228,24 +229,24 @@ public class ClassUnloader { /** * Forces GC to unload previously loaded classes by cleaning all references - * to class loader with its loaded classes and eating memory. + * to class loader with its loaded classes. * * @return true if classes unloading has been detected or false otherwise * * @throws Failure if exception other than OutOfMemoryError - * is thrown while eating memory + * is thrown while triggering full GC * - * @see #eatMemory() + * @see WhiteBox.getWhiteBox().fullGC() */ - public boolean unloadClass(ExecutionController stresser) { + public boolean unloadClass() { // free references to class and class loader to be able for collecting by GC classObjects.removeAllElements(); customClassLoader = null; - // force class unloading by eating memory pool - eatMemory(stresser); + // force class unloading by triggering full GC + WhiteBox.getWhiteBox().fullGC(); // force GC to unload marked class loader and its classes if (isClassLoaderReclaimed()) { @@ -256,34 +257,4 @@ public class ClassUnloader { // class loader has not been reclaimed return false; } - - public boolean unloadClass() { - Stresser stresser = new Stresser() { - - @Override - public boolean continueExecution() { - return true; - } - - }; - return unloadClass(stresser); - } - - // Stresses memory by allocating arrays of bytes. - public static void eatMemory(ExecutionController stresser) { - GarbageUtils.eatMemory(stresser, 50, 1024, 2); - } - - // Stresses memory by allocating arrays of bytes. - public static void eatMemory() { - Stresser stresser = new Stresser() { - - @Override - public boolean continueExecution() { - return true; - } - - }; - eatMemory(stresser); - } } From 2b1e11c2541f799142bd71e9526cbd04743c6f4e Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 15 Jan 2026 02:46:20 +0000 Subject: [PATCH 040/328] 8374879: NMethodRelocationTest fails with -Xcomp after 8369150 Reviewed-by: lmesnik, chagedorn --- .../jvmti/NMethodRelocation/NMethodRelocationTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java index 10888dce1b4..5b4a1c7e663 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java +++ b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java @@ -29,7 +29,8 @@ * vm.gc != "Epsilon" & * vm.flavor == "server" & * !vm.emulatedClient & - * (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) + * (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) & + * vm.compMode == "Xmixed" * @library /test/lib /test/hotspot/jtreg * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox From 499b58820225eb96c728816af9ea2ade47d1fc6b Mon Sep 17 00:00:00 2001 From: Alexander Matveev Date: Thu, 15 Jan 2026 03:53:53 +0000 Subject: [PATCH 041/328] 8374215: [macos] Clean and fix "lic_template.plist" to correctly work with multiple languages Reviewed-by: asemenyuk --- .../jdk/jpackage/internal/MacDmgLicense.java | 103 +++++++++ .../jdk/jpackage/internal/MacDmgPackager.java | 31 +-- .../resources/MacResources.properties | 5 + .../resources/MacResources_de.properties | 7 +- .../resources/MacResources_ja.properties | 7 +- .../resources/MacResources_zh_CN.properties | 7 +- .../internal/resources/lic_template.plist | 210 ++++-------------- .../helpers/jdk/jpackage/test/Executor.java | 4 +- .../jdk/tools/jpackage/share/LicenseTest.java | 33 ++- 9 files changed, 210 insertions(+), 197 deletions(-) create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgLicense.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgLicense.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgLicense.java new file mode 100644 index 00000000000..eea09b80929 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgLicense.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Base64; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; + +import jdk.jpackage.internal.resources.ResourceLocator; + +final class MacDmgLicense { + + public static void prepareLicensePListFile(Path licenseFile, Path licensePListFile) + throws IOException { + byte[] licenseContentOriginal = + Files.readAllBytes(licenseFile); + String licenseInBase64 = + Base64.getEncoder().encodeToString(licenseContentOriginal); + + Map data = new HashMap<>(); + data.put("APPLICATION_LICENSE_TEXT", licenseInBase64); + data.put("STR_DATA_ENGLISH", + getSTRData("English", Locale.ENGLISH, "MacRoman")); + data.put("STR_DATA_GERMAN", + getSTRData("German", Locale.GERMAN, "MacRoman")); + data.put("STR_DATA_JAPANESE", + getSTRData("Japanese", Locale.JAPANESE, "Shift_JIS")); + data.put("STR_DATA_SIMPLIFIED_CHINESE", + getSTRData("Simplified Chinese", Locale.SIMPLIFIED_CHINESE, "GB2312")); + + new OverridableResource(DEFAULT_LICENSE_PLIST, ResourceLocator.class) + .setCategory(I18N.getString("resource.license-setup")) + .setSubstitutionData(data) + .saveToFile(licensePListFile); + } + + private static void writeSTRDataString(ByteArrayOutputStream bos, + String str, String charset) { + byte [] bytes = str.getBytes(Charset.forName(charset)); + byte [] bytesLength = {(byte)bytes.length}; + bos.writeBytes(bytesLength); + bos.writeBytes(bytes); + } + + // Returns base64 decoded STR section data. + // Strings should be in following order: + // Language, message.dmg.license.button.agree, + // message.dmg.license.button.disagree, message.dmg.license.button.print + // message.dmg.license.button.save, message.dmg.license.message + // STR section data encoded: + // Number of strings in the list (unsigned 16-bit integer, big endian): 6 + // A sequence of strings prefixed with string length (unsigned 8-bit integer) + // Note: Language should not be translated. + private static String getSTRData(String language, Locale locale, String charset) { + ResourceBundle bundle = ResourceBundle.getBundle( + "jdk.jpackage.internal.resources.MacResources", locale); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + byte [] numberOfStrings = {0x00, 0x06}; // Always 6 + bos.writeBytes(numberOfStrings); + + writeSTRDataString(bos, language, charset); + writeSTRDataString(bos, bundle.getString("message.dmg.license.button.agree"), charset); + writeSTRDataString(bos, bundle.getString("message.dmg.license.button.disagree"), charset); + writeSTRDataString(bos, bundle.getString("message.dmg.license.button.print"), charset); + writeSTRDataString(bos, bundle.getString("message.dmg.license.button.save"), charset); + writeSTRDataString(bos, bundle.getString("message.dmg.license.message"), charset); + + return Base64.getEncoder().encodeToString(bos.toByteArray()); + } + + private static final String DEFAULT_LICENSE_PLIST = "lic_template.plist"; +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java index 82bb9fc4dad..cf4db226d37 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java @@ -34,7 +34,6 @@ import java.nio.file.LinkOption; import java.nio.file.Path; import java.text.MessageFormat; import java.util.ArrayList; -import java.util.Base64; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -105,7 +104,7 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, return env.configDir().resolve(pkg.app().name() + "-volume.icns"); } - Path licenseFile() { + Path licensePListFile() { return env.configDir().resolve(pkg.app().name() + "-license.plist"); } @@ -175,26 +174,6 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, .saveToFile(dmgSetup); } - private void prepareLicense() throws IOException { - final var licFile = pkg.licenseFile(); - if (licFile.isEmpty()) { - return; - } - - byte[] licenseContentOriginal = - Files.readAllBytes(licFile.orElseThrow()); - String licenseInBase64 = - Base64.getEncoder().encodeToString(licenseContentOriginal); - - Map data = new HashMap<>(); - data.put("APPLICATION_LICENSE_TEXT", licenseInBase64); - - env.createResource(DEFAULT_LICENSE_PLIST) - .setCategory(I18N.getString("resource.license-setup")) - .setSubstitutionData(data) - .saveToFile(licenseFile()); - } - private void prepareConfigFiles() throws IOException { env.createResource(DEFAULT_BACKGROUND_IMAGE) @@ -206,7 +185,9 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, .setExternal(pkg.icon().orElse(null)) .saveToFile(volumeIcon()); - prepareLicense(); + if (pkg.licenseFile().isPresent()) { + MacDmgLicense.prepareLicensePListFile(pkg.licenseFile().get(), licensePListFile()); + } prepareDMGSetupScript(); } @@ -359,7 +340,7 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, "udifrez", normalizedAbsolutePathString(finalDMG), "-xml", - normalizedAbsolutePathString(licenseFile()) + normalizedAbsolutePathString(licensePListFile()) ).retry() .setMaxAttemptsCount(10) .setAttemptTimeout(3, TimeUnit.SECONDS) @@ -441,6 +422,4 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, private static final String DEFAULT_BACKGROUND_IMAGE = "background_dmg.tiff"; private static final String DEFAULT_DMG_SETUP_SCRIPT = "DMGsetup.scpt"; private static final String TEMPLATE_BUNDLE_ICON = "JavaApp.icns"; - - private static final String DEFAULT_LICENSE_PLIST="lic_template.plist"; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties index ceeab587f66..0237d49f399 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties @@ -64,6 +64,11 @@ message.signing.pkg=Warning: For signing PKG, you might need to set "Always Trus message.setfile.dmg=Setting custom icon on DMG file skipped because 'SetFile' utility was not found. Installing Xcode with Command Line Tools should resolve this issue. message.codesign.failed.reason.app.content="codesign" failed and additional application content was supplied via the "--app-content" parameter. Probably the additional content broke the integrity of the application bundle and caused the failure. Ensure content supplied via the "--app-content" parameter does not break the integrity of the application bundle, or add it in the post-processing step. message.codesign.failed.reason.xcode.tools=Possible reason for "codesign" failure is missing Xcode with command line developer tools. Install Xcode with command line developer tools to see if it resolves the problem. +message.dmg.license.button.agree=Agree +message.dmg.license.button.disagree=Disagree +message.dmg.license.button.print=Print +message.dmg.license.button.save=Save... +message.dmg.license.message=If you agree with the terms of this license, press "Agree" to install the software. If you do not agree, press "Disagree". warning.unsigned.app.image=Warning: Using unsigned app-image to build signed {0}. warning.per.user.app.image.signed=Warning: Support for per-user configuration of the installed application will not be supported due to missing "{0}" in predefined signed application image. warning.non.standard.contents.sub.dir=Warning: The file name of the directory "{0}" specified for the --app-content option is not a standard subdirectory name in the "Contents" directory of the application bundle. The result application bundle may fail code signing and/or notarization. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties index 3cc56bb6cdf..367f3216f85 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2026, 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 @@ -71,6 +71,11 @@ message.signing.pkg=Warnung: Zum Signieren von PKG müssen Sie möglicherweise m message.setfile.dmg=Das Festlegen des benutzerdefinierten Symbols für die DMG-Datei wurde übersprungen, weil das Utility "SetFile" nicht gefunden wurde. Durch Installieren von Xcode mit Befehlszeilentools sollte dieses Problem behoben werden. message.codesign.failed.reason.app.content="codesign" war nicht erfolgreich, und zusätzlicher Anwendungsinhalt wurde über den Parameter "--app-content" angegeben. Wahrscheinlich hat der zusätzliche Inhalt die Integrität des Anwendungs-Bundles beeinträchtigt und den Fehler verursacht. Stellen Sie sicher, das der über den Parameter "--app-content" angegebene Inhalt nicht die Integrität des Anwendungs-Bundles beeinträchtigt, oder fügen Sie ihn im Nachverarbeitungsschritt hinzu. message.codesign.failed.reason.xcode.tools=Möglicher Grund für "codesign"-Fehler ist fehlender Xcode mit Befehlszeilen-Entwicklertools. Installieren Sie Xcode mit Befehlszeilen-Entwicklertools, und prüfen Sie, ob das Problem dadurch beseitigt wird. +message.dmg.license.button.agree=Akzeptieren +message.dmg.license.button.disagree=Ablehnen +message.dmg.license.button.print=Drucken +message.dmg.license.button.save=Sichern... +message.dmg.license.message=Klicken Sie in “Akzeptieren”, wenn Sie mit den Bestimmungen des Software-Lizenzvertrags einverstanden sind. Falls nicht, bitte “Ablehnen” anklicken. Sie können die Software nur installieren, wenn Sie “Akzeptieren” angeklickt haben. warning.unsigned.app.image=Warnung: Nicht signiertes app-image wird zum Erstellen von signiertem {0} verwendet. warning.per.user.app.image.signed=Warnung: Konfiguration der installierten Anwendung pro Benutzer wird nicht unterstützt, da "{0}" im vordefinierten signierten Anwendungsimage fehlt. warning.non.standard.contents.sub.dir=Warnung: Der Dateiname des Verzeichnisses "{0}", das für die Option --app-content angegeben wurde, ist kein Standardunterverzeichnisname im Verzeichnis "Contents" des Anwendungs-Bundles. Möglicherweise verläuft die Codesignierung und/oder Notarisierung im Ergebnisanwendungs-Bundle nicht erfolgreich. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties index d3150a34a86..ba2497d30dd 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2026, 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 @@ -71,6 +71,11 @@ message.signing.pkg=警告: PKGへの署名の場合、「キーチェーン・ message.setfile.dmg='SetFile'ユーティリティが見つからないため、DMGファイルでのカスタム・アイコンの設定がスキップされました。Xcodeとコマンド・ライン・ツールをインストールすると、この問題は解決されます。 message.codesign.failed.reason.app.content="codesign"が失敗したため、追加のアプリケーション・コンテンツが、"--app-content"パラメータを介して提供されました。追加のコンテンツにより、アプリケーション・バンドルの整合性が損われ、失敗の原因になった可能性があります。"--app-content"パラメータを介して提供されたコンテンツによって、アプリケーション・バンドルの整合性が損われていないことを確認するか、処理後のステップで追加してください。 message.codesign.failed.reason.xcode.tools="codesign"失敗の考えられる理由は、Xcodeとコマンドライン・デベロッパ・ツールの欠落です。Xcodeとコマンドライン・デベロッパ・ツールをインストールして、問題が解決されるかを確認してください。 +message.dmg.license.button.agree=同意します +message.dmg.license.button.disagree=同意しません +message.dmg.license.button.print=印刷する +message.dmg.license.button.save=保存... +message.dmg.license.message=本ソフトウエア使用許諾契約の条件に同意される場合には、ソフトウエアをインストールするために「同意します」を押してください。 同意されない場合には、「同意しません」を押してください。 warning.unsigned.app.image=警告: 署名されていないapp-imageを使用して署名された{0}を作成します。 warning.per.user.app.image.signed=警告: 事前定義済の署名付きアプリケーション・イメージに"{0}"がないため、インストール済アプリケーションのユーザーごとの構成はサポートされません。 warning.non.standard.contents.sub.dir=警告: --app-contentオプションに指定されたディレクトリ"{0}"のファイル名が、アプリケーション・バンドルの"Contents"ディレクトリ内の標準サブディレクトリ名ではありません。結果アプリケーション・バンドルは、コード署名および/または公証に失敗することがあります。 diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties index 8ca2219b72f..f855a31caae 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2026, 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 @@ -71,6 +71,11 @@ message.signing.pkg=警告:要对 PKG 进行签名,可能需要使用“密 message.setfile.dmg=由于未找到 'SetFile' 实用程序,跳过了针对 DMG 文件设置定制图标的操作。安装带命令行工具的 Xcode 应能解决此问题。 message.codesign.failed.reason.app.content="codesign" 失败,并通过 "--app-content" 参数提供了附加应用程序内容。可能是附加内容破坏了应用程序包的完整性,导致了故障。请确保通过 "--app-content" 参数提供的内容不会破坏应用程序包的完整性,或者在后处理步骤中添加该内容。 message.codesign.failed.reason.xcode.tools="codesign" 失败可能是因为缺少带命令行开发人员工具的 Xcode。请安装带命令行开发人员工具的 Xcode,看看是否可以解决问题。 +message.dmg.license.button.agree=同意 +message.dmg.license.button.disagree=不同意 +message.dmg.license.button.print=打印 +message.dmg.license.button.save=存储... +message.dmg.license.message=如果您同意本许可协议的条款,请按“同意”来安装此软件。如果您不同意,请按“不同意”。 warning.unsigned.app.image=警告:使用未签名的 app-image 生成已签名的 {0}。 warning.per.user.app.image.signed=警告:由于预定义的已签名应用程序映像中缺少 "{0}",不支持对已安装应用程序的每用户配置提供支持。 warning.non.standard.contents.sub.dir=警告:为 --app-content 选项指定的目录 "{0}" 的文件名不是应用程序包的 "Contents" 目录中的标准子目录名称。结果应用程序包可能会使代码签名和/或公证失败。 diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/lic_template.plist b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/lic_template.plist index 072e7168fb7..ac1b32325e8 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/lic_template.plist +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/lic_template.plist @@ -8,7 +8,9 @@ Attributes 0x0000 Data - AAAAAgAAAAAAAAAAAAQAAA== + + AAAABAAAAAAAAAADAAEAAAAOAAIAAQA0AAMAAQ== + ID 5000 Name @@ -21,17 +23,22 @@ Attributes 0x0000 Data - AAYPRW5nbGlzaCBkZWZhdWx0BUFncmVlCERpc2FncmVlBVByaW50B1NhdmUuLi56SWYgeW91IGFncmVlIHdpdGggdGhlIHRlcm1zIG9mIHRoaXMgbGljZW5zZSwgY2xpY2sgIkFncmVlIiB0byBhY2Nlc3MgdGhlIHNvZnR3YXJlLiAgSWYgeW91IGRvIG5vdCBhZ3JlZSwgcHJlc3MgIkRpc2FncmVlLiI= + + STR_DATA_ENGLISH + ID 5000 + Name - English buttons + English (United States) Attributes 0x0000 Data - AAYHRGV1dHNjaAtBa3plcHRpZXJlbghBYmxlaG5lbgdEcnVja2VuClNpY2hlcm4uLi7nS2xpY2tlbiBTaWUgaW4g0kFremVwdGllcmVu0ywgd2VubiBTaWUgbWl0IGRlbiBCZXN0aW1tdW5nZW4gZGVzIFNvZnR3YXJlLUxpemVuenZlcnRyYWdzIGVpbnZlcnN0YW5kZW4gc2luZC4gRmFsbHMgbmljaHQsIGJpdHRlINJBYmxlaG5lbtMgYW5rbGlja2VuLiBTaWUga5pubmVuIGRpZSBTb2Z0d2FyZSBudXIgaW5zdGFsbGllcmVuLCB3ZW5uIFNpZSDSQWt6ZXB0aWVyZW7TIGFuZ2VrbGlja3QgaGFiZW4u + + STR_DATA_GERMAN + ID 5001 Name @@ -41,151 +48,25 @@ Attributes 0x0000 Data - AAYHRW5nbGlzaAVBZ3JlZQhEaXNhZ3JlZQVQcmludAdTYXZlLi4ue0lmIHlvdSBhZ3JlZSB3aXRoIHRoZSB0ZXJtcyBvZiB0aGlzIGxpY2Vuc2UsIHByZXNzICJBZ3JlZSIgdG8gaW5zdGFsbCB0aGUgc29mdHdhcmUuICBJZiB5b3UgZG8gbm90IGFncmVlLCBwcmVzcyAiRGlzYWdyZWUiLg== + + STR_DATA_JAPANESE + ID 5002 Name - English - - - Attributes - 0x0000 - Data - AAYHRXNwYZZvbAdBY2VwdGFyCk5vIGFjZXB0YXIISW1wcmltaXIKR3VhcmRhci4uLsBTaSBlc3SHIGRlIGFjdWVyZG8gY29uIGxvcyB0jnJtaW5vcyBkZSBlc3RhIGxpY2VuY2lhLCBwdWxzZSAiQWNlcHRhciIgcGFyYSBpbnN0YWxhciBlbCBzb2Z0d2FyZS4gRW4gZWwgc3VwdWVzdG8gZGUgcXVlIG5vIGVzdI4gZGUgYWN1ZXJkbyBjb24gbG9zIHSOcm1pbm9zIGRlIGVzdGEgbGljZW5jaWEsIHB1bHNlICJObyBhY2VwdGFyLiI= - ID - 5003 - Name - Spanish - - - Attributes - 0x0000 - Data - AAYIRnJhbo1haXMIQWNjZXB0ZXIHUmVmdXNlcghJbXByaW1lcg5FbnJlZ2lzdHJlci4uLrpTaSB2b3VzIGFjY2VwdGV6IGxlcyB0ZXJtZXMgZGUgbGEgcHKOc2VudGUgbGljZW5jZSwgY2xpcXVleiBzdXIgIkFjY2VwdGVyIiBhZmluIGQnaW5zdGFsbGVyIGxlIGxvZ2ljaWVsLiBTaSB2b3VzIG4nkHRlcyBwYXMgZCdhY2NvcmQgYXZlYyBsZXMgdGVybWVzIGRlIGxhIGxpY2VuY2UsIGNsaXF1ZXogc3VyICJSZWZ1c2VyIi4= - ID - 5004 - Name - French - - - Attributes - 0x0000 - Data - AAYISXRhbGlhbm8HQWNjZXR0bwdSaWZpdXRvBlN0YW1wYQtSZWdpc3RyYS4uLn9TZSBhY2NldHRpIGxlIGNvbmRpemlvbmkgZGkgcXVlc3RhIGxpY2VuemEsIGZhaSBjbGljIHN1ICJBY2NldHRvIiBwZXIgaW5zdGFsbGFyZSBpbCBzb2Z0d2FyZS4gQWx0cmltZW50aSBmYWkgY2xpYyBzdSAiUmlmaXV0byIu - ID - 5005 - Name - Italian - - - Attributes - 0x0000 - Data - AAYISmFwYW5lc2UKk6+I04K1gtyCtwyTr4jTgrWC3IK5gvEIiPON/IK3gukHlduRti4uLrSWe4Ncg3SDZ4NFg0eDQY5nl3CLlpH4jF+W8YLMj/CMj4LJk6+I04KzguqC6Y/qjYeCyYLNgUGDXIN0g2eDRYNHg0GC8INDg5ODWINngVuDi4K3gumCvYLfgsmBdZOviNOCtYLcgreBdoLwiZ+CtYLEgq2CvoKzgqKBQoFAk6+I04KzguqCyIKij+qNh4LJgs2BQYF1k6+I04K1gtyCuYLxgXaC8ImfgrWCxIKtgr6Cs4KigUI= - ID - 5006 - Name Japanese Attributes 0x0000 Data - AAYKTmVkZXJsYW5kcwJKYQNOZWUFUHJpbnQJQmV3YWFyLi4upEluZGllbiB1IGFra29vcmQgZ2FhdCBtZXQgZGUgdm9vcndhYXJkZW4gdmFuIGRlemUgbGljZW50aWUsIGt1bnQgdSBvcCAnSmEnIGtsaWtrZW4gb20gZGUgcHJvZ3JhbW1hdHV1ciB0ZSBpbnN0YWxsZXJlbi4gSW5kaWVuIHUgbmlldCBha2tvb3JkIGdhYXQsIGtsaWt0IHUgb3AgJ05lZScu + + STR_DATA_SIMPLIFIED_CHINESE + ID - 5007 + 5003 Name - Dutch - - - Attributes - 0x0000 - Data - AAYGU3ZlbnNrCEdvZGuKbm5zBkF2YppqcwhTa3JpdiB1dAhTcGFyYS4uLpNPbSBEdSBnb2Rrim5uZXIgbGljZW5zdmlsbGtvcmVuIGtsaWNrYSBwjCAiR29ka4pubnMiIGaaciBhdHQgaW5zdGFsbGVyYSBwcm9ncmFtcHJvZHVrdGVuLiBPbSBEdSBpbnRlIGdvZGuKbm5lciBsaWNlbnN2aWxsa29yZW4sIGtsaWNrYSBwjCAiQXZimmpzIi4= - ID - 5008 - Name - Swedish - - - Attributes - 0x0000 - Data - AAYRUG9ydHVndZBzLCBCcmFzaWwJQ29uY29yZGFyCURpc2NvcmRhcghJbXByaW1pcglTYWx2YXIuLi6MU2UgZXN0hyBkZSBhY29yZG8gY29tIG9zIHRlcm1vcyBkZXN0YSBsaWNlbo1hLCBwcmVzc2lvbmUgIkNvbmNvcmRhciIgcGFyYSBpbnN0YWxhciBvIHNvZnR3YXJlLiBTZSBui28gZXN0hyBkZSBhY29yZG8sIHByZXNzaW9uZSAiRGlzY29yZGFyIi4= - ID - 5009 - Name - Brazilian Portuguese - - - Attributes - 0x0000 - Data - AAYSU2ltcGxpZmllZCBDaGluZXNlBM2s0uIGsrvNrNLiBLTy06EGtOa0oqGtVMjnufvE+s2s0uKxvtDtv8nQrdLptcTM9b/uo6zH67C0obDNrNLiobHAtLCy17C0y8jtvP6ho8jnufvE+rK7zazS4qOsx+uwtKGwsrvNrNLiobGhow== - ID - 5010 - Name - Simplified Chinese - - - Attributes - 0x0000 - Data - AAYTVHJhZGl0aW9uYWwgQ2hpbmVzZQSmULdOBqSjplC3TgSmQ6ZMBsB4pnOhS1CmcKpHsXqmULdOpbuzXKVpw9K4zKq6sfi02qFBvdCr9qGnplC3TqGopUimd7jLs27F6aFDpnCqR6SjplC3TqFBvdCr9qGnpKOmULdOoaihQw== - ID - 5011 - Name - Traditional Chinese - - - Attributes - 0x0000 - Data - AAYFRGFuc2sERW5pZwVVZW5pZwdVZHNrcml2CkFya2l2ZXIuLi6YSHZpcyBkdSBhY2NlcHRlcmVyIGJldGluZ2Vsc2VybmUgaSBsaWNlbnNhZnRhbGVuLCBza2FsIGR1IGtsaWtrZSBwjCDSRW5pZ9MgZm9yIGF0IGluc3RhbGxlcmUgc29mdHdhcmVuLiBLbGlrIHCMINJVZW5pZ9MgZm9yIGF0IGFubnVsbGVyZSBpbnN0YWxsZXJpbmdlbi4= - ID - 5012 - Name - Danish - - - Attributes - 0x0000 - Data - AAYFU3VvbWkISHl2imtzeW4KRW4gaHl2imtzeQdUdWxvc3RhCVRhbGxlbm5hyW9IeXaKa3N5IGxpc2Vuc3Npc29waW11a3NlbiBlaGRvdCBvc29pdHRhbWFsbGEg1Uh5doprc3nVLiBKb3MgZXQgaHl2imtzeSBzb3BpbXVrc2VuIGVodG9qYSwgb3NvaXRhINVFbiBoeXaKa3N51S4= - ID - 5013 - Name - Finnish - - - Attributes - 0x0000 - Data - AAYRRnJhbo1haXMgY2FuYWRpZW4IQWNjZXB0ZXIHUmVmdXNlcghJbXByaW1lcg5FbnJlZ2lzdHJlci4uLrpTaSB2b3VzIGFjY2VwdGV6IGxlcyB0ZXJtZXMgZGUgbGEgcHKOc2VudGUgbGljZW5jZSwgY2xpcXVleiBzdXIgIkFjY2VwdGVyIiBhZmluIGQnaW5zdGFsbGVyIGxlIGxvZ2ljaWVsLiBTaSB2b3VzIG4nkHRlcyBwYXMgZCdhY2NvcmQgYXZlYyBsZXMgdGVybWVzIGRlIGxhIGxpY2VuY2UsIGNsaXF1ZXogc3VyICJSZWZ1c2VyIi4= - ID - 5014 - Name - French Canadian - - - Attributes - 0x0000 - Data - AAYGS29yZWFuBLW/wMcJtb/AxyC+yMfUBsfBuLDGrgfA+sDlLi4ufrvnv+sgsOi+4LytwMcgs7u/67+hILW/wMfHz7jpLCAitb/AxyIgtNzD37imILStt68gvNLHwcauv/6+7rimILyzxKHHz73KvcO/wC4gtb/Ax8fPwfYgvsq0wrTZuOksICK1v8DHIL7Ix9QiILTcw9+4piC0qbijvcq9w7/ALg== - ID - 5015 - Name - Korean - - - Attributes - 0x0000 - Data - AAYFTm9yc2sERW5pZwlJa2tlIGVuaWcIU2tyaXYgdXQKQXJraXZlci4uLqNIdmlzIERlIGVyIGVuaWcgaSBiZXN0ZW1tZWxzZW5lIGkgZGVubmUgbGlzZW5zYXZ0YWxlbiwga2xpa2tlciBEZSBwjCAiRW5pZyIta25hcHBlbiBmb3IgjCBpbnN0YWxsZXJlIHByb2dyYW12YXJlbi4gSHZpcyBEZSBpa2tlIGVyIGVuaWcsIGtsaWtrZXIgRGUgcIwgIklra2UgZW5pZyIu - ID - 5016 - Name - Norwegian + Chinese (Simplified) TEXT @@ -194,50 +75,49 @@ Attributes 0x0000 Data - APPLICATION_LICENSE_TEXT + + APPLICATION_LICENSE_TEXT + ID 5000 Name - English SLA + English (United States) SLA + + + Attributes + 0x0000 + Data + + APPLICATION_LICENSE_TEXT + + ID + 5001 + Name + German SLA - - TMPL - Attributes 0x0000 Data - E0RlZmF1bHQgTGFuZ3VhZ2UgSUREV1JEBUNvdW50T0NOVAQqKioqTFNUQwtzeXMgbGFuZyBJRERXUkQebG9jYWwgcmVzIElEIChvZmZzZXQgZnJvbSA1MDAwRFdSRBAyLWJ5dGUgbGFuZ3VhZ2U/RFdSRAQqKioqTFNURQ== + + APPLICATION_LICENSE_TEXT + ID - 128 + 5002 Name - LPic + Japanese SLA - - plst - - - Attributes - 0x0050 - Data - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - ID - 0 - Name - - - - styl - Attributes 0x0000 Data - AAMAAAAAAAwACQAUAAAAAAAAAAAAAAAAACcADAAJABQBAAAAAAAAAAAAAAAAKgAMAAkAFAAAAAAAAAAAAAA= + + APPLICATION_LICENSE_TEXT + ID - 5000 + 5003 Name - English SLA + Chinese (Simplified) SLA diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java index b508d4f5ffe..1ae678cd944 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -183,12 +183,12 @@ public final class Executor extends CommandArguments { return commandOutputControl.charset(); } - Executor storeOutputInFiles(boolean v) { + public Executor storeOutputInFiles(boolean v) { commandOutputControl.storeOutputInFiles(v); return this; } - Executor storeOutputInFiles() { + public Executor storeOutputInFiles() { return storeOutputInFiles(true); } diff --git a/test/jdk/tools/jpackage/share/LicenseTest.java b/test/jdk/tools/jpackage/share/LicenseTest.java index 1c6bfd51b62..9c2d1077584 100644 --- a/test/jdk/tools/jpackage/share/LicenseTest.java +++ b/test/jdk/tools/jpackage/share/LicenseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -56,6 +56,9 @@ import jdk.jpackage.test.TKit; * * Mac: * + * For DMG license should be displayed on command line when "hdiutil attach" + * is called. + * * Windows * * Installer should display license text matching contents of the license file @@ -96,6 +99,7 @@ public class LicenseTest { LICENSE_FILE)); }); + initMacDmgLicenseVerifier(test.forTypes(PackageType.MAC_DMG)); initLinuxLicenseVerifier(test.forTypes(PackageType.LINUX)); test.run(); @@ -131,6 +135,33 @@ public class LicenseTest { new CustomDebianCopyrightTest().withSubstitution(true).run(); } + private static PackageTest initMacDmgLicenseVerifier(PackageTest test) { + return test + .addBundleVerifier(cmd -> { + verifyLicenseFileInDMGPackage(cmd); + }); + } + + private static void verifyLicenseFileInDMGPackage(JPackageCommand cmd) + throws IOException { + // DMG should have license, so attach with "no", since we only need license. + // With "no" attach will be canceled. + final var attachExec = Executor.of("sh", "-c", String.join(" ", + "no", + "|", + "/usr/bin/hdiutil", + "attach", + JPackageCommand.escapeAndJoin(cmd.outputBundle().toString()) + )).saveOutput().storeOutputInFiles(); + + // Expected exit code is 1, since we canceling license. + final var attachResult = attachExec.executeAndRepeatUntilExitCode(1, 10, 6); + TKit.assertStringListEquals(Files.readAllLines(LICENSE_FILE), + attachResult.stdout(), String.format( + "Check output of \"hdiutil attach\" has the same license as contents of source license file [%s]", + LICENSE_FILE)); + } + private static PackageTest initLinuxLicenseVerifier(PackageTest test) { return test .addBundleVerifier(cmd -> { From b6b337926d5f13ee2bca12ea94530ea59911ff2f Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Thu, 15 Jan 2026 05:58:18 +0000 Subject: [PATCH 042/328] 8371762: Incorrect use of checked_cast in Arguments::process_settings_file Reviewed-by: dholmes, kbarrett --- src/hotspot/share/runtime/arguments.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index cf0a1ab9757..546ae610769 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -64,7 +64,6 @@ #include "runtime/vm_version.hpp" #include "services/management.hpp" #include "utilities/align.hpp" -#include "utilities/checkedCast.hpp" #include "utilities/debug.hpp" #include "utilities/defaultStream.hpp" #include "utilities/macros.hpp" @@ -1207,16 +1206,22 @@ bool Arguments::process_settings_file(const char* file_name, bool should_exist, } char token[1024]; - int pos = 0; + size_t pos = 0; bool in_white_space = true; bool in_comment = false; bool in_quote = false; - int quote_c = 0; + char quote_c = 0; bool result = true; - int c = getc(stream); - while(c != EOF && pos < (int)(sizeof(token)-1)) { + int c_or_eof = getc(stream); + while (c_or_eof != EOF && pos < (sizeof(token) - 1)) { + // We have checked the c_or_eof for EOF. getc should only ever return the + // EOF or an unsigned char converted to an int. We cast down to a char to + // avoid the char to int promotions we would otherwise do in the comparisons + // below (which would be incorrect if we ever compared to a non-ascii char), + // and the int to char conversions we would otherwise do in the assignments. + const char c = static_cast(c_or_eof); if (in_white_space) { if (in_comment) { if (c == '\n') in_comment = false; @@ -1224,7 +1229,7 @@ bool Arguments::process_settings_file(const char* file_name, bool should_exist, if (c == '#') in_comment = true; else if (!isspace((unsigned char) c)) { in_white_space = false; - token[pos++] = checked_cast(c); + token[pos++] = c; } } } else { @@ -1244,10 +1249,10 @@ bool Arguments::process_settings_file(const char* file_name, bool should_exist, } else if (in_quote && (c == quote_c)) { in_quote = false; } else { - token[pos++] = checked_cast(c); + token[pos++] = c; } } - c = getc(stream); + c_or_eof = getc(stream); } if (pos > 0) { token[pos] = '\0'; From d16a9b2ec507251a44f034f1ccf8039f02023d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Galder=20Zamarre=C3=B1o?= Date: Thu, 15 Jan 2026 07:22:54 +0000 Subject: [PATCH 043/328] 8373134: C2: Min/Max users of Min/Max uses should be enqueued for GVN Reviewed-by: epeter, bmaillard, dlong --- src/hotspot/share/opto/addnode.cpp | 30 +-- src/hotspot/share/opto/addnode.hpp | 46 ++--- src/hotspot/share/opto/loopnode.cpp | 18 +- src/hotspot/share/opto/macro.cpp | 4 +- src/hotspot/share/opto/movenode.cpp | 4 +- src/hotspot/share/opto/node.hpp | 3 + src/hotspot/share/opto/phaseX.cpp | 9 + src/hotspot/share/opto/vectorization.cpp | 2 +- .../compiler/igvn/TestMinMaxIdentity.java | 186 ++++++++++++++++++ 9 files changed, 251 insertions(+), 51 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/igvn/TestMinMaxIdentity.java diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index 40cd6337c17..e04da430ef0 100644 --- a/src/hotspot/share/opto/addnode.cpp +++ b/src/hotspot/share/opto/addnode.cpp @@ -1195,7 +1195,7 @@ const Type* XorLNode::Value(PhaseGVN* phase) const { return AddNode::Value(phase); } -Node* MaxNode::build_min_max_int(Node* a, Node* b, bool is_max) { +Node* MinMaxNode::build_min_max_int(Node* a, Node* b, bool is_max) { if (is_max) { return new MaxINode(a, b); } else { @@ -1203,7 +1203,7 @@ Node* MaxNode::build_min_max_int(Node* a, Node* b, bool is_max) { } } -Node* MaxNode::build_min_max_long(PhaseGVN* phase, Node* a, Node* b, bool is_max) { +Node* MinMaxNode::build_min_max_long(PhaseGVN* phase, Node* a, Node* b, bool is_max) { if (is_max) { return new MaxLNode(phase->C, a, b); } else { @@ -1211,7 +1211,7 @@ Node* MaxNode::build_min_max_long(PhaseGVN* phase, Node* a, Node* b, bool is_max } } -Node* MaxNode::build_min_max(Node* a, Node* b, bool is_max, bool is_unsigned, const Type* t, PhaseGVN& gvn) { +Node* MinMaxNode::build_min_max(Node* a, Node* b, bool is_max, bool is_unsigned, const Type* t, PhaseGVN& gvn) { bool is_int = gvn.type(a)->isa_int(); assert(is_int || gvn.type(a)->isa_long(), "int or long inputs"); assert(is_int == (gvn.type(b)->isa_int() != nullptr), "inconsistent inputs"); @@ -1243,7 +1243,7 @@ Node* MaxNode::build_min_max(Node* a, Node* b, bool is_max, bool is_unsigned, co return res; } -Node* MaxNode::build_min_max_diff_with_zero(Node* a, Node* b, bool is_max, const Type* t, PhaseGVN& gvn) { +Node* MinMaxNode::build_min_max_diff_with_zero(Node* a, Node* b, bool is_max, const Type* t, PhaseGVN& gvn) { bool is_int = gvn.type(a)->isa_int(); assert(is_int || gvn.type(a)->isa_long(), "int or long inputs"); assert(is_int == (gvn.type(b)->isa_int() != nullptr), "inconsistent inputs"); @@ -1290,7 +1290,7 @@ static bool can_overflow(const TypeLong* t, jlong c) { // Let = x_operands and = y_operands. // If x == y and neither add(x, x_off) nor add(y, y_off) overflow, return // add(x, op(x_off, y_off)). Otherwise, return nullptr. -Node* MaxNode::extract_add(PhaseGVN* phase, ConstAddOperands x_operands, ConstAddOperands y_operands) { +Node* MinMaxNode::extract_add(PhaseGVN* phase, ConstAddOperands x_operands, ConstAddOperands y_operands) { Node* x = x_operands.first; Node* y = y_operands.first; int opcode = Opcode(); @@ -1327,7 +1327,7 @@ static ConstAddOperands as_add_with_constant(Node* n) { return ConstAddOperands(x, c_type->is_int()->get_con()); } -Node* MaxNode::IdealI(PhaseGVN* phase, bool can_reshape) { +Node* MinMaxNode::IdealI(PhaseGVN* phase, bool can_reshape) { Node* n = AddNode::Ideal(phase, can_reshape); if (n != nullptr) { return n; @@ -1401,7 +1401,7 @@ Node* MaxINode::Identity(PhaseGVN* phase) { return in(2); } - return MaxNode::Identity(phase); + return MinMaxNode::Identity(phase); } //============================================================================= @@ -1434,7 +1434,7 @@ Node* MinINode::Identity(PhaseGVN* phase) { return in(1); } - return MaxNode::Identity(phase); + return MinMaxNode::Identity(phase); } //------------------------------add_ring--------------------------------------- @@ -1564,7 +1564,7 @@ Node* MaxLNode::Identity(PhaseGVN* phase) { return in(2); } - return MaxNode::Identity(phase); + return MinMaxNode::Identity(phase); } Node* MaxLNode::Ideal(PhaseGVN* phase, bool can_reshape) { @@ -1596,7 +1596,7 @@ Node* MinLNode::Identity(PhaseGVN* phase) { return in(1); } - return MaxNode::Identity(phase); + return MinMaxNode::Identity(phase); } Node* MinLNode::Ideal(PhaseGVN* phase, bool can_reshape) { @@ -1610,7 +1610,7 @@ Node* MinLNode::Ideal(PhaseGVN* phase, bool can_reshape) { return nullptr; } -int MaxNode::opposite_opcode() const { +int MinMaxNode::opposite_opcode() const { if (Opcode() == max_opcode()) { return min_opcode(); } else { @@ -1621,7 +1621,7 @@ int MaxNode::opposite_opcode() const { // Given a redundant structure such as Max/Min(A, Max/Min(B, C)) where A == B or A == C, return the useful part of the structure. // 'operation' is the node expected to be the inner 'Max/Min(B, C)', and 'operand' is the node expected to be the 'A' operand of the outer node. -Node* MaxNode::find_identity_operation(Node* operation, Node* operand) { +Node* MinMaxNode::find_identity_operation(Node* operation, Node* operand) { if (operation->Opcode() == Opcode() || operation->Opcode() == opposite_opcode()) { Node* n1 = operation->in(1); Node* n2 = operation->in(2); @@ -1645,17 +1645,17 @@ Node* MaxNode::find_identity_operation(Node* operation, Node* operand) { return nullptr; } -Node* MaxNode::Identity(PhaseGVN* phase) { +Node* MinMaxNode::Identity(PhaseGVN* phase) { if (in(1) == in(2)) { return in(1); } - Node* identity_1 = MaxNode::find_identity_operation(in(2), in(1)); + Node* identity_1 = MinMaxNode::find_identity_operation(in(2), in(1)); if (identity_1 != nullptr) { return identity_1; } - Node* identity_2 = MaxNode::find_identity_operation(in(1), in(2)); + Node* identity_2 = MinMaxNode::find_identity_operation(in(1), in(2)); if (identity_2 != nullptr) { return identity_2; } diff --git a/src/hotspot/share/opto/addnode.hpp b/src/hotspot/share/opto/addnode.hpp index 1bbdae92e48..4151ab5d065 100644 --- a/src/hotspot/share/opto/addnode.hpp +++ b/src/hotspot/share/opto/addnode.hpp @@ -324,14 +324,16 @@ public: //------------------------------MaxNode---------------------------------------- // Max (or min) of 2 values. Included with the ADD nodes because it inherits // all the behavior of addition on a ring. -class MaxNode : public AddNode { +class MinMaxNode : public AddNode { private: static Node* build_min_max(Node* a, Node* b, bool is_max, bool is_unsigned, const Type* t, PhaseGVN& gvn); static Node* build_min_max_diff_with_zero(Node* a, Node* b, bool is_max, const Type* t, PhaseGVN& gvn); Node* extract_add(PhaseGVN* phase, ConstAddOperands x_operands, ConstAddOperands y_operands); public: - MaxNode( Node *in1, Node *in2 ) : AddNode(in1,in2) {} + MinMaxNode(Node* in1, Node* in2) : AddNode(in1, in2) { + init_class_id(Class_MinMax); + } virtual int Opcode() const = 0; virtual int max_opcode() const = 0; virtual int min_opcode() const = 0; @@ -373,9 +375,9 @@ public: //------------------------------MaxINode--------------------------------------- // Maximum of 2 integers. Included with the ADD nodes because it inherits // all the behavior of addition on a ring. -class MaxINode : public MaxNode { +class MaxINode : public MinMaxNode { public: - MaxINode( Node *in1, Node *in2 ) : MaxNode(in1,in2) {} + MaxINode(Node* in1, Node* in2) : MinMaxNode(in1, in2) {} virtual int Opcode() const; virtual const Type *add_ring( const Type *, const Type * ) const; virtual const Type *add_id() const { return TypeInt::make(min_jint); } @@ -390,9 +392,9 @@ public: //------------------------------MinINode--------------------------------------- // MINimum of 2 integers. Included with the ADD nodes because it inherits // all the behavior of addition on a ring. -class MinINode : public MaxNode { +class MinINode : public MinMaxNode { public: - MinINode( Node *in1, Node *in2 ) : MaxNode(in1,in2) {} + MinINode(Node* in1, Node* in2) : MinMaxNode(in1, in2) {} virtual int Opcode() const; virtual const Type *add_ring( const Type *, const Type * ) const; virtual const Type *add_id() const { return TypeInt::make(max_jint); } @@ -406,9 +408,9 @@ public: //------------------------------MaxLNode--------------------------------------- // MAXimum of 2 longs. -class MaxLNode : public MaxNode { +class MaxLNode : public MinMaxNode { public: - MaxLNode(Compile* C, Node* in1, Node* in2) : MaxNode(in1, in2) { + MaxLNode(Compile* C, Node* in1, Node* in2) : MinMaxNode(in1, in2) { init_flags(Flag_is_macro); C->add_macro_node(this); } @@ -425,9 +427,9 @@ public: //------------------------------MinLNode--------------------------------------- // MINimum of 2 longs. -class MinLNode : public MaxNode { +class MinLNode : public MinMaxNode { public: - MinLNode(Compile* C, Node* in1, Node* in2) : MaxNode(in1, in2) { + MinLNode(Compile* C, Node* in1, Node* in2) : MinMaxNode(in1, in2) { init_flags(Flag_is_macro); C->add_macro_node(this); } @@ -444,9 +446,9 @@ public: //------------------------------MaxFNode--------------------------------------- // Maximum of 2 floats. -class MaxFNode : public MaxNode { +class MaxFNode : public MinMaxNode { public: - MaxFNode(Node *in1, Node *in2) : MaxNode(in1, in2) {} + MaxFNode(Node* in1, Node* in2) : MinMaxNode(in1, in2) {} virtual int Opcode() const; virtual const Type *add_ring(const Type*, const Type*) const; virtual const Type *add_id() const { return TypeF::NEG_INF; } @@ -458,9 +460,9 @@ public: //------------------------------MinFNode--------------------------------------- // Minimum of 2 floats. -class MinFNode : public MaxNode { +class MinFNode : public MinMaxNode { public: - MinFNode(Node *in1, Node *in2) : MaxNode(in1, in2) {} + MinFNode(Node* in1, Node* in2) : MinMaxNode(in1, in2) {} virtual int Opcode() const; virtual const Type *add_ring(const Type*, const Type*) const; virtual const Type *add_id() const { return TypeF::POS_INF; } @@ -472,9 +474,9 @@ public: //------------------------------MaxHFNode-------------------------------------- // Maximum of 2 half floats. -class MaxHFNode : public MaxNode { +class MaxHFNode : public MinMaxNode { public: - MaxHFNode(Node* in1, Node* in2) : MaxNode(in1, in2) {} + MaxHFNode(Node* in1, Node* in2) : MinMaxNode(in1, in2) {} virtual int Opcode() const; virtual const Type* add_ring(const Type*, const Type*) const; virtual const Type* add_id() const { return TypeH::NEG_INF; } @@ -486,9 +488,9 @@ public: //------------------------------MinHFNode--------------------------------------- // Minimum of 2 half floats. -class MinHFNode : public MaxNode { +class MinHFNode : public MinMaxNode { public: - MinHFNode(Node* in1, Node* in2) : MaxNode(in1, in2) {} + MinHFNode(Node* in1, Node* in2) : MinMaxNode(in1, in2) {} virtual int Opcode() const; virtual const Type* add_ring(const Type*, const Type*) const; virtual const Type* add_id() const { return TypeH::POS_INF; } @@ -500,9 +502,9 @@ public: //------------------------------MaxDNode--------------------------------------- // Maximum of 2 doubles. -class MaxDNode : public MaxNode { +class MaxDNode : public MinMaxNode { public: - MaxDNode(Node *in1, Node *in2) : MaxNode(in1, in2) {} + MaxDNode(Node* in1, Node* in2) : MinMaxNode(in1, in2) {} virtual int Opcode() const; virtual const Type *add_ring(const Type*, const Type*) const; virtual const Type *add_id() const { return TypeD::NEG_INF; } @@ -514,9 +516,9 @@ public: //------------------------------MinDNode--------------------------------------- // Minimum of 2 doubles. -class MinDNode : public MaxNode { +class MinDNode : public MinMaxNode { public: - MinDNode(Node *in1, Node *in2) : MaxNode(in1, in2) {} + MinDNode(Node* in1, Node* in2) : MinMaxNode(in1, in2) {} virtual int Opcode() const; virtual const Type *add_ring(const Type*, const Type*) const; virtual const Type *add_id() const { return TypeD::POS_INF; } diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index dacc1a1a734..8dc34af9c19 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -979,9 +979,9 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { Node* inner_iters_max = nullptr; if (stride_con > 0) { - inner_iters_max = MaxNode::max_diff_with_zero(limit, outer_phi, TypeInteger::bottom(bt), _igvn); + inner_iters_max = MinMaxNode::max_diff_with_zero(limit, outer_phi, TypeInteger::bottom(bt), _igvn); } else { - inner_iters_max = MaxNode::max_diff_with_zero(outer_phi, limit, TypeInteger::bottom(bt), _igvn); + inner_iters_max = MinMaxNode::max_diff_with_zero(outer_phi, limit, TypeInteger::bottom(bt), _igvn); } Node* inner_iters_limit = _igvn.integercon(iters_limit, bt); @@ -989,7 +989,7 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { // Long.MIN_VALUE to Long.MAX_VALUE for instance). Use an unsigned // min. const TypeInteger* inner_iters_actual_range = TypeInteger::make(0, iters_limit, Type::WidenMin, bt); - Node* inner_iters_actual = MaxNode::unsigned_min(inner_iters_max, inner_iters_limit, inner_iters_actual_range, _igvn); + Node* inner_iters_actual = MinMaxNode::unsigned_min(inner_iters_max, inner_iters_limit, inner_iters_actual_range, _igvn); Node* inner_iters_actual_int; if (bt == T_LONG) { @@ -1618,7 +1618,7 @@ void PhaseIdealLoop::transform_long_range_checks(int stride_con, const Node_List Node* max_jint_plus_one_long = longcon((jlong)max_jint + 1); Node* max_range = new AddLNode(max_jint_plus_one_long, L); register_new_node(max_range, entry_control); - R = MaxNode::unsigned_min(R, max_range, TypeLong::POS, _igvn); + R = MinMaxNode::unsigned_min(R, max_range, TypeLong::POS, _igvn); set_subtree_ctrl(R, true); } @@ -1717,9 +1717,9 @@ void PhaseIdealLoop::transform_long_range_checks(int stride_con, const Node_List } Node* PhaseIdealLoop::clamp(Node* R, Node* L, Node* H) { - Node* min = MaxNode::signed_min(R, H, TypeLong::LONG, _igvn); + Node* min = MinMaxNode::signed_min(R, H, TypeLong::LONG, _igvn); set_subtree_ctrl(min, true); - Node* max = MaxNode::signed_max(L, min, TypeLong::LONG, _igvn); + Node* max = MinMaxNode::signed_max(L, min, TypeLong::LONG, _igvn); set_subtree_ctrl(max, true); return max; } @@ -3485,14 +3485,14 @@ void OuterStripMinedLoopNode::adjust_strip_mined_loop(PhaseIterGVN* igvn) { // the loop body to be run for LoopStripMiningIter. Node* max = nullptr; if (stride > 0) { - max = MaxNode::max_diff_with_zero(limit, iv_phi, TypeInt::INT, *igvn); + max = MinMaxNode::max_diff_with_zero(limit, iv_phi, TypeInt::INT, *igvn); } else { - max = MaxNode::max_diff_with_zero(iv_phi, limit, TypeInt::INT, *igvn); + max = MinMaxNode::max_diff_with_zero(iv_phi, limit, TypeInt::INT, *igvn); } // sub is positive and can be larger than the max signed int // value. Use an unsigned min. Node* const_iters = igvn->intcon(scaled_iters); - Node* min = MaxNode::unsigned_min(max, const_iters, TypeInt::make(0, scaled_iters, Type::WidenMin), *igvn); + Node* min = MinMaxNode::unsigned_min(max, const_iters, TypeInt::make(0, scaled_iters, Type::WidenMin), *igvn); // min is the number of iterations for the next inner loop execution: // unsigned_min(max(limit - iv_phi, 0), scaled_iters) if stride > 0 // unsigned_min(max(iv_phi - limit, 0), scaled_iters) if stride < 0 diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 80818a4ddc7..4df03714376 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -2577,11 +2577,11 @@ void PhaseMacroExpand::eliminate_opaque_looplimit_macro_nodes() { // a CMoveL construct now. At least until here, the type could be computed // precisely. CMoveL is not so smart, but we can give it at least the best // type we know abouot n now. - Node* repl = MaxNode::signed_max(n->in(1), n->in(2), _igvn.type(n), _igvn); + Node* repl = MinMaxNode::signed_max(n->in(1), n->in(2), _igvn.type(n), _igvn); _igvn.replace_node(n, repl); success = true; } else if (n->Opcode() == Op_MinL) { - Node* repl = MaxNode::signed_min(n->in(1), n->in(2), _igvn.type(n), _igvn); + Node* repl = MinMaxNode::signed_min(n->in(1), n->in(2), _igvn.type(n), _igvn); _igvn.replace_node(n, repl); success = true; } diff --git a/src/hotspot/share/opto/movenode.cpp b/src/hotspot/share/opto/movenode.cpp index 66db1df339b..6b6becb434f 100644 --- a/src/hotspot/share/opto/movenode.cpp +++ b/src/hotspot/share/opto/movenode.cpp @@ -271,9 +271,9 @@ Node* CMoveNode::Ideal_minmax(PhaseGVN* phase, CMoveNode* cmove) { // Create the Min/Max node based on the type and kind if (cmp_op == Op_CmpL) { - return MaxNode::build_min_max_long(phase, cmp_l, cmp_r, is_max); + return MinMaxNode::build_min_max_long(phase, cmp_l, cmp_r, is_max); } else { - return MaxNode::build_min_max_int(cmp_l, cmp_r, is_max); + return MinMaxNode::build_min_max_int(cmp_l, cmp_r, is_max); } } diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 0adb2072100..f1d9785a746 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -130,6 +130,7 @@ class MemBarNode; class MemBarStoreStoreNode; class MemNode; class MergeMemNode; +class MinMaxNode; class MoveNode; class MulNode; class MultiNode; @@ -809,6 +810,7 @@ public: DEFINE_CLASS_ID(AddP, Node, 9) DEFINE_CLASS_ID(BoxLock, Node, 10) DEFINE_CLASS_ID(Add, Node, 11) + DEFINE_CLASS_ID(MinMax, Add, 0) DEFINE_CLASS_ID(Mul, Node, 12) DEFINE_CLASS_ID(ClearArray, Node, 14) DEFINE_CLASS_ID(Halt, Node, 15) @@ -986,6 +988,7 @@ public: DEFINE_CLASS_QUERY(MemBar) DEFINE_CLASS_QUERY(MemBarStoreStore) DEFINE_CLASS_QUERY(MergeMem) + DEFINE_CLASS_QUERY(MinMax) DEFINE_CLASS_QUERY(Move) DEFINE_CLASS_QUERY(Mul) DEFINE_CLASS_QUERY(Multi) diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index c4bdc5e8903..52badca8050 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -2633,6 +2633,15 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ } } } + // Check for Max/Min(A, Max/Min(B, C)) where A == B or A == C + if (use->is_MinMax()) { + for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { + Node* u = use->fast_out(i2); + if (u->Opcode() == use->Opcode()) { + worklist.push(u); + } + } + } auto enqueue_init_mem_projs = [&](ProjNode* proj) { add_users_to_worklist0(proj, worklist); }; diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index 1755b0453eb..8e0ca927a16 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -1122,7 +1122,7 @@ Node* make_last(Node* initL, jint stride, Node* limitL, PhaseIdealLoop* phase) { Node* last = new AddLNode(initL, k_mul_stride); // Make sure that the last does not lie "before" init. - Node* last_clamped = MaxNode::build_min_max_long(&igvn, initL, last, stride > 0); + Node* last_clamped = MinMaxNode::build_min_max_long(&igvn, initL, last, stride > 0); phase->register_new_node_with_ctrl_of(diffL, initL); phase->register_new_node_with_ctrl_of(diffL_m1, initL); diff --git a/test/hotspot/jtreg/compiler/igvn/TestMinMaxIdentity.java b/test/hotspot/jtreg/compiler/igvn/TestMinMaxIdentity.java new file mode 100644 index 00000000000..d358359ff14 --- /dev/null +++ b/test/hotspot/jtreg/compiler/igvn/TestMinMaxIdentity.java @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2025 IBM Corporation. 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 8373134 + * @summary Verify that min/max add identity optimizations get applied correctly + * @modules java.base/jdk.internal.misc + * @modules jdk.incubator.vector + * @library /test/lib / + * @run driver ${test.main.class} + */ + +package compiler.igvn; + +import compiler.lib.compile_framework.CompileFramework; +import compiler.lib.template_framework.Template; +import compiler.lib.template_framework.TemplateToken; +import compiler.lib.template_framework.library.CodeGenerationDataNameType; +import compiler.lib.template_framework.library.PrimitiveType; +import compiler.lib.template_framework.library.TestFrameworkClass; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; + +import static compiler.lib.template_framework.Template.let; +import static compiler.lib.template_framework.Template.scope; + +public class TestMinMaxIdentity { + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a java source file. + comp.addJavaSourceCode("compiler.igvn.templated.MinMaxIdentity", generate(comp)); + + // Compile the source file. + comp.compile("--add-modules=jdk.incubator.vector"); + + comp.invoke("compiler.igvn.templated.MinMaxIdentity", "main", new Object[] {new String[] { + "--add-modules=jdk.incubator.vector", + "--add-opens", "jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED" + }}); + } + + private static String generate(CompileFramework comp) { + // Create a list to collect all tests. + List testTemplateTokens = new ArrayList<>(); + + Stream.of(MinMaxOp.values()) + .flatMap(MinMaxOp::generate) + .forEach(testTemplateTokens::add); + + Stream.of(Fp16MinMaxOp.values()) + .flatMap(Fp16MinMaxOp::generate) + .forEach(testTemplateTokens::add); + + // Create the test class, which runs all testTemplateTokens. + return TestFrameworkClass.render( + // package and class name. + "compiler.igvn.templated", "MinMaxIdentity", + // List of imports. + Set.of("jdk.incubator.vector.Float16"), + // classpath, so the Test VM has access to the compiled class files. + comp.getEscapedClassPathOfCompiledClasses(), + // The list of tests. + testTemplateTokens); + } + + enum MinMaxOp { + MIN_D("min", CodeGenerationDataNameType.doubles()), + MAX_D("max", CodeGenerationDataNameType.doubles()), + MIN_F("min", CodeGenerationDataNameType.floats()), + MAX_F("max", CodeGenerationDataNameType.floats()), + MIN_I("min", CodeGenerationDataNameType.ints()), + MAX_I("max", CodeGenerationDataNameType.ints()), + MIN_L("min", CodeGenerationDataNameType.longs()), + MAX_L("max", CodeGenerationDataNameType.longs()); + + final String functionName; + final PrimitiveType type; + + MinMaxOp(String functionName, PrimitiveType type) { + this.functionName = functionName; + this.type = type; + } + + Stream generate() { + return Stream.of(template("a", "b"), template("b", "a")). + map(Template.ZeroArgs::asToken); + } + + private Template.ZeroArgs template(String arg1, String arg2) { + return Template.make(() -> scope( + let("boxedTypeName", type.boxedTypeName()), + let("op", name()), + let("type", type.name()), + let("functionName", functionName), + let("arg1", arg1), + let("arg2", arg2), + """ + @Test + @IR(counts = {IRNode.#op, "= 1"}, + phase = CompilePhase.BEFORE_MACRO_EXPANSION) + @Arguments(values = {Argument.NUMBER_42, Argument.NUMBER_42}) + public #type $test(#type #arg1, #type #arg2) { + int i; + for (i = -10; i < 1; i++) { + } + #type c = a * i; + return #boxedTypeName.#functionName(a, #boxedTypeName.#functionName(b, c)); + } + """ + )); + } + } + + enum Fp16MinMaxOp { + MAX_HF("max"), + MIN_HF("min"); + + final String functionName; + + Fp16MinMaxOp(String functionName) { + this.functionName = functionName; + } + + Stream generate() { + return Stream.of(template("a", "b"), template("b", "a")). + map(Template.ZeroArgs::asToken); + } + + private Template.ZeroArgs template(String arg1, String arg2) { + return Template.make(() -> scope( + let("op", name()), + let("functionName", functionName), + let("arg1", arg1), + let("arg2", arg2), + """ + @Setup + private static Object[] $setup() { + return new Object[] {Float16.valueOf(42), Float16.valueOf(42)}; + } + + @Test + @IR(counts = {IRNode.#op, "= 1"}, + phase = CompilePhase.BEFORE_MACRO_EXPANSION, + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.#op, "= 1"}, + phase = CompilePhase.BEFORE_MACRO_EXPANSION, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) + @Arguments(setup = "$setup") + public Float16 $test(Float16 #arg1, Float16 #arg2) { + int i; + for (i = -10; i < 1; i++) { + } + Float16 c = Float16.multiply(a, Float16.valueOf(i)); + return Float16.#functionName(a, Float16.#functionName(b, c)); + } + """ + )); + } + } +} From f6d26c6b32a3ea394cc9b7f6046cd9d7d635c568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Thu, 15 Jan 2026 07:50:52 +0000 Subject: [PATCH 044/328] 8354853: Clean up x86 registers after 32-bit x86 removal Reviewed-by: aph, shade, mchevalier --- src/hotspot/cpu/x86/register_x86.cpp | 8 +--- src/hotspot/cpu/x86/register_x86.hpp | 56 +++++++----------------- src/hotspot/cpu/x86/vmreg_x86.cpp | 4 +- src/hotspot/cpu/x86/vmreg_x86.hpp | 13 +----- src/hotspot/cpu/x86/vmreg_x86.inline.hpp | 4 +- 5 files changed, 23 insertions(+), 62 deletions(-) diff --git a/src/hotspot/cpu/x86/register_x86.cpp b/src/hotspot/cpu/x86/register_x86.cpp index e6083429344..188af9264a8 100644 --- a/src/hotspot/cpu/x86/register_x86.cpp +++ b/src/hotspot/cpu/x86/register_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,14 +32,10 @@ const KRegister::KRegisterImpl all_KRegisterImpls [KRegister::number_ const char * Register::RegisterImpl::name() const { static const char *const names[number_of_registers] = { -#ifdef _LP64 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" -#else - "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" -#endif // _LP64 }; return is_valid() ? names[encoding()] : "noreg"; } @@ -54,11 +50,9 @@ const char* FloatRegister::FloatRegisterImpl::name() const { const char* XMMRegister::XMMRegisterImpl::name() const { static const char *const names[number_of_registers] = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" -#ifdef _LP64 ,"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" ,"xmm16", "xmm17", "xmm18", "xmm19", "xmm20", "xmm21", "xmm22", "xmm23" ,"xmm24", "xmm25", "xmm26", "xmm27", "xmm28", "xmm29", "xmm30", "xmm31" -#endif // _LP64 }; return is_valid() ? names[encoding()] : "xnoreg"; } diff --git a/src/hotspot/cpu/x86/register_x86.hpp b/src/hotspot/cpu/x86/register_x86.hpp index 0a8ecb7be26..5e0326b9aad 100644 --- a/src/hotspot/cpu/x86/register_x86.hpp +++ b/src/hotspot/cpu/x86/register_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ class VMRegImpl; typedef VMRegImpl* VMReg; -// The implementation of integer registers for the x86/x64 architectures. +// The implementation of integer registers for the x64 architectures. class Register { private: int _encoding; @@ -44,11 +44,9 @@ private: public: inline friend constexpr Register as_Register(int encoding); - enum { - number_of_registers = LP64_ONLY( 32 ) NOT_LP64( 8 ), - number_of_byte_registers = LP64_ONLY( 32 ) NOT_LP64( 4 ), - max_slots_per_register = LP64_ONLY( 2 ) NOT_LP64( 1 ) - }; + static const int number_of_registers = 32; + static const int number_of_byte_registers = 32; + static const int max_slots_per_register = 2; class RegisterImpl: public AbstractRegisterImpl { friend class Register; @@ -79,11 +77,9 @@ public: // Actually available GP registers for use, depending on actual CPU capabilities and flags. static int available_gp_registers() { -#ifdef _LP64 if (!UseAPX) { return number_of_registers / 2; } -#endif // _LP64 return number_of_registers; } }; @@ -116,9 +112,8 @@ constexpr Register rsp = as_Register(4); constexpr Register rbp = as_Register(5); constexpr Register rsi = as_Register(6); constexpr Register rdi = as_Register(7); -#ifdef _LP64 -constexpr Register r8 = as_Register( 8); -constexpr Register r9 = as_Register( 9); +constexpr Register r8 = as_Register(8); +constexpr Register r9 = as_Register(9); constexpr Register r10 = as_Register(10); constexpr Register r11 = as_Register(11); constexpr Register r12 = as_Register(12); @@ -141,7 +136,6 @@ constexpr Register r28 = as_Register(28); constexpr Register r29 = as_Register(29); constexpr Register r30 = as_Register(30); constexpr Register r31 = as_Register(31); -#endif // _LP64 // The implementation of x87 floating point registers for the ia32 architecture. @@ -154,10 +148,8 @@ private: public: inline friend constexpr FloatRegister as_FloatRegister(int encoding); - enum { - number_of_registers = 8, - max_slots_per_register = 2 - }; + static const int number_of_registers = 8; + static const int max_slots_per_register = 2; class FloatRegisterImpl: public AbstractRegisterImpl { friend class FloatRegister; @@ -217,10 +209,8 @@ private: public: inline friend constexpr XMMRegister as_XMMRegister(int encoding); - enum { - number_of_registers = LP64_ONLY( 32 ) NOT_LP64( 8 ), - max_slots_per_register = LP64_ONLY( 16 ) NOT_LP64( 16 ) // 512-bit - }; + static const int number_of_registers = 32; + static const int max_slots_per_register = 16; // 512-bit class XMMRegisterImpl: public AbstractRegisterImpl { friend class XMMRegister; @@ -250,11 +240,9 @@ public: // Actually available XMM registers for use, depending on actual CPU capabilities and flags. static int available_xmm_registers() { -#ifdef _LP64 if (UseAVX < 3) { return number_of_registers / 2; } -#endif // _LP64 return number_of_registers; } }; @@ -287,7 +275,6 @@ constexpr XMMRegister xmm4 = as_XMMRegister( 4); constexpr XMMRegister xmm5 = as_XMMRegister( 5); constexpr XMMRegister xmm6 = as_XMMRegister( 6); constexpr XMMRegister xmm7 = as_XMMRegister( 7); -#ifdef _LP64 constexpr XMMRegister xmm8 = as_XMMRegister( 8); constexpr XMMRegister xmm9 = as_XMMRegister( 9); constexpr XMMRegister xmm10 = as_XMMRegister(10); @@ -312,7 +299,6 @@ constexpr XMMRegister xmm28 = as_XMMRegister(28); constexpr XMMRegister xmm29 = as_XMMRegister(29); constexpr XMMRegister xmm30 = as_XMMRegister(30); constexpr XMMRegister xmm31 = as_XMMRegister(31); -#endif // _LP64 // The implementation of AVX-512 opmask registers. @@ -394,25 +380,17 @@ constexpr KRegister k7 = as_KRegister(7); // Define a class that exports it. class ConcreteRegisterImpl : public AbstractRegisterImpl { public: - enum { - max_gpr = Register::number_of_registers * Register::max_slots_per_register, - max_fpr = max_gpr + FloatRegister::number_of_registers * FloatRegister::max_slots_per_register, - max_xmm = max_fpr + XMMRegister::number_of_registers * XMMRegister::max_slots_per_register, - max_kpr = max_xmm + KRegister::number_of_registers * KRegister::max_slots_per_register, + static const int max_gpr = Register::number_of_registers * Register::max_slots_per_register; + static const int max_fpr = max_gpr + FloatRegister::number_of_registers * FloatRegister::max_slots_per_register; + static const int max_xmm = max_fpr + XMMRegister::number_of_registers * XMMRegister::max_slots_per_register; + static const int max_kpr = max_xmm + KRegister::number_of_registers * KRegister::max_slots_per_register; // A big enough number for C2: all the registers plus flags // This number must be large enough to cover REG_COUNT (defined by c2) registers. // There is no requirement that any ordering here matches any ordering c2 gives // it's optoregs. - - // x86_32.ad defines additional dummy FILL0-FILL7 registers, in order to tally - // REG_COUNT (computed by ADLC based on the number of reg_defs seen in .ad files) - // with ConcreteRegisterImpl::number_of_registers additional count of 8 is being - // added for 32 bit jvm. - number_of_registers = max_kpr + // gpr/fpr/xmm/kpr - NOT_LP64( 8 + ) // FILL0-FILL7 in x86_32.ad - 1 // eflags - }; + static const int number_of_registers = max_kpr + // gpr/fpr/xmm/kpr + 1; // eflags }; template <> diff --git a/src/hotspot/cpu/x86/vmreg_x86.cpp b/src/hotspot/cpu/x86/vmreg_x86.cpp index 44aee56ef15..45269e69fcb 100644 --- a/src/hotspot/cpu/x86/vmreg_x86.cpp +++ b/src/hotspot/cpu/x86/vmreg_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,9 +32,7 @@ void VMRegImpl::set_regName() { int i; for (i = 0; i < ConcreteRegisterImpl::max_gpr ; ) { regName[i++] = reg->name(); -#ifdef AMD64 regName[i++] = reg->name(); -#endif // AMD64 reg = reg->successor(); } diff --git a/src/hotspot/cpu/x86/vmreg_x86.hpp b/src/hotspot/cpu/x86/vmreg_x86.hpp index 6f7c7fafb32..032ce654f2f 100644 --- a/src/hotspot/cpu/x86/vmreg_x86.hpp +++ b/src/hotspot/cpu/x86/vmreg_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2026, 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,14 +52,8 @@ inline bool is_KRegister() { } inline Register as_Register() { - - assert( is_Register(), "must be"); - // Yuk -#ifdef AMD64 + assert(is_Register(), "must be"); return ::as_Register(value() >> 1); -#else - return ::as_Register(value()); -#endif // AMD64 } inline FloatRegister as_FloatRegister() { @@ -82,9 +76,6 @@ inline KRegister as_KRegister() { inline bool is_concrete() { assert(is_reg(), "must be"); -#ifndef AMD64 - if (is_Register()) return true; -#endif // AMD64 // Do not use is_XMMRegister() here as it depends on the UseAVX setting. if (value() >= ConcreteRegisterImpl::max_fpr && value() < ConcreteRegisterImpl::max_xmm) { int base = value() - ConcreteRegisterImpl::max_fpr; diff --git a/src/hotspot/cpu/x86/vmreg_x86.inline.hpp b/src/hotspot/cpu/x86/vmreg_x86.inline.hpp index 1aeedc094fd..76d70900fe4 100644 --- a/src/hotspot/cpu/x86/vmreg_x86.inline.hpp +++ b/src/hotspot/cpu/x86/vmreg_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ #define CPU_X86_VMREG_X86_INLINE_HPP inline VMReg Register::RegisterImpl::as_VMReg() const { - return VMRegImpl::as_VMReg(encoding() LP64_ONLY( << 1 )); + return VMRegImpl::as_VMReg(encoding() << 1); } inline VMReg FloatRegister::FloatRegisterImpl::as_VMReg() const { From bf0da3dd5c20410aceab8e6f7a7a31432d17b96d Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Thu, 15 Jan 2026 09:22:42 +0000 Subject: [PATCH 045/328] 8375040: Clearer names for non-metadata oop iterators in ObjArrayKlass Reviewed-by: tschatzl, kbarrett, aboldtch --- .../share/gc/g1/g1FullGCMarker.inline.hpp | 2 +- .../share/gc/g1/g1ParScanThreadState.cpp | 8 ++--- src/hotspot/share/gc/serial/serialFullGC.cpp | 2 +- .../gc/shenandoah/shenandoahMark.inline.hpp | 6 ++-- src/hotspot/share/gc/z/zHeapIterator.cpp | 2 +- src/hotspot/share/gc/z/zIterator.hpp | 2 +- src/hotspot/share/gc/z/zIterator.inline.hpp | 4 +-- src/hotspot/share/oops/objArrayKlass.hpp | 13 ++++--- .../share/oops/objArrayKlass.inline.hpp | 34 ++++++------------- src/hotspot/share/oops/objArrayOop.hpp | 4 +-- src/hotspot/share/oops/objArrayOop.inline.hpp | 10 ++++++ 11 files changed, 42 insertions(+), 45 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp index 6cbfe2674e8..398ef046bf5 100644 --- a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp @@ -108,7 +108,7 @@ void G1FullGCMarker::follow_array_chunk(objArrayOop array, int index) { push_objarray(array, end_index); } - array->oop_iterate_range(mark_closure(), beg_index, end_index); + array->oop_iterate_elements_range(mark_closure(), beg_index, end_index); } inline void G1FullGCMarker::follow_object(oop obj) { diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index 80e5fd44fcd..e7b02ed68e7 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -238,9 +238,9 @@ void G1ParScanThreadState::do_partial_array(PartialArrayState* state, bool stole G1HeapRegionAttr dest_attr = _g1h->region_attr(to_array); G1SkipCardMarkSetter x(&_scanner, dest_attr.is_new_survivor()); // Process claimed task. - to_array->oop_iterate_range(&_scanner, - checked_cast(claim._start), - checked_cast(claim._end)); + to_array->oop_iterate_elements_range(&_scanner, + checked_cast(claim._start), + checked_cast(claim._end)); } MAYBE_INLINE_EVACUATION @@ -260,7 +260,7 @@ void G1ParScanThreadState::start_partial_objarray(oop from_obj, // 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(initial_chunk_size)); + to_array->oop_iterate_elements_range(&_scanner, 0, checked_cast(initial_chunk_size)); } MAYBE_INLINE_EVACUATION diff --git a/src/hotspot/share/gc/serial/serialFullGC.cpp b/src/hotspot/share/gc/serial/serialFullGC.cpp index 546084e38dd..0c8ca51fc99 100644 --- a/src/hotspot/share/gc/serial/serialFullGC.cpp +++ b/src/hotspot/share/gc/serial/serialFullGC.cpp @@ -412,7 +412,7 @@ void SerialFullGC::follow_array_chunk(objArrayOop array, int index) { const int stride = MIN2(len - beg_index, (int) ObjArrayMarkingStride); const int end_index = beg_index + stride; - array->oop_iterate_range(&mark_and_push_closure, beg_index, end_index); + array->oop_iterate_elements_range(&mark_and_push_closure, beg_index, end_index); if (end_index < len) { SerialFullGC::push_objarray(array, end_index); // Push the continuation. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index 0a95ee9f149..849459157b5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -167,7 +167,7 @@ inline void ShenandoahMark::do_chunked_array_start(ShenandoahObjToScanQueue* q, if (len <= (int) ObjArrayMarkingStride*2) { // A few slices only, process directly - array->oop_iterate_range(cl, 0, len); + array->oop_iterate_elements_range(cl, 0, len); } else { int bits = log2i_graceful(len); // Compensate for non-power-of-two arrays, cover the array in excess: @@ -216,7 +216,7 @@ inline void ShenandoahMark::do_chunked_array_start(ShenandoahObjToScanQueue* q, // Process the irregular tail, if present int from = last_idx; if (from < len) { - array->oop_iterate_range(cl, from, len); + array->oop_iterate_elements_range(cl, from, len); } } } @@ -248,7 +248,7 @@ inline void ShenandoahMark::do_chunked_array(ShenandoahObjToScanQueue* q, T* cl, assert (0 < to && to <= len, "to is sane: %d/%d", to, len); #endif - array->oop_iterate_range(cl, from, to); + array->oop_iterate_elements_range(cl, from, to); } template diff --git a/src/hotspot/share/gc/z/zHeapIterator.cpp b/src/hotspot/share/gc/z/zHeapIterator.cpp index d6289178ea8..73ced211058 100644 --- a/src/hotspot/share/gc/z/zHeapIterator.cpp +++ b/src/hotspot/share/gc/z/zHeapIterator.cpp @@ -456,7 +456,7 @@ void ZHeapIterator::follow_array_chunk(const ZHeapIteratorContext& context, cons // Follow array chunk ZHeapIteratorOopClosure cl(this, context, obj); - ZIterator::oop_iterate_range(obj, &cl, start, end); + ZIterator::oop_iterate_elements_range(obj, &cl, start, end); } template diff --git a/src/hotspot/share/gc/z/zIterator.hpp b/src/hotspot/share/gc/z/zIterator.hpp index 3a1de049dd0..e048002e52e 100644 --- a/src/hotspot/share/gc/z/zIterator.hpp +++ b/src/hotspot/share/gc/z/zIterator.hpp @@ -41,7 +41,7 @@ public: static void oop_iterate(oop obj, OopClosureT* cl); template - static void oop_iterate_range(objArrayOop obj, OopClosureT* cl, int start, int end); + static void oop_iterate_elements_range(objArrayOop obj, OopClosureT* cl, int start, int end); // This function skips invisible roots template diff --git a/src/hotspot/share/gc/z/zIterator.inline.hpp b/src/hotspot/share/gc/z/zIterator.inline.hpp index fb20a424288..cbfe1a79aaf 100644 --- a/src/hotspot/share/gc/z/zIterator.inline.hpp +++ b/src/hotspot/share/gc/z/zIterator.inline.hpp @@ -66,9 +66,9 @@ void ZIterator::oop_iterate(oop obj, OopClosureT* cl) { } template -void ZIterator::oop_iterate_range(objArrayOop obj, OopClosureT* cl, int start, int end) { +void ZIterator::oop_iterate_elements_range(objArrayOop obj, OopClosureT* cl, int start, int end) { assert(!is_invisible_object_array(obj), "not safe"); - obj->oop_iterate_range(cl, start, end); + obj->oop_iterate_elements_range(cl, start, end); } template diff --git a/src/hotspot/share/oops/objArrayKlass.hpp b/src/hotspot/share/oops/objArrayKlass.hpp index 12db56351ed..cdf28b883e6 100644 --- a/src/hotspot/share/oops/objArrayKlass.hpp +++ b/src/hotspot/share/oops/objArrayKlass.hpp @@ -135,17 +135,16 @@ class ObjArrayKlass : public ArrayKlass { template inline void oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr); - // Iterate over oop elements within [start, end), and metadata. - template - inline void oop_oop_iterate_range(objArrayOop a, OopClosureType* closure, int start, int end); - - public: - // Iterate over all oop elements. + // Iterate over all oop elements, and no metadata. template inline void oop_oop_iterate_elements(objArrayOop a, OopClosureType* closure); + // Iterate over oop elements within index range [start, end), and no metadata. + template + inline void oop_oop_iterate_elements_range(objArrayOop a, OopClosureType* closure, int start, int end); + private: - // Iterate over all oop elements with indices within mr. + // Iterate over all oop elements bounded by addresses [low, high), and no metadata. template inline void oop_oop_iterate_elements_bounded(objArrayOop a, OopClosureType* closure, void* low, void* high); diff --git a/src/hotspot/share/oops/objArrayKlass.inline.hpp b/src/hotspot/share/oops/objArrayKlass.inline.hpp index a92c42d21a8..ee559548529 100644 --- a/src/hotspot/share/oops/objArrayKlass.inline.hpp +++ b/src/hotspot/share/oops/objArrayKlass.inline.hpp @@ -38,10 +38,18 @@ template void ObjArrayKlass::oop_oop_iterate_elements(objArrayOop a, OopClosureType* closure) { - T* p = (T*)a->base(); - T* const end = p + a->length(); + oop_oop_iterate_elements_range(a, closure, 0, a->length()); +} - for (;p < end; p++) { +// Like oop_oop_iterate but only iterates over a specified range and only used +// for objArrayOops. +template +void ObjArrayKlass::oop_oop_iterate_elements_range(objArrayOop a, OopClosureType* closure, int start, int end) { + T* base = (T*)a->base(); + T* p = base + start; + T* const end_p = base + end; + + for (;p < end_p; ++p) { Devirtualizer::do_oop(closure, p); } } @@ -98,24 +106,4 @@ void ObjArrayKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, Me oop_oop_iterate_elements_bounded(a, closure, mr.start(), mr.end()); } -// Like oop_oop_iterate but only iterates over a specified range and only used -// for objArrayOops. -template -void ObjArrayKlass::oop_oop_iterate_range(objArrayOop a, OopClosureType* closure, int start, int end) { - T* low = (T*)a->base() + start; - T* high = (T*)a->base() + end; - - oop_oop_iterate_elements_bounded(a, closure, low, high); -} - -// Placed here to resolve include cycle between objArrayKlass.inline.hpp and objArrayOop.inline.hpp -template -void objArrayOopDesc::oop_iterate_range(OopClosureType* blk, int start, int end) { - if (UseCompressedOops) { - ((ObjArrayKlass*)klass())->oop_oop_iterate_range(this, blk, start, end); - } else { - ((ObjArrayKlass*)klass())->oop_oop_iterate_range(this, blk, start, end); - } -} - #endif // SHARE_OOPS_OBJARRAYKLASS_INLINE_HPP diff --git a/src/hotspot/share/oops/objArrayOop.hpp b/src/hotspot/share/oops/objArrayOop.hpp index 82bb41b5fd1..0af059efccf 100644 --- a/src/hotspot/share/oops/objArrayOop.hpp +++ b/src/hotspot/share/oops/objArrayOop.hpp @@ -83,9 +83,9 @@ class objArrayOopDesc : public arrayOopDesc { Klass* element_klass(); public: - // special iterators for index ranges, returns size of object + // Special iterators for an element index range. template - void oop_iterate_range(OopClosureType* blk, int start, int end); + void oop_iterate_elements_range(OopClosureType* blk, int start, int end); }; // See similar requirement for oopDesc. diff --git a/src/hotspot/share/oops/objArrayOop.inline.hpp b/src/hotspot/share/oops/objArrayOop.inline.hpp index 21f95b756de..63295a1459d 100644 --- a/src/hotspot/share/oops/objArrayOop.inline.hpp +++ b/src/hotspot/share/oops/objArrayOop.inline.hpp @@ -29,6 +29,7 @@ #include "oops/access.hpp" #include "oops/arrayOop.hpp" +#include "oops/objArrayKlass.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/globals.hpp" @@ -51,4 +52,13 @@ inline void objArrayOopDesc::obj_at_put(int index, oop value) { HeapAccess::oop_store_at(as_oop(), offset, value); } +template +void objArrayOopDesc::oop_iterate_elements_range(OopClosureType* blk, int start, int end) { + if (UseCompressedOops) { + ((ObjArrayKlass*)klass())->oop_oop_iterate_elements_range(this, blk, start, end); + } else { + ((ObjArrayKlass*)klass())->oop_oop_iterate_elements_range(this, blk, start, end); + } +} + #endif // SHARE_OOPS_OBJARRAYOOP_INLINE_HPP From f6e5c885e7ca90da2f9fd9ec1c00b4a955ccdf29 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 15 Jan 2026 11:16:00 +0000 Subject: [PATCH 046/328] 8375282: G1: Fix wrong indendation introduced by JDK-8374743 Reviewed-by: kbarrett --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 2ad5a26d5e6..3a0c4a04441 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -687,8 +687,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) { // before the allocation is that we avoid having to keep track of the newly // allocated memory while we do a GC. // Only try that if we can actually perform a GC. - if (is_init_completed() && policy()->need_to_start_conc_mark("concurrent humongous allocation", - word_size)) { + if (is_init_completed() && + policy()->need_to_start_conc_mark("concurrent humongous allocation", word_size)) { try_collect(word_size, GCCause::_g1_humongous_allocation, collection_counters(this)); } From 8ad8920aae5c27de947532ba3cd2b57213208d1e Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 15 Jan 2026 12:37:50 +0000 Subject: [PATCH 047/328] 8374984: Convert workerUtils to use Atomic Reviewed-by: shade, stefank --- src/hotspot/share/gc/shared/workerUtils.cpp | 25 +++++++++++---------- src/hotspot/share/gc/shared/workerUtils.hpp | 12 +++++----- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/gc/shared/workerUtils.cpp b/src/hotspot/share/gc/shared/workerUtils.cpp index 422d513a5cd..1826b9d7df8 100644 --- a/src/hotspot/share/gc/shared/workerUtils.cpp +++ b/src/hotspot/share/gc/shared/workerUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,8 +22,9 @@ * */ +#include "cppstdlib/new.hpp" #include "gc/shared/workerUtils.hpp" -#include "runtime/atomicAccess.hpp" +#include "runtime/atomic.hpp" #include "runtime/mutexLocker.hpp" // *** WorkerThreadsBarrierSync @@ -80,21 +81,21 @@ void WorkerThreadsBarrierSync::abort() { SubTasksDone::SubTasksDone(uint n) : _tasks(nullptr), _n_tasks(n) { - _tasks = NEW_C_HEAP_ARRAY(bool, n, mtInternal); + _tasks = NEW_C_HEAP_ARRAY(Atomic, n, mtInternal); for (uint i = 0; i < _n_tasks; i++) { - _tasks[i] = false; + ::new (&_tasks[i]) Atomic(false); } } #ifdef ASSERT void SubTasksDone::all_tasks_claimed_impl(uint skipped[], size_t skipped_size) { - if (AtomicAccess::cmpxchg(&_verification_done, false, true)) { + if (!_verification_done.compare_set(false, true)) { // another thread has done the verification return; } // all non-skipped tasks are claimed for (uint i = 0; i < _n_tasks; ++i) { - if (!_tasks[i]) { + if (!_tasks[i].load_relaxed()) { auto is_skipped = false; for (size_t j = 0; j < skipped_size; ++j) { if (i == skipped[j]) { @@ -109,27 +110,27 @@ void SubTasksDone::all_tasks_claimed_impl(uint skipped[], size_t skipped_size) { for (size_t i = 0; i < skipped_size; ++i) { auto task_index = skipped[i]; assert(task_index < _n_tasks, "Array in range."); - assert(!_tasks[task_index], "%d is both claimed and skipped.", task_index); + assert(!_tasks[task_index].load_relaxed(), "%d is both claimed and skipped.", task_index); } } #endif bool SubTasksDone::try_claim_task(uint t) { assert(t < _n_tasks, "bad task id."); - return !_tasks[t] && !AtomicAccess::cmpxchg(&_tasks[t], false, true); + return !_tasks[t].load_relaxed() && _tasks[t].compare_set(false, true); } SubTasksDone::~SubTasksDone() { - assert(_verification_done, "all_tasks_claimed must have been called."); - FREE_C_HEAP_ARRAY(bool, _tasks); + assert(_verification_done.load_relaxed(), "all_tasks_claimed must have been called."); + FREE_C_HEAP_ARRAY(Atomic, _tasks); } // *** SequentialSubTasksDone bool SequentialSubTasksDone::try_claim_task(uint& t) { - t = _num_claimed; + t = _num_claimed.load_relaxed(); if (t < _num_tasks) { - t = AtomicAccess::add(&_num_claimed, 1u) - 1; + t = _num_claimed.fetch_then_add(1u); } return t < _num_tasks; } diff --git a/src/hotspot/share/gc/shared/workerUtils.hpp b/src/hotspot/share/gc/shared/workerUtils.hpp index 5f771a57837..7bf9d7d7656 100644 --- a/src/hotspot/share/gc/shared/workerUtils.hpp +++ b/src/hotspot/share/gc/shared/workerUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "cppstdlib/type_traits.hpp" #include "memory/allocation.hpp" #include "metaprogramming/enableIf.hpp" +#include "runtime/atomic.hpp" #include "runtime/mutex.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" @@ -79,11 +80,11 @@ public: // enumeration type. class SubTasksDone: public CHeapObj { - volatile bool* _tasks; + Atomic* _tasks; uint _n_tasks; // make sure verification logic is run exactly once to avoid duplicate assertion failures - DEBUG_ONLY(volatile bool _verification_done = false;) + DEBUG_ONLY(Atomic _verification_done;) void all_tasks_claimed_impl(uint skipped[], size_t skipped_size) NOT_DEBUG_RETURN; NONCOPYABLE(SubTasksDone); @@ -127,7 +128,7 @@ public: class SequentialSubTasksDone : public CHeapObj { uint _num_tasks; // Total number of tasks available. - volatile uint _num_claimed; // Number of tasks claimed. + Atomic _num_claimed; // Number of tasks claimed. NONCOPYABLE(SequentialSubTasksDone); @@ -135,7 +136,8 @@ public: SequentialSubTasksDone(uint num_tasks) : _num_tasks(num_tasks), _num_claimed(0) { } ~SequentialSubTasksDone() { // Claiming may try to claim more tasks than there are. - assert(_num_claimed >= _num_tasks, "Claimed %u tasks of %u", _num_claimed, _num_tasks); + assert(_num_claimed.load_relaxed() >= _num_tasks, + "Claimed %u tasks of %u", _num_claimed.load_relaxed(), _num_tasks); } // Attempt to claim the next unclaimed task in the sequence, From 78a106ffbba0e056e7421ca9d77af02f9b8379d3 Mon Sep 17 00:00:00 2001 From: Artur Barashev Date: Thu, 15 Jan 2026 13:18:20 +0000 Subject: [PATCH 048/328] 8375183: Remove unused SSLConfiguration.maximumProtocolVersion variable Reviewed-by: djelinski, myankelevich, hchao --- .../sun/security/ssl/SSLConfiguration.java | 19 +------------------ .../sun/security/ssl/TransportContext.java | 3 +-- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java b/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java index ace60e41af9..3c68c669d05 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -64,9 +64,6 @@ final class SSLConfiguration implements Cloneable { // the configured named groups for the "supported_groups" extensions String[] namedGroups; - // the maximum protocol version of enabled protocols - ProtocolVersion maximumProtocolVersion; - // Configurations per SSLSocket or SSLEngine instance. boolean isClientMode; boolean enableSessionCreation; @@ -249,13 +246,6 @@ final class SSLConfiguration implements Cloneable { CustomizedServerSignatureSchemes.signatureSchemes : SupportedSigSchemes.DEFAULT; this.namedGroups = NamedGroup.SupportedGroups.namedGroups; - this.maximumProtocolVersion = ProtocolVersion.NONE; - for (ProtocolVersion pv : enabledProtocols) { - if (pv.compareTo(maximumProtocolVersion) > 0) { - this.maximumProtocolVersion = pv; - } - } - // Configurations per SSLSocket or SSLEngine instance. this.isClientMode = isClientMode; this.enableSessionCreation = true; @@ -323,13 +313,6 @@ final class SSLConfiguration implements Cloneable { sa = params.getProtocols(); if (sa != null) { this.enabledProtocols = ProtocolVersion.namesOf(sa); - - this.maximumProtocolVersion = ProtocolVersion.NONE; - for (ProtocolVersion pv : enabledProtocols) { - if (pv.compareTo(maximumProtocolVersion) > 0) { - this.maximumProtocolVersion = pv; - } - } } // otherwise, use the default values if (params.getNeedClientAuth()) { diff --git a/src/java.base/share/classes/sun/security/ssl/TransportContext.java b/src/java.base/share/classes/sun/security/ssl/TransportContext.java index 980d9c4a6ce..35bdd2fff36 100644 --- a/src/java.base/share/classes/sun/security/ssl/TransportContext.java +++ b/src/java.base/share/classes/sun/security/ssl/TransportContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -144,7 +144,6 @@ final class TransportContext implements ConnectionContext { // initial security parameters this.conSession = new SSLSessionImpl(); - this.protocolVersion = this.sslConfig.maximumProtocolVersion; this.clientVerifyData = emptyByteArray; this.serverVerifyData = emptyByteArray; From 203eb70110dd546784e03243bf98ff3ddb407030 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Thu, 15 Jan 2026 15:54:11 +0000 Subject: [PATCH 049/328] 8291986: ProcessBuilder.redirectErrorStream(true) leaves error stream available Reviewed-by: jpai --- .../unix/native/libjava/ProcessImpl_md.c | 13 +- .../lang/ProcessBuilder/PipelineLeaksFD.java | 263 +++++++++++++++--- .../java/lang/ProcessBuilder/TEST.properties | 1 + 3 files changed, 230 insertions(+), 47 deletions(-) create mode 100644 test/jdk/java/lang/ProcessBuilder/TEST.properties diff --git a/src/java.base/unix/native/libjava/ProcessImpl_md.c b/src/java.base/unix/native/libjava/ProcessImpl_md.c index f7531ad5abe..12597fbb650 100644 --- a/src/java.base/unix/native/libjava/ProcessImpl_md.c +++ b/src/java.base/unix/native/libjava/ProcessImpl_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2026, 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 @@ -729,12 +729,13 @@ Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env, if ((fds[0] == -1 && pipe(in) < 0) || (fds[1] == -1 && pipe(out) < 0) || - (fds[2] == -1 && pipe(err) < 0) || + (fds[2] == -1 && !redirectErrorStream && pipe(err) < 0) || // if not redirecting create the pipe (pipe(childenv) < 0) || (pipe(fail) < 0)) { throwInternalIOException(env, errno, "Bad file descriptor", mode); goto Catch; } + c->fds[0] = fds[0]; c->fds[1] = fds[1]; c->fds[2] = fds[2]; @@ -764,17 +765,19 @@ Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env, assert(resultPid != 0); if (resultPid < 0) { + char * failMessage = "unknown"; switch (c->mode) { case MODE_VFORK: - throwInternalIOException(env, errno, "vfork failed", c->mode); + failMessage = "vfork failed"; break; case MODE_FORK: - throwInternalIOException(env, errno, "fork failed", c->mode); + failMessage = "fork failed"; break; case MODE_POSIX_SPAWN: - throwInternalIOException(env, errno, "posix_spawn failed", c->mode); + failMessage = "posix_spawn failed"; break; } + throwInternalIOException(env, errno, failMessage, c->mode); goto Catch; } close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec (childproc.c) */ diff --git a/test/jdk/java/lang/ProcessBuilder/PipelineLeaksFD.java b/test/jdk/java/lang/ProcessBuilder/PipelineLeaksFD.java index d3c44bc9279..2b4cdfa9bdd 100644 --- a/test/jdk/java/lang/ProcessBuilder/PipelineLeaksFD.java +++ b/test/jdk/java/lang/ProcessBuilder/PipelineLeaksFD.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, 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,32 +21,42 @@ * questions. */ -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.condition.EnabledIf; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.*; import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.Writer; +import java.lang.ProcessHandle; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; /* * @test - * @bug 8289643 8291760 - * @requires (os.family == "linux" & !vm.musl) + * @bug 8289643 8291760 8291986 + * @requires os.family == "mac" | (os.family == "linux" & !vm.musl) * @summary File descriptor leak detection with ProcessBuilder.startPipeline - * @run testng/othervm PipelineLeaksFD + * @run junit/othervm PipelineLeaksFD */ -@Test public class PipelineLeaksFD { - @DataProvider - public Object[][] builders() { + + private static final String OS_NAME = System.getProperty("os.name", "Unknown"); + + private static final long MY_PID = ProcessHandle.current().pid(); + + private static final boolean LSOF_AVAILABLE = checkForLSOF(); + + // Test cases for pipelines with a number of pipeline sequences + public static Object[][] builders() { return new Object[][]{ {List.of(new ProcessBuilder("cat"))}, {List.of(new ProcessBuilder("cat"), @@ -59,20 +69,43 @@ public class PipelineLeaksFD { }; } - @Test(dataProvider = "builders") + // True if lsof is runnable and collect pipe usage. + private static boolean lsofAvailable() { + return LSOF_AVAILABLE; + } + + // Check if lsof is available + private static boolean checkForLSOF() { + try { + lsofForAll(); + return true; + } catch (IOException ioe) { + System.err.println("Skipping: " + ioe); + return false; + } + } + + @EnabledIf("lsofAvailable") + @ParameterizedTest + @MethodSource("builders") void checkForLeaks(List builders) throws IOException { - Set pipesBefore = myPipes(); + List lsofLines = lsofForAll(); + Set pipesBefore = pipesFromLSOF(lsofLines, MY_PID); if (pipesBefore.size() < 3) { - System.out.println(pipesBefore); - Assert.fail("There should be at least 3 pipes before, (0, 1, 2)"); + // Dump all lsof output to aid debugging + System.out.println("Output from lsof"); + lsofLines.forEach(System.err::println); + System.err.println(pipesBefore); + fail("There should be at least 3 pipes before, (0, 1, 2)"); } + printPipes(pipesBefore, "Before start"); List processes = ProcessBuilder.startPipeline(builders); // Write something through the pipeline final String text = "xyz"; - try (Writer out = processes.get(0).outputWriter()) { + try (Writer out = processes.getFirst().outputWriter()) { out.write(text); } @@ -84,16 +117,17 @@ public class PipelineLeaksFD { try (BufferedReader inputStream = p.inputReader(); BufferedReader errorStream = p.errorReader()) { String outActual = inputStream.readLine(); - Assert.assertEquals(outActual, expectedOut, "stdout, process[ " + i + "]: " + p); + assertEquals(expectedOut, outActual, "stdout, process[ " + i + "]: " + p); String errActual = errorStream.readLine(); - Assert.assertEquals(errActual, expectedErr, "stderr, process[ " + i + "]: " + p); + assertEquals(expectedErr, errActual, "stderr, process[ " + i + "]: " + p); } } - processes.forEach(p -> waitForQuiet(p)); + processes.forEach(PipelineLeaksFD::waitForQuiet); - Set pipesAfter = myPipes(); + lsofLines = lsofForAll(); + Set pipesAfter = pipesFromLSOF(lsofLines, MY_PID); if (!pipesBefore.equals(pipesAfter)) { Set missing = new HashSet<>(pipesBefore); missing.removeAll(pipesAfter); @@ -101,46 +135,191 @@ public class PipelineLeaksFD { Set extra = new HashSet<>(pipesAfter); extra.removeAll(pipesBefore); printPipes(extra, "Extra pipes in pipesAfter"); - Assert.fail("More or fewer pipes than expected"); + // Dump all lsof output to aid debugging + System.out.println("\nOutput from lsof"); + lsofLines.forEach(System.err::println); + fail("More or fewer pipes than expected"); + } + } + + // Test redirectErrorStream, both true and false + public static Object[][] redirectCases() { + return new Object[][] { + {true}, + {false}, + }; + } + + // Test redirectErrorStream (true/false) has the right number of pipes in use + @EnabledIf("lsofAvailable") + @ParameterizedTest() + @MethodSource("redirectCases") + void checkRedirectErrorStream(boolean redirectError) throws IOException { + try (Process p = new ProcessBuilder("cat") + .redirectErrorStream(redirectError) + .start()) { + System.err.printf("Parent PID; %d, Child Pid: %d\n", MY_PID, p.pid()); + List lsofLines = lsofForAll(); + final Set pipes = pipesFromLSOF(lsofLines, p.pid()); + printPipes(pipes, "Parent and waiting child pipes"); + int uniquePipes = redirectError ? 8 : 9; + if (uniquePipes != pipes.size()) { + // Dump all lsof output to aid debugging + System.out.println("\nOutput from lsof"); + lsofLines.forEach(System.err::println); + } + assertEquals(uniquePipes, pipes.size(), + "wrong number of pipes for redirect: " + redirectError); + String expectedTypeName = redirectError + ? "java.lang.ProcessBuilder$NullInputStream" + : "java.lang.ProcessImpl$ProcessPipeInputStream"; + assertEquals(expectedTypeName, p.getErrorStream().getClass().getName(), + "errorStream type is incorrect"); + } catch (IOException ioe) { + fail("Process start", ioe); } } static void printPipes(Set pipes, String label) { - System.out.printf("%s: [%d]%n", label, pipes.size()); - pipes.forEach(r -> System.out.printf("%-20s: %s%n", r.fd(), r.link())); + System.err.printf("%s: [%d]%n", label, pipes.size()); + pipes.forEach(System.err::println); } static void waitForQuiet(Process p) { try { int st = p.waitFor(); if (st != 0) { - System.out.println("non-zero exit status: " + p); + System.err.println("non-zero exit status: " + p); } } catch (InterruptedException ie) { } } /** - * Collect a Set of pairs of /proc fd paths and the symbol links that are pipes. + * Collect a Set of file descriptors and identifying information. + * To identify the pipes in use the `lsof` command is invoked and output scrapped for + * fd's, pids, unique identities of the pipes (to match with parent). * @return A set of PipeRecords, possibly empty */ - static Set myPipes() { - Path path = Path.of("/proc/" + ProcessHandle.current().pid() + "/fd"); - Set pipes = new HashSet<>(); - File[] files = path.toFile().listFiles(f -> Files.isSymbolicLink(f.toPath())); - if (files != null) { - for (File file : files) { - try { - Path link = Files.readSymbolicLink(file.toPath()); - if (link.toString().startsWith("pipe:")) { - pipes.add(new PipeRecord(file.toPath(), link)); - } - } catch (IOException ioe) { - } - } - } - return pipes; + private static Set pipesForPid(long pid) throws IOException { + var lines = lsofForAll(); + return pipesFromLSOF(lines, pid); } - record PipeRecord(Path fd, Path link) { }; + /** + * Extract the PipeRecords from the `lsof` output for this process and a designated child process. + * + * @param lines lines of lsof output + * @param pid pid of child process of interest + * @return a Set of PipeRecords for parent and child + */ + private static LinkedHashSet pipesFromLSOF(List lines, long pid) { + return lines.stream() + .map(PipelineLeaksFD::pipeFromLSOF) + .filter(pr -> pr != null && + (pr.pid() == pid || pr.pid() == MY_PID)) + .collect(Collectors.toCollection(LinkedHashSet::new)); + } + + /** + * Collect the output of `lsof` for all files. + * Files are used for `lsof` input and output to avoid creating pipes. + * @return a List of lines output from `lsof`. + */ + private static List lsofForAll() throws IOException { + Path tmpDir = Path.of("."); + String tmpPrefix = "lsof-"; + Path lsofEmptyInput = Files.createTempFile(tmpDir, tmpPrefix, ".empty"); + Path lsofOutput = Files.createTempFile(tmpDir, tmpPrefix, ".tmp"); + try (Process p = new ProcessBuilder("lsof") + .redirectOutput(lsofOutput.toFile()) + .redirectInput(lsofEmptyInput.toFile()) // empty input + .redirectError(ProcessBuilder.Redirect.DISCARD) // ignored output + .start()) { + int status = p.waitFor(); + assertEquals(0, status, "Process 'lsof' failed"); + + return Files.readAllLines(lsofOutput); + } catch (InterruptedException ie) { + throw new IOException("Waiting for lsof exit interrupted", ie); + } + } + + // Return pipe records by parsing the appropriate platform specific `lsof` output. + static PipeRecord pipeFromLSOF(String s) { + return switch (OS_NAME) { + case "Linux" -> pipeFromLinuxLSOF(s); + case "Mac OS X" -> pipeFromMacLSOF(s); + default -> throw new RuntimeException("lsof not supported on platform: " + OS_NAME); + }; + } + + // Return Pipe from lsof output put, or null (on Mac OS X) + // lsof 55221 rriggs 0 PIPE 0xc76402237956a5cb 16384 ->0xfcb0c07ae447908c + // lsof 55221 rriggs 1 PIPE 0xb486e02f86da463e 16384 ->0xf94eacc85896b4e6 + static PipeRecord pipeFromMacLSOF(String s) { + String[] fields = s.split("\\s+"); + if ("PIPE".equals(fields[4])) { + final int pid = Integer.parseInt(fields[1]); + final String myKey = (fields.length > 5) ? fields[5] : ""; + final String otherKey = (fields.length > 7) ? fields[7].substring(2) : ""; + return PipeRecord.lookup(Integer.parseInt(fields[3]), myKey, otherKey, pid); + } + return null; + } + + // Return Pipe from lsof output put, or null (on Linux) + // java 7612 rriggs 14w FIFO 0,12 0t0 117662267 pipe + // java 7612 rriggs 15r FIFO 0,12 0t0 117662268 pipe + static PipeRecord pipeFromLinuxLSOF(String s) { + String[] fields = s.split("\\s+"); + if ("FIFO".equals(fields[4])) { + final int pid = Integer.parseInt(fields[1]); + final String key = (fields.length > 7) ? fields[7] : ""; + final int fdNum = Integer.parseInt(fields[3].substring(0, fields[3].length() - 1)); + return PipeRecord.lookup(fdNum, key, null, pid); + } + return null; + } + + // Identify a pipe by pid, fd, and a key (unique across processes) + // Mac OS X has separate keys for read and write sides, both are matched to the same "name" + record PipeRecord(long pid, int fd, KeyedString myKey) { + static PipeRecord lookup(int fd, String myKey, String otherKey, int pid) { + return new PipeRecord(pid, fd, KeyedString.getKey(myKey, otherKey)); + } + } + + // A unique name for a string with a count of uses + // Used to associate pipe between parent and child. + static class KeyedString { + private static final HashMap map = new HashMap<>(); + private static int nextInt = 1; + private final String key; + private final String name; + private int count; + KeyedString(String key, String name) { + this.key = key; + this.name = name; + this.count = 0; + } + + KeyedString(String s) { + String k = "p" + nextInt++; + this(s, k); + } + + static KeyedString getKey(String key, String otherKey) { + var k = map.computeIfAbsent(key, KeyedString::new); + k.count++; + if (otherKey != null) { + map.putIfAbsent(otherKey, k); + } + return k; + } + + public String toString() { + return name + "(" + count + ")"; + } + } } diff --git a/test/jdk/java/lang/ProcessBuilder/TEST.properties b/test/jdk/java/lang/ProcessBuilder/TEST.properties new file mode 100644 index 00000000000..c7e8a6850ca --- /dev/null +++ b/test/jdk/java/lang/ProcessBuilder/TEST.properties @@ -0,0 +1 @@ +maxOutputSize=6000000 From ee0387be4c562c7f7ad5240f412d4d5363358855 Mon Sep 17 00:00:00 2001 From: Roger Calnan Date: Thu, 15 Jan 2026 17:08:49 +0000 Subject: [PATCH 050/328] 8375342: jdk/javadoc/doccheck/checks/jdkCheckHtml.java failed with duplicate anchors Reviewed-by: alanb, iris --- src/java.base/share/man/java.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 4343df663e6..956a6aa144b 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -3283,7 +3283,7 @@ Flags to Xlog]. The following provides quick reference to the `-Xlog` command and syntax for options: -[`-Xlog`]{#-Xlog} +`-Xlog` : Enables JVM logging on an `info` level. `-Xlog:help` From 34705a77f9a90da5ab2a440c11d79aef7bb3ba54 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Thu, 15 Jan 2026 17:38:46 +0000 Subject: [PATCH 051/328] 8375231: Refactor util/ServiceLoader tests to use JUnit 8375232: Refactor util/StringJoiner tests to use JUnit 8375233: Refactor util/Vector tests to use JUnit Reviewed-by: naoto, alanb --- .../util/ServiceLoader/BadProvidersTest.java | 79 +++----- .../java/util/ServiceLoader/CachingTest.java | 18 +- .../java/util/ServiceLoader/ModulesTest.java | 42 ++-- .../ServiceLoader/NoInterferenceTest.java | 14 +- .../java/util/ServiceLoader/ReloadTest.java | 31 +-- .../java/util/ServiceLoader/TwoIterators.java | 19 +- .../basic/ServiceLoaderBasicTest.java | 40 ++-- .../jdk/java/util/StringJoiner/MergeTest.java | 55 +++--- .../StringJoinerOomUtf16Test.java | 19 +- .../util/StringJoiner/StringJoinerTest.java | 182 ++++++++++-------- .../jdk/java/util/Vector/ArrayManagement.java | 81 ++++---- 11 files changed, 304 insertions(+), 276 deletions(-) diff --git a/test/jdk/java/util/ServiceLoader/BadProvidersTest.java b/test/jdk/java/util/ServiceLoader/BadProvidersTest.java index 8560126eb00..0a734a2b214 100644 --- a/test/jdk/java/util/ServiceLoader/BadProvidersTest.java +++ b/test/jdk/java/util/ServiceLoader/BadProvidersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * @library /test/lib * @modules jdk.compiler * @build jdk.test.lib.compiler.CompilerUtils - * @run testng/othervm BadProvidersTest + * @run junit/othervm BadProvidersTest * @summary Basic test of ServiceLoader with bad provider and bad provider * factories deployed on the module path */ @@ -50,8 +50,6 @@ import java.util.stream.Collectors; import jdk.test.lib.compiler.CompilerUtils; -import org.testng.annotations.Test; -import org.testng.annotations.DataProvider; import static java.lang.classfile.ClassFile.ACC_PUBLIC; import static java.lang.classfile.ClassFile.ACC_STATIC; @@ -59,13 +57,16 @@ import static java.lang.constant.ConstantDescs.CD_Object; import static java.lang.constant.ConstantDescs.INIT_NAME; import static java.lang.constant.ConstantDescs.MTD_void; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; /** * Basic test of `provides S with PF` and `provides S with P` where the provider * factory or provider */ - public class BadProvidersTest { private static final String TEST_SRC = System.getProperty("test.src"); @@ -137,22 +138,10 @@ public class BadProvidersTest { assertTrue(p != null); } - - @DataProvider(name = "badfactories") - public Object[][] createBadFactories() { - return new Object[][] { - { "classnotpublic", null }, - { "methodnotpublic", null }, - { "badreturntype", null }, - { "returnsnull", null }, - { "throwsexception", null }, - }; - } - - - @Test(dataProvider = "badfactories", - expectedExceptions = ServiceConfigurationError.class) - public void testBadFactory(String testName, String ignore) throws Exception { + @ParameterizedTest + @ValueSource(strings = { "classnotpublic", "methodnotpublic", "badreturntype", + "returnsnull", "throwsexception" }) + public void testBadFactory(String testName) throws Exception { Path mods = compileTest(TEST1_MODULE); // compile the bad factory @@ -164,28 +153,18 @@ public class BadProvidersTest { // copy the compiled class into the module Path classFile = Paths.get("p", "ProviderFactory.class"); Files.copy(output.resolve(classFile), - mods.resolve(TEST1_MODULE).resolve(classFile), - StandardCopyOption.REPLACE_EXISTING); + mods.resolve(TEST1_MODULE).resolve(classFile), + StandardCopyOption.REPLACE_EXISTING); - // load providers and instantiate each one - loadProviders(mods, TEST1_MODULE).forEach(Provider::get); + Assertions.assertThrows(ServiceConfigurationError.class, + // load providers and instantiate each one + () -> loadProviders(mods, TEST1_MODULE).forEach(Provider::get) + ); } - - @DataProvider(name = "badproviders") - public Object[][] createBadProviders() { - return new Object[][] { - { "notpublic", null }, - { "ctornotpublic", null }, - { "notasubtype", null }, - { "throwsexception", null } - }; - } - - - @Test(dataProvider = "badproviders", - expectedExceptions = ServiceConfigurationError.class) - public void testBadProvider(String testName, String ignore) throws Exception { + @ParameterizedTest + @ValueSource(strings = { "notpublic", "ctornotpublic", "notasubtype", "throwsexception" }) + public void testBadProvider(String testName) throws Exception { Path mods = compileTest(TEST2_MODULE); // compile the bad provider @@ -197,11 +176,13 @@ public class BadProvidersTest { // copy the compiled class into the module Path classFile = Paths.get("p", "Provider.class"); Files.copy(output.resolve(classFile), - mods.resolve(TEST2_MODULE).resolve(classFile), - StandardCopyOption.REPLACE_EXISTING); + mods.resolve(TEST2_MODULE).resolve(classFile), + StandardCopyOption.REPLACE_EXISTING); - // load providers and instantiate each one - loadProviders(mods, TEST2_MODULE).forEach(Provider::get); + Assertions.assertThrows(ServiceConfigurationError.class, + // load providers and instantiate each one + () -> loadProviders(mods, TEST2_MODULE).forEach(Provider::get) + ); } @@ -209,7 +190,7 @@ public class BadProvidersTest { * Test a service provider that defines more than one no-args * public static "provider" method. */ - @Test(expectedExceptions = ServiceConfigurationError.class) + @Test public void testWithTwoFactoryMethods() throws Exception { Path mods = compileTest(TEST1_MODULE); @@ -244,8 +225,10 @@ public class BadProvidersTest { .resolve("ProviderFactory.class"); Files.write(classFile, bytes); - // load providers and instantiate each one - loadProviders(mods, TEST1_MODULE).forEach(Provider::get); + Assertions.assertThrows(ServiceConfigurationError.class, + // load providers and instantiate each one + () -> loadProviders(mods, TEST1_MODULE).forEach(Provider::get) + ); } } diff --git a/test/jdk/java/util/ServiceLoader/CachingTest.java b/test/jdk/java/util/ServiceLoader/CachingTest.java index 264c646b5af..138b6b6862f 100644 --- a/test/jdk/java/util/ServiceLoader/CachingTest.java +++ b/test/jdk/java/util/ServiceLoader/CachingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /** * @test * @summary Test ServiceLoader caches - * @run testng CachingTest + * @run junit CachingTest */ import java.nio.file.Files; @@ -38,9 +38,9 @@ import java.util.ServiceLoader.Provider; import java.util.Spliterator; import java.util.stream.Collectors; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; public class CachingTest { @@ -52,17 +52,17 @@ public class CachingTest { public static class S2 implements S { } - private ClassLoader testClassLoader; + private static ClassLoader testClassLoader; // creates the services configuration file and sets the ClassLoader - @BeforeClass - void setup() throws Exception { + @BeforeAll + static void setup() throws Exception { String classes = System.getProperty("test.classes"); Path dir = Paths.get(classes, "META-INF", "services"); Files.createDirectories(dir); Path config = dir.resolve(S.class.getName()); Files.write(config, List.of(S1.class.getName(), S2.class.getName())); - this.testClassLoader = CachingTest.class.getClassLoader(); + testClassLoader = CachingTest.class.getClassLoader(); } private void checkLists(List list1, List list2) { diff --git a/test/jdk/java/util/ServiceLoader/ModulesTest.java b/test/jdk/java/util/ServiceLoader/ModulesTest.java index 002b8458865..d265ce18f60 100644 --- a/test/jdk/java/util/ServiceLoader/ModulesTest.java +++ b/test/jdk/java/util/ServiceLoader/ModulesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -29,7 +29,7 @@ * @build jdk.test.lib.util.JarUtils * @compile classpath/pearscript/org/pear/PearScriptEngineFactory.java * classpath/pearscript/org/pear/PearScript.java - * @run testng/othervm ModulesTest + * @run junit/othervm ModulesTest * @summary Basic test for ServiceLoader with a provider deployed as a module. */ @@ -55,9 +55,10 @@ import javax.script.ScriptEngineFactory; import jdk.test.lib.util.JarUtils; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeTest; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; /** * Basic test for ServiceLoader. The test make use of two service providers: @@ -67,12 +68,11 @@ import static org.testng.Assert.*; * 2. PearScriptEngine - a ScriptEngineFactory deployed on the class path * with a service configuration file. */ - public class ModulesTest { // Copy the services configuration file for "pearscript" into place. - @BeforeTest - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { Path src = Paths.get(System.getProperty("test.src")); Path classes = Paths.get(System.getProperty("test.classes")); String st = ScriptEngineFactory.class.getName(); @@ -428,30 +428,36 @@ public class ModulesTest { // -- nulls -- - @Test(expectedExceptions = { NullPointerException.class }) + @Test public void testLoadNull1() { - ServiceLoader.load(null); + Assertions.assertThrows(NullPointerException.class, + () -> ServiceLoader.load(null)); } - @Test(expectedExceptions = { NullPointerException.class }) + @Test public void testLoadNull2() { - ServiceLoader.load((Class) null, ClassLoader.getSystemClassLoader()); + Assertions.assertThrows(NullPointerException.class, + () -> ServiceLoader.load((Class) null, ClassLoader.getSystemClassLoader())); } - @Test(expectedExceptions = { NullPointerException.class }) + @Test public void testLoadNull3() { class S { } - ServiceLoader.load((ModuleLayer) null, S.class); + Assertions.assertThrows(NullPointerException.class, () -> { + ServiceLoader.load((ModuleLayer) null, S.class); + }); } - @Test(expectedExceptions = { NullPointerException.class }) + @Test public void testLoadNull4() { - ServiceLoader.load(ModuleLayer.empty(), null); + Assertions.assertThrows(NullPointerException.class, + () -> ServiceLoader.load(ModuleLayer.empty(), null)); } - @Test(expectedExceptions = { NullPointerException.class }) + @Test public void testLoadNull5() { - ServiceLoader.loadInstalled(null); + Assertions.assertThrows(NullPointerException.class, + () -> ServiceLoader.loadInstalled(null)); } /** diff --git a/test/jdk/java/util/ServiceLoader/NoInterferenceTest.java b/test/jdk/java/util/ServiceLoader/NoInterferenceTest.java index ff83b836e20..d91bc9c759f 100644 --- a/test/jdk/java/util/ServiceLoader/NoInterferenceTest.java +++ b/test/jdk/java/util/ServiceLoader/NoInterferenceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * @library /test/lib * @modules jdk.compiler * @build jdk.test.lib.compiler.CompilerUtils - * @run testng NoInterferenceTest + * @run junit NoInterferenceTest * @summary Basic test of ServiceLoader that ensures there is no interference * when there are two service interfaces of the same name in a layer * or overridden in a child layer. @@ -46,9 +46,9 @@ import java.util.Set; import jdk.test.lib.compiler.CompilerUtils; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; public class NoInterferenceTest { @@ -57,8 +57,8 @@ public class NoInterferenceTest { private static final Path MODS_DIR = Paths.get("mods"); private static final List MODULES = Arrays.asList("s1", "p1", "s2", "p2"); - @BeforeTest - void compile() throws Exception { + @BeforeAll + static void compile() throws Exception { Files.createDirectory(MODS_DIR); for (String name : MODULES) { Path src = SRC_DIR.resolve(name); diff --git a/test/jdk/java/util/ServiceLoader/ReloadTest.java b/test/jdk/java/util/ServiceLoader/ReloadTest.java index d48b5c29f4d..be2c0d68773 100644 --- a/test/jdk/java/util/ServiceLoader/ReloadTest.java +++ b/test/jdk/java/util/ServiceLoader/ReloadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * @modules java.scripting * @library modules classpath/pearscript * @build ReloadTest org.pear.PearScript org.pear.PearScriptEngineFactory bananascript/* - * @run testng/othervm ReloadTest + * @run junit/othervm ReloadTest * @summary Basic test of ServiceLoader.reload */ @@ -40,12 +40,14 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import static java.util.ServiceLoader.*; import javax.script.ScriptEngineFactory; -import org.testng.annotations.Test; -import static org.testng.Assert.*; -@Test +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + public class ReloadTest { + @Test public void testReload() { ServiceLoader sl = load(ScriptEngineFactory.class); List names1 = sl.stream() @@ -58,41 +60,42 @@ public class ReloadTest { .map(Provider::get) .map(ScriptEngineFactory::getEngineName) .collect(Collectors.toList()); - assertEquals(names1, names2); + assertEquals(names2, names1); } - @Test(expectedExceptions = { ConcurrentModificationException.class }) + @Test public void testIteratorHasNext() { ServiceLoader sl = load(ScriptEngineFactory.class); Iterator iterator = sl.iterator(); sl.reload(); - iterator.hasNext(); + Assertions.assertThrows(ConcurrentModificationException.class, iterator::hasNext); } - @Test(expectedExceptions = { ConcurrentModificationException.class }) + @Test public void testIteratorNext() { ServiceLoader sl = load(ScriptEngineFactory.class); Iterator iterator = sl.iterator(); assertTrue(iterator.hasNext()); sl.reload(); - iterator.next(); + Assertions.assertThrows(ConcurrentModificationException.class, iterator::next); } - @Test(expectedExceptions = { ConcurrentModificationException.class }) + @Test public void testStreamFindAny() { ServiceLoader sl = load(ScriptEngineFactory.class); Stream> stream = sl.stream(); sl.reload(); - stream.findAny(); + Assertions.assertThrows(ConcurrentModificationException.class, stream::findAny); } - @Test(expectedExceptions = { ConcurrentModificationException.class }) + @Test public void testSpliteratorTryAdvance() { ServiceLoader sl = load(ScriptEngineFactory.class); Stream> stream = sl.stream(); Spliterator> spliterator = stream.spliterator(); sl.reload(); - spliterator.tryAdvance(System.out::println); + Assertions.assertThrows(ConcurrentModificationException.class, + () -> spliterator.tryAdvance(System.out::println)); } } diff --git a/test/jdk/java/util/ServiceLoader/TwoIterators.java b/test/jdk/java/util/ServiceLoader/TwoIterators.java index ddb9cc09508..b86cc45f17f 100644 --- a/test/jdk/java/util/ServiceLoader/TwoIterators.java +++ b/test/jdk/java/util/ServiceLoader/TwoIterators.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @summary Test ServiceLoader with two iterators, interleaving their use * to test that they don't interfere with each other - * @run testng TwoIterators + * @run junit TwoIterators */ import java.nio.file.Files; @@ -35,9 +35,9 @@ import java.util.Arrays; import java.util.Iterator; import java.util.ServiceLoader; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; public class TwoIterators { @@ -48,18 +48,17 @@ public class TwoIterators { public static class S1 implements S { } public static class S2 implements S { } - private ClassLoader testClassLoader; + private static ClassLoader testClassLoader; // creates the services configuration file and sets the ClassLoader - @BeforeClass - void setup() throws Exception { + @BeforeAll + static void setup() throws Exception { String classes = System.getProperty("test.classes"); Path dir = Paths.get(classes, "META-INF", "services"); Files.createDirectories(dir); Path config = dir.resolve(S.class.getName()); Files.write(config, Arrays.asList(S1.class.getName(), S2.class.getName())); - - this.testClassLoader = TwoIterators.class.getClassLoader(); + testClassLoader = TwoIterators.class.getClassLoader(); } @Test diff --git a/test/jdk/java/util/ServiceLoader/basic/ServiceLoaderBasicTest.java b/test/jdk/java/util/ServiceLoader/basic/ServiceLoaderBasicTest.java index 91aba564cd1..4a9bc808851 100644 --- a/test/jdk/java/util/ServiceLoader/basic/ServiceLoaderBasicTest.java +++ b/test/jdk/java/util/ServiceLoader/basic/ServiceLoaderBasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -29,7 +29,7 @@ * @build jdk.test.lib.process.* * jdk.test.lib.util.JarUtils * Basic Load FooService FooProvider1 FooProvider2 FooProvider3 BarProvider - * @run testng ServiceLoaderBasicTest + * @run junit ServiceLoaderBasicTest */ @@ -44,14 +44,16 @@ import jdk.test.lib.Utils; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.util.JarUtils; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.nio.file.StandardOpenOption.CREATE; import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import static java.util.Arrays.asList; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + public class ServiceLoaderBasicTest { private static final String METAINFO = "META-INF/services/FooService"; @@ -79,8 +81,8 @@ public class ServiceLoaderBasicTest { private static final String XTESTXMETA_CP = XTEST_CP + XMETA; private static final String XTESTXMETAP2_CP = XTESTXMETA_CP + P2; - @BeforeClass - public void initialize() throws Exception { + @BeforeAll + public static void initialize() throws Exception { createProviderConfig(XTEST_CONFIG, "FooProvider1"); createProviderConfig(XMETA_CONFIG, "FooProvider42"); createJar(P2JAR, "FooProvider2", List.of("FooProvider2")); @@ -88,8 +90,7 @@ public class ServiceLoaderBasicTest { Files.copy(P2JAR, P2DUPJAR, REPLACE_EXISTING); } - @DataProvider - public Object[][] testCases() { + private static Object[][] testCases() { return new Object[][]{ // CLI options, Test, Runtime arguments // Success cases @@ -110,23 +111,14 @@ public class ServiceLoaderBasicTest { }; } - @DataProvider - public Object[][] negativeTestCases() { - return new Object[][]{ - {"blah blah"}, - {"9234"}, - {"X!"}, - {"BarProvider"}, - {"FooProvider42"} - }; - } - - @Test(dataProvider = "testCases") + @ParameterizedTest + @MethodSource("testCases") public void testProvider(List args) throws Throwable { runJava(args); } - @Test(dataProvider = "negativeTestCases") + @ParameterizedTest // negative test cases + @ValueSource(strings = { "blah blah", "9234", "X!", "BarProvider", "FooProvider42" }) public void testBadProvider(String providerName) throws Throwable { Files.write(XMETA_CONFIG, providerName.getBytes()); runJava(List.of("-cp", XMETA_CP, "Load", "fail")); @@ -144,12 +136,12 @@ public class ServiceLoaderBasicTest { .shouldHaveExitValue(0); } - private void createProviderConfig(Path config, String providerName) throws Exception { + private static void createProviderConfig(Path config, String providerName) throws Exception { Files.createDirectories(config.getParent()); Files.write(config, providerName.getBytes(), CREATE); } - private void createJar(Path jar, String provider, List files) throws Exception { + private static void createJar(Path jar, String provider, List files) throws Exception { Path xdir = Path.of(provider); createProviderConfig(xdir.resolve(METAINFO), provider); diff --git a/test/jdk/java/util/StringJoiner/MergeTest.java b/test/jdk/java/util/StringJoiner/MergeTest.java index f47ed3ee094..574124b9bdd 100644 --- a/test/jdk/java/util/StringJoiner/MergeTest.java +++ b/test/jdk/java/util/StringJoiner/MergeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, 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,17 +27,18 @@ * @summary test StringJoiner::merge * @modules java.base/jdk.internal.util * @requires vm.bits == "64" & os.maxMemory > 4G - * @run testng/othervm -Xmx4g -XX:+CompactStrings MergeTest + * @run junit/othervm -Xmx4g -XX:+CompactStrings MergeTest */ import java.util.StringJoiner; import java.util.stream.Stream; -import org.testng.annotations.Test; import static jdk.internal.util.ArraysSupport.SOFT_MAX_ARRAY_LENGTH; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; -@Test +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; + public class MergeTest { private static final String[] PREFIXES = {"", "{", "@#$%"}; private static final String[] SUFFIXES = {"", "}", "*&%$"}; @@ -69,12 +70,13 @@ public class MergeTest { return builder.build(); } - @Test(expectedExceptions = {NullPointerException.class}) + @Test public void testNull() { StringJoiner sj = new StringJoiner(",", "{", "}"); - sj.merge(null); + Assertions.assertThrows(NullPointerException.class, () -> sj.merge(null)); } + @Test public void testSimple() { fixesStream().forEach(fixes -> { StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0); @@ -83,10 +85,11 @@ public class MergeTest { Stream.of("d", "e", "f").forEachOrdered(other::add); sj.merge(other); - assertEquals(sj.toString(), fixes.pre0 + "a,b,c,d,e,f" + fixes.suf0); + assertEquals(fixes.pre0 + "a,b,c,d,e,f" + fixes.suf0, sj.toString()); }); } + @Test public void testEmptyOther() { fixesStream().forEach(fixes -> { StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0); @@ -94,14 +97,15 @@ public class MergeTest { Stream.of("a", "b", "c").forEachOrdered(sj::add); sj.merge(other); - assertEquals(sj.toString(), fixes.pre0 + "a,b,c" + fixes.suf0); + assertEquals(fixes.pre0 + "a,b,c" + fixes.suf0, sj.toString()); other.setEmptyValue("EMPTY"); sj.merge(other); - assertEquals(sj.toString(), fixes.pre0 + "a,b,c" + fixes.suf0); + assertEquals(fixes.pre0 + "a,b,c" + fixes.suf0, sj.toString()); }); } + @Test public void testEmptyThis() { fixesStream().forEach(fixes -> { StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0); @@ -109,34 +113,36 @@ public class MergeTest { Stream.of("d", "e", "f").forEachOrdered(other::add); sj.merge(other); - assertEquals(sj.toString(), fixes.pre0 + "d:e:f" + fixes.suf0); + assertEquals(fixes.pre0 + "d:e:f" + fixes.suf0, sj.toString()); sj = new StringJoiner(",", fixes.pre0, fixes.suf0).setEmptyValue("EMPTY"); - assertEquals(sj.toString(), "EMPTY"); + assertEquals("EMPTY", sj.toString()); sj.merge(other); - assertEquals(sj.toString(), fixes.pre0 + "d:e:f" + fixes.suf0); + assertEquals(fixes.pre0 + "d:e:f" + fixes.suf0, sj.toString()); }); } + @Test public void testEmptyBoth() { fixesStream().forEach(fixes -> { StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0); StringJoiner other = new StringJoiner(":", fixes.pre1, fixes.suf1); sj.merge(other); - assertEquals(sj.toString(), fixes.pre0 + fixes.suf0); + assertEquals(fixes.pre0 + fixes.suf0, sj.toString()); other.setEmptyValue("NOTHING"); sj.merge(other); - assertEquals(sj.toString(), fixes.pre0 + fixes.suf0); + assertEquals(fixes.pre0 + fixes.suf0, sj.toString()); sj = new StringJoiner(",", fixes.pre0, fixes.suf0).setEmptyValue("EMPTY"); - assertEquals(sj.toString(), "EMPTY"); + assertEquals("EMPTY", sj.toString()); sj.merge(other); - assertEquals(sj.toString(), "EMPTY"); + assertEquals("EMPTY", sj.toString()); }); } + @Test public void testCascadeEmpty() { fixesStream().forEach(fixes -> { StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0); @@ -144,13 +150,14 @@ public class MergeTest { StringJoiner o2 = new StringJoiner(",", "<", ">").setEmptyValue("Empty2"); o1.merge(o2); - assertEquals(o1.toString(), "Empty1"); + assertEquals("Empty1", o1.toString()); sj.merge(o1); - assertEquals(sj.toString(), fixes.pre0 + fixes.suf0); + assertEquals(fixes.pre0 + fixes.suf0, sj.toString()); }); } + @Test public void testDelimiter() { fixesStream().forEach(fixes -> { StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0); @@ -159,18 +166,20 @@ public class MergeTest { Stream.of("d", "e", "f").forEachOrdered(other::add); sj.merge(other); - assertEquals(sj.toString(), fixes.pre0 + "a,b,c,d:e:f" + fixes.suf0); + assertEquals(fixes.pre0 + "a,b,c,d:e:f" + fixes.suf0, sj.toString()); }); } + @Test public void testMergeSelf() { fixesStream().forEach(fixes -> { final StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0).add("a").add("b"); - assertEquals(sj.merge(sj).toString(), fixes.pre0 + "a,b,a,b" + fixes.suf0); - assertEquals(sj.merge(sj).toString(), fixes.pre0 + "a,b,a,b,a,b,a,b" + fixes.suf0); + assertEquals(fixes.pre0 + "a,b,a,b" + fixes.suf0, sj.merge(sj).toString()); + assertEquals(fixes.pre0 + "a,b,a,b,a,b,a,b" + fixes.suf0, sj.merge(sj).toString()); }); } + @Test public void OOM() { String maxString = "*".repeat(SOFT_MAX_ARRAY_LENGTH); diff --git a/test/jdk/java/util/StringJoiner/StringJoinerOomUtf16Test.java b/test/jdk/java/util/StringJoiner/StringJoinerOomUtf16Test.java index b45e66b4d8b..7fde8b36ffa 100644 --- a/test/jdk/java/util/StringJoiner/StringJoinerOomUtf16Test.java +++ b/test/jdk/java/util/StringJoiner/StringJoinerOomUtf16Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,18 +26,23 @@ * @summary tests StringJoiner OOME when joining sub-max-length Strings * @modules java.base/jdk.internal.util * @requires vm.bits == "64" & os.maxMemory > 4G - * @run testng/othervm -Xmx4g -XX:+CompactStrings StringJoinerOomUtf16Test + * @run junit/othervm -Xmx4g -XX:+CompactStrings StringJoinerOomUtf16Test */ -import org.testng.annotations.Test; import static jdk.internal.util.ArraysSupport.SOFT_MAX_ARRAY_LENGTH; -import static org.testng.Assert.fail; + +import static org.junit.jupiter.api.Assertions.fail; import java.util.StringJoiner; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; -@Test(groups = {"unit","string","util","libs"}) +@Tag("unit") +@Tag("string") +@Tag("util") +@Tag("libs") public class StringJoinerOomUtf16Test { // the sum of lengths of the following two strings is way less than @@ -48,6 +53,7 @@ public class StringJoinerOomUtf16Test { private static final String OVERFLOW_UTF16_STRING = "\u017D".repeat(((Integer.MAX_VALUE - SOFT_MAX_ARRAY_LENGTH) >> 1) + 1); + @Test public void OOM1() { try { new StringJoiner("") @@ -60,6 +66,7 @@ public class StringJoinerOomUtf16Test { } } + @Test public void OOM2() { try { new StringJoiner(HALF_MAX_LATIN1_STRING) @@ -72,6 +79,7 @@ public class StringJoinerOomUtf16Test { } } + @Test public void OOM3() { try { new StringJoiner(OVERFLOW_UTF16_STRING) @@ -84,6 +92,7 @@ public class StringJoinerOomUtf16Test { } } + @Test public void OOM4() { try { new StringJoiner("", HALF_MAX_LATIN1_STRING, OVERFLOW_UTF16_STRING) diff --git a/test/jdk/java/util/StringJoiner/StringJoinerTest.java b/test/jdk/java/util/StringJoiner/StringJoinerTest.java index 25948fb8e55..aa25623dbc3 100644 --- a/test/jdk/java/util/StringJoiner/StringJoinerTest.java +++ b/test/jdk/java/util/StringJoiner/StringJoinerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,18 +26,25 @@ * @summary tests StringJoinerTest * @modules java.base/jdk.internal.util * @requires vm.bits == "64" & os.maxMemory > 4G - * @run testng/othervm -Xmx4g -XX:+CompactStrings StringJoinerTest + * @run junit/othervm -Xmx4g -XX:+CompactStrings StringJoinerTest * @author Jim Gish */ + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + import java.util.ArrayList; import java.util.StringJoiner; -import org.testng.annotations.Test; + import static jdk.internal.util.ArraysSupport.SOFT_MAX_ARRAY_LENGTH; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; - -@Test(groups = {"unit","string","util","libs"}) +@Tag("unit") +@Tag("string") +@Tag("util") +@Tag("libs") public class StringJoinerTest { private static final String EMPTY = "EMPTY"; @@ -51,6 +58,7 @@ public class StringJoinerTest { private static final String DASH = "-"; private static final String MAX_STRING = "*".repeat(SOFT_MAX_ARRAY_LENGTH); + @Test public void addAddAll() { StringJoiner sj = new StringJoiner(DASH, "{", "}"); sj.add(ONE); @@ -61,7 +69,7 @@ public class StringJoinerTest { nextOne.stream().forEachOrdered(sj::add); String expected = "{"+ONE+DASH+TWO+DASH+THREE+"}"; - assertEquals(sj.toString(), expected); + assertEquals(expected, sj.toString()); } void addAlladd() { @@ -75,10 +83,11 @@ public class StringJoinerTest { sj.add(THREE); String expected = "{"+ONE+DASH+TWO+DASH+THREE+"}"; - assertEquals(sj.toString(), expected); + assertEquals(expected, sj.toString()); } // The following tests do two successive adds of different types + @Test public void addAlladdAll() { StringJoiner sj = new StringJoiner(DASH, "{", "}"); ArrayList firstOne = new ArrayList<>(); @@ -93,9 +102,10 @@ public class StringJoinerTest { nextOne.stream().forEachOrdered(sj::add); String expected = "{"+ONE+DASH+TWO+DASH+THREE+DASH+FOUR+DASH+FIVE+"}"; - assertEquals(sj.toString(), expected); + assertEquals(expected, sj.toString()); } + @Test public void addCharSequence() { StringJoiner sj = new StringJoiner(","); CharSequence cs_one = ONE; @@ -104,13 +114,13 @@ public class StringJoinerTest { sj.add(cs_one); sj.add(cs_two); - assertEquals(sj.toString(), ONE + "," + TWO); + assertEquals(ONE + "," + TWO, sj.toString()); sj = new StringJoiner(DASH, "{", "}"); sj.add(cs_one); sj.add(cs_two); - assertEquals(sj.toString(), "{" + ONE + DASH + TWO + "}"); + assertEquals("{" + ONE + DASH + TWO + "}", sj.toString()); StringBuilder builder = new StringBuilder(ONE); StringBuffer buffer = new StringBuffer(THREE); @@ -118,13 +128,14 @@ public class StringJoinerTest { sj.add(builder).add(buffer); builder.append(TWO); buffer.append(FOUR); - assertEquals(sj.toString(), "{ " + ONE + ", " + THREE + " }", + assertEquals("{ " + ONE + ", " + THREE + " }", sj.toString(), "CharSequence is copied when add"); sj.add(builder); - assertEquals(sj.toString(), "{ " + ONE + ", " + THREE + ", " + ONE + - TWO + " }"); + assertEquals("{ " + ONE + ", " + THREE + ", " + ONE + + TWO + " }", sj.toString()); } + @Test public void addCharSequenceWithEmptyValue() { StringJoiner sj = new StringJoiner(",").setEmptyValue(EMPTY); CharSequence cs_one = ONE; @@ -133,189 +144,200 @@ public class StringJoinerTest { sj.add(cs_one); sj.add(cs_two); - assertEquals(sj.toString(), ONE + "," + TWO); + assertEquals(ONE + "," + TWO, sj.toString()); sj = new StringJoiner(DASH, "{", "}"); sj.add(cs_one); sj.add(cs_two); - assertEquals(sj.toString(), "{" + ONE + DASH + TWO + "}"); + assertEquals("{" + ONE + DASH + TWO + "}", sj.toString()); sj = new StringJoiner(DASH, "{", "}"); - assertEquals(sj.toString(), "{}"); + assertEquals("{}", sj.toString()); sj = new StringJoiner("=", "{", "}").setEmptyValue(""); - assertEquals(sj.toString(), ""); + assertEquals("", sj.toString()); sj = new StringJoiner(DASH, "{", "}").setEmptyValue(EMPTY); - assertEquals(sj.toString(), EMPTY); + assertEquals(EMPTY, sj.toString()); sj.add(cs_one); sj.add(cs_two); - assertEquals(sj.toString(), "{" + ONE + DASH + TWO + "}"); + assertEquals("{" + ONE + DASH + TWO + "}", sj.toString()); } + @Test public void addString() { StringJoiner sj = new StringJoiner(DASH); sj.add(ONE); - assertEquals(sj.toString(), ONE); + assertEquals(ONE, sj.toString()); sj = new StringJoiner(DASH, "{", "}"); sj.add(ONE); - assertEquals(sj.toString(), "{" + ONE + "}"); + assertEquals("{" + ONE + "}", sj.toString()); sj.add(TWO); - assertEquals(sj.toString(), "{" + ONE + DASH + TWO + "}"); + assertEquals("{" + ONE + DASH + TWO + "}", sj.toString()); } + @Test public void lengthWithCustomEmptyValue() { StringJoiner sj = new StringJoiner(DASH, "<", ">").setEmptyValue(EMPTY); - assertEquals(sj.length(), EMPTY.length()); + assertEquals(EMPTY.length(), sj.length()); sj.add(""); - assertEquals(sj.length(), "<>".length()); + assertEquals("<>".length(), sj.length()); sj.add(""); - assertEquals(sj.length(), "<->".length()); + assertEquals("<->".length(), sj.length()); sj.add(ONE); - assertEquals(sj.length(), 4 + ONE_LEN); - assertEquals(sj.toString().length(), sj.length()); + assertEquals(4 + ONE_LEN, sj.length()); + assertEquals(sj.length(), sj.toString().length()); sj.add(TWO); - assertEquals(sj.length(), 5 + ONE_LEN + TWO_LEN); - assertEquals(sj.toString().length(), sj.length()); + assertEquals(5 + ONE_LEN + TWO_LEN, sj.length()); + assertEquals(sj.length(), sj.toString().length()); sj = new StringJoiner("||", "<", "-->"); - assertEquals(sj.length(), 4); - assertEquals(sj.toString().length(), sj.length()); + assertEquals(4, sj.length()); + assertEquals(sj.length(), sj.toString().length()); sj.add("abcdef"); - assertEquals(sj.length(), 10); - assertEquals(sj.toString().length(), sj.length()); + assertEquals(10, sj.length()); + assertEquals(sj.length(), sj.toString().length()); sj.add("xyz"); - assertEquals(sj.length(), 15); - assertEquals(sj.toString().length(), sj.length()); + assertEquals(15, sj.length()); + assertEquals(sj.length(), sj.toString().length()); } + @Test public void noAddAndEmptyValue() { StringJoiner sj = new StringJoiner(DASH, "", "").setEmptyValue(EMPTY); - assertEquals(sj.toString(), EMPTY); + assertEquals(EMPTY, sj.toString()); sj = new StringJoiner(DASH, "<..", ""); - assertEquals(sj.toString(), "<.."); + assertEquals("<..", sj.toString()); sj = new StringJoiner(DASH, "<..", ""); - assertEquals(sj.toString(), "<.."); + assertEquals("<..", sj.toString()); sj = new StringJoiner(DASH, "", "==>"); - assertEquals(sj.toString(), "==>"); + assertEquals("==>", sj.toString()); sj = new StringJoiner(DASH, "{", "}"); - assertEquals(sj.toString(), "{}"); + assertEquals("{}", sj.toString()); } - @Test(expectedExceptions = {NullPointerException.class}) + @Test public void setEmptyValueNull() { - new StringJoiner(DASH, "{", "}").setEmptyValue(null); + Assertions.assertThrows(NullPointerException.class, + () -> new StringJoiner(DASH, "{", "}").setEmptyValue(null)); } - @Test(expectedExceptions = {NullPointerException.class}) + @Test public void setDelimiterNull() { - new StringJoiner(null); + Assertions.assertThrows(NullPointerException.class, + () -> new StringJoiner(null)); } - @Test(expectedExceptions = {NullPointerException.class}) + @Test public void setPrefixNull() { - new StringJoiner(DASH, null, "}"); + Assertions.assertThrows(NullPointerException.class, + () -> new StringJoiner(DASH, null, "}")); } - @Test(expectedExceptions = {NullPointerException.class}) + @Test public void setSuffixNull() { - new StringJoiner(DASH, "{", null); + Assertions.assertThrows(NullPointerException.class, + () -> new StringJoiner(DASH, "{", null)); } + @Test public void stringFromtoString() { StringJoiner sj = new StringJoiner(", "); - assertEquals(sj.toString(), ""); + assertEquals("", sj.toString()); sj = new StringJoiner(",", "{", "}"); - assertEquals(sj.toString(), "{}"); + assertEquals("{}", sj.toString()); sj = new StringJoiner(","); sj.add(ONE); - assertEquals(sj.toString(), ONE); + assertEquals(ONE, sj.toString()); sj.add(TWO); - assertEquals(sj.toString(), ONE + "," + TWO); + assertEquals(ONE + "," + TWO, sj.toString()); sj = new StringJoiner(",", "{--", "--}"); sj.add(ONE); sj.add(TWO); - assertEquals(sj.toString(), "{--" + ONE + "," + TWO + "--}"); + assertEquals("{--" + ONE + "," + TWO + "--}", sj.toString()); } + @Test public void stringFromtoStringWithEmptyValue() { StringJoiner sj = new StringJoiner(" ", "", ""); - assertEquals(sj.toString(), ""); + assertEquals("", sj.toString()); sj = new StringJoiner(", "); - assertEquals(sj.toString(), ""); + assertEquals("", sj.toString()); sj = new StringJoiner(",", "{", "}"); - assertEquals(sj.toString(), "{}"); + assertEquals("{}", sj.toString()); sj = new StringJoiner(",", "{", "}").setEmptyValue(""); - assertEquals(sj.toString(), ""); + assertEquals("", sj.toString()); sj = new StringJoiner(","); sj.add(ONE); - assertEquals(sj.toString(), ONE); + assertEquals(ONE, sj.toString()); sj.add(TWO); - assertEquals(sj.toString(), ONE + "," + TWO); + assertEquals(ONE + "," + TWO, sj.toString()); sj = new StringJoiner(",", "{--", "--}"); sj.add(ONE); - assertEquals(sj.toString(), "{--" + ONE + "--}" ); + assertEquals("{--" + ONE + "--}", sj.toString() ); sj.add(TWO); - assertEquals(sj.toString(), "{--" + ONE + "," + TWO + "--}"); + assertEquals("{--" + ONE + "," + TWO + "--}", sj.toString()); } + @Test public void toStringWithCustomEmptyValue() { StringJoiner sj = new StringJoiner(DASH, "<", ">").setEmptyValue(EMPTY); - assertEquals(sj.toString(), EMPTY); + assertEquals(EMPTY, sj.toString()); sj.add(""); - assertEquals(sj.toString(), "<>"); + assertEquals("<>", sj.toString()); sj.add(""); - assertEquals(sj.toString(), "<->"); + assertEquals("<->", sj.toString()); } private void testCombos(String infix, String prefix, String suffix) { StringJoiner sj = new StringJoiner(infix, prefix, suffix); - assertEquals(sj.toString(), prefix + suffix); - assertEquals(sj.toString().length(), sj.length()); + assertEquals(prefix + suffix, sj.toString()); + assertEquals(sj.length(), sj.toString().length()); // EmptyValue sj = new StringJoiner(infix, prefix, suffix).setEmptyValue(""); - assertEquals(sj.toString(), ""); - assertEquals(sj.toString().length(), sj.length()); + assertEquals("", sj.toString()); + assertEquals(sj.length(), sj.toString().length()); // empty in front sj.add(""); - assertEquals(sj.toString(), prefix + suffix); + assertEquals(prefix + suffix, sj.toString()); // empty in middle sj.add(""); - assertEquals(sj.toString(), prefix + infix + suffix); + assertEquals(prefix + infix + suffix, sj.toString()); sj.add("1"); - assertEquals(sj.toString(), prefix + infix + infix + "1" + suffix); + assertEquals(prefix + infix + infix + "1" + suffix, sj.toString()); // empty at end sj.add(""); - assertEquals(sj.toString(), prefix + infix + infix + "1" + infix + suffix); + assertEquals(prefix + infix + infix + "1" + infix + suffix, sj.toString()); sj = new StringJoiner(infix, prefix, suffix).setEmptyValue(""); sj.add("1"); - assertEquals(sj.toString(), prefix + "1" + suffix); + assertEquals(prefix + "1" + suffix, sj.toString()); sj.add("2"); - assertEquals(sj.toString(), prefix + "1" + infix + "2" + suffix); + assertEquals(prefix + "1" + infix + "2" + suffix, sj.toString()); sj.add(""); - assertEquals(sj.toString(), prefix + "1" + infix + "2" + infix + suffix); + assertEquals(prefix + "1" + infix + "2" + infix + suffix, sj.toString()); sj.add("3"); - assertEquals(sj.toString(), prefix + "1" + infix + "2" + infix + infix + "3" + suffix); + assertEquals(prefix + "1" + infix + "2" + infix + infix + "3" + suffix, sj.toString()); } + @Test public void testDelimiterCombinations() { testCombos("", "", ""); testCombos("", "<", ""); @@ -327,6 +349,7 @@ public class StringJoinerTest { testCombos(",", "<", ">"); } + @Test public void OOM1() { try { new StringJoiner(MAX_STRING, MAX_STRING, MAX_STRING).toString(); @@ -336,6 +359,7 @@ public class StringJoinerTest { } } + @Test public void OOM2() { try { new StringJoiner(MAX_STRING, MAX_STRING, "").toString(); @@ -345,6 +369,7 @@ public class StringJoinerTest { } } + @Test public void OOM3() { try { new StringJoiner(MAX_STRING, "", MAX_STRING).toString(); @@ -354,6 +379,7 @@ public class StringJoinerTest { } } + @Test public void OOM4() { try { new StringJoiner("", MAX_STRING, MAX_STRING).toString(); diff --git a/test/jdk/java/util/Vector/ArrayManagement.java b/test/jdk/java/util/Vector/ArrayManagement.java index ce4e695487c..c1fa6d1c9bc 100644 --- a/test/jdk/java/util/Vector/ArrayManagement.java +++ b/test/jdk/java/util/Vector/ArrayManagement.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * Copyright 2016 Google, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -25,7 +26,7 @@ * @test * @bug 8148174 * @summary brittle white box test of internal array management - * @run testng ArrayManagement + * @run junit ArrayManagement */ import java.lang.reflect.Field; @@ -35,8 +36,8 @@ import java.util.Collections; import java.util.List; import java.util.SplittableRandom; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class ArrayManagement { @@ -61,9 +62,9 @@ public class ArrayManagement { super.ensureCapacity(minCapacity); assertTrue(capacity() >= minCapacity); if (minCapacity <= oldCapacity) - assertEquals(capacity(), oldCapacity); + assertEquals(oldCapacity, capacity()); if (minCapacity > 0) - assertEquals(modCount(), oldModCount + 1); + assertEquals(oldModCount + 1, modCount()); } } @@ -89,117 +90,117 @@ public class ArrayManagement { case 3: assertTrue(list.addAll(size, singletonList())); break; default: throw new AssertionError(); } - assertEquals(list.modCount(), modCount + 1); - assertEquals(list.size(), size + 1); + assertEquals(modCount + 1, list.modCount()); + assertEquals(size + 1, list.size()); } @Test public void defaultCapacity() { PublicVector list = new PublicVector<>(); - assertEquals(new PublicVector().capacity(), DEFAULT_CAPACITY); + assertEquals(DEFAULT_CAPACITY, new PublicVector().capacity()); for (int i = 0; i < DEFAULT_CAPACITY; i++) { addOneElement(list); - assertEquals(list.capacity(), DEFAULT_CAPACITY); + assertEquals(DEFAULT_CAPACITY, list.capacity()); } addOneElement(list); - assertEquals(list.capacity(), newCapacity(DEFAULT_CAPACITY)); + assertEquals(newCapacity(DEFAULT_CAPACITY), list.capacity()); } @Test public void defaultCapacityEnsureCapacity() { PublicVector list = new PublicVector<>(); for (int i = 0; i <= DEFAULT_CAPACITY; i++) { list.ensureCapacity(i); // no-op! - assertEquals(list.capacity(), DEFAULT_CAPACITY); + assertEquals(DEFAULT_CAPACITY, list.capacity()); } for (int i = 0; i < DEFAULT_CAPACITY; i++) { addOneElement(list); - assertEquals(list.capacity(), DEFAULT_CAPACITY); + assertEquals(DEFAULT_CAPACITY, list.capacity()); } addOneElement(list); - assertEquals(list.capacity(), newCapacity(DEFAULT_CAPACITY)); + assertEquals(newCapacity(DEFAULT_CAPACITY), list.capacity()); { int capacity = list.capacity(); list.ensureCapacity(capacity + 1); - assertEquals(list.capacity(), newCapacity(capacity)); + assertEquals(newCapacity(capacity), list.capacity()); } { int capacity = list.capacity(); list.ensureCapacity(3 * capacity); - assertEquals(list.capacity(), 3 * capacity); + assertEquals(3 * capacity, list.capacity()); } } @Test public void ensureCapacityBeyondDefaultCapacity() { PublicVector list = new PublicVector<>(); list.ensureCapacity(DEFAULT_CAPACITY + 1); - assertEquals(list.capacity(), newCapacity(DEFAULT_CAPACITY)); + assertEquals(newCapacity(DEFAULT_CAPACITY), list.capacity()); } @Test public void explicitZeroCapacity() { PublicVector list = new PublicVector<>(0); - assertEquals(list.capacity(), 0); + assertEquals(0, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 1); + assertEquals(1, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 2); + assertEquals(2, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 4); + assertEquals(4, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 4); + assertEquals(4, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 8); + assertEquals(8, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 8); + assertEquals(8, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 8); + assertEquals(8, list.capacity()); list.clear(); - assertEquals(list.capacity(), 8); + assertEquals(8, list.capacity()); } @Test public void explicitZeroCapacityWithCapacityIncrement() { PublicVector list = new PublicVector<>(0, 2); - assertEquals(list.capacity(), 0); + assertEquals(0, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 2); + assertEquals(2, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 2); + assertEquals(2, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 4); + assertEquals(4, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 4); + assertEquals(4, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 6); + assertEquals(6, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 6); + assertEquals(6, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 8); + assertEquals(8, list.capacity()); list.clear(); - assertEquals(list.capacity(), 8); + assertEquals(8, list.capacity()); } @Test public void explicitLargeCapacity() { int n = DEFAULT_CAPACITY * 3; PublicVector list = new PublicVector<>(n); - assertEquals(list.capacity(), n); + assertEquals(n, list.capacity()); list.ensureCapacity(0); list.ensureCapacity(n); for (int i = 0; i < n; i++) addOneElement(list); - assertEquals(list.capacity(), n); + assertEquals(n, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), newCapacity(n)); + assertEquals(newCapacity(n), list.capacity()); } @Test public void explicitLargeCapacityWithCapacityIncrement() { int n = DEFAULT_CAPACITY * 3; PublicVector list = new PublicVector<>(n, 2); - assertEquals(list.capacity(), n); + assertEquals(n, list.capacity()); list.ensureCapacity(0); list.ensureCapacity(n); for (int i = 0; i < n; i++) addOneElement(list); - assertEquals(list.capacity(), n); + assertEquals(n, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), n + 2); + assertEquals(n + 2, list.capacity()); } @Test public void emptyArraysAreNotShared() { From 3f01e8b9b8f68560545540f9a70391a7ff7726d0 Mon Sep 17 00:00:00 2001 From: Kirill Shirokov Date: Thu, 15 Jan 2026 18:52:44 +0000 Subject: [PATCH 052/328] 8366522: CodeSource.getCodeSigners() throws NPE within empty certs Reviewed-by: mullan --- .../classes/java/security/CodeSource.java | 9 +- .../CodeSource/CodeSourceNoInputs.java | 110 ++++++++++++++++++ 2 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 test/jdk/java/security/CodeSource/CodeSourceNoInputs.java diff --git a/src/java.base/share/classes/java/security/CodeSource.java b/src/java.base/share/classes/java/security/CodeSource.java index 7476b8a1d61..9e69b2f0849 100644 --- a/src/java.base/share/classes/java/security/CodeSource.java +++ b/src/java.base/share/classes/java/security/CodeSource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -238,7 +238,12 @@ public class CodeSource implements java.io.Serializable { } else if (certs != null) { // Convert the certs to code signers signers = convertCertArrayToSignerArray(certs); - return signers.clone(); + if (signers != null) { + return signers.clone(); + + } else { + return new CodeSigner[0]; + } } else { return null; diff --git a/test/jdk/java/security/CodeSource/CodeSourceNoInputs.java b/test/jdk/java/security/CodeSource/CodeSourceNoInputs.java new file mode 100644 index 00000000000..e1d2497667b --- /dev/null +++ b/test/jdk/java/security/CodeSource/CodeSourceNoInputs.java @@ -0,0 +1,110 @@ +/* + * Copyright Amazon.com Inc. 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.security.CodeSigner; +import java.security.CodeSource; +import java.security.PublicKey; +import java.security.cert.Certificate; + +/** + * @test + * @bug 8366522 + * @summary Verify that getCertificates() and getCodeSigners() return correct + * results when CodeSource is created with empty or null Certificate[] + * or CodeSigner[] arguments, or there are no X509 certificates in + * certs. Make sure that NPE is not thrown from + * CodeSource.getCodeSigners() + */ +public class CodeSourceNoInputs { + private static final Certificate NON_X509_CERT = new Certificate("") { + @Override + public byte[] getEncoded() { + return new byte[0]; + } + + @Override + public void verify(PublicKey key) { + } + + @Override + public void verify(PublicKey key, String sigProvider) { + } + + @Override + public String toString() { + return ""; + } + + @Override + public PublicKey getPublicKey() { + return null; + } + }; + + public static void main(String[] args) throws Exception { + CodeSource cs; + + cs = new CodeSource(null, (Certificate[]) null); + if (cs.getCodeSigners() != null || cs.getCertificates() != null) { + + throw new SecurityException("Both CodeSource.getCodeSigners() " + + "and CodeSource.getCertificates() should return null for " + + "new CodeSource(null, (Certificate[]) null)"); + } + + cs = new CodeSource(null, (CodeSigner[]) null); + if (cs.getCodeSigners() != null || cs.getCertificates() != null) { + + throw new SecurityException("Both CodeSource.getCodeSigners() " + + "and CodeSource.getCertificates() should return null for " + + "new CodeSource(null, (CodeSigners[]) null)"); + } + + cs = new CodeSource(null, new Certificate[0]); + if (cs.getCodeSigners().length != 0 + || cs.getCertificates().length != 0) { + + throw new SecurityException("Both CodeSource.getCodeSigners()" + + "and CodeSource.getCertificates() should return empty arrays " + + "for new CodeSource(null, new Certificate[0])"); + + } + + cs = new CodeSource(null, new CodeSigner[0]); + if (cs.getCodeSigners().length != 0 + || cs.getCertificates().length != 0) { + + throw new SecurityException("Both CodeSource.getCodeSigners() and" + + " CodeSource.getCertificates() should return empty arrays for" + + " new CodeSource(null, new CodeSigners[0])"); + } + + cs = new CodeSource(null, new Certificate[]{NON_X509_CERT}); + if (cs.getCodeSigners().length != 0 || cs.getCertificates() == null) { + + throw new SecurityException("Both CodeSource.getCodeSigners() and" + + " CodeSource.getCertificates() should return arrays for new" + + " CodeSource(null, new CodeSigners[1]{NON-X509-CERTIFICATE})"); + } + } +} From e97fb0e2072a16c59014599719b64e8ea52a4976 Mon Sep 17 00:00:00 2001 From: Koushik Thirupattur Date: Thu, 15 Jan 2026 19:01:24 +0000 Subject: [PATCH 053/328] 8367024: JNI exception pending in Java_sun_security_pkcs11_wrapper_PKCS11_C_1DeriveKey of p11_keymgmt.c:950 Reviewed-by: valeriep, hchao, djelinski --- .../share/native/libj2pkcs11/p11_keymgmt.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_keymgmt.c b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_keymgmt.c index f2e1a46565d..e540f3b5ed9 100644 --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_keymgmt.c +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_keymgmt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -929,6 +929,11 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DeriveKey rv = (*ckpFunctions->C_DeriveKey)(ckSessionHandle, ckpMechanism, ckBaseKeyHandle, ckpAttributes, ckAttributesLength, phKey); + /* If derivation failed, do not attempt copy-back */ + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + goto cleanup; + } + jKeyHandle = ckLongToJLong(ckKeyHandle); switch (ckpMechanism->mechanism) { @@ -956,8 +961,9 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DeriveKey // empty break; } - if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { - jKeyHandle =0L; + /* Do not continue if any copy-back operation raised an exception */ + if ((*env)->ExceptionCheck(env)) { + goto cleanup; } cleanup: From 25c834a897ac0cac94942a019c9e377a53851f2c Mon Sep 17 00:00:00 2001 From: Koushik Thirupattur Date: Thu, 15 Jan 2026 19:05:19 +0000 Subject: [PATCH 054/328] 8366807: JNI exception pending in Java_sun_security_pkcs11_wrapper_PKCS11_initializeLibrary of p11_general.c:106 Reviewed-by: valeriep --- .../share/native/libj2pkcs11/p11_general.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_general.c b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_general.c index e9bcf597a03..f61b8a5fb49 100644 --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_general.c +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_general.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -100,6 +100,12 @@ Java_sun_security_pkcs11_wrapper_PKCS11_initializeLibrary #ifndef NO_CALLBACKS if (notifyListLock == NULL) { notifyListLock = createLockObject(env); + + /* Return immediately if lock creation failed or an exception is pending. */ + if (notifyListLock == NULL || (*env)->ExceptionCheck(env)) { + TRACE0("DEBUG: createLockObject failed, aborting initialization\n"); + return; + } } #endif From a8b845e08ce2f1fbe7d807cd963cb6b5e4df5ce6 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 15 Jan 2026 19:14:46 +0000 Subject: [PATCH 055/328] 8374445: Fix -Wzero-as-null-pointer-constant warnings in JfrSet Reviewed-by: mgronlun --- src/hotspot/share/jfr/utilities/jfrSet.hpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/jfr/utilities/jfrSet.hpp b/src/hotspot/share/jfr/utilities/jfrSet.hpp index 1432d40e4b2..3d394d10d8b 100644 --- a/src/hotspot/share/jfr/utilities/jfrSet.hpp +++ b/src/hotspot/share/jfr/utilities/jfrSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #ifndef SHARE_JFR_UTILITIES_JFRSET_HPP #define SHARE_JFR_UTILITIES_JFRSET_HPP +#include "cppstdlib/new.hpp" #include "jfr/utilities/jfrTypes.hpp" #include "memory/allocation.hpp" @@ -67,7 +68,9 @@ class JfrSetStorage : public AnyObj { } else { table = NEW_RESOURCE_ARRAY(K, table_size); } - memset(table, 0, table_size * sizeof(K)); + for (unsigned i = 0; i < table_size; ++i) { + ::new (&table[i]) K{}; + } return table; } @@ -88,7 +91,7 @@ class JfrSetStorage : public AnyObj { assert(is_nonempty(), "invariant"); for (unsigned i = 0; i < _table_size; ++i) { K k = _table[i]; - if (k != 0) { + if (k != K{}) { functor(k); } } @@ -136,11 +139,11 @@ class JfrSet : public JfrSetStorage { _resize_threshold = old_table_size; for (unsigned i = 0; i < old_table_size; ++i) { const K k = old_table[i]; - if (k != 0) { + if (k != K{}) { uint32_t idx = slot_idx(CONFIG::hash(k)); do { K v = this->_table[idx]; - if (v == 0) { + if (v == K{}) { this->_table[idx] = k; break; } @@ -161,7 +164,7 @@ class JfrSet : public JfrSetStorage { K* result = nullptr; while (true) { K v = this->_table[idx]; - if (v == 0) { + if (v == K{}) { result = &this->_table[idx]; break; } @@ -196,7 +199,7 @@ class JfrSet : public JfrSetStorage { // Already exists. return false; } - assert(*slot == 0, "invariant"); + assert(*slot == K{}, "invariant"); *slot = k; if (++this->_elements == _resize_threshold) { resize(); From 30cda00010888b6e9a2bf8cdeaedbb3eb4b6a222 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 15 Jan 2026 19:31:11 +0000 Subject: [PATCH 056/328] 8375294: (fs) Files.copy can fail with EOPNOTSUPP when copy_file_range not supported Reviewed-by: alanb, jpai --- src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c | 5 +++-- src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c b/src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c index efbd0ca5684..54d640b03a4 100644 --- a/src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c +++ b/src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -63,7 +63,7 @@ Java_sun_nio_ch_FileDispatcherImpl_transferFrom0(JNIEnv *env, jobject this, if (n < 0) { if (errno == EAGAIN) return IOS_UNAVAILABLE; - if (errno == ENOSYS) + if (errno == ENOSYS || errno == EOPNOTSUPP) return IOS_UNSUPPORTED_CASE; if ((errno == EBADF || errno == EINVAL || errno == EXDEV) && ((ssize_t)count >= 0)) @@ -103,6 +103,7 @@ Java_sun_nio_ch_FileDispatcherImpl_transferTo0(JNIEnv *env, jobject this, case EINVAL: case ENOSYS: case EXDEV: + case EOPNOTSUPP: // ignore and try sendfile() break; default: diff --git a/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c b/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c index c90e99dda07..4677411b0ba 100644 --- a/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c +++ b/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, 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 @@ -193,6 +193,7 @@ Java_sun_nio_fs_LinuxNativeDispatcher_directCopy0 case EINVAL: case ENOSYS: case EXDEV: + case EOPNOTSUPP: // ignore and try sendfile() break; default: From a1b039aa989ca91b6e70962363f720f581c5bfaf Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Thu, 15 Jan 2026 22:33:34 +0000 Subject: [PATCH 057/328] 8286032: keytool -list -alias should not assume it is always a certificate Reviewed-by: weijun --- .../sun/security/tools/keytool/Main.java | 9 +-- .../sun/security/tools/keytool/ListAlias.java | 71 +++++++++++++++++++ .../sun/security/tools/keytool/WeakAlg.java | 14 ++-- 3 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 test/jdk/sun/security/tools/keytool/ListAlias.java diff --git a/src/java.base/share/classes/sun/security/tools/keytool/Main.java b/src/java.base/share/classes/sun/security/tools/keytool/Main.java index 9fb830da338..7f415da5270 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -1294,7 +1294,7 @@ public final class Main { } if (alias != null) { - doPrintEntry(rb.getString("the.certificate"), alias, out); + doPrintEntry(alias, out); } else { doPrintEntries(out); } @@ -2177,9 +2177,10 @@ public final class Main { /** * Prints a single keystore entry. */ - private void doPrintEntry(String label, String alias, PrintStream out) + private void doPrintEntry(String alias, PrintStream out) throws Exception { + String label = "<" + alias + ">"; CertPathConstraintsParameters cpcp; if (!keyStore.containsAlias(alias)) { MessageFormat form = new MessageFormat @@ -2631,7 +2632,7 @@ public final class Main { List aliases = Collections.list(keyStore.aliases()); aliases.sort(String::compareTo); for (String alias : aliases) { - doPrintEntry("<" + alias + ">", alias, out); + doPrintEntry(alias, out); if (verbose || rfc) { out.println(rb.getString("NEWLINE")); out.println(rb.getString diff --git a/test/jdk/sun/security/tools/keytool/ListAlias.java b/test/jdk/sun/security/tools/keytool/ListAlias.java new file mode 100644 index 00000000000..91994c04a9c --- /dev/null +++ b/test/jdk/sun/security/tools/keytool/ListAlias.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2026, 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 8286032 + * @summary Validate the warnings of the keytool -list -alias command + * @library /test/lib + */ + +import jdk.test.lib.SecurityTools; + +public class ListAlias { + + public static void main(String[] args) throws Exception { + SecurityTools.keytool("-keystore ks -storepass changeit " + + "-genseckey -keyalg DES -alias deskey") + .shouldContain("Warning") + .shouldMatch("The generated secret key uses the DES algorithm.*considered a security risk") + .shouldHaveExitValue(0); + + SecurityTools.keytool("-keystore ks -storepass changeit " + + "-list -alias deskey -v") + .shouldContain("Warning") + .shouldMatch(" uses the DES algorithm.*considered a security risk") + .shouldNotContain("The certificate") + .shouldHaveExitValue(0); + + SecurityTools.keytool("-keystore ks -storepass changeit " + + "-genkeypair -keyalg RSA -alias ca -dname CN=CA -ext bc:c " + + "-sigalg SHA1withRSA") + .shouldContain("Warning") + .shouldMatch("The generated certificate uses the SHA1withRSA.*considered a security risk") + .shouldHaveExitValue(0); + + SecurityTools.keytool("-keystore ks -storepass changeit " + + "-list -alias ca -v") + .shouldContain("Warning") + .shouldMatch(" uses the SHA1withRSA.*considered a security risk") + .shouldNotContain("The certificate") + .shouldHaveExitValue(0); + + SecurityTools.keytool("-keystore ks -storepass changeit " + + "-list -v") + .shouldContain("Warning") + .shouldMatch(" uses the DES algorithm.*considered a security risk") + .shouldMatch(" uses the SHA1withRSA.*considered a security risk") + .shouldNotContain("The certificate") + .shouldHaveExitValue(0); + } +} \ No newline at end of file diff --git a/test/jdk/sun/security/tools/keytool/WeakAlg.java b/test/jdk/sun/security/tools/keytool/WeakAlg.java index de2435a4f4b..546a4182e97 100644 --- a/test/jdk/sun/security/tools/keytool/WeakAlg.java +++ b/test/jdk/sun/security/tools/keytool/WeakAlg.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -750,7 +750,7 @@ public class WeakAlg { oa.shouldNotContain("Warning"); } else { oa.shouldContain("Warning") - .shouldMatch("The certificate.*" + bad + ".*is disabled"); + .shouldMatch("uses.*" + bad + ".*is disabled"); } // With cert content @@ -770,7 +770,7 @@ public class WeakAlg { } else { oa.shouldContain("Warning") .shouldContain(bad + " (disabled)") - .shouldMatch("The certificate.*" + bad + ".*is disabled"); + .shouldMatch("uses.*" + bad + ".*is disabled"); } } @@ -844,11 +844,11 @@ public class WeakAlg { break; case "SHA1withRSA": oa.shouldContain("Warning") - .shouldMatch("The certificate.*" + bad + ".*considered a security risk"); + .shouldMatch("uses.*" + bad + ".*considered a security risk"); break; case "1024-bit RSA key": oa.shouldContain("Warning") - .shouldMatch("The certificate.*" + bad + ".*will be disabled"); + .shouldMatch("uses.*" + bad + ".*will be disabled"); break; } @@ -879,12 +879,12 @@ public class WeakAlg { case "SHA1withRSA": oa.shouldContain("Warning") .shouldContain(bad + " (weak)") - .shouldMatch("The certificate.*" + bad + ".*considered a security risk"); + .shouldMatch("uses.*" + bad + ".*considered a security risk"); break; case "1024-bit RSA key": oa.shouldContain("Warning") .shouldContain(bad + " (weak)") - .shouldMatch("The certificate.*" + bad + ".*will be disabled"); + .shouldMatch("uses.*" + bad + ".*will be disabled"); break; } } From 87cbcadacfa20b24e9ba0bf8374ecbcd331d2b35 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Thu, 15 Jan 2026 22:35:49 +0000 Subject: [PATCH 058/328] 8351892: GenShen: Remove vestigial young generation sizing options Reviewed-by: kdnilsen, ysr --- .../gc/shenandoah/shenandoahGenerationalHeap.cpp | 11 ----------- .../share/gc/shenandoah/shenandoah_globals.hpp | 12 ------------ 2 files changed, 23 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index f887cc9064e..fa78e02e6af 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -104,17 +104,6 @@ void ShenandoahGenerationalHeap::initialize_heuristics() { // Initialize global generation and heuristics even in generational mode. ShenandoahHeap::initialize_heuristics(); - // Max capacity is the maximum _allowed_ capacity. That is, the maximum allowed capacity - // for old would be total heap - minimum capacity of young. This means the sum of the maximum - // allowed for old and young could exceed the total heap size. It remains the case that the - // _actual_ capacity of young + old = total. - size_t region_count = num_regions(); - size_t max_young_regions = MAX2((region_count * ShenandoahMaxYoungPercentage) / 100, (size_t) 1U); - size_t initial_capacity_young = max_young_regions * ShenandoahHeapRegion::region_size_bytes(); - size_t max_capacity_young = initial_capacity_young; - size_t initial_capacity_old = max_capacity() - max_capacity_young; - size_t max_capacity_old = max_capacity() - initial_capacity_young; - _young_generation = new ShenandoahYoungGeneration(max_workers()); _old_generation = new ShenandoahOldGeneration(max_workers()); _young_generation->initialize_heuristics(mode()); diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index 15520c47bbc..254483d1923 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -430,18 +430,6 @@ "by thread type (worker or mutator) and evacuation type (young, " \ "old, or promotion.") \ \ - product(uintx, ShenandoahMinYoungPercentage, 20, EXPERIMENTAL, \ - "The minimum percentage of the heap to use for the young " \ - "generation. Heuristics will not adjust the young generation " \ - "to be less than this.") \ - range(0, 100) \ - \ - product(uintx, ShenandoahMaxYoungPercentage, 100, EXPERIMENTAL, \ - "The maximum percentage of the heap to use for the young " \ - "generation. Heuristics will not adjust the young generation " \ - "to be more than this.") \ - range(0, 100) \ - \ product(uintx, ShenandoahCriticalFreeThreshold, 1, EXPERIMENTAL, \ "How much of the heap needs to be free after recovery cycles, " \ "either Degenerated or Full GC to be claimed successful. If this "\ From 1d889b92bde5dfcb1fbe6cddb389a77f92eb1ce7 Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Thu, 15 Jan 2026 23:11:12 +0000 Subject: [PATCH 059/328] 8360271: String.indexOf intrinsics fail with +EnableX86ECoreOpts and -CompactStrings Reviewed-by: thartmann, jbhateja, sviswanathan --- .../x86/c2_stubGenerator_x86_64_string.cpp | 8 +++++--- test/jdk/java/lang/String/IndexOf.java | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp b/src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp index 0951bda0d17..77a149addb5 100644 --- a/src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp +++ b/src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Intel Corporation. All rights reserved. + * Copyright (c) 2024, 2026, Intel Corporation. All rights reserved. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1330,10 +1330,12 @@ static void big_case_loop_helper(bool sizeKnown, int size, Label &noMatch, Label // Clarification: The BYTE_K compare above compares haystack[(n-32):(n-1)]. We need to // compare haystack[(k-1):(k-1+31)]. Subtracting either index gives shift value of // (k + 31 - n): x = (k-1+31)-(n-1) = k-1+31-n+1 = k+31-n. + // When isU is set, similarly, shift is from haystack[(n-32):(n-1)] to [(k-2):(k-2+31)] + if (sizeKnown) { - __ movl(temp2, 31 + size); + __ movl(temp2, (isU ? 30 : 31) + size); } else { - __ movl(temp2, 31); + __ movl(temp2, isU ? 30 : 31); __ addl(temp2, needleLen); } __ subl(temp2, hsLength); diff --git a/test/jdk/java/lang/String/IndexOf.java b/test/jdk/java/lang/String/IndexOf.java index b4fd17105a8..48f23de79b0 100644 --- a/test/jdk/java/lang/String/IndexOf.java +++ b/test/jdk/java/lang/String/IndexOf.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Intel Corporation. All rights reserved. + * Copyright (c) 2024, 2026, Intel Corporation. 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,6 +37,15 @@ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xcomp -XX:-TieredCompilation -XX:UseAVX=2 -XX:+UnlockDiagnosticVMOptions -XX:+EnableX86ECoreOpts IndexOf */ +/* + * @test + * @bug 8360271 + * @summary test String indexOf() intrinsic + * @requires vm.cpu.features ~= ".*avx2.*" + * @requires vm.compiler2.enabled + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xcomp -XX:-TieredCompilation -XX:UseAVX=2 -XX:+UnlockDiagnosticVMOptions -XX:+EnableX86ECoreOpts -XX:-CompactStrings IndexOf + */ + public class IndexOf { final int scope = 32*2+16+8; final char a, aa, b, c, d; @@ -56,11 +65,11 @@ d = 'd'; break; case UU: - a = '\u0061'; + a = '\u1061'; aa = a; - b = '\u0062'; + b = '\u1062'; c = '\u1063'; - d = '\u0064'; + d = '\u1064'; break; default: //case UL: a = 'a'; @@ -73,7 +82,7 @@ } // needle =~ /ab*d/ - // badNeedle =~ /ab*db*d/ + // badNeedle =~ /ab*cb*d/ interface Append {void append(int pos, char cc);} String newNeedle(int size, int badPosition) { if (size<2) {throw new RuntimeException("Fix testcase "+size);} From fddba3b7ecb11136e9699861b5d86aeb3d481be6 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 16 Jan 2026 00:47:24 +0000 Subject: [PATCH 060/328] 8375350: Remove usage of AppContext from javax.imageio implementation Reviewed-by: kizune, dnguyen --- .../share/classes/javax/imageio/ImageIO.java | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/java.desktop/share/classes/javax/imageio/ImageIO.java b/src/java.desktop/share/classes/javax/imageio/ImageIO.java index 8180145a8ea..5d3526df917 100644 --- a/src/java.desktop/share/classes/javax/imageio/ImageIO.java +++ b/src/java.desktop/share/classes/javax/imageio/ImageIO.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,6 @@ import javax.imageio.spi.ImageTranscoderSpi; import javax.imageio.spi.ServiceRegistry; import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageOutputStream; -import sun.awt.AppContext; /** * A class containing static convenience methods for locating @@ -108,9 +107,7 @@ public final class ImageIO { // ImageInputStreams /** - * A class to hold information about caching. Each - * {@code ThreadGroup} will have its own copy - * via the {@code AppContext} mechanism. + * A class to hold information about caching. */ static class CacheInfo { boolean useCache = true; @@ -144,17 +141,12 @@ public final class ImageIO { } } + private static final CacheInfo info = new CacheInfo(); + /** - * Returns the {@code CacheInfo} object associated with this - * {@code ThreadGroup}. + * Returns the {@code CacheInfo} object. */ private static synchronized CacheInfo getCacheInfo() { - AppContext context = AppContext.getAppContext(); - CacheInfo info = (CacheInfo)context.get(CacheInfo.class); - if (info == null) { - info = new CacheInfo(); - context.put(CacheInfo.class, info); - } return info; } From 9876875e37b5cd4ac5263007ff96611ab0707cd5 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 16 Jan 2026 02:51:40 +0000 Subject: [PATCH 061/328] 8375364: [macos] Some jpackage signing tests fail after JDK-8375240 Reviewed-by: almatvee --- .../jpackage/helpers/jdk/jpackage/test/JPackageCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 9b8b05af93b..7874df3fd69 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -971,7 +971,7 @@ public class JPackageCommand extends CommandArguments { executePrerequisiteActions(); nullableOutputBundle().filter(_ -> { - return removeOldOutputBundle; + return !(TKit.isOSX() && MacHelper.signPredefinedAppImage(this)) && removeOldOutputBundle; }).ifPresent(path -> { ThrowingRunnable.toRunnable(() -> { if (Files.isDirectory(path)) { From e4474ad8ae250771e031b8c18809d3e461970365 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Fri, 16 Jan 2026 03:19:28 +0000 Subject: [PATCH 062/328] 8375367: vmTestbase tests reported variable uninitialized by clang23 Reviewed-by: sspitsyn, amenkov, lmesnik --- .../nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002.cpp | 4 ++-- .../nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002a.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002.cpp index 52459a7994f..8205729e4ef 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, 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 @@ -113,7 +113,7 @@ static int prepare(JNIEnv* jni) { /** Agent algorithm. */ static void JNICALL agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { - jint dummy; + jint dummy = 0; if (!nsk_jvmti_waitForSync(timeout)) return; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002a.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002a.cpp index 7f716d009ce..f2cff01948b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002a.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002a.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, 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 @@ -113,7 +113,7 @@ static int prepare(JNIEnv* jni) { /** Agent algorithm. */ static void JNICALL agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { - jint dummy; + jint dummy = 0; if (!nsk_jvmti_waitForSync(timeout)) return; From fda8d0506a511c00e65c3f97aaaf6f018945b213 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 16 Jan 2026 07:48:26 +0000 Subject: [PATCH 063/328] 8375455: G1: Remove unused G1HeapRegionStats::coarsen_stats() Reviewed-by: kbarrett --- src/hotspot/share/gc/g1/g1CardSet.cpp | 6 +----- src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp | 5 +---- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index 80cf5fea76a..3441e6bc608 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -1024,10 +1024,6 @@ size_t G1CardSet::num_containers() { return cl._count; } -G1CardSetCoarsenStats G1CardSet::coarsen_stats() { - return _coarsen_stats; -} - void G1CardSet::print_coarsen_stats(outputStream* out) { _last_coarsen_stats.subtract_from(_coarsen_stats); diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp index 0f78e0d6271..878d35397aa 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -123,9 +123,6 @@ public: static void initialize(MemRegion reserved); - // Coarsening statistics since VM start. - static G1CardSetCoarsenStats coarsen_stats() { return G1CardSet::coarsen_stats(); } - inline uintptr_t to_card(OopOrNarrowOopStar from) const; private: From 5664d9148401934cd26308dc4493f4a5656e89bd Mon Sep 17 00:00:00 2001 From: Richard Reingruber Date: Fri, 16 Jan 2026 08:01:40 +0000 Subject: [PATCH 064/328] 8374769: PPC: MASM::pop_cont_fastpath() should reset _cont_fastpath if SP == _cont_fastpath Reviewed-by: mdoerr --- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 5649ead2ea8..809285afddb 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -4535,7 +4535,7 @@ void MacroAssembler::push_cont_fastpath() { Label done; ld_ptr(R0, JavaThread::cont_fastpath_offset(), R16_thread); cmpld(CR0, R1_SP, R0); - ble(CR0, done); + ble(CR0, done); // if (SP <= _cont_fastpath) goto done; st_ptr(R1_SP, JavaThread::cont_fastpath_offset(), R16_thread); bind(done); } @@ -4546,7 +4546,7 @@ void MacroAssembler::pop_cont_fastpath() { Label done; ld_ptr(R0, JavaThread::cont_fastpath_offset(), R16_thread); cmpld(CR0, R1_SP, R0); - ble(CR0, done); + blt(CR0, done); // if (SP < _cont_fastpath) goto done; li(R0, 0); st_ptr(R0, JavaThread::cont_fastpath_offset(), R16_thread); bind(done); From b7346c307fc1aba01c10fc6dc745e5e520b1d7b9 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 16 Jan 2026 08:03:55 +0000 Subject: [PATCH 065/328] 8375311: Some builds are missing debug helpers Reviewed-by: mdoerr, aph --- src/hotspot/share/utilities/debug.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp index 9e167141259..0e1ca1efb98 100644 --- a/src/hotspot/share/utilities/debug.cpp +++ b/src/hotspot/share/utilities/debug.cpp @@ -70,8 +70,10 @@ #include #include -// These functions needs to be exported on Windows only -#define DEBUGEXPORT WINDOWS_ONLY(JNIEXPORT) +// These functions needs to be exported on Windows +// On Linux it is also beneficial to export them to avoid +// losing them e.g. with linktime gc +#define DEBUGEXPORT JNIEXPORT // Support for showing register content on asserts/guarantees. #ifdef CAN_SHOW_REGISTERS_ON_ASSERT @@ -653,13 +655,12 @@ extern "C" DEBUGEXPORT intptr_t u5p(intptr_t addr, void pp(intptr_t p) { pp((void*)p); } void pp(oop p) { pp((void*)p); } -void help() { +extern "C" DEBUGEXPORT void help() { Command c("help"); tty->print_cr("basic"); tty->print_cr(" pp(void* p) - try to make sense of p"); tty->print_cr(" ps() - print current thread stack"); tty->print_cr(" pss() - print all thread stacks"); - tty->print_cr(" pm(int pc) - print Method* given compiled PC"); tty->print_cr(" findnm(intptr_t pc) - find nmethod*"); tty->print_cr(" findm(intptr_t pc) - find Method*"); tty->print_cr(" find(intptr_t x) - find & print nmethod/stub/bytecode/oop based on pointer into it"); From e7432d574540109e2c4faca11cf49d9272a147e6 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 16 Jan 2026 20:03:00 +0000 Subject: [PATCH 066/328] 8375323: Improve handling of the "--app-content" and "--input" options in jpackage Reviewed-by: almatvee --- .../jdk/jpackage/internal/LinuxPackager.java | 4 +- .../jdk/jpackage/internal/AppImageSigner.java | 2 +- .../internal/MacApplicationBuilder.java | 22 +- .../internal/MacDmgPackageBuilder.java | 16 +- .../jdk/jpackage/internal/MacDmgPackager.java | 6 +- .../jdk/jpackage/internal/MacFromOptions.java | 11 +- .../jdk/jpackage/internal/MacPkgPackager.java | 1 - .../internal/model/MacDmgPackageMixin.java | 13 +- .../jpackage/internal/ApplicationBuilder.java | 24 +- .../internal/ApplicationImageUtils.java | 49 +- .../internal/DefaultBundlingEnvironment.java | 3 +- .../jdk/jpackage/internal/FromOptions.java | 15 +- .../internal/LauncherFromOptions.java | 5 +- .../jpackage/internal/PackagingPipeline.java | 10 +- .../cli/JOptSimpleOptionsBuilder.java | 7 +- .../cli/OptionArrayValueConverter.java | 4 +- .../jdk/jpackage/internal/cli/OptionSpec.java | 13 +- .../internal/cli/OptionSpecBuilder.java | 120 +++-- .../cli/OptionSpecMapperOptionScope.java | 103 +++- .../internal/cli/OptionValueConverter.java | 503 ++++++++++++++---- .../internal/cli/OptionsAnalyzer.java | 1 - .../internal/cli/OptionsProcessor.java | 7 +- .../cli/StandardAppImageFileOption.java | 2 +- .../jpackage/internal/cli/StandardOption.java | 100 +++- .../internal/cli/StandardValueConverter.java | 76 ++- .../jdk/jpackage/internal/cli/Validator.java | 10 +- .../jpackage/internal/cli/ValueConverter.java | 27 +- .../internal/cli/ValueConverterFunction.java | 40 ++ .../jpackage/internal/model/Application.java | 43 +- .../resources/MainResources.properties | 1 + .../jdk/jpackage/internal/util/FileUtils.java | 26 +- .../jpackage/internal/util/RootedPath.java | 185 +++++++ .../jdk/jpackage/internal/WinExePackager.java | 2 +- .../jdk/jpackage/internal/WinMsiPackager.java | 2 +- .../jpackage/internal/AppImageFileTest.java | 2 +- .../internal/PackagingPipelineTest.java | 2 +- .../cli/OptionSpecMutatorOptionScopeTest.java | 10 +- .../jpackage/internal/cli/OptionSpecTest.java | 10 +- .../cli/OptionValueConverterTest.java | 188 ++++++- .../internal/cli/StandardOptionTest.java | 256 ++++++++- .../cli/StandardValueConverterTest.java | 12 +- .../jpackage/internal/util/FileUtilsTest.java | 76 +-- .../tools/jdk/jpackage/test/JUnitUtils.java | 23 +- .../tools/jpackage/share/AppContentTest.java | 80 ++- .../tools/jpackage/share/InOutPathTest.java | 173 +++--- 45 files changed, 1706 insertions(+), 579 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverterFunction.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/RootedPath.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java index af7f5288cc5..551e1ab1af6 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ abstract class LinuxPackager implements Consumer { + return rootedPath.branch().getNameCount() == 1; + }).map(RootedPath::fullPath).forEach(contentDir -> { if (!Files.isDirectory(contentDir)) { Log.info(I18N.format("warning.app.content.is.not.dir", contentDir)); - } else if (!CONTENTS_SUB_DIRS.contains(contentDir.getFileName().toString())) { + } else if (!CONTENTS_SUB_DIRS.contains(contentDir.getFileName())) { Log.info(I18N.format("warning.non.standard.contents.sub.dir", contentDir)); } - } + }); } private MacApplicationBuilder createCopyForExternalInfoPlistFile() { @@ -258,6 +263,11 @@ final class MacApplicationBuilder { private static final int MAX_BUNDLE_NAME_LENGTH = 16; // List of standard subdirectories of the "Contents" directory - private static final Set CONTENTS_SUB_DIRS = Set.of("MacOS", - "Resources", "Frameworks", "PlugIns", "SharedSupport"); + private static final Set CONTENTS_SUB_DIRS = Stream.of( + "MacOS", + "Resources", + "Frameworks", + "PlugIns", + "SharedSupport" + ).map(Path::of).collect(Collectors.toUnmodifiableSet()); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java index 10754b1f1b6..b9e407b4a47 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,13 @@ package jdk.jpackage.internal; import java.nio.file.Path; +import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Optional; import jdk.jpackage.internal.model.MacDmgPackage; import jdk.jpackage.internal.model.MacDmgPackageMixin; +import jdk.jpackage.internal.util.RootedPath; final class MacDmgPackageBuilder { @@ -37,8 +39,8 @@ final class MacDmgPackageBuilder { this.pkgBuilder = Objects.requireNonNull(pkgBuilder); } - MacDmgPackageBuilder dmgContent(List v) { - dmgContent = v; + MacDmgPackageBuilder dmgRootDirSources(Collection v) { + dmgRootDirSources = v; return this; } @@ -47,8 +49,8 @@ final class MacDmgPackageBuilder { return this; } - List validatedDmgContent() { - return Optional.ofNullable(dmgContent).orElseGet(List::of); + private Collection validatedDmgRootDirSources() { + return Optional.ofNullable(dmgRootDirSources).orElseGet(List::of); } MacDmgPackage create() { @@ -56,10 +58,10 @@ final class MacDmgPackageBuilder { return MacDmgPackage.create(pkg, new MacDmgPackageMixin.Stub( Optional.ofNullable(icon).or((pkg.app())::icon), - validatedDmgContent())); + validatedDmgRootDirSources())); } private Path icon; - private List dmgContent; + private Collection dmgRootDirSources; private final MacPackageBuilder pkgBuilder; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java index cf4db226d37..24474c88162 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java @@ -46,6 +46,7 @@ import jdk.jpackage.internal.PackagingPipeline.TaskID; import jdk.jpackage.internal.model.MacDmgPackage; import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.PathGroup; +import jdk.jpackage.internal.util.RootedPath; record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, MacDmgSystemEnvironment sysEnv) implements Consumer { @@ -60,7 +61,6 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, @Override public void accept(PackagingPipeline.Builder pipelineBuilder) { pipelineBuilder - .excludeDirFromCopying(outputDir) .task(DmgPackageTaskID.COPY_DMG_CONTENT) .action(this::copyDmgContent) .addDependent(PackageTaskID.CREATE_PACKAGE_FILE) @@ -130,9 +130,7 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, private void copyDmgContent() throws IOException { final var srcFolder = env.appImageDir(); - for (Path path : pkg.content()) { - FileUtils.copyRecursive(path, srcFolder.resolve(path.getFileName())); - } + RootedPath.copy(pkg.dmgRootDirSources().stream(), srcFolder); } private Executor hdiutil(String... args) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java index cdf33d6dcba..f3c1765210f 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java @@ -52,6 +52,7 @@ import static jdk.jpackage.internal.model.StandardPackageType.MAC_PKG; import static jdk.jpackage.internal.util.function.ExceptionBox.toUnchecked; import java.nio.file.Path; +import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -75,6 +76,7 @@ import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.RuntimeLayout; import jdk.jpackage.internal.util.MacBundle; import jdk.jpackage.internal.util.Result; +import jdk.jpackage.internal.util.RootedPath; import jdk.jpackage.internal.util.function.ExceptionBox; @@ -92,7 +94,14 @@ final class MacFromOptions { final var pkgBuilder = new MacDmgPackageBuilder(superPkgBuilder); - MAC_DMG_CONTENT.ifPresentIn(options, pkgBuilder::dmgContent); + MAC_DMG_CONTENT.findIn(options).map((List> v) -> { + // Reverse the order of content sources. + // If there are multiple source files for the same + // destination file, only the first will be used. + // Reversing the order of content sources makes it use the last file + // from the original list of source files for the given destination file. + return v.reversed().stream().flatMap(Collection::stream).toList(); + }).ifPresent(pkgBuilder::dmgRootDirSources); return pkgBuilder.create(); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java index 126248e2330..fc5c85c699c 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java @@ -215,7 +215,6 @@ record MacPkgPackager(BuildEnv env, MacPkgPackage pkg, Optional servic @Override public void accept(PackagingPipeline.Builder pipelineBuilder) { pipelineBuilder - .excludeDirFromCopying(outputDir) .task(PkgPackageTaskID.PREPARE_MAIN_SCRIPTS) .action(this::prepareMainScripts) .addDependent(PackageTaskID.RUN_POST_IMAGE_USER_SCRIPT) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java index 0b502e7ce7e..08797b11509 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,23 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; -import java.util.List; +import java.util.Collection; import java.util.Optional; +import jdk.jpackage.internal.util.RootedPath; public interface MacDmgPackageMixin { Optional icon(); /** - * Returns additional top=level content for DMG package. + * Returns the source paths that should be copied into the top-level directory of a DMG package. *

* Each item in the list can be a directory or a file. * - * @return the additional top=level content for DMG package + * @return the source paths of additional top-level content for DMG package */ - List content(); + Collection dmgRootDirSources(); - record Stub(Optional icon, List content) implements MacDmgPackageMixin { + record Stub(Optional icon, Collection dmgRootDirSources) implements MacDmgPackageMixin { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index 6896668ffdc..9d5407524a8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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,6 +27,7 @@ package jdk.jpackage.internal; import static jdk.jpackage.internal.I18N.buildConfigException; import java.nio.file.Path; +import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; @@ -44,6 +45,7 @@ import jdk.jpackage.internal.model.LauncherIcon; import jdk.jpackage.internal.model.LauncherStartupInfo; import jdk.jpackage.internal.model.ResourceDirLauncherIcon; import jdk.jpackage.internal.model.RuntimeBuilder; +import jdk.jpackage.internal.util.RootedPath; final class ApplicationBuilder { @@ -65,8 +67,8 @@ final class ApplicationBuilder { Optional.ofNullable(version).orElseGet(DEFAULTS::version), Optional.ofNullable(vendor).orElseGet(DEFAULTS::vendor), Optional.ofNullable(copyright).orElseGet(DEFAULTS::copyright), - Optional.ofNullable(srcDir), - Optional.ofNullable(contentDirs).orElseGet(List::of), + Optional.ofNullable(appDirSources).orElseGet(List::of), + Optional.ofNullable(contentDirSources).orElseGet(List::of), appImageLayout, Optional.ofNullable(runtimeBuilder), launchersAsList, @@ -126,13 +128,13 @@ final class ApplicationBuilder { return this; } - ApplicationBuilder srcDir(Path v) { - srcDir = v; + ApplicationBuilder appDirSources(Collection v) { + appDirSources = v; return this; } - ApplicationBuilder contentDirs(List v) { - contentDirs = v; + ApplicationBuilder contentDirSources(Collection v) { + contentDirSources = v; return this; } @@ -246,8 +248,8 @@ final class ApplicationBuilder { app.version(), app.vendor(), app.copyright(), - app.srcDir(), - app.contentDirs(), + app.appDirSources(), + app.contentDirSources(), Objects.requireNonNull(appImageLayout), app.runtimeBuilder(), app.launchers(), @@ -294,9 +296,9 @@ final class ApplicationBuilder { private String version; private String vendor; private String copyright; - private Path srcDir; + private Collection appDirSources; private ExternalApplication externalApp; - private List contentDirs; + private Collection contentDirSources; private AppImageLayout appImageLayout; private RuntimeBuilder runtimeBuilder; private ApplicationLaunchers launchers; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java index 3d2ffbfdc7c..5edc4d69c81 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,19 +25,14 @@ package jdk.jpackage.internal; -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; - -import java.io.IOException; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Stream; import jdk.jpackage.internal.PackagingPipeline.ApplicationImageTaskAction; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; @@ -45,7 +40,7 @@ import jdk.jpackage.internal.model.CustomLauncherIcon; import jdk.jpackage.internal.model.DefaultLauncherIcon; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.ResourceDirLauncherIcon; -import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.RootedPath; final class ApplicationImageUtils { @@ -86,21 +81,14 @@ final class ApplicationImageUtils { }; } - static ApplicationImageTaskAction createCopyContentAction(Supplier> excludeCopyDirs) { + static ApplicationImageTaskAction createCopyContentAction() { return env -> { - var excludeCandidates = Stream.concat( - excludeCopyDirs.get().stream(), - Stream.of(env.env().buildRoot(), env.env().appImageDir()) - ).map(Path::toAbsolutePath).toList(); - - env.app().srcDir().ifPresent(toConsumer(srcDir -> { - copyRecursive(srcDir, env.resolvedLayout().appDirectory(), excludeCandidates); - })); - - for (var srcDir : env.app().contentDirs()) { - copyRecursive(srcDir, - env.resolvedLayout().contentDirectory().resolve(srcDir.getFileName()), - excludeCandidates); + for (var e : List.of( + Map.entry(env.app().appDirSources(), env.resolvedLayout().appDirectory()), + Map.entry(env.app().contentDirSources(), env.resolvedLayout().contentDirectory()) + )) { + RootedPath.copy(e.getKey().stream(), e.getValue(), + StandardCopyOption.REPLACE_EXISTING, LinkOption.NOFOLLOW_LINKS); } }; } @@ -126,21 +114,4 @@ final class ApplicationImageUtils { } }; } - - private static void copyRecursive(Path srcDir, Path dstDir, List excludeDirs) throws IOException { - srcDir = srcDir.toAbsolutePath(); - - List excludes = new ArrayList<>(); - - for (var path : excludeDirs) { - if (Files.isDirectory(path)) { - if (path.startsWith(srcDir) && !Files.isSameFile(path, srcDir)) { - excludes.add(path); - } - } - } - - FileUtils.copyRecursive(srcDir, dstDir.toAbsolutePath(), excludes, - LinkOption.NOFOLLOW_LINKS, StandardCopyOption.REPLACE_EXISTING); - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java index 3a99dfb04da..331bde29d27 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java @@ -146,8 +146,7 @@ class DefaultBundlingEnvironment implements CliBundlingEnvironment { throw new JPackageException(I18N.format("error.root-exists", outputDir)); } - pipelineBuilder.excludeDirFromCopying(outputDir.getParent()) - .create().execute(BuildEnv.withAppImageDir(env, outputDir), app); + pipelineBuilder.create().execute(BuildEnv.withAppImageDir(env, outputDir), app); Log.verbose(I18N.getString("message.app-image-created")); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java index 6b74cab4e65..cccd05792d6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,6 +46,7 @@ import static jdk.jpackage.internal.cli.StandardOption.RESOURCE_DIR; import static jdk.jpackage.internal.cli.StandardOption.VENDOR; import java.nio.file.Path; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; @@ -60,6 +61,7 @@ import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.LauncherModularStartupInfo; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.RuntimeLayout; +import jdk.jpackage.internal.util.RootedPath; final class FromOptions { @@ -168,8 +170,15 @@ final class FromOptions { APP_VERSION.ifPresentIn(options, appBuilder::version); VENDOR.ifPresentIn(options, appBuilder::vendor); COPYRIGHT.ifPresentIn(options, appBuilder::copyright); - INPUT.ifPresentIn(options, appBuilder::srcDir); - APP_CONTENT.ifPresentIn(options, appBuilder::contentDirs); + INPUT.ifPresentIn(options, appBuilder::appDirSources); + APP_CONTENT.findIn(options).map((List> v) -> { + // Reverse the order of content sources. + // If there are multiple source files for the same + // destination file, only the first will be used. + // Reversing the order of content sources makes it use the last file + // from the original list of source files for the given destination file. + return v.reversed().stream().flatMap(Collection::stream).toList(); + }).ifPresent(appBuilder::contentDirSources); if (isRuntimeInstaller) { appBuilder.appImageLayout(runtimeLayout); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java index 9e81d144a1e..1ba384dba2d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java @@ -56,6 +56,7 @@ import jdk.jpackage.internal.model.DefaultLauncherIcon; import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.LauncherIcon; +import jdk.jpackage.internal.util.RootedPath; final class LauncherFromOptions { @@ -92,7 +93,9 @@ final class LauncherFromOptions { if (PREDEFINED_APP_IMAGE.findIn(options).isEmpty()) { final var startupInfoBuilder = new LauncherStartupInfoBuilder(); - INPUT.ifPresentIn(options, startupInfoBuilder::inputDir); + INPUT.findIn(options).flatMap(v -> { + return v.stream().findAny().map(RootedPath::root); + }).ifPresent(startupInfoBuilder::inputDir); ARGUMENTS.ifPresentIn(options, startupInfoBuilder::defaultParameters); JAVA_OPTIONS.ifPresentIn(options, startupInfoBuilder::javaOptions); MAIN_JAR.ifPresentIn(options, startupInfoBuilder::mainJar); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java index f15768b2cbf..315e3bce0f1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java @@ -32,7 +32,6 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -428,12 +427,6 @@ final class PackagingPipeline { }); } - Builder excludeDirFromCopying(Path path) { - Objects.requireNonNull(path); - excludeCopyDirs.add(path); - return this; - } - Builder contextMapper(UnaryOperator v) { contextMapper = v; return this; @@ -456,7 +449,6 @@ final class PackagingPipeline { } private final FixedDAG.Builder taskGraphBuilder = FixedDAG.build(); - private final List excludeCopyDirs = new ArrayList<>(); private final Map taskConfig = new HashMap<>(); private UnaryOperator contextMapper; private FixedDAG taskGraphSnapshot; @@ -490,7 +482,7 @@ final class PackagingPipeline { builder.task(BuildApplicationTaskID.CONTENT) .addDependent(BuildApplicationTaskID.APP_IMAGE_FILE) - .applicationAction(ApplicationImageUtils.createCopyContentAction(() -> builder.excludeCopyDirs)).add(); + .applicationAction(ApplicationImageUtils.createCopyContentAction()).add(); return builder; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/JOptSimpleOptionsBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/JOptSimpleOptionsBuilder.java index 57b92471e4a..bff35874645 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/JOptSimpleOptionsBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/JOptSimpleOptionsBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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,6 +27,7 @@ package jdk.jpackage.internal.cli; import static java.util.stream.Collectors.toUnmodifiableMap; import static java.util.stream.Collectors.toUnmodifiableSet; +import static jdk.jpackage.internal.cli.OptionValueConverter.convertString; import java.lang.reflect.Array; import java.util.ArrayList; @@ -565,7 +566,7 @@ final class JOptSimpleOptionsBuilder { final var converter = optionSpec.converter().orElseThrow(); final Result conversionResult = optionValue.map(v -> { - return converter.convert(optionName(), StringToken.of(v)); + return convertString(converter, optionName(), StringToken.of(v)); }).orElseGet(() -> { return Result.ofValue(optionSpec.defaultOptionalValue().orElseThrow()); }); @@ -579,7 +580,7 @@ final class JOptSimpleOptionsBuilder { final String str = getOptionValue(List.of(tokens), optionSpec.mergePolicy()).getFirst(); final String[] token = arrConverter.tokenize(str); if (token.length == 1 && str.equals(token[0])) { - final var singleTokenConversionResult = converter.convert(optionName(), StringToken.of(str)); + final var singleTokenConversionResult = convertString(converter, optionName(), StringToken.of(str)); if (singleTokenConversionResult.hasValue()) { return singleTokenConversionResult; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionArrayValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionArrayValueConverter.java index 401d5e15d28..9b757c29d36 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionArrayValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionArrayValueConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -29,7 +29,7 @@ package jdk.jpackage.internal.cli; * * @param option value element type */ -interface OptionArrayValueConverter extends OptionValueConverter { +interface OptionArrayValueConverter extends OptionValueConverter { /** * Splits the given string into tokens and returns the result. diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java index c6aa46a6940..60674e6bdfe 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Stream; +import jdk.jpackage.internal.util.Result; /** @@ -56,7 +57,7 @@ import java.util.stream.Stream; */ record OptionSpec( List names, - Optional> converter, + Optional> converter, Set scope, MergePolicy mergePolicy, Optional defaultOptionalValue, @@ -134,7 +135,7 @@ record OptionSpec( }); } - OptionSpec copyWithConverter(OptionValueConverter converter) { + OptionSpec copyWithConverter(OptionValueConverter converter) { if (!defaultOptionalValue.isEmpty()) { throw new UnsupportedOperationException("Can not convert an option spec with optional value"); } @@ -169,12 +170,16 @@ record OptionSpec( return valueType(converter).orElseThrow(); } + Result convert(OptionName optionName, StringToken optionValue) { + return OptionValueConverter.convertString(converter().orElseThrow(), optionName, optionValue); + } + @SuppressWarnings("unchecked") Optional> arrayValueConverter() { return converter.filter(OptionArrayValueConverter.class::isInstance).map(v -> (OptionArrayValueConverter)v); } - private static Optional> valueType(Optional> valueConverter) { + private static Optional> valueType(Optional> valueConverter) { return valueConverter.map(OptionValueConverter::valueType); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java index 6cd1c05b57e..5eecbc9b464 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal.cli; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; + import java.io.File; import java.lang.reflect.Array; import java.util.Arrays; @@ -61,23 +63,49 @@ final class OptionSpecBuilder { this.valueType = Objects.requireNonNull(valueType); } - OptionSpecBuilder(OptionSpecBuilder other) { + private OptionSpecBuilder(OptionSpecBuilder other) { valueType = other.valueType; - name = other.name; - nameAliases.addAll(other.nameAliases); - description = other.description; - mergePolicy = other.mergePolicy; - scope = Set.copyOf(other.scope); + initFrom(other); defaultValue = other.defaultValue; defaultOptionalValue = other.defaultOptionalValue; - valuePattern = other.valuePattern; converterBuilder = other.converterBuilder.copy(); validatorBuilder = other.validatorBuilder.copy(); validator = other.validator; if (other.arrayDefaultValue != null) { arrayDefaultValue = Arrays.copyOf(other.arrayDefaultValue, other.arrayDefaultValue.length); + } else { + arrayDefaultValue = null; } + } + + private OptionSpecBuilder(OptionSpecBuilder other, ValueConverter converter) { + Function converterFunction = toFunction(converter::convert); + + this.valueType = converter.valueType(); + initFrom(other); + converter(other, converter); + + other.defaultValue().map(converterFunction).ifPresent(this::defaultValue); + other.defaultOptionalValue().map(converterFunction).ifPresent(this::defaultOptionalValue); + + if (other.arrayDefaultValue != null) { + arrayDefaultValue = Stream.of(other.arrayDefaultValue).map(converterFunction).toArray(length -> { + @SuppressWarnings("unchecked") + var arr = (T[])Array.newInstance(valueType, length); + return arr; + }); + } + } + + private void initFrom(OptionSpecBuilder other) { + name = other.name; + nameAliases.clear(); + nameAliases.addAll(other.nameAliases); + description = other.description; + mergePolicy = other.mergePolicy; + scope = Set.copyOf(other.scope); + valuePattern = other.valuePattern; arrayValuePatternSeparator = other.arrayValuePatternSeparator; arrayTokenizer = other.arrayTokenizer; } @@ -86,6 +114,14 @@ final class OptionSpecBuilder { return new OptionSpecBuilder<>(this); } + OptionSpecBuilder map(ValueConverter converter) { + return new OptionSpecBuilder<>(this, converter); + } + + OptionSpecBuilder map(Function, OptionSpecBuilder> mapper) { + return mapper.apply(this); + } + Class valueType() { return valueType; } @@ -177,8 +213,8 @@ final class OptionSpecBuilder { return this; } - OptionSpecBuilder validatorExceptionFormatString(UnaryOperator mutator) { - validatorBuilder.formatString(mutator.apply(validatorBuilder.formatString().orElse(null))); + OptionSpecBuilder validatorExceptionFormatString(UnaryOperator mapper) { + validatorBuilder.formatString(mapper.apply(validatorBuilder.formatString().orElse(null))); validator = null; return this; } @@ -188,8 +224,8 @@ final class OptionSpecBuilder { return this; } - OptionSpecBuilder converterExceptionFormatString(UnaryOperator mutator) { - converterBuilder.formatString(mutator.apply(converterBuilder.formatString().orElse(null))); + OptionSpecBuilder converterExceptionFormatString(UnaryOperator mapper) { + converterBuilder.formatString(mapper.apply(converterBuilder.formatString().orElse(null))); return this; } @@ -199,8 +235,8 @@ final class OptionSpecBuilder { return this; } - OptionSpecBuilder validatorExceptionFactory(UnaryOperator> mutator) { - return validatorExceptionFactory(mutator.apply(validatorBuilder.exceptionFactory().orElse(null))); + OptionSpecBuilder validatorExceptionFactory(UnaryOperator> mapper) { + return validatorExceptionFactory(mapper.apply(validatorBuilder.exceptionFactory().orElse(null))); } OptionSpecBuilder converterExceptionFactory(OptionValueExceptionFactory v) { @@ -208,32 +244,42 @@ final class OptionSpecBuilder { return this; } - OptionSpecBuilder converterExceptionFactory(UnaryOperator> mutator) { - return converterExceptionFactory(mutator.apply(converterBuilder.exceptionFactory().orElse(null))); + OptionSpecBuilder converterExceptionFactory(UnaryOperator> mapper) { + return converterExceptionFactory(mapper.apply(converterBuilder.exceptionFactory().orElse(null))); } OptionSpecBuilder exceptionFormatString(String v) { return validatorExceptionFormatString(v).converterExceptionFormatString(v); } - OptionSpecBuilder exceptionFormatString(UnaryOperator mutator) { - return validatorExceptionFormatString(mutator).converterExceptionFormatString(mutator); + OptionSpecBuilder exceptionFormatString(UnaryOperator mapper) { + return validatorExceptionFormatString(mapper).converterExceptionFormatString(mapper); } OptionSpecBuilder exceptionFactory(OptionValueExceptionFactory v) { return validatorExceptionFactory(v).converterExceptionFactory(v); } - OptionSpecBuilder exceptionFactory(UnaryOperator> mutator) { - return validatorExceptionFactory(mutator).converterExceptionFactory(mutator); + OptionSpecBuilder exceptionFactory(UnaryOperator> mapper) { + return validatorExceptionFactory(mapper).converterExceptionFactory(mapper); } - OptionSpecBuilder converter(ValueConverter v) { + OptionSpecBuilder converter(ValueConverter v) { converterBuilder.converter(v); return this; } - OptionSpecBuilder converter(Function v) { + OptionSpecBuilder converter(OptionSpecBuilder other, ValueConverter v) { + converterBuilder = other.finalizeConverterBuilder().map(v); + return this; + } + + OptionSpecBuilder interimConverter(OptionSpecBuilder other) { + converterBuilder = converterBuilder.map(other.finalizeConverterBuilder()); + return this; + } + + OptionSpecBuilder converter(ValueConverterFunction v) { return converter(ValueConverter.create(v, valueType)); } @@ -251,8 +297,8 @@ final class OptionSpecBuilder { } @SuppressWarnings("overloads") - OptionSpecBuilder validator(UnaryOperator> mutator) { - validatorBuilder = mutator.apply(validatorBuilder); + OptionSpecBuilder validator(UnaryOperator> mapper) { + validatorBuilder = mapper.apply(validatorBuilder); validator = null; return this; } @@ -303,8 +349,8 @@ final class OptionSpecBuilder { return this; } - OptionSpecBuilder scope(UnaryOperator> mutator) { - return scope(mutator.apply(scope().orElseGet(Set::of))); + OptionSpecBuilder scope(UnaryOperator> mapper) { + return scope(mapper.apply(scope().orElseGet(Set::of))); } OptionSpecBuilder inScope(OptionScope... v) { @@ -424,10 +470,12 @@ final class OptionSpecBuilder { } private Optional defaultValuePattern() { - return converterBuilder.converter().map(_ -> { + if (converterBuilder.hasConverter()) { final var tokens = name.split("-"); - return tokens[tokens.length - 1]; - }); + return Optional.of(tokens[tokens.length - 1]); + } else { + return Optional.empty(); + } } private List names() { @@ -437,17 +485,21 @@ final class OptionSpecBuilder { ).flatMap(Collection::stream).map(OptionName::new).distinct().toList(); } - private Optional> createConverter() { - if (converterBuilder.converter().isPresent()) { - final var newBuilder = converterBuilder.copy(); - createValidator().ifPresent(newBuilder::validator); - return Optional.of(newBuilder.create()); + private Optional> createConverter() { + if (converterBuilder.hasConverter()) { + return Optional.of(finalizeConverterBuilder().create()); } else { return Optional.empty(); } } - private OptionValueConverter createArrayConverter() { + private OptionValueConverter.Builder finalizeConverterBuilder() { + final var newBuilder = converterBuilder.copy(); + createValidator().ifPresent(newBuilder::validator); + return newBuilder; + } + + private OptionValueConverter createArrayConverter() { final var newBuilder = converterBuilder.copy(); newBuilder.tokenizer(Optional.ofNullable(arrayTokenizer).orElse(str -> { return new String[] { str }; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecMapperOptionScope.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecMapperOptionScope.java index 7b517f768bf..42ed704ec6e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecMapperOptionScope.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecMapperOptionScope.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,17 @@ package jdk.jpackage.internal.cli; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; +import java.util.Optional; +import java.util.SequencedMap; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Stream; +import jdk.jpackage.internal.util.IdentityWrapper; import jdk.jpackage.internal.util.SetBuilder; /** @@ -42,9 +48,9 @@ import jdk.jpackage.internal.util.SetBuilder; * varies depending on the current OS. * * @param the type of option value - * @param the type of context + * @param the type of context */ -interface OptionSpecMapperOptionScope extends OptionScope { +sealed interface OptionSpecMapperOptionScope extends OptionScope { OptionSpec createOptionSpec(U context, boolean createArray); @@ -52,7 +58,7 @@ interface OptionSpecMapperOptionScope extends OptionScope { @SuppressWarnings("unchecked") static OptionSpec mapOptionSpec(OptionSpec optionSpec, U context) { - return optionSpec.scope().stream() + var mappedOptionSpec = optionSpec.scope().stream() .filter(OptionSpecMapperOptionScope.class::isInstance) .map(OptionSpecMapperOptionScope.class::cast) .filter(scope -> { @@ -62,6 +68,25 @@ interface OptionSpecMapperOptionScope extends OptionScope { return ((OptionSpecMapperOptionScope)scope).createOptionSpec( context, optionSpec.arrayValueConverter().isPresent()); }).orElse(optionSpec); + + Optional valueType = optionSpec.converter().map(OptionValueConverter::valueType); + Optional mappedValueType = mappedOptionSpec.converter().map(OptionValueConverter::valueType); + + while (!mappedValueType.equals(valueType)) { + // Source and mapped option specs have different option value types. + if (Stream.of(valueType, mappedValueType).anyMatch(Optional::isEmpty) && + Stream.of(valueType, mappedValueType) + .filter(Optional::isPresent).map(Optional::get) + .anyMatch(Predicate.isEqual(Boolean.class))) { + // One option spec doesn't have a converter and another has a converter of type `Boolean`. + // They are compatible, let it pass. + break; + } + + throw new IllegalStateException(String.format("Bad option spec mapping from %s to %s", valueType, mappedValueType)); + } + + return mappedOptionSpec; } static Consumer> createOptionSpecBuilderMutator( @@ -94,23 +119,23 @@ interface OptionSpecMapperOptionScope extends OptionScope { var contextOptionScope = scope.stream() .filter(AccumulatingContextOptionScope.class::isInstance) - .map(AccumulatingContextOptionScope.class::cast) + .map(v -> { + @SuppressWarnings("unchecked") + var tv = (AccumulatingContextOptionScope)v; + return tv; + }) .filter(s -> { return s.contextType().equals(contextType); }) .findFirst(); + contextOptionScope.ifPresent(v -> { - @SuppressWarnings("unchecked") - var mutators = (AccumulatingContextOptionScope)v; - mutators.addMutator(optionSpecBuilderMutator); - if (optionSpecBuilder != mutators.optionSpecBuilder) { - throw new IllegalArgumentException(); - } + v.addMutator(optionSpecBuilder, optionSpecBuilderMutator); }); if (contextOptionScope.isEmpty()) { - var mutators = new AccumulatingContextOptionScope(optionSpecBuilder, contextType); - mutators.addMutator(optionSpecBuilderMutator); + var mutators = new AccumulatingContextOptionScope(contextType); + mutators.addMutator(optionSpecBuilder, optionSpecBuilderMutator); scope = SetBuilder.build().add(scope).add(mutators).create(); } @@ -119,23 +144,24 @@ interface OptionSpecMapperOptionScope extends OptionScope { private static final class AccumulatingContextOptionScope implements OptionSpecMapperOptionScope { - AccumulatingContextOptionScope(OptionSpecBuilder optionSpecBuilder, Class contextType) { - this.optionSpecBuilder = Objects.requireNonNull(optionSpecBuilder); + AccumulatingContextOptionScope(Class contextType) { this.contextType = Objects.requireNonNull(contextType); } @SuppressWarnings("unchecked") @Override public OptionSpec createOptionSpec(U context, boolean createArray) { - var copy = optionSpecBuilder.copy(); - for (var mutator : optionSpecBuilderMutators) { - mutator.accept(copy, context); + var it = builders.values().iterator(); + + var builder = it.next().initBuilder(context, Optional.empty()); + while (it.hasNext()) { + builder = it.next().initBuilder(context, Optional.of(builder)); } if (createArray) { - return (OptionSpec)copy.createArrayOptionSpec(); + return (OptionSpec)builder.createArrayOptionSpec(); } else { - return copy.createOptionSpec(); + return (OptionSpec)builder.createOptionSpec(); } } @@ -144,14 +170,43 @@ interface OptionSpecMapperOptionScope extends OptionScope { return contextType; } - void addMutator(BiConsumer, U> mutator) { - optionSpecBuilderMutators.add(mutator); + void addMutator(OptionSpecBuilder builder, BiConsumer, U> mutator) { + @SuppressWarnings("unchecked") + var builderWithMutators = ((OptionSpecBuilderWithMutators)builders.computeIfAbsent(new IdentityWrapper<>(builder), _ -> { + return new OptionSpecBuilderWithMutators(builder); + })); + + builderWithMutators.addMutator(mutator); } - private final OptionSpecBuilder optionSpecBuilder; private final Class contextType; - private final List, U>> optionSpecBuilderMutators = new ArrayList<>(); + private final SequencedMap>, OptionSpecBuilderWithMutators> builders = new LinkedHashMap<>(); } + private static final class OptionSpecBuilderWithMutators { + + OptionSpecBuilderWithMutators(OptionSpecBuilder builder) { + this.builder = Objects.requireNonNull(builder); + } + + OptionSpecBuilder initBuilder(U context, Optional> other) { + Objects.requireNonNull(context); + Objects.requireNonNull(other); + + var copy = builder.copy(); + other.ifPresent(copy::interimConverter); + for (var mutator : mutators) { + mutator.accept(copy, context); + } + return copy; + } + + void addMutator(BiConsumer, U> mutator) { + mutators.add(Objects.requireNonNull(mutator)); + } + + private final OptionSpecBuilder builder; + private final List, U>> mutators = new ArrayList<>(); + } } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionValueConverter.java index 8544853d584..7e249ca1508 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionValueConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,28 +35,35 @@ import jdk.jpackage.internal.cli.Validator.ParsedValue; import jdk.jpackage.internal.util.Result; /** - * Defines creating an option value of type {@link T} from a string. + * Defines creating an option value of type {@link U} from value of type {@link T}. * - * @param option value type + * @param input option value type + * @param output option value type */ -interface OptionValueConverter { +interface OptionValueConverter { /** - * Converts the given string value corresponding to the given option name into a - * Java type. + * Converts the given value of type {@link T} corresponding to the given option name + * and option string value to an object of type {@link U}. * * @param optionName the option name - * @param optionValue the string value of the option to convert + * @param optionValue the string value of the option + * @param value the value of the option to convert * @return the conversion result + * @throws ConverterException if internal converter error occurs */ - Result convert(OptionName optionName, StringToken optionValue); + Result convert(OptionName optionName, StringToken optionValue, T value) throws ConverterException; /** * Gives the class of the type of values this converter converts to. * * @return the target class for conversion */ - Class valueType(); + Class valueType(); + + static Result convertString(OptionValueConverter converter, OptionName optionName, StringToken optionValue) { + return converter.convert(optionName, optionValue, optionValue.value()); + } /** * Thrown to indicate an error in the normal execution of the converter. @@ -74,54 +81,78 @@ interface OptionValueConverter { return new Builder<>(); } + static final class Builder { private Builder() { + this(new OneStepBackend<>(new StepBuilder<>(true))); + } + + private Builder(Backend backend) { + this.backend = Objects.requireNonNull(backend); } private Builder(Builder other) { - converter = other.converter; - validator = other.validator; + backend = other.backend.copy(); tokenizer = other.tokenizer; - formatString = other.formatString; - exceptionFactory = other.exceptionFactory; } Builder copy() { return new Builder<>(this); } - OptionValueConverter create() { - return new DefaultOptionValueConverter<>( - converter, - formatString().orElseGet(() -> { - if (exceptionFactory == null) { - return ""; - } else { - return null; - } - }), - exceptionFactory().orElseGet(() -> { - if (formatString == null) { - return OptionValueExceptionFactory.unreachable(); - } else { - return null; - } - }), - validator()); + Builder map(ValueConverter converter) { + Objects.requireNonNull(converter); + return new Builder<>(new TwoStepBackend<>( + backend, + new StepBuilder(false).converter(converter))).tokenizer(tokenizer); + } + + Builder map(Builder other) { + Objects.requireNonNull(other); + switch (backend) { + case OneStepBackend _ -> { + throw new UnsupportedOperationException(); + } + case TwoStepBackend b -> { + var fromInterimValueType = other.backend.valueType().orElseThrow(); + var toInterimValueType = b.interimValueType(); + if (fromInterimValueType.equals(toInterimValueType)) { + @SuppressWarnings("unchecked") + var twoStepBackend = (TwoStepBackend)b; + return new Builder<>(new TwoStepBackend<>( + other.backend, + twoStepBackend.otherConvBuilder())).tokenizer(tokenizer); + } else { + throw new IllegalArgumentException(String.format( + "Expected (%s); actual (%s)", toInterimValueType, fromInterimValueType)); + } + } + } + } + + OptionValueConverter create() { + return backend.create(); } OptionArrayValueConverter createArray() { return new DefaultOptionArrayValueConverter<>(create(), tokenizer); } - Builder converter(ValueConverter v) { - converter = v; + Builder converter(ValueConverter v) { + switch (backend) { + case OneStepBackend b -> { + b.stringConvBuilder().converter(v); + } + case TwoStepBackend _ -> { + throw new UnsupportedOperationException(); + } + } return this; } Builder validator(Validator v) { - validator = v; + backend.validator(v); return this; } @@ -131,12 +162,12 @@ interface OptionValueConverter { } Builder formatString(String v) { - formatString = v; + backend.formatString(v); return this; } Builder exceptionFactory(OptionValueExceptionFactory v) { - exceptionFactory = v; + backend.exceptionFactory(v); return this; } @@ -145,12 +176,30 @@ interface OptionValueConverter { return this; } - Optional> converter() { - return Optional.ofNullable(converter); + boolean hasConverter() { + switch (backend) { + case OneStepBackend b -> { + return b.stringConvBuilder().converter().isPresent(); + } + case TwoStepBackend _ -> { + return true; + } + } } Optional> validator() { - return Optional.ofNullable(validator); + return backend.validator(); + } + + Optional> converter() { + switch (backend) { + case OneStepBackend b -> { + return b.stringConvBuilder().converter(); + } + case TwoStepBackend _ -> { + throw new UnsupportedOperationException(); + } + } } Optional> tokenizer() { @@ -158,68 +207,15 @@ interface OptionValueConverter { } Optional formatString() { - return Optional.ofNullable(formatString); + return backend.formatString(); } Optional> exceptionFactory() { - return Optional.ofNullable(exceptionFactory); + return backend.exceptionFactory(); } - private record DefaultOptionValueConverter(ValueConverter converter, String formatString, - OptionValueExceptionFactory exceptionFactory, - Optional> validator) implements OptionValueConverter { - - DefaultOptionValueConverter { - Objects.requireNonNull(converter); - Objects.requireNonNull(formatString); - Objects.requireNonNull(exceptionFactory); - Objects.requireNonNull(validator); - } - - @Override - public Result convert(OptionName optionName, StringToken optionValue) { - Objects.requireNonNull(optionName); - - final T convertedValue; - try { - convertedValue = converter.convert(optionValue.value()); - } catch (Exception ex) { - return handleException(optionName, optionValue, ex); - } - - final List validationExceptions = validator.map(val -> { - try { - return val.validate(optionName, ParsedValue.create(convertedValue, optionValue)); - } catch (Validator.ValidatorException ex) { - // All unexpected exceptions that the converter yields should be tunneled via ConverterException. - throw new ConverterException(ex.getCause()); - } - }).orElseGet(List::of); - - if (validationExceptions.isEmpty()) { - return Result.ofValue(convertedValue); - } else { - return Result.ofErrors(validationExceptions); - } - } - - @Override - public Class valueType() { - return converter.valueType(); - } - - private Result handleException(OptionName optionName, StringToken optionValue, Exception ex) { - if (ex instanceof IllegalArgumentException) { - return Result.ofError(exceptionFactory.create(optionName, optionValue, formatString, Optional.of(ex))); - } else { - throw new ConverterException(ex); - } - } - } - - - private record DefaultOptionArrayValueConverter(OptionValueConverter elementConverter, + private record DefaultOptionArrayValueConverter(OptionValueConverter elementConverter, Function tokenizer) implements OptionArrayValueConverter { DefaultOptionArrayValueConverter { @@ -229,14 +225,18 @@ interface OptionValueConverter { @SuppressWarnings("unchecked") @Override - public Result convert(OptionName optionName, StringToken optionValue) { + public Result convert(OptionName optionName, StringToken optionValue, String value) { + + if (!value.equals(optionValue.value())) { + throw new IllegalArgumentException(); + } final List exceptions = new ArrayList<>(); final List convertedValues = new ArrayList<>(); final var tokens = tokenize(optionValue.value()); for (var token : tokens) { - final var result = elementConverter.convert(optionName, StringToken.of(optionValue.value(), token)); + final var result = elementConverter.convert(optionName, StringToken.of(optionValue.value(), token), token); exceptions.addAll(result.errors()); if (exceptions.isEmpty()) { result.value().ifPresent(convertedValues::add); @@ -264,10 +264,311 @@ interface OptionValueConverter { } } - private ValueConverter converter; - private Validator validator; + + private record TwoStepOptionValueConverter(OptionValueConverter stringConverter, + OptionValueConverter converter) implements OptionValueConverter { + + TwoStepOptionValueConverter { + Objects.requireNonNull(stringConverter); + Objects.requireNonNull(converter); + } + + @Override + public Result convert(OptionName optionName, StringToken optionValue, String value) { + final var interimResult = stringConverter.convert(optionName, optionValue, value); + return interimResult.flatMap(interimValue -> { + return converter.convert(optionName, optionValue, interimValue); + }); + } + + @Override + public Class valueType() { + return converter.valueType(); + } + } + + + private sealed interface Backend { + + OptionValueConverter create(); + + Backend copy(); + + void validator(Validator v); + + void formatString(String v); + + void exceptionFactory(OptionValueExceptionFactory v); + + Optional> valueType(); + + Optional> validator(); + + Optional formatString(); + + Optional> exceptionFactory(); + } + + + private record OneStepBackend(StepBuilder stringConvBuilder) implements Backend { + + OneStepBackend { + Objects.requireNonNull(stringConvBuilder); + } + + @Override + public Backend copy() { + return new OneStepBackend<>(stringConvBuilder.copy()); + } + + @Override + public OptionValueConverter create() { + return stringConvBuilder.create(); + } + + @Override + public void validator(Validator v) { + stringConvBuilder.validator(v); + } + + @Override + public void formatString(String v) { + stringConvBuilder.formatString(v); + } + + @Override + public void exceptionFactory(OptionValueExceptionFactory v) { + stringConvBuilder.exceptionFactory(v); + } + + @Override + public Optional> valueType() { + return stringConvBuilder.converter().map(ValueConverter::valueType); + } + + @Override + public Optional> validator() { + return stringConvBuilder.validator(); + } + + @Override + public Optional formatString() { + return stringConvBuilder.formatString(); + } + + @Override + public Optional> exceptionFactory() { + return stringConvBuilder.exceptionFactory(); + } + } + + + private record TwoStepBackend(Backend stringConvBuilder, StepBuilder otherConvBuilder) implements Backend { + + TwoStepBackend { + Objects.requireNonNull(stringConvBuilder); + Objects.requireNonNull(otherConvBuilder); + } + + Class interimValueType() { + return stringConvBuilder.valueType().orElseThrow(); + } + + @Override + public Backend copy() { + return new TwoStepBackend<>(stringConvBuilder.copy(), otherConvBuilder.copy()); + } + + @Override + public OptionValueConverter create() { + return new TwoStepOptionValueConverter<>(stringConvBuilder.create(), otherConvBuilder.create()); + } + + @Override + public void validator(Validator v) { + otherConvBuilder.validator(v); + } + + @Override + public void formatString(String v) { + otherConvBuilder.formatString(v); + } + + @Override + public void exceptionFactory(OptionValueExceptionFactory v) { + otherConvBuilder.exceptionFactory(v); + } + + @Override + public Optional> valueType() { + return otherConvBuilder.converter().map(ValueConverter::valueType); + } + + @Override + public Optional> validator() { + return otherConvBuilder.validator(); + } + + @Override + public Optional formatString() { + return otherConvBuilder.formatString(); + } + + @Override + public Optional> exceptionFactory() { + return otherConvBuilder.exceptionFactory(); + } + } + + + private static final class StepBuilder { + + private StepBuilder(boolean starter) { + this.starter = starter; + } + + private StepBuilder(StepBuilder other) { + starter = other.starter; + converter = other.converter; + validator = other.validator; + formatString = other.formatString; + exceptionFactory = other.exceptionFactory; + } + + StepBuilder copy() { + return new StepBuilder<>(this); + } + + OptionValueConverter create() { + return new DefaultOptionValueConverter<>( + converter, + formatString().orElseGet(() -> { + if (exceptionFactory == null) { + return ""; + } else { + return null; + } + }), + exceptionFactory().orElseGet(() -> { + if (formatString == null) { + return OptionValueExceptionFactory.unreachable(); + } else { + return null; + } + }), + validator(), + starter); + } + + StepBuilder converter(ValueConverter v) { + converter = v; + return this; + } + + StepBuilder validator(Validator v) { + validator = v; + return this; + } + + StepBuilder formatString(String v) { + formatString = v; + return this; + } + + StepBuilder exceptionFactory(OptionValueExceptionFactory v) { + exceptionFactory = v; + return this; + } + + Optional> converter() { + return Optional.ofNullable(converter); + } + + Optional> validator() { + return Optional.ofNullable(validator); + } + + Optional formatString() { + return Optional.ofNullable(formatString); + } + + Optional> exceptionFactory() { + return Optional.ofNullable(exceptionFactory); + } + + + private record DefaultOptionValueConverter( + ValueConverter converter, + String formatString, + OptionValueExceptionFactory exceptionFactory, + Optional> validator, + boolean starter) implements OptionValueConverter { + + DefaultOptionValueConverter { + Objects.requireNonNull(converter); + Objects.requireNonNull(formatString); + Objects.requireNonNull(exceptionFactory); + Objects.requireNonNull(validator); + } + + @Override + public Result convert(OptionName optionName, StringToken optionValue, T value) { + Objects.requireNonNull(optionName); + Objects.requireNonNull(optionValue); + Objects.requireNonNull(value); + + if (starter && !value.equals(optionValue.value())) { + throw new IllegalArgumentException(); + } + + final U convertedValue; + try { + convertedValue = converter.convert(value); + } catch (Exception ex) { + return handleException(optionName, optionValue, ex); + } + + final List validationExceptions = validator.map(val -> { + try { + return val.validate(optionName, ParsedValue.create(convertedValue, optionValue)); + } catch (Validator.ValidatorException ex) { + // All unexpected exceptions that the converter yields should be tunneled via ConverterException. + throw new ConverterException(ex.getCause()); + } + }).orElseGet(List::of); + + if (validationExceptions.isEmpty()) { + return Result.ofValue(convertedValue); + } else { + return Result.ofErrors(validationExceptions); + } + } + + @Override + public Class valueType() { + return converter.valueType(); + } + + private Result handleException(OptionName optionName, StringToken optionValue, Exception ex) { + if (ex instanceof IllegalArgumentException) { + return Result.ofError(exceptionFactory.create(optionName, optionValue, formatString, Optional.of(ex))); + } else { + throw new ConverterException(ex); + } + } + } + + + private final boolean starter; + private ValueConverter converter; + private Validator validator; + private String formatString; + private OptionValueExceptionFactory exceptionFactory; + } + + + private final Backend backend; private Function tokenizer; - private String formatString; - private OptionValueExceptionFactory exceptionFactory; } } + diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsAnalyzer.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsAnalyzer.java index 363aa1b863e..6c32a3d1569 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsAnalyzer.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsAnalyzer.java @@ -272,7 +272,6 @@ final class OptionsAnalyzer { } else { var spec = new StandardOptionContext(os).mapOptionSpec(typeOption.spec()); return spec - .converter().orElseThrow() .convert(spec.name(), StringToken.of(((String[])obj)[0])) .orElseThrow(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsProcessor.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsProcessor.java index 54003b714a2..3c0eab77f8a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsProcessor.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -29,6 +29,7 @@ import static java.util.stream.Collectors.counting; import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.toMap; import static jdk.jpackage.internal.cli.Option.fromOptionSpecPredicate; +import static jdk.jpackage.internal.cli.OptionValueConverter.convertString; import static jdk.jpackage.internal.cli.StandardOption.ADDITIONAL_LAUNCHERS; import static jdk.jpackage.internal.cli.StandardOption.platformOption; @@ -380,8 +381,8 @@ final class OptionsProcessor { } @Override - public Result convert(OptionName optionName, StringToken optionValue) { - return converter.convert(optionName, optionValue).flatMap(arr -> { + public Result convert(OptionName optionName, StringToken optionValue, String value) { + return convertString(converter, optionName, optionValue).flatMap(arr -> { return Stream.of(arr).map(mapper).reduce(Result.>ofValue(new ArrayList<>()), (result, o) -> { if (Result.allHaveValues(result, o)) { return result.map(v -> { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardAppImageFileOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardAppImageFileOption.java index 42f90536753..2538bbf4fb4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardAppImageFileOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardAppImageFileOption.java @@ -230,7 +230,7 @@ public final class StandardAppImageFileOption { } return strValue.map(v -> { - return spec.converter().orElseThrow().convert(spec.name(), StringToken.of(v)).orElseThrow(); + return spec.convert(spec.name(), StringToken.of(v)).orElseThrow(); }).map(v -> { return Map.entry(option, v); }); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java index fadd9bacb1c..fedb55116a3 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java @@ -37,6 +37,7 @@ import static jdk.jpackage.internal.cli.StandardOptionValueExceptionFactory.ERRO import static jdk.jpackage.internal.cli.StandardOptionValueExceptionFactory.forMessageWithOptionValueAndName; import static jdk.jpackage.internal.cli.StandardValueConverter.addLauncherShortcutConv; import static jdk.jpackage.internal.cli.StandardValueConverter.booleanConv; +import static jdk.jpackage.internal.cli.StandardValueConverter.explodedPathConverter; import static jdk.jpackage.internal.cli.StandardValueConverter.identityConv; import static jdk.jpackage.internal.cli.StandardValueConverter.mainLauncherShortcutConv; import static jdk.jpackage.internal.cli.StandardValueConverter.pathConv; @@ -44,11 +45,13 @@ import static jdk.jpackage.internal.cli.StandardValueConverter.uuidConv; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; import java.util.function.UnaryOperator; import java.util.regex.Matcher; @@ -61,7 +64,7 @@ import jdk.jpackage.internal.model.BundlingOperationDescriptor; import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.LauncherShortcut; import jdk.jpackage.internal.model.LauncherShortcutStartupDirectory; -import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.util.RootedPath; import jdk.jpackage.internal.model.SelfContainedException; import jdk.jpackage.internal.util.SetBuilder; @@ -120,9 +123,12 @@ public final class StandardOption { }); })).create(); - public static final OptionValue INPUT = directoryOption("input").addAliases("i") + public static final OptionValue> INPUT = directoryOption("input").addAliases("i") .outOfScope(NOT_BUILDING_APP_IMAGE) - .create(); + .map(explodedPathOptionMapper(explodedPathConverter().create())) + .create(optionValueBuilder -> { + return optionValueBuilder.to(List::of).create(); + }); public static final OptionValue DEST = directoryOption("dest").addAliases("d") .valuePattern("destination path") @@ -193,16 +199,17 @@ public final class StandardOption { .inScope(LauncherProperty.VALUE) .createArray(toList()); - public static final OptionValue> APP_CONTENT = pathOption("app-content") + public static final OptionValue>> APP_CONTENT = existingPathOption("app-content") .tokenizer(",") .valuePattern("additional content") .outOfScope(NOT_BUILDING_APP_IMAGE) + .map(explodedPathOptionMapper(explodedPathConverter().withPathFileName().create())) .mutate(createOptionSpecBuilderMutator((b, context) -> { if (context.os() == OperatingSystem.MACOS) { b.description("help.option.app-content" + resourceKeySuffix(context.os())); } })) - .createArray(toList()); + .createArray(toExplodedPathList()); static final OptionValue FILE_ASSOCIATIONS_INTERNAL = fileOption("file-associations") .tokenizer(pathSeparator()) @@ -324,10 +331,11 @@ public final class StandardOption { // MacOS-specific // - public static final OptionValue> MAC_DMG_CONTENT = pathOption("mac-dmg-content") + public static final OptionValue>> MAC_DMG_CONTENT = existingPathOption("mac-dmg-content") .valuePattern("additional content path") .tokenizer(",") - .createArray(toList()); + .map(explodedPathOptionMapper(explodedPathConverter().withPathFileName().create())) + .createArray(toExplodedPathList()); public static final OptionValue MAC_SIGN = booleanOption("mac-sign").scope(MAC_SIGNING).addAliases("s").create(); @@ -513,12 +521,57 @@ public final class StandardOption { static Consumer> directoryOptionMutator() { return builder -> { builder.mutate(pathOptionMutator()) + .mutate(createOptionSpecBuilderMutator((b, context) -> { + context.asFileSource().ifPresent(propertyFile -> { + b.validatorExceptionFactory(forMessageWithOptionValueAndName(propertyFile)); + b.validatorExceptionFormatString("error.properties-parameter-not-directory"); + }); + })) .validator(StandardValidator.IS_DIRECTORY) .validatorExceptionFactory(ERROR_WITH_VALUE_AND_OPTION_NAME) .validatorExceptionFormatString("error.parameter-not-directory"); }; } + static Consumer> existingPathOptionMutator() { + + return builder -> { + builder.mutate(pathOptionMutator()) + .validator(createExistingPathValidator(Validator.build().exceptionFactory(ERROR_WITH_VALUE_AND_OPTION_NAME), true)) + .mutate(createOptionSpecBuilderMutator((b, context) -> { + context.asFileSource().ifPresent(propertyFile -> { + var validatorBuilder = Validator.build(); + validatorBuilder.exceptionFactory(forMessageWithOptionValueAndName(propertyFile)); + b.validator(createExistingPathValidator(validatorBuilder, false)); + }); + })); + }; + } + + private static Validator createExistingPathValidator(Validator.Builder builder, boolean cmdline) { + + if (cmdline) { + builder.formatString("error.parameter-not-directory"); + } else { + builder.formatString("error.properties-parameter-not-directory"); + } + + var isDirectoryValidator = builder.predicate(StandardValidator.IS_DIRECTORY).create(); + + if (cmdline) { + builder.formatString("error.parameter-not-file"); + } else { + builder.formatString("error.properties-parameter-not-file"); + } + + var isFileValidator = builder.predicate(StandardValidator.IS_FILE_OR_SYMLINK).create(); + + @SuppressWarnings("unchecked") + var validator = (Validator)isDirectoryValidator.or(isFileValidator); + + return validator; + } + static Consumer> booleanOptionMutator() { return builder -> { builder.mutate(createOptionSpecBuilderMutator((b, context) -> { @@ -546,6 +599,30 @@ public final class StandardOption { }; } + static Function, OptionSpecBuilder> explodedPathOptionMapper(ValueConverter conv) { + Objects.requireNonNull(conv); + return builder -> { + return builder.map(conv) + .converterExceptionFactory(ERROR_WITH_VALUE_AND_OPTION_NAME) + .converterExceptionFormatString("error.path-parameter-ioexception") + // Add empty mutator to OptionSpecMapperOptionScope to make + // mapped option spec have `RootedPath[]` type. + // Otherwise, it will have `Path` type. + .mutate(createOptionSpecBuilderMutator((b, context) -> { + })); + }; + } + + private static Function, OptionValue>>> toExplodedPathList() { + return builder -> { + return builder.to((RootedPath[][] v) -> { + return Stream.of(v).map(arr -> { + return (Collection)List.of(arr); + }).toList(); + }).create(); + }; + } + private static OptionSpecBuilder option(String name, Class valueType) { return OptionSpecBuilder.create(valueType) .name(Objects.requireNonNull(name)) @@ -574,6 +651,10 @@ public final class StandardOption { return option(name, Path.class).mutate(pathOptionMutator()); } + private static OptionSpecBuilder existingPathOption(String name) { + return option(name, Path.class).mutate(existingPathOptionMutator()); + } + private static OptionSpecBuilder fileOption(String name) { return option(name, Path.class) .valuePattern("file path") @@ -624,8 +705,7 @@ public final class StandardOption { } private static OptionValue createAddLauncherOption(String name) { - OptionValueConverter propertyFileConverter = fileOption(name) - .create().getSpec().converter().orElseThrow(); + var propertyFileSpec = fileOption(name).create().getSpec(); return option(name, AdditionalLauncher.class) .valuePattern("=") @@ -657,7 +737,7 @@ public final class StandardOption { final Path propertyFile; try { - propertyFile = propertyFileConverter.convert(OptionName.of(name), + propertyFile = propertyFileSpec.convert(OptionName.of(name), StringToken.of(value, components[1])).orElseThrow(); } catch (JPackageException ex) { throw new AddLauncherInvalidPropertyFileException(I18N.format( diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java index 3a310166fa8..b1e1189654d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,15 @@ package jdk.jpackage.internal.cli; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.util.UUID; +import java.util.function.Function; import jdk.jpackage.internal.model.LauncherShortcut; import jdk.jpackage.internal.model.ParseUtils; +import jdk.jpackage.internal.util.RootedPath; final class StandardValueConverter { @@ -37,33 +41,59 @@ final class StandardValueConverter { private StandardValueConverter() { } - static ValueConverter identityConv() { + static ValueConverter identityConv() { return IDENTITY_CONV; } - static ValueConverter pathConv() { + static ValueConverter pathConv() { return PATH_CONV; } - static ValueConverter uuidConv() { + static ValueConverter uuidConv() { return UUID_CONV; } - static ValueConverter booleanConv() { + static ValueConverter booleanConv() { return BOOLEAN_CONV; } - static ValueConverter mainLauncherShortcutConv() { + static ValueConverter mainLauncherShortcutConv() { return MAIN_LAUNCHER_SHORTCUT_CONV; } - static ValueConverter addLauncherShortcutConv() { + static ValueConverter addLauncherShortcutConv() { return ADD_LAUNCHER_SHORTCUT_CONV; } - private static final ValueConverter IDENTITY_CONV = ValueConverter.create(x -> x, String.class); + static ExplodedPathConverterBuilder explodedPathConverter() { + return new ExplodedPathConverterBuilder(); + } - private static final ValueConverter PATH_CONV = ValueConverter.create(str -> { + static final class ExplodedPathConverterBuilder { + private ExplodedPathConverterBuilder() { + } + + ValueConverter create() { + return ValueConverter.create(path -> { + return explodePath(path, withPathFileName); + }, RootedPath[].class); + } + + ExplodedPathConverterBuilder withPathFileName(boolean v) { + withPathFileName = v; + return this; + } + + ExplodedPathConverterBuilder withPathFileName() { + return withPathFileName(true); + } + + private boolean withPathFileName; + } + + private static final ValueConverter IDENTITY_CONV = ValueConverter.create(x -> x, String.class); + + private static final ValueConverter PATH_CONV = ValueConverter.create(str -> { try { return Path.of(str); } catch (InvalidPathException ex) { @@ -71,13 +101,33 @@ final class StandardValueConverter { } }, Path.class); - private static final ValueConverter UUID_CONV = ValueConverter.create(UUID::fromString, UUID.class); + private static final ValueConverter UUID_CONV = ValueConverter.create(UUID::fromString, UUID.class); - private static final ValueConverter BOOLEAN_CONV = ValueConverter.create(Boolean::valueOf, Boolean.class); + private static final ValueConverter BOOLEAN_CONV = ValueConverter.create(Boolean::valueOf, Boolean.class); - private static final ValueConverter MAIN_LAUNCHER_SHORTCUT_CONV = ValueConverter.create( + private static final ValueConverter MAIN_LAUNCHER_SHORTCUT_CONV = ValueConverter.create( ParseUtils::parseLauncherShortcutForMainLauncher, LauncherShortcut.class); - private static final ValueConverter ADD_LAUNCHER_SHORTCUT_CONV = ValueConverter.create( + private static final ValueConverter ADD_LAUNCHER_SHORTCUT_CONV = ValueConverter.create( ParseUtils::parseLauncherShortcutForAddLauncher, LauncherShortcut.class); + + private static RootedPath[] explodePath(Path path, boolean withPathFileName) throws Exception { + + Function mapper; + if (withPathFileName) { + mapper = RootedPath.toRootedPath(path.getParent()); + } else { + mapper = RootedPath.toRootedPath(path); + } + + RootedPath[] items; + try (var walk = Files.walk(path)) { + items = walk.map(mapper).toArray(RootedPath[]::new); + } catch (IOException ex) { + // IOException is not a converter error, it is a converting error, so map it into IAE. + throw new IllegalArgumentException(ex); + } + + return items; + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Validator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Validator.java index 91d9d03bd9f..0701071b00f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Validator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Validator.java @@ -34,7 +34,15 @@ import java.util.stream.Stream; @FunctionalInterface interface Validator { - List validate(OptionName optionName, ParsedValue optionValue); + /** + * Validates the given option value. + * + * @param optionName the name of an option to validate + * @param optionValue the value of an option to validate + * @return the list of validation errors + * @throws ValidatorException if internal validator error occurs + */ + List validate(OptionName optionName, ParsedValue optionValue) throws ValidatorException; default Validator and(Validator after) { Objects.requireNonNull(after); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java index ba52ca35f50..122b212d295 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,41 +25,30 @@ package jdk.jpackage.internal.cli; import java.util.Objects; -import java.util.function.Function; -interface ValueConverter { - - /** - * Converts the given string value into a Java type. - * - * @param value the string to convert - * @return the converted value - * @throws IllegalArgumentException if the given string value can not be - * converted to an object of type {@link T} - */ - T convert(String value) throws IllegalArgumentException; +interface ValueConverter extends ValueConverterFunction { /** * Gives the class of the type of values this converter converts to. * * @return the target class for conversion */ - Class valueType(); + Class valueType(); - static ValueConverter create(Function mapper, Class type) { - Objects.requireNonNull(mapper); + static ValueConverter create(ValueConverterFunction conv, Class type) { + Objects.requireNonNull(conv); Objects.requireNonNull(type); return new ValueConverter<>() { @Override - public T convert(String value) { + public U convert(T value) throws Exception { Objects.requireNonNull(value); - return Objects.requireNonNull(mapper.apply(value)); + return Objects.requireNonNull(conv.convert(value)); } @Override - public Class valueType() { + public Class valueType() { return type; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverterFunction.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverterFunction.java new file mode 100644 index 00000000000..28702afff75 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverterFunction.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.cli; + +@FunctionalInterface +interface ValueConverterFunction { + + /** + * Converts value of one type into another. + * + * @param value the value to convert + * @return the converted value + * @throws IllegalArgumentException if the given value can not be converted to + * an object of type {@link U} + * @throws Exception if internal converter error occurs + */ + U convert(T value) throws Exception, IllegalArgumentException; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index 5b20a0690d3..7860a04faac 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,13 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Stream; +import jdk.jpackage.internal.util.RootedPath; /** * A generic application for packaging. @@ -78,27 +80,25 @@ public non-sealed interface Application extends BundleSpec { String copyright(); /** - * Gets the source directory of this application if available or an empty - * {@link Optional} instance. + * Gets the source paths that should be copied into + * {@link ApplicationLayout#appDirectory()} directory of the image of this + * application. *

- * Source directory is a directory with the applications's classes and other + * Source paths are supposed to contain the applications's classes and other * resources. * - * @return the source directory of this application + * @return the source paths */ - Optional srcDir(); + Collection appDirSources(); /** - * Gets the input content directories of this application. - *

- * Contents of the content directories will be copied as-is into the dedicated - * location of the application image. + * Gets the source paths that should be copied into + * {@link ApplicationLayout#contentDirectory()} directory of the image of this + * application. * - * @see ApplicationLayout#contentDirectory - * - * @return the input content directories of this application + * @return the source paths */ - List contentDirs(); + Collection contentDirSources(); /** * Gets the unresolved app image layout of this application. @@ -244,8 +244,17 @@ public non-sealed interface Application extends BundleSpec { /** * Default implementation of {@link Application} interface. */ - record Stub(String name, String description, String version, String vendor, String copyright, Optional srcDir, - List contentDirs, AppImageLayout imageLayout, Optional runtimeBuilder, - List launchers, Map extraAppImageFileData) implements Application { + record Stub( + String name, + String description, + String version, + String vendor, + String copyright, + Collection appDirSources, + Collection contentDirSources, + AppImageLayout imageLayout, + Optional runtimeBuilder, + List launchers, + Map extraAppImageFileData) implements Application { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index e1f41e3ff48..6e5de3d9729 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -91,6 +91,7 @@ error.parameter-add-launcher-malformed=The value "{0}" provided for parameter {1 error.parameter-add-launcher-not-file=The value of path to a property file "{0}" provided for additional launcher "{1}" is not a valid file path error.properties-parameter-not-path=The value "{0}" provided for property "{1}" in "{2}" file is not a valid path error.properties-parameter-not-file=The value "{0}" provided for property "{1}" in "{2}" file is not a file +error.properties-parameter-not-directory=The value "{0}" provided for property "{1}" in "{2}" file is not a directory error.properties-parameter-not-launcher-shortcut-dir=The value "{0}" provided for property "{1}" in "{2}" file is not a valid shortcut startup directory error.no-extensions-for-file-association=No extensions were specified for File Association number {0} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java index 2f7f2682a71..b143a54cb5c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, 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 @@ -57,12 +57,6 @@ public final class FileUtils { public static void copyRecursive(Path src, Path dest, CopyOption... options) throws IOException { - copyRecursive(src, dest, List.of(), options); - } - - public static void copyRecursive(Path src, Path dest, - final List excludes, CopyOption... options) - throws IOException { List copyActions = new ArrayList<>(); @@ -71,24 +65,18 @@ public final class FileUtils { @Override public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) { - if (isPathMatch(dir, excludes)) { - return FileVisitResult.SKIP_SUBTREE; - } else { - copyActions.add(new CopyAction(null, dest.resolve(src.relativize(dir)))); - return FileVisitResult.CONTINUE; - } + copyActions.add(new CopyAction(null, dest.resolve(src.relativize(dir)))); + return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) { - if (!isPathMatch(file, excludes)) { - copyActions.add(new CopyAction(file, dest.resolve(src.relativize(file)))); - } + copyActions.add(new CopyAction(file, dest.resolve(src.relativize(file)))); return FileVisitResult.CONTINUE; } }); - } else if (!isPathMatch(src, excludes)) { + } else { Optional.ofNullable(dest.getParent()).ifPresent(dstDir -> { copyActions.add(new CopyAction(null, dstDir)); }); @@ -113,10 +101,6 @@ public final class FileUtils { } } - private static boolean isPathMatch(Path what, List paths) { - return paths.stream().anyMatch(what::endsWith); - } - private static record CopyAction(Path src, Path dest) { void apply(CopyOption... options) throws IOException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/RootedPath.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/RootedPath.java new file mode 100644 index 00000000000..21d3b6b17b0 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/RootedPath.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.CopyOption; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Stream; + +/** + * A relative path (branch) rooted at the root. + */ +public sealed interface RootedPath { + + Path root(); + Path branch(); + + default Path fullPath() { + return root().resolve(branch()); + } + + public static Function toRootedPath(Path root) { + return path -> { + if (!path.startsWith(root)) { + throw new IllegalArgumentException(String.format("Expected path [%s] to start with [%s] root", path, root)); + } + return new Details.DefaultRootedPath(root, root.relativize(path), Files.isDirectory(path)); + }; + } + + public static void copy(Stream rootedPaths, Path dest, CopyOption...options) throws IOException { + Objects.requireNonNull(rootedPaths); + Objects.requireNonNull(dest); + + var marks = new HashMap(); + + // Preset marks for the preexisting paths. + Files.walkFileTree(dest, new FileVisitor() { + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + marks.put(dir, new Details.PathMark(true, true)); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + marks.put(file, new Details.PathMark(false, true)); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { + return FileVisitResult.TERMINATE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + + }); + + var replacePreexisting = Set.of(options).contains(StandardCopyOption.REPLACE_EXISTING); + + Predicate canReplace = v -> { + return v.isPreexisting() && replacePreexisting; + }; + + try { + rootedPaths.sequential().map(Details.DefaultRootedPath.class::cast).forEach(rootedPath -> { + + final var dstPath = dest.resolve(rootedPath.branch()); + + var dstPathMark = marks.get(dstPath); + + if (!Optional.ofNullable(dstPathMark).map(canReplace::test).orElse(true)) { + // Destination path can not be replaced, bail out. + return; + } + + // Check the ancestors of the destination path. + for (var ancestor : Details.ancestorPaths(rootedPath.branch())) { + var mark = Optional.ofNullable(marks.get(dest.resolve(ancestor))); + + if (!mark.map(Details.PathMark::isDirectory).orElse(true)) { + // `ancestor` is a file, don't overwrite it. + return; + } + } + + dstPathMark = rootedPath.createPathMark(); + marks.put(dstPath, dstPathMark); + + try { + if (replacePreexisting && (rootedPath.isDirectory() != dstPathMark.isDirectory())) { + FileUtils.deleteRecursive(dstPath); + } + + if (rootedPath.isDirectory()) { + Files.createDirectories(dstPath); + } else { + Files.createDirectories(dstPath.getParent()); + Files.copy(rootedPath.fullPath(), dstPath, options); + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); + } catch (UncheckedIOException ex) { + throw ex.getCause(); + } + } + + static final class Details { + + private Details() { + } + + private record DefaultRootedPath(Path root, Path branch, boolean isDirectory) implements RootedPath { + + DefaultRootedPath { + Objects.requireNonNull(root); + Objects.requireNonNull(branch); + if (branch.isAbsolute()) { + throw new IllegalArgumentException(); + } + } + + PathMark createPathMark() { + return new PathMark(isDirectory); + } + } + + private record PathMark(boolean isDirectory, boolean isPreexisting) { + PathMark(boolean isDirectory) { + this(isDirectory, false); + } + } + + private static List ancestorPaths(Path path) { + var ancestors = new ArrayList(); + while ((path = path.getParent()) != null) { + ancestors.add(path); + } + return ancestors; + } + } +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java index fd86331e2f1..21f941eedf5 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java @@ -52,7 +52,7 @@ final record WinExePackager(BuildEnv env, WinExePackage pkg, Path outputDir, Pat @Override public void accept(PackagingPipeline.Builder pipelineBuilder) { - pipelineBuilder.excludeDirFromCopying(outputDir) + pipelineBuilder .task(ExePackageTaskID.RUN_POST_MSI_USER_SCRIPT) .action(this::runPostMsiScript) .addDependency(PackageTaskID.CREATE_PACKAGE_FILE) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java index c52be726fd2..c72b14a76d5 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java @@ -162,7 +162,7 @@ final class WinMsiPackager implements Consumer { @Override public void accept(PackagingPipeline.Builder pipelineBuilder) { - pipelineBuilder.excludeDirFromCopying(outputDir) + pipelineBuilder .task(PackagingPipeline.PackageTaskID.CREATE_CONFIG_FILES) .action(this::prepareConfigFiles) .add() diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java index 53f4b9b95aa..8fdcc96acff 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java @@ -222,7 +222,7 @@ public class AppImageFileTest { version, null, null, - Optional.empty(), + List.of(), List.of(), null, Optional.empty(), diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java index 86a6cb075d0..de0ba67fece 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java @@ -616,7 +616,7 @@ public class PackagingPipelineTest { "1.0", "Acme", "copyright", - Optional.empty(), + List.of(), List.of(), appImageLayout, runtimeBuilder, diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionSpecMutatorOptionScopeTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionSpecMutatorOptionScopeTest.java index 1849a3b5333..59c7c85ce85 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionSpecMutatorOptionScopeTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionSpecMutatorOptionScopeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,11 +75,11 @@ public class OptionSpecMutatorOptionScopeTest { assertEquals(OptionName.of("foo"), mappedSpec.name()); } - assertEquals("731", mappedSpec.converter().orElseThrow().convert(spec.name(), StringToken.of("str")).orElseThrow()); + assertEquals("731", mappedSpec.convert(spec.name(), StringToken.of("str")).orElseThrow()); assertEquals(OptionName.of("foo"), spec.name()); - assertEquals("123", spec.converter().orElseThrow().convert(spec.name(), StringToken.of("str")).orElseThrow()); + assertEquals("123", spec.convert(spec.name(), StringToken.of("str")).orElseThrow()); } @Test @@ -99,11 +99,11 @@ public class OptionSpecMutatorOptionScopeTest { var mappedSpec = new DummyContext(731).mapOptionSpec(spec); - assertArrayEquals(new String[] {"731"}, mappedSpec.converter().orElseThrow().convert(spec.name(), StringToken.of("str")).orElseThrow()); + assertArrayEquals(new String[] {"731"}, mappedSpec.convert(spec.name(), StringToken.of("str")).orElseThrow()); assertEquals(OptionName.of("foo"), spec.name()); - assertArrayEquals(new String[] {"123"}, spec.converter().orElseThrow().convert(spec.name(), StringToken.of("str")).orElseThrow()); + assertArrayEquals(new String[] {"123"}, spec.convert(spec.name(), StringToken.of("str")).orElseThrow()); } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionSpecTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionSpecTest.java index a92c677d9cf..66bd44a2402 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionSpecTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionSpecTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -293,11 +293,11 @@ public class OptionSpecTest { return toOptionNames(List.of(names)); } - private static OptionValueConverter converter(ValueConverter conv) { + private static OptionValueConverter converter(ValueConverter conv) { return buildConverter(conv).create(); } - private static OptionValueConverter.Builder buildConverter(ValueConverter conv) { + private static OptionValueConverter.Builder buildConverter(ValueConverter conv) { return OptionValueConverter.build().converter(conv); } @@ -329,7 +329,7 @@ public class OptionSpecTest { return this; } - OptionSpecBuilder converter(OptionValueConverter v) { + OptionSpecBuilder converter(OptionValueConverter v) { converter = v; return this; } @@ -355,7 +355,7 @@ public class OptionSpecTest { } private List names; - private OptionValueConverter converter; + private OptionValueConverter converter; private T defaultOptionalValue; private Set scope = Set.of(new OptionScope() {}); private MergePolicy mergePolicy = MergePolicy.USE_LAST; diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionValueConverterTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionValueConverterTest.java index c026ee0639f..3d8f26523a0 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionValueConverterTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionValueConverterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,12 @@ */ package jdk.jpackage.internal.cli; +import static jdk.jpackage.internal.cli.OptionValueConverter.convertString; import static jdk.jpackage.internal.cli.TestUtils.assertExceptionListEquals; import static jdk.jpackage.internal.cli.TestUtils.configureConverter; import static jdk.jpackage.internal.cli.TestUtils.configureValidator; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotSame; @@ -33,6 +35,7 @@ import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.nio.file.Path; import java.util.List; import java.util.function.Function; import java.util.stream.Stream; @@ -55,10 +58,10 @@ public class OptionValueConverterTest { if (positive) { final var token = StringToken.of("758"); - assertEquals(758, converter.convert(OptionName.of("number"), token).orElseThrow()); + assertEquals(758, convertString(converter, OptionName.of("number"), token).orElseThrow()); } else { final var token = StringToken.of("foo"); - final var result = converter.convert(OptionName.of("number"), token); + final var result = convertString(converter, OptionName.of("number"), token); assertEquals(1, result.errors().size()); @@ -77,7 +80,7 @@ public class OptionValueConverterTest { .converter(ValueConverter.create(Integer::valueOf, Integer.class)).create(); Function> convertString = (v) -> { - return converter.convert(OptionName.of("foo"), StringToken.of(v)); + return convertString(converter, OptionName.of("foo"), StringToken.of(v)); }; assertEquals(10, convertString.apply("10").orElseThrow()); @@ -89,24 +92,32 @@ public class OptionValueConverterTest { public void test_Builder_invalid() { assertThrowsExactly(NullPointerException.class, OptionValueConverter.build() - .converter(ValueConverter.create(Integer::valueOf, Integer.class)) + .converter(phonyConverter(Integer.class)) .mutate(configureConverter()) .formatString(null)::create); assertThrowsExactly(NullPointerException.class, OptionValueConverter.build() - .converter(ValueConverter.create(Integer::valueOf, Integer.class)) + .converter(phonyConverter(Integer.class)) .mutate(configureConverter()) .exceptionFactory(null)::create); } - @Test - public void test_Builder_copy() { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_Builder_copy(boolean twoStep) { Function tokenizer = _ -> { throw new UnsupportedOperationException(); }; - var builder = OptionValueConverter.build() - .converter(ValueConverter.create(Integer::valueOf, Integer.class)) - .validator(Validator.build().predicate(_ -> true).create()) + final OptionValueConverter.Builder builder; + if (twoStep) { + builder = OptionValueConverter.build() + .converter(phonyConverter(Path.class)) + .map(phonyConverter(Integer.class)); + } else { + builder = OptionValueConverter.build().converter(phonyConverter(Integer.class)); + } + + builder.validator(Validator.build().predicate(_ -> true).create()) .mutate(configureConverter()) .tokenizer(tokenizer); @@ -114,7 +125,10 @@ public class OptionValueConverterTest { assertNotSame(copy, builder); - assertSame(builder.converter().orElse(null), copy.converter().orElse(null)); + if (!twoStep) { + assertSame(builder.converter().orElse(null), copy.converter().orElse(null)); + } + assertSame(builder.formatString().orElse(null), copy.formatString().orElse(null)); assertSame(builder.exceptionFactory().orElse(null), copy.exceptionFactory().orElse(null)); assertSame(builder.tokenizer().orElse(null), copy.tokenizer().orElse(null)); @@ -125,6 +139,23 @@ public class OptionValueConverterTest { assertNotEquals(builder.formatString().orElse(null), copy.formatString().orElse(null)); } + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_Builder_hasConverter(boolean twoStep) { + + if (twoStep) { + final var builder = OptionValueConverter.build() + .converter(phonyConverter(Path.class)) + .map(phonyConverter(String.class)); + assertTrue(builder.hasConverter()); + } else { + final var builder = OptionValueConverter.build(); + assertFalse(builder.hasConverter()); + builder.converter(phonyConverter(String.class)); + assertTrue(builder.hasConverter()); + } + } + @Test public void test_Builder_createArray() { @@ -134,7 +165,7 @@ public class OptionValueConverterTest { .tokenizer(str -> str.split(":")) .createArray(); - assertNotEquals(List.of(100, 67, 145), List.of(converter.convert(OptionName.of("foo"), StringToken.of("110:67:145")).orElseThrow())); + assertNotEquals(List.of(100, 67, 145), List.of(convertString(converter, OptionName.of("foo"), StringToken.of("110:67:145")).orElseThrow())); assertEquals(Integer[].class, converter.valueType()); } @@ -170,7 +201,7 @@ public class OptionValueConverterTest { var converter = builder.createArray(); - var result = converter.convert(OptionName.of("foo"), StringToken.of("100:-10:-10:67:str:145:-7")); + var result = convertString(converter, OptionName.of("foo"), StringToken.of("100:-10:-10:67:str:145:-7")); assertExceptionListEquals(Stream.of( new IllegalArgumentException("-10"), @@ -192,7 +223,7 @@ public class OptionValueConverterTest { }, Integer.class)).mutate(configureConverter()).create(); final var token = StringToken.of("foo"); - final var ex = assertThrowsExactly(ConverterException.class, () -> converter.convert(OptionName.of("number"), token)); + final var ex = assertThrowsExactly(ConverterException.class, () -> convertString(converter, OptionName.of("number"), token)); assertSame(exception, ex.getCause()); } @@ -209,8 +240,133 @@ public class OptionValueConverterTest { }).mutate(configureValidator()).create()).create(); final var token = StringToken.of("100"); - final var ex = assertThrowsExactly(ConverterException.class, () -> converter.convert(OptionName.of("number"), token)); + final var ex = assertThrowsExactly(ConverterException.class, () -> convertString(converter, OptionName.of("number"), token)); assertSame(exception, ex.getCause()); } + + @Test + public void testTwoStep() { + + final var multiplyConverter = ValueConverter.create(v -> { + return (long)(v * -1); + }, Long.class); + + final var converter = OptionValueConverter.build() + .converter(ValueConverter.create(Integer::parseInt, Integer.class)) + .map(multiplyConverter) + .create(); + + assertEquals(Long.class, converter.valueType()); + + var result = convertString(converter, OptionName.of("foo"), StringToken.of("123")).orElseThrow(); + assertEquals(-123, result); + } + + @Test + public void testMultiStep() { + + final var converter = OptionValueConverter.build() + .converter(ValueConverter.create(Path::of, Path.class)) + .map(ValueConverter.create(v -> { + return v.normalize().toString(); + }, String.class)) + .map(ValueConverter.create(Integer::valueOf, Integer.class)) + .create(); + + assertEquals(Integer.class, converter.valueType()); + + var result = convertString(converter, OptionName.of("foo"), StringToken.of("./123")).orElseThrow(); + assertEquals(123, result); + } + + @ParameterizedTest + @ValueSource(ints = {0, 1, 2}) + public void testTwoStep_map(int type) { + + var tolower = ValueConverter.create(String::toLowerCase, String.class); + var toupper = ValueConverter.create(String::toUpperCase, String.class); + var reverse = ValueConverter.create(str -> { + return new StringBuilder(str).reverse().toString(); + }, String.class); + + final var baseBuilder = OptionValueConverter.build().converter(toupper); + + switch (type) { + case 0 -> { + assertThrowsExactly(UnsupportedOperationException.class, () -> { + baseBuilder.map(OptionValueConverter.build()); + }); + } + case 1 -> { + var builder = baseBuilder.map(reverse); + var ex = assertThrowsExactly(IllegalArgumentException.class, () -> { + builder.map(OptionValueConverter.build().converter(phonyConverter(Object.class))); + }); + assertEquals(String.format("Expected (%s); actual (%s)", String.class, Object.class), ex.getMessage()); + + assertEquals("CBA", convertString(builder.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + + var copy = builder.map(baseBuilder); + assertNotSame(copy, builder); + assertEquals("CBA", convertString(copy.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + assertEquals("CBA", convertString(builder.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + + copy = builder.map(baseBuilder.copy().converter(tolower)); + assertNotSame(copy, builder); + assertEquals("cba", convertString(copy.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + assertEquals("CBA", convertString(builder.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + } + case 2 -> { + var builder = baseBuilder.map(reverse).map(reverse); + var ex = assertThrowsExactly(IllegalArgumentException.class, () -> { + builder.map(OptionValueConverter.build().converter(phonyConverter(Object.class))); + }); + assertEquals(String.format("Expected (%s); actual (%s)", String.class, Object.class), ex.getMessage()); + + assertEquals("ABC", convertString(builder.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + + var copy = builder.map(baseBuilder.map(reverse)); + assertNotSame(copy, builder); + assertEquals("ABC", convertString(copy.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + assertEquals("ABC", convertString(builder.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + + copy = builder.map(baseBuilder.copy().converter(tolower).map(reverse)); + assertNotSame(copy, builder); + assertEquals("abc", convertString(copy.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + assertEquals("ABC", convertString(builder.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + + copy = builder.map(baseBuilder.copy().converter(tolower)); + assertNotSame(copy, builder); + assertEquals("cba", convertString(copy.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + assertEquals("ABC", convertString(builder.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + } + } + } + + @Test + public void testTwoStep_converter() { + + final var builder = OptionValueConverter.build() + // Create the "String -> Path" converter + .converter(ValueConverter.create(Path::of, Path.class)) + // Map the "String -> Path" converter into the "Path -> String" converter + .map(phonyConverter(String.class)) + // Map the "Path -> String" converter into the "String -> String" converter + .map(phonyConverter(String.class)); + + assertThrowsExactly(UnsupportedOperationException.class, () -> { + builder.converter(phonyConverter(String.class)); + }); + + assertThrowsExactly(UnsupportedOperationException.class, () -> { + builder.converter(); + }); + } + + private static ValueConverter phonyConverter(Class valueType) { + return ValueConverter.create(v -> { + throw new AssertionError(); + }, valueType); + } } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardOptionTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardOptionTest.java index 0b70f4151cc..58a78edb627 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardOptionTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardOptionTest.java @@ -24,6 +24,8 @@ package jdk.jpackage.internal.cli; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toMap; +import static jdk.jpackage.internal.cli.TestUtils.assertExceptionListEquals; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertSame; @@ -58,9 +60,11 @@ import jdk.jpackage.internal.model.BundleType; import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.LauncherShortcut; import jdk.jpackage.internal.model.LauncherShortcutStartupDirectory; +import jdk.jpackage.internal.util.RootedPath; import jdk.jpackage.internal.util.StringBundle; import jdk.jpackage.test.Comm; import jdk.jpackage.test.JUnitAdapter; +import jdk.jpackage.test.JUnitUtils; import jdk.jpackage.test.TKit; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -111,7 +115,7 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { var spec = StandardOption.ICON.getSpec(); - var result = spec.converter().orElseThrow().convert(spec.name(), StringToken.of(name)); + var result = spec.convert(spec.name(), StringToken.of(name)); assertEquals(Path.of(name), result.orElseThrow()); } @@ -121,7 +125,7 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { var spec = StandardOption.ICON.getSpec(); - var result = spec.converter().orElseThrow().convert(spec.name(), StringToken.of(workDir.toString())); + var result = spec.convert(spec.name(), StringToken.of(workDir.toString())); var ex = assertThrows(JPackageException.class, result::orElseThrow); @@ -135,7 +139,7 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { var spec = new StandardOptionContext().forFile(propertyFile).mapOptionSpec(StandardOption.ICON.getSpec()); - var result = spec.converter().orElseThrow().convert(spec.name(), StringToken.of(workDir.toString())); + var result = spec.convert(spec.name(), StringToken.of(workDir.toString())); var ex = assertThrows(JPackageException.class, result::orElseThrow); @@ -150,7 +154,7 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { var tempRoot = workDir.resolve(dir); - var value = spec.converter().orElseThrow().convert(spec.name(), StringToken.of(tempRoot.toString())).orElseThrow(); + var value = spec.convert(spec.name(), StringToken.of(tempRoot.toString())).orElseThrow(); assertEquals(tempRoot, value); } @@ -165,14 +169,14 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { Files.writeString(tempRoot, "foo"); var ex = assertThrowsExactly(JPackageException.class, - spec.converter().orElseThrow().convert(spec.name(), StringToken.of(tempRoot.toString()))::orElseThrow); + spec.convert(spec.name(), StringToken.of(tempRoot.toString()))::orElseThrow); assertEquals(I18N.format("error.parameter-not-empty-directory", tempRoot, "--temp"), ex.getMessage()); assertEquals(NotDirectoryException.class, ex.getCause().getClass()); tempRoot = workDir; ex = assertThrowsExactly(JPackageException.class, - spec.converter().orElseThrow().convert(spec.name(), StringToken.of(tempRoot.toString()))::orElseThrow); + spec.convert(spec.name(), StringToken.of(tempRoot.toString()))::orElseThrow); assertEquals(I18N.format("error.parameter-not-empty-directory", tempRoot, "--temp"), ex.getMessage()); assertEquals(DirectoryNotEmptyException.class, ex.getCause().getClass()); } @@ -200,13 +204,146 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { var spec = StandardOption.TYPE.getSpec(); - var result = spec.converter().orElseThrow().convert(spec.name(), StringToken.of(name)); + var result = spec.convert(spec.name(), StringToken.of(name)); var ex = assertThrows(JPackageException.class, result::orElseThrow); assertEquals(I18N.format("ERR_InvalidInstallerType", name), ex.getMessage()); } + @Test + public void test_APP_CONTENT_valid(@TempDir Path workDir) throws IOException { + + var spec = StandardOption.APP_CONTENT.getSpec(); + + var contentDir = workDir.resolve("a"); + var emptyDir = contentDir.resolve("b/empty-dir"); + var file = contentDir.resolve("file.txt"); + + Files.createDirectories(emptyDir); + Files.createDirectories(file.getParent()); + Files.createFile(file); + + Object convertedValue = spec.convert( + spec.name(), + StringToken.of(Stream.of(contentDir, file).map(Path::toString).collect(joining(","))) + ).orElseThrow(); + + var paths = StandardOption.APP_CONTENT.getFrom(Options.of(Map.of(StandardOption.APP_CONTENT, convertedValue))); + var sortedPathList = paths.stream().flatMap(Collection::stream).map(RootedPath::branch).sorted().toList(); + + var expectedPathList = Stream.of( + "a", + "a/b", + "a/b/empty-dir", + "a/file.txt", + "file.txt" + ).map(Path::of).sorted().toList(); + + assertEquals(expectedPathList, sortedPathList); + } + + @Test + public void test_APP_CONTENT_invalid(@TempDir Path workDir) throws IOException { + var spec = StandardOption.APP_CONTENT.getSpec(); + + var token = StringToken.of(workDir.resolve("nonexistent").toString()); + var result = spec.convert(spec.name(), token); + + assertExceptionListEquals(Stream.of( + "error.parameter-not-directory", + "error.parameter-not-file" + ).map(key -> { + return new JPackageException(I18N.format(key, token.value(), spec.name().formatForCommandLine())); + }).toList(), result.errors()); + } + + @ParameterizedTest + @EnumSource(OptionMutatorTest.TestType.class) + public void test_pathOptionMutator(OptionMutatorTest.TestType type) { + new OptionMutatorTest<>(StandardOption.pathOptionMutator(), StandardValueConverter.pathConv()) + .validValue("file.txt") + .invalidValue("\0") + .cmdlineErrorFormatKeys("error.parameter-not-path") + .propertyFileErrorFormatKeys("error.properties-parameter-not-path") + .test(OptionSpecBuilder.create(Path.class), type); + } + + @ParameterizedTest + @EnumSource(OptionMutatorTest.TestType.class) + public void test_existingPathOptionMutator(OptionMutatorTest.TestType type, @TempDir Path workDir) { + new OptionMutatorTest<>(StandardOption.existingPathOptionMutator(), StandardValueConverter.pathConv()) + .validValue(workDir.toString()) + .invalidValue(workDir.resolve("nonexistent").toString()) + .cmdlineErrorFormatKeys("error.parameter-not-directory", "error.parameter-not-file") + .propertyFileErrorFormatKeys("error.properties-parameter-not-directory", "error.properties-parameter-not-file") + .test(OptionSpecBuilder.create(Path.class), type); + } + + @ParameterizedTest + @EnumSource(OptionMutatorTest.TestType.class) + public void test_directoryOptionMutator(OptionMutatorTest.TestType type, @TempDir Path workDir) { + new OptionMutatorTest<>(StandardOption.directoryOptionMutator(), StandardValueConverter.pathConv()) + .validValue(workDir.toString()) + .invalidValue(workDir.resolve("nonexistent").toString()) + .cmdlineErrorFormatKeys("error.parameter-not-directory") + .propertyFileErrorFormatKeys("error.properties-parameter-not-directory") + .test(OptionSpecBuilder.create(Path.class), type); + } + + @ParameterizedTest + @EnumSource(OptionMutatorTest.TestType.class) + public void test_fileOptionMutator(OptionMutatorTest.TestType type, @TempDir Path workDir) throws IOException { + var test = new OptionMutatorTest<>(StandardOption.fileOptionMutator(), StandardValueConverter.pathConv()) + .invalidValue(workDir.resolve("nonexistent").toString()) + .cmdlineErrorFormatKeys("error.parameter-not-file") + .propertyFileErrorFormatKeys("error.properties-parameter-not-file"); + + switch (type) { + case TEST_CMDLINE_VALID, TEST_PROPERTY_FILE_VALID -> { + var file = workDir.resolve("file.txt"); + Files.createFile(file); + test.validValue(file.toString()); + } + default -> {} + } + + test.test(OptionSpecBuilder.create(Path.class), type); + } + + @ParameterizedTest + @EnumSource(OptionMutatorTest.TestType.class) + public void test_explodedPathOptionMapper(OptionMutatorTest.TestType type, @TempDir Path workDir) throws IOException { + + var explodePath = StandardValueConverter.explodedPathConverter().withPathFileName().create(); + + ValueConverter conv = ValueConverter.create(str -> { + var path = StandardValueConverter.pathConv().convert(str); + return explodePath.convert(path); + }, RootedPath[].class); + + var test = new OptionMutatorTest<>(_ -> {}, conv) + .invalidValue(workDir.resolve("nonexistent").toString()) + .cmdlineErrorFormatKeys("error.parameter-not-directory") + .propertyFileErrorFormatKeys("error.properties-parameter-not-directory"); + + switch (type) { + case TEST_CMDLINE_VALID, TEST_PROPERTY_FILE_VALID -> { + var dir = workDir.resolve("dir"); + Files.createDirectories(dir); + for (var file : List.of("foo.txt", "bar.txt")) { + Files.createFile(workDir.resolve(file)); + } + test.validValue(dir.toString()); + } + default -> {} + } + + test.test(OptionSpecBuilder.create(Path.class) + .mutate(StandardOption.directoryOptionMutator()) + .map(StandardOption.explodedPathOptionMapper(explodePath)), type); + } + @Test public void test_booleanOptionMutator() { @@ -221,6 +358,13 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { assertFalse(option.containsIn(empty)); } + @Test + public void test_booleanOptionMutator_in_property_file() { + new OptionMutatorTest<>(StandardOption.booleanOptionMutator(), StandardValueConverter.booleanConv()) + .validValue(Boolean.TRUE.toString()) + .test(OptionSpecBuilder.create(Boolean.class), OptionMutatorTest.TestType.TEST_PROPERTY_FILE_VALID); + } + @ParameterizedTest @MethodSource public void testLauncherShortcutOptions(LauncherShortcutTestSpec testSpec) { @@ -303,7 +447,7 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { var spec = StandardOption.ARGUMENTS.getOption().spec(); - var result = spec.converter().orElseThrow().convert(spec.name(), StringToken.of(value)); + var result = spec.convert(spec.name(), StringToken.of(value)); assertEquals(expectedTokens, List.of(result.map(String[].class::cast).orElseThrow())); } @@ -350,7 +494,7 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { || (bundlingOperation.os() == appImageOS); }).forEach(bundlingOperation -> { var bundleTypeStr = bundlingOperation.bundleTypeValue(); - var bundleType = spec.converter().orElseThrow().convert(spec.name(), StringToken.of(bundleTypeStr)).orElseThrow(); + var bundleType = spec.convert(spec.name(), StringToken.of(bundleTypeStr)).orElseThrow(); assertSame(bundlingOperation.bundleType(), bundleType); }); } @@ -391,6 +535,100 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { } + static final class OptionMutatorTest { + + enum TestType { + TEST_CMDLINE_VALID, + TEST_PROPERTY_FILE_VALID, + TEST_CMDLINE_INVALID, + TEST_PROPERTY_FILE_INVALID; + } + + OptionMutatorTest(Consumer> testee, ValueConverter conv) { + this.testee = Objects.requireNonNull(testee); + this.conv = Objects.requireNonNull(conv); + } + + void test(OptionSpecBuilder specBuilder, TestType type) { + var srcSpec = specBuilder.name("foo").mutate(testee).createOptionSpec(); + OptionSpec spec; + + var propertyFile = Path.of("foo.properties"); + + switch (type) { + case TEST_PROPERTY_FILE_VALID, TEST_PROPERTY_FILE_INVALID -> { + spec = new StandardOptionContext().forFile(propertyFile).mapOptionSpec(srcSpec); + } + default -> { + spec = srcSpec; + } + } + + StringToken token; + switch (type) { + case TEST_CMDLINE_VALID, TEST_PROPERTY_FILE_VALID -> { + token = StringToken.of(Objects.requireNonNull(validValue)); + } + default -> { + token = StringToken.of(Objects.requireNonNull(invalidValue)); + } + } + + var result = spec.convert(spec.name(), token); + + switch (type) { + case TEST_CMDLINE_VALID, TEST_PROPERTY_FILE_VALID -> { + var expected = toFunction(conv::convert).apply(token.value()); + var actual = result.orElseThrow(); + + if (spec.valueType().isArray()) { + JUnitUtils.assertArrayEquals(expected, actual); + } else { + assertEquals(expected, actual); + } + } + case TEST_CMDLINE_INVALID -> { + assertExceptionListEquals(cmdlineErrorFormatKeys.stream().map(key -> { + return new JPackageException(I18N.format(key, token.value(), spec.name().formatForCommandLine())); + }).map(JUnitUtils::removeExceptionCause).toList(), result.errors().stream().map(JUnitUtils::removeExceptionCause).toList()); + } + case TEST_PROPERTY_FILE_INVALID -> { + assertExceptionListEquals(propertyFileErrorFormatKeys.stream().map(key -> { + return new JPackageException(I18N.format(key, token.value(), spec.name().name(), propertyFile)); + }).map(JUnitUtils::removeExceptionCause).toList(), result.errors().stream().map(JUnitUtils::removeExceptionCause).toList()); + } + } + } + + OptionMutatorTest validValue(String v) { + validValue = v; + return this; + } + + OptionMutatorTest invalidValue(String v) { + invalidValue = v; + return this; + } + + OptionMutatorTest cmdlineErrorFormatKeys(String... v) { + cmdlineErrorFormatKeys = List.of(v); + return this; + } + + OptionMutatorTest propertyFileErrorFormatKeys(String... v) { + propertyFileErrorFormatKeys = List.of(v); + return this; + } + + private final Consumer> testee; + private final ValueConverter conv; + private List cmdlineErrorFormatKeys; + private List propertyFileErrorFormatKeys; + private String validValue; + private String invalidValue; + } + + record AddLauncherTestSpec(Optional expected, List expectedErrors, Optional optionValue) { AddLauncherTestSpec { if (expected.isEmpty() == expectedErrors.isEmpty()) { diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardValueConverterTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardValueConverterTest.java index 6b16b1099c7..491dae60d5f 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardValueConverterTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardValueConverterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ import org.junit.jupiter.params.provider.ValueSource; public class StandardValueConverterTest { @Test - public void test_identityConv() { + public void test_identityConv() throws Exception { final var testee = StandardValueConverter.identityConv(); @@ -58,7 +58,7 @@ public class StandardValueConverterTest { @ParameterizedTest @ValueSource(booleans = {true, false}) - public void test_pathConv(boolean positive) { + public void test_pathConv(boolean positive) throws Exception { final var testee = StandardValueConverter.pathConv(); @@ -72,14 +72,14 @@ public class StandardValueConverterTest { @ParameterizedTest @MethodSource - public void test_booleanConv(String value, Boolean expected) { + public void test_booleanConv(String value, Boolean expected) throws Exception { assertEquals(expected, StandardValueConverter.booleanConv().convert(value)); } @ParameterizedTest @MethodSource - public void test_mainLauncherShortcutConv(String value, LauncherShortcut expected) { + public void test_mainLauncherShortcutConv(String value, LauncherShortcut expected) throws Exception { assertEquals(expected, StandardValueConverter.mainLauncherShortcutConv().convert(value)); } @@ -93,7 +93,7 @@ public class StandardValueConverterTest { @ParameterizedTest @MethodSource - public void test_addLauncherShortcutConv(String value, LauncherShortcut expected) { + public void test_addLauncherShortcutConv(String value, LauncherShortcut expected) throws Exception { assertEquals(expected, StandardValueConverter.addLauncherShortcutConv().convert(value)); } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/FileUtilsTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/FileUtilsTest.java index 2067f0fa628..b7639dbfad4 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/FileUtilsTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/FileUtilsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,92 +24,36 @@ package jdk.jpackage.internal.util; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; -import org.junit.jupiter.params.provider.ValueSource; public class FileUtilsTest { - @ParameterizedTest - @EnumSource(ExcludeType.class) - public void test_copyRecursive_dir(ExcludeType exclude, @TempDir Path workdir) throws IOException { + @Test + public void test_copyRecursive_dir(@TempDir Path workdir) throws IOException { Files.createDirectories(workdir.resolve("from/foo/bar")); Files.createDirectories(workdir.resolve("from/foo/buz")); Files.writeString(workdir.resolve("from/foo/bar/file.txt"), "Hello"); - List excludes = new ArrayList<>(); - switch (exclude) { - case EXCLUDE_FILE -> { - excludes.add(Path.of("file.txt")); - } - case EXCLUDE_DIR -> { - excludes.add(Path.of("bar")); - } - case EXCLUDE_SUBDIR -> { - excludes.add(Path.of("foo")); - } - case EXCLUDE_NONE -> { - } - } - - FileUtils.copyRecursive(workdir.resolve("from"), workdir.resolve("to"), excludes); + FileUtils.copyRecursive(workdir.resolve("from"), workdir.resolve("to")); assertEquals("Hello", Files.readString(workdir.resolve("from/foo/bar/file.txt"))); - - switch (exclude) { - case EXCLUDE_FILE -> { - assertFalse(Files.exists(workdir.resolve("to/foo/bar/file.txt"))); - assertTrue(Files.isDirectory(workdir.resolve("to/foo/bar"))); - } - case EXCLUDE_DIR -> { - assertFalse(Files.exists(workdir.resolve("to/foo/bar"))); - assertTrue(Files.isDirectory(workdir.resolve("to/foo/buz"))); - } - case EXCLUDE_SUBDIR -> { - assertFalse(Files.exists(workdir.resolve("to/foo"))); - assertTrue(Files.isDirectory(workdir.resolve("to"))); - } - case EXCLUDE_NONE -> { - assertEquals("Hello", Files.readString(workdir.resolve("to/foo/bar/file.txt"))); - } - } + assertEquals("Hello", Files.readString(workdir.resolve("to/foo/bar/file.txt"))); } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void test_copyRecursive_file(boolean exclude, @TempDir Path workdir) throws IOException { + @Test + public void test_copyRecursive_file(@TempDir Path workdir) throws IOException { Files.createDirectories(workdir.resolve("from/foo/bar")); Files.writeString(workdir.resolve("from/foo/bar/file.txt"), "Hello"); - List excludes = new ArrayList<>(); - if (exclude) { - excludes.add(Path.of("bar/file.txt")); - } - - FileUtils.copyRecursive(workdir.resolve("from/foo/bar/file.txt"), workdir.resolve("to/foo/bar/file.txt"), excludes); + FileUtils.copyRecursive(workdir.resolve("from/foo/bar/file.txt"), workdir.resolve("to/foo/bar/file.txt")); assertEquals("Hello", Files.readString(workdir.resolve("from/foo/bar/file.txt"))); - if (exclude) { - assertFalse(Files.exists(workdir.resolve("to"))); - } else { - assertEquals("Hello", Files.readString(workdir.resolve("to/foo/bar/file.txt"))); - } - } - - enum ExcludeType { - EXCLUDE_NONE, - EXCLUDE_FILE, - EXCLUDE_DIR, - EXCLUDE_SUBDIR, + assertEquals("Hello", Files.readString(workdir.resolve("to/foo/bar/file.txt"))); } } diff --git a/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java b/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java index 0b63688ee20..530a0d5cb1f 100644 --- a/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java +++ b/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -64,6 +64,10 @@ public final class JUnitUtils { return EXCEPTION_OM.toMap(ex); } + public static Exception removeExceptionCause(Exception ex) { + return new ExceptionCauseRemover(ex); + } + public static final class ExceptionPattern { @@ -117,6 +121,23 @@ public final class JUnitUtils { } + private static final class ExceptionCauseRemover extends Exception { + + ExceptionCauseRemover(Exception ex) { + super(ex.getMessage()); + type = ex.getClass(); + } + + public Class getType() { + return type; + } + + private final Class type; + + private static final long serialVersionUID = 1L; + } + + @FunctionalInterface private interface ArrayEqualsAsserter { void accept(T expected, T actual); diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java index b6066bb9cc4..e275fae262c 100644 --- a/test/jdk/tools/jpackage/share/AppContentTest.java +++ b/test/jdk/tools/jpackage/share/AppContentTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.TreeMap; +import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Stream; @@ -85,6 +86,7 @@ public class AppContentTest { @Test @ParameterSupplier("test") @ParameterSupplier(value="testSymlink", ifNotOS = WINDOWS) + @ParameterSupplier public void testAppImage(TestSpec testSpec) throws Exception { testSpec.test(new ConfigurationTarget(JPackageCommand.helloAppImage())); } @@ -126,6 +128,14 @@ public class AppContentTest { }).toList(); } + public static Collection testAppImage() { + return Stream.of( + build().add(NonExistentPath.create("*output-app-image*", JPackageCommand::outputBundle)) + ).map(TestSpec.Builder::create).map(v -> { + return new Object[] {v}; + }).toList(); + } + public static Collection testSymlink() { return Stream.of( build().add(TEST_JAVA) @@ -150,7 +160,7 @@ public class AppContentTest { void test(ConfigurationTarget target) { final int expectedJPackageExitCode; - if (contentFactories.stream().flatMap(List::stream).anyMatch(TEST_BAD::equals)) { + if (contentFactories.stream().flatMap(List::stream).anyMatch(NonExistentPath.class::isInstance)) { expectedJPackageExitCode = 1; } else { expectedJPackageExitCode = 0; @@ -159,9 +169,11 @@ public class AppContentTest { final List> allContent = new ArrayList<>(); target.addInitializer(JPackageCommand::setFakeRuntime) - .addRunOnceInitializer(_ -> { + .addInitializer(cmd -> { contentFactories.stream().map(group -> { - return group.stream().map(ContentFactory::create).toList(); + return group.stream().map(contentFactory -> { + return contentFactory.create(cmd); + }).toList(); }).forEach(allContent::add); }).addInitializer(cmd -> { allContent.stream().map(group -> { @@ -192,6 +204,10 @@ public class AppContentTest { }); target.addInstallVerifier(cmd -> { + if (expectedJPackageExitCode != 0) { + return; + } + var appContentRoot = getAppContentRoot(cmd); Set disabledVerifiers = new HashSet<>(); @@ -329,7 +345,7 @@ public class AppContentTest { @FunctionalInterface private interface ContentFactory { - Content create(); + Content create(JPackageCommand cmd); } private interface Content { @@ -337,12 +353,7 @@ public class AppContentTest { Iterable verifiers(Path appContentRoot); } - private sealed interface PathVerifier permits - RegularFileVerifier, - DirectoryVerifier, - SymlinkTargetVerifier, - NoPathVerifier { - + private sealed interface PathVerifier { Path path(); void verify(); } @@ -467,22 +478,45 @@ public class AppContentTest { /** * Non-existing content. */ - private static final class NonExistantPath implements ContentFactory { + private static final class NonExistentPath implements ContentFactory { + + private NonExistentPath(String label, Function makePath) { + this.label = Objects.requireNonNull(label); + this.makePath = Objects.requireNonNull(makePath); + } + @Override - public Content create() { - var nonExistant = TKit.createTempFile("non-existant"); - try { - TKit.deleteIfExists(nonExistant); - } catch (IOException ex) { - throw new UncheckedIOException(ex); + public Content create(JPackageCommand cmd) { + var nonexistent = makePath.apply(cmd); + if (Files.exists(nonexistent)) { + throw new IllegalStateException(); } - return new FileContent(nonExistant, 0); + return new FileContent(nonexistent, 0); } @Override public String toString() { - return "*non-existant*"; + return label; } + + static NonExistentPath create(String label, Function makePath) { + return new NonExistentPath(label, makePath); + } + + static NonExistentPath create(String path) { + return new NonExistentPath(String.format("*%s*", Objects.requireNonNull(path)), _ -> { + var nonexistent = TKit.createTempFile(path); + try { + TKit.deleteIfExists(nonexistent); + return nonexistent; + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); + } + + private final String label; + private final Function makePath; } /** @@ -565,7 +599,7 @@ public class AppContentTest { } @Override - public Content create() { + public Content create(JPackageCommand cmd) { final var appContentRoot = createAppContentRoot(); final var symlinkPath = appContentRoot.resolve(symlinkPath()); @@ -639,7 +673,7 @@ public class AppContentTest { } @Override - public Content create() { + public Content create(JPackageCommand cmd) { Path srcPath = factory.get(); if (!srcPath.endsWith(pathInAppContentRoot)) { throw new IllegalArgumentException(); @@ -672,7 +706,7 @@ public class AppContentTest { private static final ContentFactory TEST_JAVA = createTextFileContent("apps/PrintEnv.java", "Not what someone would expect"); private static final ContentFactory TEST_DUKE = createTextFileContent("duke.txt", "Hi Duke!"); private static final ContentFactory TEST_DIR = createDirTreeContent("apps"); - private static final ContentFactory TEST_BAD = new NonExistantPath(); + private static final ContentFactory TEST_BAD = NonExistentPath.create("non-existent"); // On OSX `--app-content` paths will be copied into the "Contents" folder // of the output app image. diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java index 6956f66df42..a9fa48dc1c6 100644 --- a/test/jdk/tools/jpackage/share/InOutPathTest.java +++ b/test/jdk/tools/jpackage/share/InOutPathTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,26 +24,28 @@ import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE_AND_UNPACK; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.function.Consumer; import java.util.function.Predicate; -import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.ApplicationLayout; +import jdk.jpackage.test.ConfigurationTarget; import jdk.jpackage.test.JPackageCommand; -import jdk.jpackage.test.JPackageCommand.StandardAssert; import jdk.jpackage.test.PackageFile; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; +import jdk.jpackage.internal.util.function.ThrowingConsumer; /* * @test @@ -76,25 +78,6 @@ public final class InOutPathTest { return data; } - @Parameters(ifNotOS = OperatingSystem.MACOS) - public static Collection appContentInputOther() { - return List.of(new Object[][]{ - {PackageTypeAlias.IMAGE, wrap(cmd -> { - additionalContent(cmd, "--app-content", cmd.outputBundle()); - }, "--app-content same as output bundle")}, - }); - } - - @Parameters(ifOS = OperatingSystem.MACOS) - public static Collection appContentInputOSX() { - var contentsFolder = "Contents/MacOS"; - return List.of(new Object[][]{ - {PackageTypeAlias.IMAGE, wrap(cmd -> { - additionalContent(cmd, "--app-content", cmd.outputBundle().resolve(contentsFolder)); - }, String.format("--app-content same as the \"%s\" folder in the output bundle", contentsFolder))}, - }); - } - @Parameters(ifOS = OperatingSystem.MACOS) public static Collection inputOSX() { return List.of(additionalContentInput(PackageType.MAC_DMG, "--mac-dmg-content").toArray(Object[][]::new)); @@ -146,67 +129,54 @@ public final class InOutPathTest { } @Test - public void test() throws Exception { + public void test() { runTest(packageTypes, configure); } private static Envelope wrap(ThrowingConsumer v, String label) { - return new Envelope(v, label); - } - - private static boolean isAppImageValid(JPackageCommand cmd) { - return !cmd.hasArgument("--app-content") && !cmd.hasArgument("--mac-dmg-content"); + return new Envelope(ThrowingConsumer.toConsumer(v), label); } private static void runTest(Set packageTypes, - ThrowingConsumer configure) throws Exception { - ThrowingConsumer configureWrapper = cmd -> { + Consumer configure) { + + ConfigurationTarget cfg; + if (packageTypes.contains(PackageType.IMAGE)) { + cfg = new ConfigurationTarget( + JPackageCommand.helloAppImage(JAR_PATH.toString() + ":")); + } else { + cfg = new ConfigurationTarget(new PackageTest() + .forTypes(packageTypes) + .configureHelloApp(JAR_PATH.toString() + ":")); + } + + var verifier = new AppDirContentVerifier(); + + cfg.addInitializer(cmd -> { // Make sure the input directory is empty in every test run. // This is needed because jpackage output directories in this test // are subdirectories of the input directory. cmd.setInputToEmptyDirectory(); configure.accept(cmd); if (cmd.hasArgument("--temp") && cmd.isImagePackageType()) { - // Request to build app image wit user supplied temp directory, + // Request to build app image with user supplied temp directory, // ignore external runtime if any to make use of the temp directory // for runtime generation. cmd.ignoreDefaultRuntime(true); } else { cmd.setFakeRuntime(); } + }) + .addInitializer(JPackageCommand::executePrerequisiteActions) + .addInitializer(verifier::captureInputDir); - if (!isAppImageValid(cmd)) { - // Standard asserts for .jpackage.xml fail in messed up app image. Disable them. - // Other standard asserts for app image contents should pass. - cmd.excludeStandardAsserts(StandardAssert.APP_IMAGE_FILE); - } - }; + cfg.cmd().ifPresent(JPackageCommand::executeAndAssertHelloAppImageCreated); - if (packageTypes.contains(PackageType.IMAGE)) { - JPackageCommand cmd = JPackageCommand.helloAppImage(JAR_PATH.toString() + ":"); - configureWrapper.accept(cmd); - cmd.executeAndAssertHelloAppImageCreated(); - if (isAppImageValid(cmd)) { - verifyAppImage(cmd); - } + cfg.addInstallVerifier(verifier::verify); - if (cmd.hasArgument("--app-content")) { - // `--app-content` can be set to the app image directory which - // should not exist before jpackage is executed: - // jpackage --name Foo --dest output --app-content output/Foo - // Verify the directory exists after jpackage execution. - // At least this will catch the case when the value of - // `--app-content` option refers to a path unrelated to jpackage I/O. - TKit.assertDirectoryExists(Path.of(cmd.getArgumentValue("--app-content"))); - } - } else { - new PackageTest() - .forTypes(packageTypes) - .configureHelloApp(JAR_PATH.toString() + ":") - .addInitializer(configureWrapper) - .addInstallVerifier(InOutPathTest::verifyAppImage) - .run(CREATE_AND_UNPACK); - } + cfg.test().ifPresent(pkg -> { + pkg.run(CREATE_AND_UNPACK); + }); } private static void outputDirInInputDir(JPackageCommand cmd) throws @@ -217,8 +187,7 @@ public final class InOutPathTest { cmd.setArgumentValue("--dest", outputDir); } - private static void outputDirSameAsInputDir(JPackageCommand cmd) throws - IOException { + private static void outputDirSameAsInputDir(JPackageCommand cmd) { // Set output dir the same as the input dir cmd.setArgumentValue("--dest", cmd.inputDir()); } @@ -238,38 +207,7 @@ public final class InOutPathTest { cmd.addArguments(argName, appContentFile.getParent()); } - private static void verifyAppImage(JPackageCommand cmd) throws IOException { - if (!isAppImageValid(cmd)) { - // Don't verify the contents of app image as it is invalid. - // jpackage exited without getting stuck in infinite spiral. - // No more expectations from the tool for the give arguments. - return; - } - - final Path rootDir = cmd.isImagePackageType() ? cmd.outputBundle() : cmd.pathToUnpackedPackageFile( - cmd.appInstallationDirectory()); - final Path appDir = ApplicationLayout.platformAppImage().resolveAt( - rootDir).appDirectory(); - - final var knownFiles = Set.of( - JAR_PATH.getName(0).toString(), - PackageFile.getPathInAppImage(Path.of("")).getFileName().toString(), - AppImageFile.getPathInAppImage(Path.of("")).getFileName().toString(), - cmd.name() + ".cfg" - ); - - TKit.assertFileExists(appDir.resolve(JAR_PATH)); - - try (Stream actualFilesStream = Files.list(appDir)) { - var unexpectedFiles = actualFilesStream.map(path -> { - return path.getFileName().toString(); - }).filter(Predicate.not(knownFiles::contains)).toList(); - TKit.assertStringListEquals(List.of(), unexpectedFiles, - "Check there are no unexpected files in `app` folder"); - } - } - - private static final record Envelope(ThrowingConsumer value, String label) { + private record Envelope(Consumer value, String label) { @Override public String toString() { // Will produce the same test description for the same label every @@ -291,8 +229,49 @@ public final class InOutPathTest { private final Set packageTypes; } + private static final class AppDirContentVerifier { + + void captureInputDir(JPackageCommand cmd) { + var root = Path.of(cmd.getArgumentValue("--input")); + try (var walk = Files.walk(root)) { + inputDirFiles = walk.map(root::relativize).toList(); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + void verify(JPackageCommand cmd) { + var expectedContent = new HashSet<>(inputDirFiles); + + expectedContent.add(Path.of(cmd.name() + ".cfg")); + if (cmd.isImagePackageType()) { + expectedContent.add(AppImageFile.getPathInAppImage(Path.of("")).getFileName()); + } else { + expectedContent.add(PackageFile.getPathInAppImage(Path.of("")).getFileName()); + } + + final var rootDir = cmd.isImagePackageType() ? cmd.outputBundle() : cmd.pathToUnpackedPackageFile( + cmd.appInstallationDirectory()); + final var appDir = ApplicationLayout.platformAppImage().resolveAt(rootDir).appDirectory(); + + try (var walk = Files.walk(appDir)) { + var unexpectedFiles = walk + .map(appDir::relativize) + .filter(Predicate.not(expectedContent::contains)) + .map(Path::toString) + .toList(); + TKit.assertStringListEquals(List.of(), unexpectedFiles, + "Check there are no unexpected files in `app` folder"); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + private Collection inputDirFiles; + } + private final Set packageTypes; - private final ThrowingConsumer configure; + private final Consumer configure; // Placing jar file in the "Resources" subdir of the input directory would allow // to use the input directory with `--app-content` on OSX. From 9b47c23b4b809f7070c6c8279b7ffdf83234dcdb Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 16 Jan 2026 23:16:43 +0000 Subject: [PATCH 067/328] 8375242: [macos] Improve jpackage signing coverage Reviewed-by: almatvee --- .../jdk/jpackage/test/JPackageCommand.java | 107 +++-- .../helpers/jdk/jpackage/test/MacHelper.java | 419 ++++++++++++++++-- .../helpers/jdk/jpackage/test/MacSign.java | 13 + .../jdk/jpackage/test/MacSignVerify.java | 18 +- .../jpackage/macosx/EntitlementsTest.java | 10 +- .../tools/jpackage/macosx/MacSignTest.java | 122 ++--- .../jpackage/macosx/SigningAppImageTest.java | 102 ++--- .../macosx/SigningAppImageTwoStepsTest.java | 202 ++++++--- .../tools/jpackage/macosx/SigningBase.java | 178 ++++++++ .../jpackage/macosx/SigningPackageTest.java | 335 ++++++++------ .../macosx/SigningPackageTwoStepTest.java | 312 ++++++------- .../SigningRuntimeImagePackageTest.java | 268 ++++++----- .../jpackage/macosx/base/SigningBase.java | 316 ------------- 13 files changed, 1413 insertions(+), 989 deletions(-) create mode 100644 test/jdk/tools/jpackage/macosx/SigningBase.java delete mode 100644 test/jdk/tools/jpackage/macosx/base/SigningBase.java diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 7874df3fd69..f81c35cea0b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -294,34 +294,8 @@ public class JPackageCommand extends CommandArguments { public JPackageCommand setFakeRuntime() { verifyMutable(); - - ThrowingConsumer createBulkFile = path -> { - Files.createDirectories(path.getParent()); - try (FileOutputStream out = new FileOutputStream(path.toFile())) { - byte[] bytes = new byte[4 * 1024]; - new SecureRandom().nextBytes(bytes); - out.write(bytes); - } - }; - addPrerequisiteAction(cmd -> { - Path fakeRuntimeDir = TKit.createTempDirectory("fake_runtime"); - - TKit.trace(String.format("Init fake runtime in [%s] directory", - fakeRuntimeDir)); - - if (TKit.isOSX()) { - // Make MacAppImageBuilder happy - createBulkFile.accept(fakeRuntimeDir.resolve(Path.of( - "lib/jli/libjli.dylib"))); - } - - // Make sure fake runtime takes some disk space. - // Package bundles with 0KB size are unexpected and considered - // an error by PackageTest. - createBulkFile.accept(fakeRuntimeDir.resolve(Path.of("lib", "bulk"))); - - cmd.setArgumentValue("--runtime-image", fakeRuntimeDir); + cmd.setArgumentValue("--runtime-image", createInputRuntimeImage(RuntimeImageType.RUNTIME_TYPE_FAKE)); }); return this; @@ -390,24 +364,77 @@ public class JPackageCommand extends CommandArguments { return cmd; } + public enum RuntimeImageType { + + /** + * Runtime suitable for running the default "Hello" test app. + */ + RUNTIME_TYPE_HELLO_APP, + + /** + * Fake runtime. + */ + RUNTIME_TYPE_FAKE, + + ; + } + public static Path createInputRuntimeImage() { + return createInputRuntimeImage(RuntimeImageType.RUNTIME_TYPE_HELLO_APP); + } + + public static Path createInputRuntimeImage(RuntimeImageType role) { + Objects.requireNonNull(role); final Path runtimeImageDir; + switch (role) { - if (JPackageCommand.DEFAULT_RUNTIME_IMAGE != null) { - runtimeImageDir = JPackageCommand.DEFAULT_RUNTIME_IMAGE; - } else { - runtimeImageDir = TKit.createTempDirectory("runtime-image").resolve("data"); + case RUNTIME_TYPE_FAKE -> { + Consumer createBulkFile = ThrowingConsumer.toConsumer(path -> { + Files.createDirectories(path.getParent()); + try (FileOutputStream out = new FileOutputStream(path.toFile())) { + byte[] bytes = new byte[4 * 1024]; + new SecureRandom().nextBytes(bytes); + out.write(bytes); + } + }); - new Executor().setToolProvider(JavaTool.JLINK) - .dumpOutput() - .addArguments( - "--output", runtimeImageDir.toString(), - "--add-modules", "java.desktop", - "--strip-debug", - "--no-header-files", - "--no-man-pages") - .execute(); + runtimeImageDir = TKit.createTempDirectory("fake_runtime"); + + TKit.trace(String.format("Init fake runtime in [%s] directory", runtimeImageDir)); + + if (TKit.isOSX()) { + // Make MacAppImageBuilder happy + createBulkFile.accept(runtimeImageDir.resolve(Path.of("lib/jli/libjli.dylib"))); + } + + // Make sure fake runtime takes some disk space. + // Package bundles with 0KB size are unexpected and considered + // an error by PackageTest. + createBulkFile.accept(runtimeImageDir.resolve(Path.of("lib", "bulk"))); + } + + case RUNTIME_TYPE_HELLO_APP -> { + if (JPackageCommand.DEFAULT_RUNTIME_IMAGE != null && !isFakeRuntime(DEFAULT_RUNTIME_IMAGE)) { + runtimeImageDir = JPackageCommand.DEFAULT_RUNTIME_IMAGE; + } else { + runtimeImageDir = TKit.createTempDirectory("runtime-image").resolve("data"); + + new Executor().setToolProvider(JavaTool.JLINK) + .dumpOutput() + .addArguments( + "--output", runtimeImageDir.toString(), + "--add-modules", "java.desktop", + "--strip-debug", + "--no-header-files", + "--no-man-pages") + .execute(); + } + } + + default -> { + throw ExceptionBox.reachedUnreachable(); + } } return runtimeImageDir; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index 1cb5532d46a..dc1a7b3512b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -46,6 +46,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; +import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -66,6 +67,7 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; +import jdk.jpackage.internal.util.Enquoter; import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.MacBundle; import jdk.jpackage.internal.util.PListReader; @@ -75,6 +77,8 @@ import jdk.jpackage.internal.util.XmlUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.internal.util.function.ThrowingSupplier; import jdk.jpackage.test.MacSign.CertificateRequest; +import jdk.jpackage.test.MacSign.CertificateType; +import jdk.jpackage.test.MacSign.ResolvedKeychain; import jdk.jpackage.test.PackageTest.PackageHandlers; import jdk.jpackage.test.RunnablePackageTest.Action; import org.xml.sax.SAXException; @@ -430,18 +434,50 @@ public final class MacHelper { } } + public static final class RuntimeBundleBuilder { + + public Path create() { + return createRuntimeBundle(type, Optional.ofNullable(mutator)); + } + + public RuntimeBundleBuilder type(JPackageCommand.RuntimeImageType v) { + type = Objects.requireNonNull(v); + return this; + } + + public RuntimeBundleBuilder mutator(Consumer v) { + mutator = v; + return this; + } + + public RuntimeBundleBuilder mutate(Consumer mutator) { + mutator.accept(this); + return this; + } + + private RuntimeBundleBuilder() { + } + + private JPackageCommand.RuntimeImageType type = JPackageCommand.RuntimeImageType.RUNTIME_TYPE_HELLO_APP; + private Consumer mutator; + }; + + public static RuntimeBundleBuilder buildRuntimeBundle() { + return new RuntimeBundleBuilder(); + } + public static Path createRuntimeBundle(Consumer mutator) { - return createRuntimeBundle(Optional.of(mutator)); + return buildRuntimeBundle().mutator(Objects.requireNonNull(mutator)).create(); } public static Path createRuntimeBundle() { - return createRuntimeBundle(Optional.empty()); + return buildRuntimeBundle().create(); } - public static Path createRuntimeBundle(Optional> mutator) { + private static Path createRuntimeBundle(JPackageCommand.RuntimeImageType type, Optional> mutator) { Objects.requireNonNull(mutator); - final var runtimeImage = JPackageCommand.createInputRuntimeImage(); + final var runtimeImage = JPackageCommand.createInputRuntimeImage(type); final var runtimeBundleWorkDir = TKit.createTempDirectory("runtime-bundle"); @@ -495,25 +531,244 @@ public final class MacHelper { return cmd; } - public record SignKeyOption(Type type, CertificateRequest certRequest) { + public static final class ResolvableCertificateRequest { + + public ResolvableCertificateRequest( + CertificateRequest certRequest, + Function certResolver, + String label) { + + Objects.requireNonNull(certRequest); + Objects.requireNonNull(certResolver); + Objects.requireNonNull(label); + if (label.isBlank()) { + throw new IllegalArgumentException(); + } + + this.certRequest = certRequest; + this.certResolver = certResolver; + this.label = label; + } + + public ResolvableCertificateRequest( + CertificateRequest certRequest, + ResolvedKeychain keychain, + String label) { + this(certRequest, keychain.asCertificateResolver(), label); + } + + @Override + public String toString() { + return label; + } + + public CertificateRequest certRequest() { + return certRequest; + } + + public X509Certificate cert() { + return certResolver.apply(certRequest); + } + + public CertificateType type() { + return certRequest.type(); + } + + public String name() { + return certRequest.name(); + } + + public String shortName() { + return certRequest.shortName(); + } + + public int days() { + return certRequest.days(); + } + + public boolean expired() { + return certRequest.expired(); + } + + public boolean trusted() { + return certRequest.trusted(); + } + + private final CertificateRequest certRequest; + private final Function certResolver; + private final String label; + } + + public interface NamedCertificateRequestSupplier { + + String name(); + + CertificateRequest certRequest(); + + default ResolvableCertificateRequest certRequest(ResolvedKeychain keychain) { + Objects.requireNonNull(keychain); + var certRequest = Objects.requireNonNull(certRequest()); + if (keychain.spec().certificateRequests().contains(certRequest)) { + return new ResolvableCertificateRequest(certRequest, keychain.asCertificateResolver(), name()); + } else { + throw new IllegalArgumentException(String.format( + "Certificate request %s not found in [%s] keychain", + name(), keychain.spec().keychain().name())); + } + } + } + + public record SignKeyOption(Type type, ResolvableCertificateRequest certRequest, Optional customOptionValue) { public SignKeyOption { Objects.requireNonNull(type); Objects.requireNonNull(certRequest); + Objects.requireNonNull(customOptionValue); + if (customOptionValue.isEmpty() == (type == Type.SIGN_KEY_USER_NAME)) { + throw new IllegalArgumentException(); + } + } + + public SignKeyOption(Type type, ResolvableCertificateRequest certRequest) { + this(type, certRequest, Optional.empty()); + } + + public SignKeyOption( + Type type, + NamedCertificateRequestSupplier certRequestSupplier, + ResolvedKeychain keychain) { + + this(type, certRequestSupplier.certRequest(keychain)); + } + + public SignKeyOption(String optionValue, ResolvableCertificateRequest certRequest) { + this(Type.SIGN_KEY_USER_NAME, certRequest, Optional.of(optionValue)); + } + + public SignKeyOption( + String optionValue, + NamedCertificateRequestSupplier certRequestSupplier, + ResolvedKeychain keychain) { + + this(optionValue, certRequestSupplier.certRequest(keychain)); + } + + public enum Name { + KEY_USER_NAME("--mac-signing-key-user-name"), + KEY_IDENTITY_APP_IMAGE("--mac-app-image-sign-identity"), + KEY_IDENTITY_INSTALLER("--mac-installer-sign-identity"), + ; + + Name(String optionName) { + this.optionName = Objects.requireNonNull(optionName); + } + + public String optionName() { + return optionName; + } + + public boolean passThrough() { + return this != KEY_USER_NAME; + } + + private final String optionName; } public enum Type { - SIGN_KEY_USER_NAME, - SIGN_KEY_IDENTITY, + /** + * "--mac-signing-key-user-name" option with custom value + */ + SIGN_KEY_USER_NAME(Name.KEY_USER_NAME), + + /** + * "--mac-signing-key-user-name" option with the short user name, e.g.: + * {@code --mac-signing-key-user-name foo} + */ + SIGN_KEY_USER_SHORT_NAME(Name.KEY_USER_NAME), + + /** + * "--mac-signing-key-user-name" option with the full user name (aka signing + * identity name), e.g.: + * {@code --mac-signing-key-user-name 'Developer ID Application: foo'} + */ + SIGN_KEY_USER_FULL_NAME(Name.KEY_USER_NAME), + + /** + * "--mac-installer-sign-identity" or "--mac-app-image-sign-identity" option + * with the signing identity name, e.g.: + * {@code --mac-app-image-sign-identity 'Developer ID Application: foo'} + */ + SIGN_KEY_IDENTITY(Map.of( + MacSign.CertificateType.CODE_SIGN, Name.KEY_IDENTITY_APP_IMAGE, + MacSign.CertificateType.INSTALLER, Name.KEY_IDENTITY_INSTALLER)), + + /** + * "--mac-app-image-sign-identity" regardless of the type of signing identity + * (for signing app image or .pkg installer). + */ + SIGN_KEY_IDENTITY_APP_IMAGE(Name.KEY_IDENTITY_APP_IMAGE), + + /** + * "--mac-installer-sign-identity" regardless of the type of signing identity + * (for signing app image or .pkg installer). + */ + SIGN_KEY_IDENTITY_INSTALLER(Name.KEY_IDENTITY_INSTALLER), + ; + + Type(Map optionNameMap) { + Objects.requireNonNull(optionNameMap); + this.optionNameMapper = certType -> { + return Optional.of(optionNameMap.get(certType)); + }; + } + + Type(Name optionName) { + Objects.requireNonNull(optionName); + this.optionNameMapper = _ -> Optional.of(optionName); + } + + Type() { + this.optionNameMapper = _ -> Optional.empty(); + } + + public Optional mapOptionName(MacSign.CertificateType certType) { + return optionNameMapper.apply(Objects.requireNonNull(certType)); + } + + public static Type[] defaultValues() { + return new Type[] { + SIGN_KEY_USER_SHORT_NAME, + SIGN_KEY_USER_FULL_NAME, + SIGN_KEY_IDENTITY + }; + } + + private final Function> optionNameMapper; } @Override public String toString() { var sb = new StringBuilder(); + sb.append('{'); applyTo((optionName, _) -> { - sb.append(String.format("{%s: %s}", optionName, certRequest)); + sb.append(optionName); + switch (type) { + case SIGN_KEY_USER_FULL_NAME -> { + sb.append("/full"); + } + case SIGN_KEY_USER_NAME -> { + customOptionValue.ifPresent(optionValue -> { + sb.append("=").append(ENQUOTER.applyTo(optionValue)); + }); + } + default -> { + // NOP + } + } + sb.append(": "); }); + sb.append(certRequest).append('}'); return sb.toString(); } @@ -527,35 +782,127 @@ public final class MacHelper { return sign(cmd); } - private void applyTo(BiConsumer sink) { - switch (certRequest.type()) { - case INSTALLER -> { - switch (type) { - case SIGN_KEY_IDENTITY -> { - sink.accept("--mac-installer-sign-identity", certRequest.name()); - return; - } - case SIGN_KEY_USER_NAME -> { - sink.accept("--mac-signing-key-user-name", certRequest.shortName()); - return; - } - } - } - case CODE_SIGN -> { - switch (type) { - case SIGN_KEY_IDENTITY -> { - sink.accept("--mac-app-image-sign-identity", certRequest.name()); - return; - } - case SIGN_KEY_USER_NAME -> { - sink.accept("--mac-signing-key-user-name", certRequest.shortName()); - return; - } - } - } - } + public List asCmdlineArgs() { + String[] args = new String[2]; + applyTo((optionName, optionValue) -> { + args[0] = optionName; + args[1] = optionValue; + }); + return List.of(args); + } - throw new AssertionError(); + private void applyTo(BiConsumer sink) { + type.mapOptionName(certRequest.type()).ifPresent(optionName -> { + sink.accept(optionName.optionName(), optionValue()); + }); + } + + private String optionValue() { + return customOptionValue.orElseGet(() -> { + switch (type) { + case SIGN_KEY_IDENTITY, + SIGN_KEY_USER_FULL_NAME, + SIGN_KEY_IDENTITY_APP_IMAGE, + SIGN_KEY_IDENTITY_INSTALLER -> { + return certRequest.name(); + } + case SIGN_KEY_USER_SHORT_NAME -> { + return certRequest.shortName(); + } + default -> { + throw new IllegalStateException(); + } + } + }); + } + + private static final Enquoter ENQUOTER = Enquoter.identity() + .setEnquotePredicate(Enquoter.QUOTE_IF_WHITESPACES).setQuoteChar('\''); + } + + public record SignKeyOptionWithKeychain(SignKeyOption signKeyOption, ResolvedKeychain keychain) { + + public SignKeyOptionWithKeychain { + Objects.requireNonNull(signKeyOption); + Objects.requireNonNull(keychain); + } + + public SignKeyOptionWithKeychain( + SignKeyOption.Type type, + ResolvableCertificateRequest certRequest, + ResolvedKeychain keychain) { + + this(new SignKeyOption(type, certRequest), keychain); + } + + public SignKeyOptionWithKeychain( + SignKeyOption.Type type, + NamedCertificateRequestSupplier certRequestSupplier, + ResolvedKeychain keychain) { + + this(type, certRequestSupplier.certRequest(keychain), keychain); + } + + public SignKeyOptionWithKeychain( + String optionValue, + ResolvableCertificateRequest certRequest, + ResolvedKeychain keychain) { + + this(new SignKeyOption(optionValue, certRequest), keychain); + } + + public SignKeyOptionWithKeychain( + String optionValue, + NamedCertificateRequestSupplier certRequestSupplier, + ResolvedKeychain keychain) { + + this(optionValue, certRequestSupplier.certRequest(keychain), keychain); + } + + public SignKeyOptionWithKeychain( + SignKeyOption.Type type, + CertificateRequest certRequest, + ResolvedKeychain keychain) { + + this(new SignKeyOption( + type, + new ResolvableCertificateRequest( + certRequest, + keychain.asCertificateResolver(), + certRequest.toString())), + keychain); + } + + @Override + public String toString() { + return String.format("%s@%s", signKeyOption, keychain.name()); + } + + public SignKeyOption.Type type() { + return signKeyOption.type(); + } + + public ResolvableCertificateRequest certRequest() { + return signKeyOption.certRequest(); + } + + public JPackageCommand addTo(JPackageCommand cmd) { + Optional.ofNullable(cmd.getArgumentValue("--mac-signing-keychain")).ifPresentOrElse(configuredKeychain -> { + if (!configuredKeychain.equals(keychain.name())) { + throw new IllegalStateException(String.format( + "Command line [%s] already has the '--mac-signing-keychain' option, not adding another one with [%s] value", + cmd, keychain.name())); + } + }, () -> { + useKeychain(cmd, keychain); + }); + return signKeyOption.addTo(cmd); + } + + public JPackageCommand setTo(JPackageCommand cmd) { + cmd.removeArgumentWithValue("--mac-signing-keychain"); + useKeychain(cmd, keychain); + return signKeyOption.setTo(cmd); } } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java index 70de6ba92af..3bbbf436300 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java @@ -61,6 +61,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; import javax.naming.ldap.LdapName; @@ -1132,6 +1133,18 @@ public final class MacSign { return certMap; } + public Function asCertificateResolver() { + return certRequest -> { + if (!spec.certificateRequests().contains(certRequest)) { + throw new IllegalArgumentException(String.format( + "Certificate request %s not found in [%s] keychain", + certRequest, name())); + } else { + return Objects.requireNonNull(mapCertificateRequests().get(certRequest)); + } + }; + } + private final KeychainWithCertsSpec spec; private volatile Map certMap; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java index 9c469c9362e..ddf899d603c 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java @@ -33,6 +33,7 @@ import java.util.Objects; import java.util.Optional; import java.util.regex.Pattern; import jdk.jpackage.internal.util.PListReader; +import jdk.jpackage.test.MacHelper.ResolvableCertificateRequest; import jdk.jpackage.test.MacSign.CertificateHash; import jdk.jpackage.test.MacSign.CertificateRequest; @@ -41,12 +42,10 @@ import jdk.jpackage.test.MacSign.CertificateRequest; */ public final class MacSignVerify { - public static void verifyAppImageSigned( - JPackageCommand cmd, CertificateRequest certRequest, MacSign.ResolvedKeychain keychain) { + public static void verifyAppImageSigned(JPackageCommand cmd, ResolvableCertificateRequest certRequest) { - cmd.verifyIsOfType(PackageType.MAC); + cmd.verifyIsOfType(PackageType.MAC_DMG, PackageType.MAC_PKG, PackageType.IMAGE); Objects.requireNonNull(certRequest); - Objects.requireNonNull(keychain); final Path bundleRoot; if (cmd.isImagePackageType()) { @@ -70,13 +69,12 @@ public final class MacSignVerify { String.format("Check [%s] has sign origin as expected", bundleRoot)); } - public static void verifyPkgSigned(JPackageCommand cmd, CertificateRequest certRequest, MacSign.ResolvedKeychain keychain) { + public static void verifyPkgSigned(JPackageCommand cmd, ResolvableCertificateRequest certRequest) { cmd.verifyIsOfType(PackageType.MAC_PKG); - assertPkgSigned(cmd.outputBundle(), certRequest, - Objects.requireNonNull(keychain.mapCertificateRequests().get(certRequest))); + assertPkgSigned(cmd.outputBundle(), certRequest); } - public static void assertSigned(Path path, CertificateRequest certRequest) { + public static void assertSigned(Path path, ResolvableCertificateRequest certRequest) { assertSigned(path); TKit.assertEquals(certRequest.name(), findCodesignSignOrigin(path).orElse(null), String.format("Check [%s] signed with certificate", path)); @@ -108,6 +106,10 @@ public final class MacSignVerify { String.format("Check [%s] unsigned", path)); } + public static void assertPkgSigned(Path path, ResolvableCertificateRequest certRequest) { + assertPkgSigned(path, certRequest.certRequest(), certRequest.cert()); + } + public static void assertPkgSigned(Path path, CertificateRequest certRequest, X509Certificate cert) { final var expectedCertChain = List.of(new SignIdentity(certRequest.name(), CertificateHash.of(cert, SHA256))); final var actualCertChain = getPkgCertificateChain(path); diff --git a/test/jdk/tools/jpackage/macosx/EntitlementsTest.java b/test/jdk/tools/jpackage/macosx/EntitlementsTest.java index 6e03c858db3..052e301a9ae 100644 --- a/test/jdk/tools/jpackage/macosx/EntitlementsTest.java +++ b/test/jdk/tools/jpackage/macosx/EntitlementsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -56,10 +56,9 @@ import jdk.jpackage.test.TKit; * @test * @summary jpackage with --type app-image "--mac-entitlements" parameter * @library /test/jdk/tools/jpackage/helpers - * @library base - * @build SigningBase * @build jdk.jpackage.test.* - * @build EntitlementsTest + * @compile -Xlint:all -Werror SigningBase.java + * @compile -Xlint:all -Werror EntitlementsTest.java * @requires (jpackage.test.MacSignTests == "run") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=EntitlementsTest @@ -142,7 +141,8 @@ public class EntitlementsTest { cmd.mutate(MacHelper.useKeychain(keychain)).mutate(new SignKeyOption( SignKeyOption.Type.SIGN_KEY_IDENTITY, - SigningBase.StandardCertificateRequest.CODESIGN.spec() + SigningBase.StandardCertificateRequest.CODESIGN, + keychain )::addTo); cmd.mutate(new AdditionalLauncher("x")::applyTo); diff --git a/test/jdk/tools/jpackage/macosx/MacSignTest.java b/test/jdk/tools/jpackage/macosx/MacSignTest.java index af7cf448bdc..a824fdb0925 100644 --- a/test/jdk/tools/jpackage/macosx/MacSignTest.java +++ b/test/jdk/tools/jpackage/macosx/MacSignTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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,12 +21,16 @@ * questions. */ +import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_IDENTITY; +import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_USER_FULL_NAME; +import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_USER_SHORT_NAME; +import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_IDENTITY_APP_IMAGE; + import java.io.IOException; import java.nio.file.Files; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; @@ -37,8 +41,11 @@ import jdk.jpackage.test.CannedFormattedString; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageStringBundle; import jdk.jpackage.test.MacHelper; +import jdk.jpackage.test.MacHelper.NamedCertificateRequestSupplier; +import jdk.jpackage.test.MacHelper.ResolvableCertificateRequest; +import jdk.jpackage.test.MacHelper.SignKeyOption; +import jdk.jpackage.test.MacHelper.SignKeyOptionWithKeychain; import jdk.jpackage.test.MacSign; -import jdk.jpackage.test.MacSign.CertificateRequest; import jdk.jpackage.test.MacSign.CertificateType; import jdk.jpackage.test.MacSignVerify; import jdk.jpackage.test.PackageType; @@ -48,10 +55,9 @@ import jdk.jpackage.test.TKit; * @test * @summary jpackage with --mac-sign * @library /test/jdk/tools/jpackage/helpers - * @library base - * @build SigningBase * @build jdk.jpackage.test.* - * @build MacSignTest + * @compile -Xlint:all -Werror SigningBase.java + * @compile -Xlint:all -Werror MacSignTest.java * @requires (jpackage.test.MacSignTests == "run") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=MacSignTest @@ -79,22 +85,28 @@ public class MacSignTest { } MacSign.withKeychain(keychain -> { + + var signingKeyOption = new SignKeyOptionWithKeychain( + SIGN_KEY_IDENTITY, + SigningBase.StandardCertificateRequest.CODESIGN, + keychain); + // --app-content and --type app-image // Expect `message.codesign.failed.reason.app.content` message in the log. // This is not a fatal error, just a warning. // To make jpackage fail, specify bad additional content. - final var cmd = JPackageCommand.helloAppImage() + JPackageCommand.helloAppImage() .ignoreDefaultVerbose(true) .validateOutput(expectedStrings.toArray(CannedFormattedString[]::new)) .addArguments("--app-content", appContent) - .addArguments("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.CODESIGN.spec().name()); + .mutate(signingKeyOption::addTo) + .mutate(cmd -> { + if (MacHelper.isXcodeDevToolsInstalled()) { + // Check there is no warning about missing xcode command line developer tools. + cmd.validateOutput(TKit.assertTextStream(xcodeWarning.getValue()).negate()); + } + }).execute(1); - if (MacHelper.isXcodeDevToolsInstalled()) { - // Check there is no warning about missing xcode command line developer tools. - cmd.validateOutput(TKit.assertTextStream(xcodeWarning.getValue()).negate()); - } - - MacHelper.useKeychain(cmd, keychain).execute(1); }, MacSign.Keychain.UsageBuilder::addToSearchList, SigningBase.StandardKeychain.MAIN.keychain()); } @@ -116,13 +128,19 @@ public class MacSignTest { expectedStrings.add(JPackageStringBundle.MAIN.cannedFormattedString("error.tool.failed.with.output", "codesign")); MacSign.withKeychain(keychain -> { - final var cmd = new JPackageCommand().setPackageType(PackageType.IMAGE) + + var signingKeyOption = new SignKeyOptionWithKeychain( + SIGN_KEY_IDENTITY, + SigningBase.StandardCertificateRequest.CODESIGN, + keychain); + + new JPackageCommand().setPackageType(PackageType.IMAGE) .ignoreDefaultVerbose(true) .validateOutput(expectedStrings.toArray(CannedFormattedString[]::new)) .addArguments("--app-image", appImageCmd.outputBundle()) - .addArguments("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.CODESIGN.spec().name()); + .mutate(signingKeyOption::addTo) + .execute(1); - MacHelper.useKeychain(cmd, keychain).execute(1); }, MacSign.Keychain.UsageBuilder::addToSearchList, SigningBase.StandardKeychain.MAIN.keychain()); } @@ -189,71 +207,78 @@ public class MacSignTest { @Test @ParameterSupplier @ParameterSupplier("testSelectSigningIdentity_JDK_8371094") - public static void testSelectSigningIdentity(String signingKeyUserName, CertificateRequest certRequest) { + public static void testSelectSigningIdentity(SignKeyOptionWithKeychain signKeyOption) { MacSign.withKeychain(keychain -> { - final var cmd = MacHelper.useKeychain(JPackageCommand.helloAppImage(), keychain) - .setFakeRuntime() - .addArguments("--mac-signing-key-user-name", signingKeyUserName); + final var cmd = JPackageCommand.helloAppImage().setFakeRuntime().mutate(signKeyOption::addTo); - cmd.executeAndAssertHelloAppImageCreated(); + cmd.executeAndAssertImageCreated(); - MacSignVerify.assertSigned(cmd.outputBundle(), certRequest); + MacSignVerify.verifyAppImageSigned(cmd, signKeyOption.certRequest()); }, MacSign.Keychain.UsageBuilder::addToSearchList, SigningBase.StandardKeychain.MAIN.keychain()); } public static Collection testSelectSigningIdentity() { + var keychain = SigningBase.StandardKeychain.MAIN.keychain(); return Stream.of( SigningBase.StandardCertificateRequest.CODESIGN, SigningBase.StandardCertificateRequest.CODESIGN_UNICODE - ).map(SigningBase.StandardCertificateRequest::spec).mapMulti((certRequest, acc) -> { - acc.accept(new Object[] {certRequest.shortName(), certRequest}); - acc.accept(new Object[] {certRequest.name(), certRequest}); + ).map(certRequest -> { + return Stream.of( + SIGN_KEY_USER_FULL_NAME, + SIGN_KEY_USER_SHORT_NAME + ).map(type -> { + return new SignKeyOptionWithKeychain(type, certRequest, keychain); + }); + }).flatMap(x -> x).map(v -> { + return new Object[] {v}; }).toList(); } public static Collection testSelectSigningIdentity_JDK_8371094() { return List.of(new Object[] { - "ACME Technologies Limited", SigningBase.StandardCertificateRequest.CODESIGN_ACME_TECH_LTD.spec() + new SignKeyOptionWithKeychain( + "ACME Technologies Limited", + SigningBase.StandardCertificateRequest.CODESIGN_ACME_TECH_LTD, + SigningBase.StandardKeychain.MAIN.keychain()) }); } enum SignOption { - EXPIRED_SIGNING_KEY_USER_NAME("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED.spec(), true, false), - EXPIRED_SIGNING_KEY_USER_NAME_PKG("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.PKG_EXPIRED.spec(), true, false), - EXPIRED_SIGN_IDENTITY("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED.spec(), false, false), - EXPIRED_CODESIGN_SIGN_IDENTITY("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED.spec(), false, true), - EXPIRED_PKG_SIGN_IDENTITY("--mac-installer-sign-identity", SigningBase.StandardCertificateRequest.PKG_EXPIRED.spec(), false, true), - GOOD_SIGNING_KEY_USER_NAME("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.CODESIGN.spec(), true, false), - GOOD_SIGNING_KEY_USER_NAME_PKG("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.PKG.spec(), true, false), - GOOD_CODESIGN_SIGN_IDENTITY("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.CODESIGN.spec(), false, true), - GOOD_PKG_SIGN_IDENTITY("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.PKG.spec(), false, true); + EXPIRED_SIGNING_KEY_USER_NAME(SIGN_KEY_USER_SHORT_NAME, SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED), + EXPIRED_SIGNING_KEY_USER_NAME_PKG(SIGN_KEY_USER_SHORT_NAME, SigningBase.StandardCertificateRequest.PKG_EXPIRED), + EXPIRED_SIGN_IDENTITY(SIGN_KEY_USER_FULL_NAME, SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED), + EXPIRED_CODESIGN_SIGN_IDENTITY(SIGN_KEY_IDENTITY, SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED), + EXPIRED_PKG_SIGN_IDENTITY(SIGN_KEY_IDENTITY, SigningBase.StandardCertificateRequest.PKG_EXPIRED), + GOOD_SIGNING_KEY_USER_NAME(SIGN_KEY_USER_SHORT_NAME, SigningBase.StandardCertificateRequest.CODESIGN), + GOOD_SIGNING_KEY_USER_NAME_PKG(SIGN_KEY_USER_SHORT_NAME, SigningBase.StandardCertificateRequest.PKG), + GOOD_CODESIGN_SIGN_IDENTITY(SIGN_KEY_IDENTITY, SigningBase.StandardCertificateRequest.CODESIGN), + GOOD_PKG_SIGN_IDENTITY(SIGN_KEY_IDENTITY_APP_IMAGE, SigningBase.StandardCertificateRequest.PKG); - SignOption(String option, MacSign.CertificateRequest cert, boolean shortName, boolean passThrough) { - this.option = Objects.requireNonNull(option); - this.cert = Objects.requireNonNull(cert); - this.shortName = shortName; - this.passThrough = passThrough; + SignOption(SignKeyOption.Type optionType, NamedCertificateRequestSupplier certRequestSupplier) { + this.option = new SignKeyOption(optionType, new ResolvableCertificateRequest(certRequestSupplier.certRequest(), _ -> { + throw new UnsupportedOperationException(); + }, certRequestSupplier.name())); } boolean passThrough() { - return passThrough; + return option.type().mapOptionName(option.certRequest().type()).orElseThrow().passThrough(); } boolean expired() { - return cert.expired(); + return option.certRequest().expired(); } String identityName() { - return cert.name(); + return option.certRequest().name(); } CertificateType identityType() { - return cert.type(); + return option.certRequest().type(); } List args() { - return List.of(option, shortName ? cert.shortName() : cert.name()); + return option.asCmdlineArgs(); } static JPackageCommand configureOutputValidation(JPackageCommand cmd, List options, @@ -274,9 +299,6 @@ public class MacSignTest { return cmd; } - private final String option; - private final MacSign.CertificateRequest cert; - private final boolean shortName; - private final boolean passThrough; + private final SignKeyOption option; } } diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java index 37ba8a6c299..0f299cb5a24 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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,90 +21,76 @@ * questions. */ -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; - -import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import jdk.jpackage.test.AdditionalLauncher; -import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.MacHelper.SignKeyOption; +import jdk.jpackage.test.MacHelper.SignKeyOptionWithKeychain; import jdk.jpackage.test.MacSign; +import jdk.jpackage.test.MacSignVerify; /** - * Tests generation of app image with --mac-sign and related arguments. Test will - * generate app image and verify signature of main launcher and app bundle itself. - * This test requires that machine is configured with test certificate for - * "Developer ID Application: jpackage.openjdk.java.net" or alternately - * "Developer ID Application: " + name specified by system property: - * "jpackage.mac.signing.key.user.name" - * in the jpackagerTest keychain (or alternately the keychain specified with - * the system property "jpackage.mac.signing.keychain". - * If this certificate is self-signed, it must have be set to - * always allowed access to this keychain" for user which runs test. - * (If cert is real (not self signed), the do not set trust to allow.) + * Tests signing of an app image. + * + *

+ * Prerequisites: Keychains with self-signed certificates as specified in + * {@link SigningBase.StandardKeychain#MAIN} and + * {@link SigningBase.StandardKeychain#SINGLE}. */ /* * @test * @summary jpackage with --type app-image --mac-sign * @library /test/jdk/tools/jpackage/helpers - * @library base - * @build SigningBase * @build jdk.jpackage.test.* - * @build SigningAppImageTest + * @compile -Xlint:all -Werror SigningBase.java + * @compile -Xlint:all -Werror SigningAppImageTest.java * @requires (jpackage.test.MacSignTests == "run") - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningAppImageTest * --jpt-before-run=SigningBase.verifySignTestEnvReady */ public class SigningAppImageTest { @Test - // ({"sign or not", "signing-key or sign-identity", "certificate index"}) - // Sign, signing-key and ASCII certificate - @Parameter({"true", "true", "ASCII_INDEX"}) - // Sign, signing-key and UNICODE certificate - @Parameter({"true", "true", "UNICODE_INDEX"}) - // Sign, signing-indentity and UNICODE certificate - @Parameter({"true", "false", "UNICODE_INDEX"}) - // Unsigned - @Parameter({"false", "true", "INVALID_INDEX"}) - public void test(boolean doSign, boolean signingKey, SigningBase.CertIndex certEnum) throws Exception { - MacSign.withKeychain(toConsumer(keychain -> { - test(keychain, doSign, signingKey, certEnum); - }), SigningBase.StandardKeychain.MAIN.keychain()); - } + @ParameterSupplier + public static void test(SignKeyOptionWithKeychain sign) { - private void test(MacSign.ResolvedKeychain keychain, boolean doSign, boolean signingKey, SigningBase.CertIndex certEnum) throws Exception { - final var certIndex = certEnum.value(); + var cmd = JPackageCommand.helloAppImage(); - JPackageCommand cmd = JPackageCommand.helloAppImage(); - if (doSign) { - cmd.addArguments("--mac-sign", - "--mac-signing-keychain", - keychain.name()); - if (signingKey) { - cmd.addArguments("--mac-signing-key-user-name", - SigningBase.getDevName(certIndex)); - } else { - cmd.addArguments("--mac-app-image-sign-identity", - SigningBase.getAppCert(certIndex)); - } - } - AdditionalLauncher testAL = new AdditionalLauncher("testAL"); + var testAL = new AdditionalLauncher("testAL"); testAL.applyTo(cmd); cmd.executeAndAssertHelloAppImageCreated(); - Path launcherPath = cmd.appLauncherPath(); - SigningBase.verifyCodesign(launcherPath, doSign, certIndex); + MacSign.withKeychain(keychain -> { + sign.addTo(cmd); + cmd.executeAndAssertHelloAppImageCreated(); + MacSignVerify.verifyAppImageSigned(cmd, sign.certRequest()); + }, sign.keychain()); + } - Path testALPath = launcherPath.getParent().resolve("testAL"); - SigningBase.verifyCodesign(testALPath, doSign, certIndex); + public static Collection test() { - Path appImage = cmd.outputBundle(); - SigningBase.verifyCodesign(appImage, doSign, certIndex); - if (doSign) { - SigningBase.verifySpctl(appImage, "exec", certIndex); + List data = new ArrayList<>(); + + for (var certRequest : List.of( + SigningBase.StandardCertificateRequest.CODESIGN, + SigningBase.StandardCertificateRequest.CODESIGN_UNICODE + )) { + for (var signIdentityType : SignKeyOption.Type.defaultValues()) { + data.add(new SignKeyOptionWithKeychain( + signIdentityType, + certRequest, + SigningBase.StandardKeychain.MAIN.keychain())); + } } + + return data.stream().map(v -> { + return new Object[] {v}; + }).toList(); } } diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java index 906734e6a9c..2c7ae205e69 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, 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,38 +21,40 @@ * questions. */ -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; - -import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; import jdk.jpackage.test.AdditionalLauncher; -import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.MacHelper.SignKeyOption; +import jdk.jpackage.test.MacHelper.SignKeyOptionWithKeychain; import jdk.jpackage.test.MacSign; +import jdk.jpackage.test.MacSignVerify; import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; /** - * Tests generation of app image and then signs generated app image with --mac-sign - * and related arguments. Test will generate app image and verify signature of main - * launcher and app bundle itself. This test requires that machine is configured with - * test certificate for "Developer ID Application: jpackage.openjdk.java.net" or - * alternately "Developer ID Application: " + name specified by system property: - * "jpackage.mac.signing.key.user.name" in the jpackagerTest keychain - * (or alternately the keychain specified with the system property - * "jpackage.mac.signing.keychain". If this certificate is self-signed, it must - * have be set to always allowed access to this keychain" for user which runs test. - * (If cert is real (not self signed), the do not set trust to allow.) + * Tests signing of a signed/unsigned predefined app image. + * + *

+ * Prerequisites: Keychains with self-signed certificates as specified in + * {@link SigningBase.StandardKeychain#MAIN} and + * {@link SigningBase.StandardKeychain#SINGLE}. */ /* * @test * @summary jpackage with --type app-image --app-image "appImage" --mac-sign * @library /test/jdk/tools/jpackage/helpers - * @library base - * @build SigningBase * @build jdk.jpackage.test.* - * @build SigningAppImageTwoStepsTest + * @compile -Xlint:all -Werror SigningBase.java + * @compile -Xlint:all -Werror SigningAppImageTwoStepsTest.java * @requires (jpackage.test.MacSignTests == "run") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningAppImageTwoStepsTest @@ -61,67 +63,123 @@ import jdk.jpackage.test.TKit; public class SigningAppImageTwoStepsTest { @Test - // ({"sign or not", "signing-key or sign-identity"}) - // Sign and signing-key - @Parameter({"true", "true"}) - // Sign and sign-identity - @Parameter({"true", "false"}) - // Unsigned - @Parameter({"false", "true"}) - public void test(boolean signAppImage, boolean signingKey) throws Exception { - MacSign.withKeychain(toConsumer(keychain -> { - test(keychain, signAppImage, signingKey); - }), SigningBase.StandardKeychain.MAIN.keychain()); + @ParameterSupplier + public static void test(TestSpec spec) { + spec.test(); } - private static void test(MacSign.ResolvedKeychain keychain, boolean signAppImage, boolean signingKey) throws Exception { + public record TestSpec(Optional signAppImage, SignKeyOptionWithKeychain sign) { - Path appimageOutput = TKit.createTempDirectory("appimage"); + public TestSpec { + Objects.requireNonNull(signAppImage); + Objects.requireNonNull(sign); + } - // Generate app image. Signed or unsigned based on test - // parameter. We should able to sign predfined app images - // which are signed or unsigned. - JPackageCommand appImageCmd = JPackageCommand.helloAppImage() - .setArgumentValue("--dest", appimageOutput); - if (signAppImage) { - appImageCmd.addArguments("--mac-sign", - "--mac-signing-keychain", - keychain.name()); - if (signingKey) { - appImageCmd.addArguments("--mac-signing-key-user-name", - SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); - } else { - appImageCmd.addArguments("--mac-app-image-sign-identity", - SigningBase.getAppCert(SigningBase.DEFAULT_INDEX)); + @Override + public String toString() { + return Stream.of( + String.format("app-image=%s", signAppImage.map(Objects::toString).orElse("unsigned")), + sign.toString() + ).collect(Collectors.joining("; ")); + } + + static Builder build() { + return new Builder(); + } + + static class Builder { + + TestSpec create() { + return new TestSpec(Optional.ofNullable(signAppImage), sign); + } + + Builder certRequest(SigningBase.StandardCertificateRequest v) { + certRequest = Objects.requireNonNull(v); + return this; + } + + Builder signIdentityType(SignKeyOption.Type v) { + signIdentityType = Objects.requireNonNull(v); + return this; + } + + Builder sign() { + sign = createSignKeyOption(); + return this; + } + + Builder signAppImage() { + signAppImage = createSignKeyOption(); + return this; + } + + private SignKeyOptionWithKeychain createSignKeyOption() { + return new SignKeyOptionWithKeychain( + signIdentityType, + certRequest, + SigningBase.StandardKeychain.MAIN.keychain()); + } + + private SigningBase.StandardCertificateRequest certRequest = SigningBase.StandardCertificateRequest.CODESIGN; + private SignKeyOption.Type signIdentityType = SignKeyOption.Type.SIGN_KEY_IDENTITY; + + private SignKeyOptionWithKeychain signAppImage; + private SignKeyOptionWithKeychain sign; + } + + void test() { + var appImageCmd = JPackageCommand.helloAppImage() + .setFakeRuntime() + .setArgumentValue("--dest", TKit.createTempDirectory("appimage")); + + // Add an additional launcher + AdditionalLauncher testAL = new AdditionalLauncher("testAL"); + testAL.applyTo(appImageCmd); + + signAppImage.ifPresentOrElse(signOption -> { + MacSign.withKeychain(keychain -> { + signOption.addTo(appImageCmd); + appImageCmd.execute(); + MacSignVerify.verifyAppImageSigned(appImageCmd, signOption.certRequest()); + }, signOption.keychain()); + }, appImageCmd::execute); + + var cmd = new JPackageCommand() + .setPackageType(PackageType.IMAGE) + .addArguments("--app-image", appImageCmd.outputBundle()) + .mutate(sign::addTo); + + cmd.executeAndAssertHelloAppImageCreated(); + MacSignVerify.verifyAppImageSigned(cmd, sign.certRequest()); + } + } + + public static Collection test() { + + List data = new ArrayList<>(); + + for (var appImageSign : withAndWithout(SignKeyOption.Type.SIGN_KEY_IDENTITY)) { + var builder = TestSpec.build(); + appImageSign.ifPresent(signIdentityType -> { + // Sign the input app image bundle with the key not used in the jpackage command line being tested. + // This way we can test if jpackage keeps or replaces the signature of the input app image bundle. + builder.signIdentityType(signIdentityType) + .certRequest(SigningBase.StandardCertificateRequest.CODESIGN_ACME_TECH_LTD) + .signAppImage(); + }); + for (var signIdentityType : SignKeyOption.Type.defaultValues()) { + builder.signIdentityType(signIdentityType) + .certRequest(SigningBase.StandardCertificateRequest.CODESIGN); + data.add(builder.sign().create()); } } - // Add addtional launcher - AdditionalLauncher testAL = new AdditionalLauncher("testAL"); - testAL.applyTo(appImageCmd); + return data.stream().map(v -> { + return new Object[] {v}; + }).toList(); + } - // Generate app image - appImageCmd.executeAndAssertHelloAppImageCreated(); - - // Double check if it is signed or unsigned based on signAppImage - SigningBase.verifyAppImageSignature(appImageCmd, signAppImage, "testAL"); - - // Sign app image - JPackageCommand cmd = new JPackageCommand(); - cmd.setPackageType(PackageType.IMAGE) - .addArguments("--app-image", appImageCmd.outputBundle().toAbsolutePath()) - .addArguments("--mac-sign") - .addArguments("--mac-signing-keychain", keychain.name()); - if (signingKey) { - cmd.addArguments("--mac-signing-key-user-name", - SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); - } else { - cmd.addArguments("--mac-app-image-sign-identity", - SigningBase.getAppCert(SigningBase.DEFAULT_INDEX)); - } - cmd.executeAndAssertImageCreated(); - - // Should be signed app image - SigningBase.verifyAppImageSignature(appImageCmd, true, "testAL"); + private static List> withAndWithout(T value) { + return List.of(Optional.empty(), Optional.of(value)); } } diff --git a/test/jdk/tools/jpackage/macosx/SigningBase.java b/test/jdk/tools/jpackage/macosx/SigningBase.java new file mode 100644 index 00000000000..5f4367e6096 --- /dev/null +++ b/test/jdk/tools/jpackage/macosx/SigningBase.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2019, 2026, 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.security.cert.X509Certificate; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; +import jdk.jpackage.test.MacHelper.NamedCertificateRequestSupplier; +import jdk.jpackage.test.MacSign; +import jdk.jpackage.test.MacSign.CertificateRequest; +import jdk.jpackage.test.MacSign.CertificateType; +import jdk.jpackage.test.MacSign.KeychainWithCertsSpec; +import jdk.jpackage.test.MacSign.ResolvedKeychain; +import jdk.jpackage.test.TKit; + + +/* + * @test + * @summary Setup the environment for jpackage macos signing tests. + * Creates required keychains and signing identities. + * Does NOT run any jpackag tests. + * @library /test/jdk/tools/jpackage/helpers + * @build jdk.jpackage.test.* + * @compile -Xlint:all -Werror SigningBase.java + * @requires (jpackage.test.MacSignTests == "setup") + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=SigningBase.setUp + */ + +/* + * @test + * @summary Tear down the environment for jpackage macos signing tests. + * Deletes required keychains and signing identities. + * Does NOT run any jpackag tests. + * @library /test/jdk/tools/jpackage/helpers + * @build jdk.jpackage.test.* + * @compile -Xlint:all -Werror SigningBase.java + * @requires (jpackage.test.MacSignTests == "teardown") + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=SigningBase.tearDown + */ + +public class SigningBase { + + public enum StandardCertificateRequest implements NamedCertificateRequestSupplier { + CODESIGN(cert().userName(NAME_ASCII)), + CODESIGN_COPY(cert().days(100).userName(NAME_ASCII)), + CODESIGN_ACME_TECH_LTD(cert().days(100).userName("ACME Technologies Limited (ABC12345)")), + PKG(cert().type(CertificateType.INSTALLER).userName(NAME_ASCII)), + PKG_COPY(cert().type(CertificateType.INSTALLER).days(100).userName(NAME_ASCII)), + CODESIGN_UNICODE(cert().userName(NAME_UNICODE)), + PKG_UNICODE(cert().type(CertificateType.INSTALLER).userName(NAME_UNICODE)), + CODESIGN_EXPIRED(cert().expired().userName("expired jpackage test")), + PKG_EXPIRED(cert().expired().type(CertificateType.INSTALLER).userName("expired jpackage test")); + + StandardCertificateRequest(CertificateRequest.Builder specBuilder) { + this.spec = specBuilder.create(); + } + + @Override + public CertificateRequest certRequest() { + return spec; + } + + private static CertificateRequest.Builder cert() { + return new CertificateRequest.Builder(); + } + + private final CertificateRequest spec; + } + + /** + * Standard keychains used in signing tests. + */ + public enum StandardKeychain { + /** + * The primary keychain with good certificates. + */ + MAIN("jpackagerTest.keychain", + StandardCertificateRequest.CODESIGN, + StandardCertificateRequest.PKG, + StandardCertificateRequest.CODESIGN_UNICODE, + StandardCertificateRequest.PKG_UNICODE, + StandardCertificateRequest.CODESIGN_ACME_TECH_LTD), + /** + * A keychain with some good and some expired certificates. + */ + EXPIRED("jpackagerTest-expired.keychain", + StandardCertificateRequest.CODESIGN, + StandardCertificateRequest.PKG, + StandardCertificateRequest.CODESIGN_EXPIRED, + StandardCertificateRequest.PKG_EXPIRED), + /** + * A keychain with duplicated certificates. + */ + DUPLICATE("jpackagerTest-duplicate.keychain", + StandardCertificateRequest.CODESIGN, + StandardCertificateRequest.PKG, + StandardCertificateRequest.CODESIGN_COPY, + StandardCertificateRequest.PKG_COPY), + ; + + StandardKeychain(String keychainName, StandardCertificateRequest... certs) { + this(keychainName, + certs[0].certRequest(), + Stream.of(certs).skip(1).map(StandardCertificateRequest::certRequest).toArray(CertificateRequest[]::new)); + } + + StandardKeychain(String keychainName, CertificateRequest cert, CertificateRequest... otherCerts) { + final var builder = keychain(keychainName).addCert(cert); + List.of(otherCerts).forEach(builder::addCert); + this.keychain = new ResolvedKeychain(builder.create()); + } + + public ResolvedKeychain keychain() { + return keychain; + } + + public X509Certificate mapCertificateRequest(CertificateRequest certRequest) { + return Objects.requireNonNull(keychain.mapCertificateRequests().get(certRequest)); + } + + public boolean contains(StandardCertificateRequest certRequest) { + return keychain.spec().certificateRequests().contains(certRequest.spec); + } + + private static KeychainWithCertsSpec.Builder keychain(String name) { + return new KeychainWithCertsSpec.Builder().name(name); + } + + private static List signingEnv() { + return Stream.of(values()).map(StandardKeychain::keychain).map(ResolvedKeychain::spec).toList(); + } + + private final ResolvedKeychain keychain; + } + + public static void setUp() { + MacSign.setUp(StandardKeychain.signingEnv()); + } + + public static void tearDown() { + MacSign.tearDown(StandardKeychain.signingEnv()); + } + + public static void verifySignTestEnvReady() { + if (!Inner.SIGN_ENV_READY) { + TKit.throwSkippedException(new IllegalStateException("Misconfigured signing test environment")); + } + } + + private final class Inner { + private static final boolean SIGN_ENV_READY = MacSign.isDeployed(StandardKeychain.signingEnv()); + } + + private static final String NAME_ASCII = "jpackage.openjdk.java.net"; + private static final String NAME_UNICODE = "jpackage.openjdk.java.net (ö)"; +} diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java index b1e9155dacb..8a93ce5f749 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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,180 +21,247 @@ * questions. */ -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; - -import java.nio.file.Path; -import jdk.jpackage.test.Annotations.Parameter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.SequencedSet; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import jdk.jpackage.internal.util.function.ExceptionBox; +import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.ApplicationLayout; -import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.MacHelper; +import jdk.jpackage.test.MacHelper.ResolvableCertificateRequest; +import jdk.jpackage.test.MacHelper.SignKeyOption; import jdk.jpackage.test.MacSign; +import jdk.jpackage.test.MacSignVerify; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; /** - * Tests generation of dmg and pkg with --mac-sign and related arguments. - * Test will generate pkg and verifies its signature. It verifies that dmg - * is not signed, but app image inside dmg is signed. This test requires that - * the machine is configured with test certificate for - * "Developer ID Installer: jpackage.openjdk.java.net" in - * jpackagerTest keychain with - * always allowed access to this keychain for user which runs test. - * note: - * "jpackage.openjdk.java.net" can be over-ridden by system property - * "jpackage.mac.signing.key.user.name", and - * "jpackagerTest" can be over-ridden by system property - * "jpackage.mac.signing.keychain" + * Tests bundling of .pkg and .dmg packages with various signing options. + * + *

+ * Prerequisites: Keychains with self-signed certificates as specified in + * {@link SigningBase.StandardKeychain#MAIN} and + * {@link SigningBase.StandardKeychain#SINGLE}. */ + /* * @test * @summary jpackage with --type pkg,dmg --mac-sign * @library /test/jdk/tools/jpackage/helpers - * @library base * @key jpackagePlatformPackage - * @build SigningBase * @build jdk.jpackage.test.* - * @build SigningPackageTest + * @compile -Xlint:all -Werror SigningBase.java + * @compile -Xlint:all -Werror SigningPackageTest.java * @requires (jpackage.test.MacSignTests == "run") * @requires (jpackage.test.SQETest != null) * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main - * --jpt-run=SigningPackageTest - * --jpt-space-subst=* - * --jpt-include=SigningPackageTest.test(true,*true,*true,*ASCII_INDEX) - * --jpt-before-run=SigningBase.verifySignTestEnvReady + * --jpt-run=SigningPackageTest.test + * --jpt-space-subst=* + * --jpt-include=({--mac-signing-key-user-name:*CODESIGN},*{--mac-signing-key-user-name:*PKG},*MAC_DMG+MAC_PKG) + * --jpt-before-run=SigningBase.verifySignTestEnvReady */ /* * @test * @summary jpackage with --type pkg,dmg --mac-sign * @library /test/jdk/tools/jpackage/helpers - * @library base * @key jpackagePlatformPackage - * @build SigningBase * @build jdk.jpackage.test.* - * @build SigningPackageTest + * @compile -Xlint:all -Werror SigningBase.java + * @compile -Xlint:all -Werror SigningPackageTest.java * @requires (jpackage.test.MacSignTests == "run") * @requires (jpackage.test.SQETest == null) - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main - * --jpt-run=SigningPackageTest + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=SigningPackageTest.test * --jpt-before-run=SigningBase.verifySignTestEnvReady */ public class SigningPackageTest { - private static boolean isAppImageSigned(JPackageCommand cmd) { - return cmd.hasArgument("--mac-signing-key-user-name") || - cmd.hasArgument("--mac-app-image-sign-identity"); + @Test + @ParameterSupplier + public static void test(TestSpec spec) { + MacSign.withKeychain(_ -> { + spec.test(); + }, spec.keychain()); } - private static boolean isPKGSigned(JPackageCommand cmd) { - return cmd.hasArgument("--mac-signing-key-user-name") || - cmd.hasArgument("--mac-installer-sign-identity"); + public static Collection test() { + return TestSpec.testCases(true).stream().map(v -> { + return new Object[] {v}; + }).toList(); } - private static void verifyPKG(JPackageCommand cmd) { - Path outputBundle = cmd.outputBundle(); - SigningBase.verifyPkgutil(outputBundle, isPKGSigned(cmd), getCertIndex(cmd)); - if (isPKGSigned(cmd)) { - SigningBase.verifySpctl(outputBundle, "install", getCertIndex(cmd)); - } - } + record TestSpec( + Optional appImageSignOption, + Optional packageSignOption, + Set packageTypes) { - private static void verifyDMG(JPackageCommand cmd) { - Path outputBundle = cmd.outputBundle(); - SigningBase.verifyDMG(outputBundle); - } + TestSpec { + Objects.requireNonNull(appImageSignOption); + Objects.requireNonNull(packageSignOption); + Objects.requireNonNull(packageTypes); - private static void verifyAppImageInDMG(JPackageCommand cmd) { - MacHelper.withExplodedDmg(cmd, dmgImage -> { - Path launcherPath = ApplicationLayout.platformAppImage() - .resolveAt(dmgImage).launchersDirectory().resolve(cmd.name()); - // We will be called with all folders in DMG since JDK-8263155, but - // we only need to verify app. - if (dmgImage.endsWith(cmd.name() + ".app")) { - SigningBase.verifyCodesign(launcherPath, isAppImageSigned(cmd), - getCertIndex(cmd)); - SigningBase.verifyCodesign(dmgImage, isAppImageSigned(cmd), - getCertIndex(cmd)); - if (isAppImageSigned(cmd)) { - SigningBase.verifySpctl(dmgImage, "exec", getCertIndex(cmd)); + if (appImageSignOption.isEmpty() && packageSignOption.isEmpty()) { + // No signing. + throw new IllegalArgumentException(); + } + + if (packageTypes.isEmpty() || !PackageType.MAC.containsAll(packageTypes)) { + // Invalid package types. + throw new IllegalArgumentException(); + } + + if (packageSignOption.isPresent()) { + if (!packageTypes.contains(PackageType.MAC_PKG)) { + // .pkg installer should be signed, but .pkg type is missing. + throw new IllegalArgumentException(); + } + + if (appImageSignOption.isEmpty()) { + if (packageSignOption.get().type() != SignKeyOption.Type.SIGN_KEY_IDENTITY) { + // They request to sign the .pkg installer without + // the "--mac-installer-sign-identity" option, + // but didn't specify a signing option for the packaged app image. + // This is wrong because only the "--mac-installer-sign-identity" option + // allows signing a .pkg installer without signing its packaged app image. + throw new IllegalArgumentException(); + } + } else if (appImageSignOption.get().type() != packageSignOption.get().type()) { + // Signing option types should be the same. + throw new IllegalArgumentException(); } } - }); - } - private static int getCertIndex(JPackageCommand cmd) { - if (cmd.hasArgument("--mac-signing-key-user-name")) { - String devName = cmd.getArgumentValue("--mac-signing-key-user-name"); - return SigningBase.getDevNameIndex(devName); - } else { - // Signing-indentity - return SigningBase.CertIndex.UNICODE_INDEX.value(); + if (!(packageTypes instanceof SequencedSet)) { + packageTypes = new TreeSet<>(packageTypes); + } + } + + TestSpec( + Optional appImageSignOption, + Optional packageSignOption, + PackageType... packageTypes) { + this(appImageSignOption, packageSignOption, Set.of(packageTypes)); + } + + @Override + public String toString() { + return Stream.of( + signKeyOptions(), + Stream.of(packageTypes.stream().map(Object::toString).collect(Collectors.joining("+"))) + ).flatMap(x -> x).map(Object::toString).collect(Collectors.joining(", ")); + } + + Stream signKeyOptions() { + return Stream.concat(appImageSignOption.stream(), packageSignOption.stream()); + } + + Optional bundleSignIdentity(PackageType type) { + switch (type) { + case MAC_DMG -> { + return Optional.empty(); + } + case MAC_PKG -> { + return packageSignOption.map(SignKeyOption::certRequest); + } + default -> { + throw new IllegalArgumentException(); + } + } + } + + void test() { + initTest().configureHelloApp().addInstallVerifier(cmd -> { + appImageSignOption.map(SignKeyOption::certRequest).ifPresent(signIdentity -> { + MacSignVerify.verifyAppImageSigned(cmd, signIdentity); + }); + }).run(); + } + + PackageTest initTest() { + return new PackageTest().forTypes(packageTypes).mutate(test -> { + appImageSignOption.ifPresent(signOption -> { + test.addInitializer(signOption::setTo); + }); + packageSignOption.ifPresent(signOption -> { + test.forTypes(PackageType.MAC_PKG, () -> { + test.addInitializer(signOption::setTo); + }); + }); + }).addBundleVerifier(cmd -> { + bundleSignIdentity(cmd.packageType()).ifPresent(signIdentity -> { + MacSignVerify.verifyPkgSigned(cmd, signIdentity); + }); + }).addInitializer(MacHelper.useKeychain(keychain())::accept); + } + + MacSign.ResolvedKeychain keychain() { + return SigningBase.StandardKeychain.MAIN.keychain(); + } + + static List testCases(boolean withUnicode) { + + List data = new ArrayList<>(); + + List> certRequestGroups; + if (withUnicode) { + certRequestGroups = List.of( + List.of(SigningBase.StandardCertificateRequest.CODESIGN, SigningBase.StandardCertificateRequest.PKG), + List.of(SigningBase.StandardCertificateRequest.CODESIGN_UNICODE, SigningBase.StandardCertificateRequest.PKG_UNICODE) + ); + } else { + certRequestGroups = List.of( + List.of(SigningBase.StandardCertificateRequest.CODESIGN, SigningBase.StandardCertificateRequest.PKG) + ); + } + + for (var certRequests : certRequestGroups) { + for (var signIdentityType : SignKeyOption.Type.defaultValues()) { + var keychain = SigningBase.StandardKeychain.MAIN.keychain(); + var appImageSignKeyOption = new SignKeyOption(signIdentityType, certRequests.getFirst(), keychain); + var pkgSignKeyOption = new SignKeyOption(signIdentityType, certRequests.getLast(), keychain); + + switch (signIdentityType) { + case SIGN_KEY_IDENTITY -> { + // Use "--mac-installer-sign-identity" and "--mac-app-image-sign-identity" signing options. + // They allows to sign the packaged app image and the installer (.pkg) separately. + data.add(new TestSpec(Optional.of(appImageSignKeyOption), Optional.empty(), PackageType.MAC)); + data.add(new TestSpec(Optional.empty(), Optional.of(pkgSignKeyOption), PackageType.MAC_PKG)); + } + case SIGN_KEY_USER_SHORT_NAME -> { + // Use "--mac-signing-key-user-name" signing option with short user name or implicit signing option. + // It signs both the packaged app image and the installer (.pkg). + // Thus, if the installer is not signed, it can be used only with .dmg packaging. + data.add(new TestSpec(Optional.of(appImageSignKeyOption), Optional.empty(), PackageType.MAC_DMG)); + } + case SIGN_KEY_USER_FULL_NAME -> { + // Use "--mac-signing-key-user-name" signing option with the full user name. + // Like SIGN_KEY_USER_SHORT_NAME, jpackage will try to use it to sign both + // the packaged app image and the installer (.pkg). + // It will fail to sign the installer, though, because the signing identity is unsuitable. + // That is why, use it with .dmg packaging only and not with .pkg packaging. + data.add(new TestSpec(Optional.of(appImageSignKeyOption), Optional.empty(), PackageType.MAC_DMG)); + continue; + } + default -> { + // SignKeyOption.Type.defaultValues() should return + // such a sequence that makes this code location unreachable. + throw ExceptionBox.reachedUnreachable(); + } + } + data.add(new TestSpec(Optional.of(appImageSignKeyOption), Optional.of(pkgSignKeyOption), PackageType.MAC)); + } + } + + return data; } } - - @Test - // ("signing-key or sign-identity", "sign app-image", "sign pkg", "certificate index"}) - // Signing-key and ASCII certificate - @Parameter({"true", "true", "true", "ASCII_INDEX"}) - // Signing-key and UNICODE certificate - @Parameter({"true", "true", "true", "UNICODE_INDEX"}) - // Signing-indentity and UNICODE certificate - @Parameter({"false", "true", "true", "UNICODE_INDEX"}) - // Signing-indentity, but sign app-image only and UNICODE certificate - @Parameter({"false", "true", "false", "UNICODE_INDEX"}) - // Signing-indentity, but sign pkg only and UNICODE certificate - @Parameter({"false", "false", "true", "UNICODE_INDEX"}) - public static void test(boolean signingKey, boolean signAppImage, boolean signPKG, SigningBase.CertIndex certEnum) throws Exception { - MacSign.withKeychain(toConsumer(keychain -> { - test(keychain, signingKey, signAppImage, signPKG, certEnum); - }), SigningBase.StandardKeychain.MAIN.keychain()); - } - - private static void test(MacSign.ResolvedKeychain keychain, boolean signingKey, boolean signAppImage, boolean signPKG, SigningBase.CertIndex certEnum) throws Exception { - final var certIndex = certEnum.value(); - - new PackageTest() - .configureHelloApp() - .forTypes(PackageType.MAC) - .addInitializer(cmd -> { - cmd.addArguments("--mac-sign", - "--mac-signing-keychain", keychain.name()); - if (signingKey) { - cmd.addArguments("--mac-signing-key-user-name", - SigningBase.getDevName(certIndex)); - } else { - if (signAppImage) { - cmd.addArguments("--mac-app-image-sign-identity", - SigningBase.getAppCert(certIndex)); - } - if (signPKG) { - cmd.addArguments("--mac-installer-sign-identity", - SigningBase.getInstallerCert(certIndex)); - } - } - }) - .forTypes(PackageType.MAC_PKG) - .addBundleVerifier(SigningPackageTest::verifyPKG) - .forTypes(PackageType.MAC_DMG) - .addInitializer(cmd -> { - if (!signingKey) { - // jpackage throws expected error with - // --mac-installer-sign-identity and DMG type - cmd.removeArgumentWithValue("--mac-installer-sign-identity"); - // In case of not signing app image and DMG we need to - // remove signing completely, otherwise we will default - // to --mac-signing-key-user-name once - // --mac-installer-sign-identity is removed. - if (!signAppImage) { - cmd.removeArgumentWithValue("--mac-signing-keychain"); - cmd.removeArgument("--mac-sign"); - } - } - }) - .addBundleVerifier(SigningPackageTest::verifyDMG) - .addBundleVerifier(SigningPackageTest::verifyAppImageInDMG) - .run(); - } } diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java index 586d8d68444..70ec0e600de 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, 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,25 +21,22 @@ * questions. */ -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; - import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.SortedMap; -import java.util.TreeMap; +import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.CannedFormattedString; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageStringBundle; -import jdk.jpackage.test.MacHelper; +import jdk.jpackage.test.MacHelper.ResolvableCertificateRequest; import jdk.jpackage.test.MacHelper.SignKeyOption; +import jdk.jpackage.test.MacHelper.SignKeyOptionWithKeychain; import jdk.jpackage.test.MacSign; import jdk.jpackage.test.MacSignVerify; import jdk.jpackage.test.PackageFile; @@ -52,22 +49,23 @@ import jdk.jpackage.test.TKit; * signed/unsigned .pkg or .dmg package. * *

- * Prerequisites: A keychain with self-signed certificates as specified in - * {@link SigningBase.StandardKeychain#MAIN}. + * Prerequisites: Keychains with self-signed certificates as specified in + * {@link SigningBase.StandardKeychain#MAIN} and + * {@link SigningBase.StandardKeychain#SINGLE}. */ /* * @test * @summary jpackage with --type pkg,dmg --app-image * @library /test/jdk/tools/jpackage/helpers - * @library base * @key jpackagePlatformPackage - * @build SigningBase * @build jdk.jpackage.test.* - * @build SigningPackageTwoStepTest + * @compile -Xlint:all -Werror SigningBase.java + * @compile -Xlint:all -Werror SigningPackageTest.java + * @compile -Xlint:all -Werror SigningPackageTwoStepTest.java * @requires (jpackage.test.MacSignTests == "run") * @requires (jpackage.test.SQETest == null) - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningPackageTwoStepTest * --jpt-before-run=SigningBase.verifySignTestEnvReady */ @@ -75,176 +73,148 @@ public class SigningPackageTwoStepTest { @Test @ParameterSupplier - public static void test(TestSpec spec) { - MacSign.withKeychain(toConsumer(keychain -> { - spec.test(keychain); - }), SigningBase.StandardKeychain.MAIN.keychain()); + public static void test(TwoStepsTestSpec spec) { + spec.test(); } - public record TestSpec(Optional signAppImage, Map signPackage) { + @Test + public static void testBundleSignedAppImage() { - public TestSpec { - Objects.requireNonNull(signAppImage); - Objects.requireNonNull(signPackage); + var appImageCmd = JPackageCommand.helloAppImage(); - if ((signAppImage.isEmpty() && signPackage.isEmpty()) || !PackageType.MAC.containsAll(signPackage.keySet())) { - // Unexpected package types. - throw new IllegalArgumentException(); - } + var predefinedAppImageSignOption = predefinedAppImageSignOption(); - // Ensure stable result of toString() call. - if (!SortedMap.class.isInstance(signPackage)) { - signPackage = new TreeMap<>(signPackage); - } - } - - @Override - public String toString() { - var sb = new StringBuilder(); - - signAppImage.ifPresent(signOption -> { - sb.append(String.format("app-image=%s", signOption)); - }); - - if (!sb.isEmpty() && !signPackage.isEmpty()) { - sb.append("; "); - } - - if (!signPackage.isEmpty()) { - sb.append(signPackage); - } - - return sb.toString(); - } - - boolean signNativeBundle() { - return signPackage.isEmpty(); - } - - static Builder build() { - return new Builder(); - } - - static class Builder { - - TestSpec create() { - return new TestSpec(Optional.ofNullable(signAppImage), signPackage); - } - - Builder certRequest(SigningBase.StandardCertificateRequest v) { - return certRequest(v.spec()); - } - - Builder certRequest(MacSign.CertificateRequest v) { - certRequest = Objects.requireNonNull(v); - return this; - } - - Builder signIdentityType(SignKeyOption.Type v) { - signIdentityType = Objects.requireNonNull(v); - return this; - } - - Builder signAppImage() { - signAppImage = createSignKeyOption(); - return this; - } - - Builder signPackage(PackageType type) { - Objects.requireNonNull(type); - signPackage.put(type, createSignKeyOption()); - return this; - } - - Builder signPackage() { - PackageType.MAC.forEach(this::signPackage); - return this; - } - - private SignKeyOption createSignKeyOption() { - return new SignKeyOption(signIdentityType, certRequest); - } - - private MacSign.CertificateRequest certRequest = SigningBase.StandardCertificateRequest.CODESIGN.spec(); - private SignKeyOption.Type signIdentityType = SignKeyOption.Type.SIGN_KEY_IDENTITY; - - private SignKeyOption signAppImage; - private Map signPackage = new HashMap<>(); - } - - void test(MacSign.ResolvedKeychain keychain) { - - var appImageCmd = JPackageCommand.helloAppImage().setFakeRuntime(); - MacHelper.useKeychain(appImageCmd, keychain); - signAppImage.ifPresent(signOption -> { - signOption.setTo(appImageCmd); - }); - - var test = new PackageTest(); - - signAppImage.map(SignKeyOption::certRequest).ifPresent(certRequest -> { - // The predefined app image is signed, verify bundled app image is signed too. - test.addInstallVerifier(cmd -> { - MacSignVerify.verifyAppImageSigned(cmd, certRequest, keychain); - }); - }); - - Optional.ofNullable(signPackage.get(PackageType.MAC_PKG)).map(SignKeyOption::certRequest).ifPresent(certRequest -> { - test.forTypes(PackageType.MAC_PKG, () -> { - test.addBundleVerifier(cmd -> { - MacSignVerify.verifyPkgSigned(cmd, certRequest, keychain); - }); - }); - }); - - test.forTypes(signPackage.keySet()).addRunOnceInitializer(() -> { - appImageCmd.setArgumentValue("--dest", TKit.createTempDirectory("appimage")).execute(0); - }).usePredefinedAppImage(appImageCmd).addInitializer(cmd -> { - MacHelper.useKeychain(cmd, keychain); - Optional.ofNullable(signPackage.get(cmd.packageType())).ifPresent(signOption -> { - signOption.setTo(cmd); - }); - - if (signAppImage.isPresent()) { - // Predefined app image is signed. Expect a warning. - cmd.validateOutput(JPackageStringBundle.MAIN.cannedFormattedString( - "warning.per.user.app.image.signed", - PackageFile.getPathInAppImage(Path.of("")))); - } else if (cmd.packageType() == PackageType.MAC_PKG && signPackage.containsKey(cmd.packageType())) { - // Create signed ".pkg" bundle from the unsigned predefined app image. Expect a warning. - cmd.validateOutput(JPackageStringBundle.MAIN.cannedFormattedString("warning.unsigned.app.image", "pkg")); - } - }) - .run(); - } + new PackageTest().addRunOnceInitializer(() -> { + createPredefinedAppImage(appImageCmd, Optional.of(predefinedAppImageSignOption)); + }).usePredefinedAppImage(appImageCmd).addInitializer(cmd -> { + configureOutputValidator(cmd, true, false); + }).addInstallVerifier(cmd -> { + MacSignVerify.verifyAppImageSigned(cmd, predefinedAppImageSignOption.certRequest()); + }).run(); } public static Collection test() { - List data = new ArrayList<>(); + List data = new ArrayList<>(); - Stream.of(SignKeyOption.Type.values()).flatMap(signIdentityType -> { - return Stream.of( - // Sign both predefined app image and native package. - TestSpec.build().signIdentityType(signIdentityType) - .signAppImage() - .signPackage() - .certRequest(SigningBase.StandardCertificateRequest.PKG) - .signPackage(PackageType.MAC_PKG), + for (var signAppImage : List.of(true, false)) { + Optional appImageSignOption; + if (signAppImage) { + // Sign the predefined app image bundle with the key not used in the jpackage command line being tested. + // This way we can test if jpackage keeps or replaces the signature of + // the predefined app image bundle when backing it in the pkg or dmg installer. + appImageSignOption = Optional.of(predefinedAppImageSignOption()); + } else { + appImageSignOption = Optional.empty(); + } - // Don't sign predefined app image, sign native package. - TestSpec.build().signIdentityType(signIdentityType) - .signPackage() - .certRequest(SigningBase.StandardCertificateRequest.PKG) - .signPackage(PackageType.MAC_PKG), + for (var signPackage : SigningPackageTest.TestSpec.testCases(false)) { + data.add(new TwoStepsTestSpec(appImageSignOption, signPackage)); + } + } - // Sign predefined app image, don't sign native package. - TestSpec.build().signIdentityType(signIdentityType).signAppImage() - ); - }).forEach(data::add); - - return data.stream().map(TestSpec.Builder::create).map(v -> { + return data.stream().map(v -> { return new Object[] {v}; }).toList(); } + + record TwoStepsTestSpec(Optional signAppImage, SigningPackageTest.TestSpec signPackage) { + + TwoStepsTestSpec { + Objects.requireNonNull(signAppImage); + Objects.requireNonNull(signPackage); + } + + @Override + public String toString() { + return Stream.of( + String.format("app-image=%s", signAppImage.map(Objects::toString).orElse("unsigned")), + signPackage.toString() + ).collect(Collectors.joining("; ")); + } + + Optional packagedAppImageSignIdentity() { + return signAppImage.map(SignKeyOptionWithKeychain::certRequest); + } + + void test() { + + var appImageCmd = JPackageCommand.helloAppImage(); + + var test = signPackage.initTest().addRunOnceInitializer(() -> { + createPredefinedAppImage(appImageCmd, signAppImage); + }).usePredefinedAppImage(appImageCmd).addInitializer(cmd -> { + configureOutputValidator(cmd, + signAppImage.isPresent(), + (cmd.packageType() == PackageType.MAC_PKG) && signPackage.packageSignOption().isPresent()); + }).addInstallVerifier(cmd -> { + packagedAppImageSignIdentity().ifPresent(certRequest -> { + MacSignVerify.verifyAppImageSigned(cmd, certRequest); + }); + }); + + MacSign.withKeychain(_ -> { + test.run(); + }, signPackage.keychain()); + } + } + + private static SignKeyOptionWithKeychain predefinedAppImageSignOption() { + // Sign the predefined app image bundle with the key not used in the jpackage command line being tested. + // This way we can test if jpackage keeps or replaces the signature of the input app image bundle. + return new SignKeyOptionWithKeychain( + SignKeyOption.Type.SIGN_KEY_USER_SHORT_NAME, + SigningBase.StandardCertificateRequest.CODESIGN_ACME_TECH_LTD, + SigningBase.StandardKeychain.MAIN.keychain()); + } + + private static void createPredefinedAppImage(JPackageCommand appImageCmd, Optional signAppImage) { + Objects.requireNonNull(appImageCmd); + Objects.requireNonNull(signAppImage); + + appImageCmd.setFakeRuntime().setArgumentValue("--dest", TKit.createTempDirectory("appimage")); + + signAppImage.ifPresentOrElse(signOption -> { + signOption.setTo(appImageCmd); + + MacSign.withKeychain(_ -> { + appImageCmd.execute(0); + }, signOption.keychain()); + + // Verify that the predefined app image is signed. + MacSignVerify.verifyAppImageSigned(appImageCmd, signOption.certRequest()); + }, () -> { + appImageCmd.execute(0); + }); + } + + private static void configureOutputValidator(JPackageCommand cmd, boolean signAppImage, boolean signPackage) { + var signedPredefinedAppImageWarning = JPackageStringBundle.MAIN.cannedFormattedString( + "warning.per.user.app.image.signed", + PackageFile.getPathInAppImage(Path.of(""))); + + var signedInstallerFromUnsignedPredefinedAppImageWarning = + JPackageStringBundle.MAIN.cannedFormattedString("warning.unsigned.app.image", "pkg"); + + // The warnings are mutually exclusive + final Optional expected; + final List unexpected = new ArrayList<>(); + + if (signAppImage) { + expected = Optional.of(signedPredefinedAppImageWarning); + } else { + unexpected.add(signedPredefinedAppImageWarning); + if (signPackage) { + expected = Optional.of(signedInstallerFromUnsignedPredefinedAppImageWarning); + } else { + expected = Optional.empty(); + unexpected.add(signedInstallerFromUnsignedPredefinedAppImageWarning); + } + } + + expected.ifPresent(cmd::validateOutput); + unexpected.forEach(str -> { + cmd.validateOutput(TKit.assertTextStream(cmd.getValue(str)).negate()); + }); + } } diff --git a/test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java b/test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java index ccc39f7a367..604399ebd7a 100644 --- a/test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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,17 +21,31 @@ * questions. */ -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; +import static jdk.jpackage.test.JPackageCommand.RuntimeImageType.RUNTIME_TYPE_FAKE; import java.nio.file.Path; -import java.util.function.Predicate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.internal.util.MacBundle; +import jdk.jpackage.internal.util.Slot; +import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.MacHelper; +import jdk.jpackage.test.MacHelper.ResolvableCertificateRequest; +import jdk.jpackage.test.MacHelper.SignKeyOption; +import jdk.jpackage.test.MacHelper.SignKeyOptionWithKeychain; import jdk.jpackage.test.MacSign; +import jdk.jpackage.test.MacSignVerify; +import jdk.jpackage.test.MacSignVerify.SpctlType; import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.TKit; /** * Tests generation of dmg and pkg with --mac-sign and related arguments. Test @@ -43,126 +57,182 @@ import jdk.jpackage.test.PackageTest; * app image signing and it will be covered by SigningPackageTest. * *

- * Following combinations are tested: - *

    - *
  1. "--runtime-image" points to unsigned JDK bundle and --mac-sign is not - * provided. Expected result: runtime image ad-hoc signed. - *
  2. "--runtime-image" points to unsigned JDK bundle and --mac-sign is - * provided. Expected result: Everything is signed with provided certificate. - *
  3. "--runtime-image" points to signed JDK bundle and --mac-sign is not - * provided. Expected result: runtime image is signed with original certificate. - *
  4. "--runtime-image" points to signed JDK bundle and --mac-sign is provided. - * Expected result: runtime image is signed with provided certificate. - *
  5. "--runtime-image" points to JDK image and --mac-sign is not provided. - * Expected result: runtime image ad-hoc signed. - *
  6. "--runtime-image" points to JDK image and --mac-sign is provided. - * Expected result: Everything is signed with provided certificate. - *
- * - * This test requires that the machine is configured with test certificate for - * "Developer ID Installer: jpackage.openjdk.java.net" in jpackagerTest keychain - * with always allowed access to this keychain for user which runs test. note: - * "jpackage.openjdk.java.net" can be over-ridden by system property - * "jpackage.mac.signing.key.user.name" + * Prerequisites: Keychains with self-signed certificates as specified in + * {@link SigningBase.StandardKeychain#MAIN} and + * {@link SigningBase.StandardKeychain#SINGLE}. */ /* * @test * @summary jpackage with --type pkg,dmg --runtime-image --mac-sign * @library /test/jdk/tools/jpackage/helpers - * @library base * @key jpackagePlatformPackage - * @build SigningBase * @build jdk.jpackage.test.* - * @build SigningRuntimeImagePackageTest + * @compile -Xlint:all -Werror SigningBase.java + * @compile -Xlint:all -Werror SigningPackageTest.java + * @compile -Xlint:all -Werror SigningRuntimeImagePackageTest.java * @requires (jpackage.test.MacSignTests == "run") * @requires (jpackage.test.SQETest == null) - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningRuntimeImagePackageTest * --jpt-before-run=SigningBase.verifySignTestEnvReady */ public class SigningRuntimeImagePackageTest { - private static JPackageCommand addSignOptions(JPackageCommand cmd, MacSign.ResolvedKeychain keychain, int certIndex) { - if (certIndex != SigningBase.CertIndex.INVALID_INDEX.value()) { - cmd.addArguments( - "--mac-sign", - "--mac-signing-keychain", keychain.name(), - "--mac-signing-key-user-name", SigningBase.getDevName(certIndex)); - } - return cmd; - } - - private static Path createInputRuntimeBundle(MacSign.ResolvedKeychain keychain, int certIndex) { - return MacHelper.createRuntimeBundle(cmd -> { - addSignOptions(cmd, keychain, certIndex); - }); + @Test + @ParameterSupplier + public static void test(RuntimeTestSpec spec) { + spec.test(); } @Test - // useJDKBundle - If "true" predefined runtime image will be converted to - // JDK bundle. If "false" JDK image will be used. - // JDKBundleCert - Certificate to sign JDK bundle before calling jpackage. - // signCert - Certificate to sign bundle produced by jpackage. - // 1) unsigned JDK bundle and --mac-sign is not provided - @Parameter({"true", "INVALID_INDEX", "INVALID_INDEX"}) - // 2) unsigned JDK bundle and --mac-sign is provided - @Parameter({"true", "INVALID_INDEX", "ASCII_INDEX"}) - // 3) signed JDK bundle and --mac-sign is not provided - @Parameter({"true", "UNICODE_INDEX", "INVALID_INDEX"}) - // 4) signed JDK bundle and --mac-sign is provided - @Parameter({"true", "UNICODE_INDEX", "ASCII_INDEX"}) - // 5) JDK image and --mac-sign is not provided - @Parameter({"false", "INVALID_INDEX", "INVALID_INDEX"}) - // 6) JDK image and --mac-sign is provided - @Parameter({"false", "INVALID_INDEX", "ASCII_INDEX"}) - public static void test(boolean useJDKBundle, - SigningBase.CertIndex jdkBundleCert, - SigningBase.CertIndex signCert) throws Exception { - MacSign.withKeychain(toConsumer(keychain -> { - test(keychain, useJDKBundle, jdkBundleCert, signCert); - }), SigningBase.StandardKeychain.MAIN.keychain()); + public static void testBundleSignedRuntime() { + + Slot predefinedRuntime = Slot.createEmpty(); + + var signRuntime = runtimeImageSignOption(); + + new PackageTest().addRunOnceInitializer(() -> { + predefinedRuntime.set(createRuntime(Optional.of(signRuntime), RuntimeType.BUNDLE)); + }).addInitializer(cmd -> { + cmd.ignoreDefaultRuntime(true); + cmd.removeArgumentWithValue("--input"); + cmd.setArgumentValue("--runtime-image", predefinedRuntime.get()); + }).addInstallVerifier(cmd -> { + MacSignVerify.verifyAppImageSigned(cmd, signRuntime.certRequest()); + }).run(); } - private static void test(MacSign.ResolvedKeychain keychain, boolean useJDKBundle, - SigningBase.CertIndex jdkBundleCert, - SigningBase.CertIndex signCert) throws Exception { + public static Collection test() { - final Path inputRuntime[] = new Path[1]; + List data = new ArrayList<>(); - new PackageTest() - .addRunOnceInitializer(() -> { - if (useJDKBundle) { - inputRuntime[0] = createInputRuntimeBundle(keychain, jdkBundleCert.value()); - } else { - inputRuntime[0] = JPackageCommand.createInputRuntimeImage(); - } - }) - .addInitializer(cmd -> { - cmd.addArguments("--runtime-image", inputRuntime[0]); - // Remove --input parameter from jpackage command line as we don't - // create input directory in the test and jpackage fails - // if --input references non existent directory. - cmd.removeArgumentWithValue("--input"); - addSignOptions(cmd, keychain, signCert.value()); - }) - .addInstallVerifier(cmd -> { - final var certIndex = Stream.of(signCert, jdkBundleCert) - .filter(Predicate.isEqual(SigningBase.CertIndex.INVALID_INDEX).negate()) - .findFirst().orElse(SigningBase.CertIndex.INVALID_INDEX).value(); + for (var runtimeSpec : List.of( + Map.entry(RuntimeType.IMAGE, false /* unsigned */), + Map.entry(RuntimeType.BUNDLE, false /* unsigned */), + Map.entry(RuntimeType.BUNDLE, true /* signed */) + )) { + var runtimeType = runtimeSpec.getKey(); + var signRuntime = runtimeSpec.getValue(); - final var signed = certIndex != SigningBase.CertIndex.INVALID_INDEX.value(); + Optional runtimeSignOption; + if (signRuntime) { + // Sign the runtime bundle with the key not used in the jpackage command line being tested. + // This way we can test if jpackage keeps or replaces the signature of + // the predefined runtime bundle when backing it in the pkg or dmg installer. + runtimeSignOption = Optional.of(runtimeImageSignOption()); + } else { + runtimeSignOption = Optional.empty(); + } - final var unfoldedBundleDir = cmd.appRuntimeDirectory(); + for (var signPackage : SigningPackageTest.TestSpec.testCases(false)) { + data.add(new RuntimeTestSpec(runtimeSignOption, runtimeType, signPackage)); + } + } - final var libjli = unfoldedBundleDir.resolve("Contents/MacOS/libjli.dylib"); + return data.stream().map(v -> { + return new Object[] {v}; + }).toList(); + } - SigningBase.verifyCodesign(libjli, signed, certIndex); - SigningBase.verifyCodesign(unfoldedBundleDir, signed, certIndex); - if (signed) { - SigningBase.verifySpctl(unfoldedBundleDir, "exec", certIndex); - } - }) - .run(); + enum RuntimeType { + IMAGE, + BUNDLE, + ; + } + + record RuntimeTestSpec( + Optional signRuntime, + RuntimeType runtimeType, + SigningPackageTest.TestSpec signPackage) { + + RuntimeTestSpec { + Objects.requireNonNull(signRuntime); + Objects.requireNonNull(runtimeType); + Objects.requireNonNull(signPackage); + } + + @Override + public String toString() { + var runtimeToken = new StringBuilder(); + runtimeToken.append("runtime={").append(runtimeType); + signRuntime.ifPresent(v -> { + runtimeToken.append(", ").append(v); + }); + runtimeToken.append('}'); + return Stream.of(runtimeToken, signPackage).map(Objects::toString).collect(Collectors.joining("; ")); + } + + Optional packagedAppImageSignIdentity() { + if (runtimeType == RuntimeType.IMAGE) { + return signPackage.appImageSignOption().map(SignKeyOption::certRequest); + } else { + return signPackage.appImageSignOption().or(() -> { + return signRuntime.map(SignKeyOptionWithKeychain::signKeyOption); + }).map(SignKeyOption::certRequest); + } + } + + void test() { + + Slot predefinedRuntime = Slot.createEmpty(); + + var test = signPackage.initTest().addRunOnceInitializer(() -> { + predefinedRuntime.set(createRuntime(signRuntime, runtimeType)); + }).addInitializer(cmd -> { + cmd.ignoreDefaultRuntime(true); + cmd.removeArgumentWithValue("--input"); + cmd.setArgumentValue("--runtime-image", predefinedRuntime.get()); + }).addInstallVerifier(cmd -> { + packagedAppImageSignIdentity().ifPresent(certRequest -> { + MacSignVerify.verifyAppImageSigned(cmd, certRequest); + }); + }); + + MacSign.withKeychain(_ -> { + test.run(); + }, signPackage.keychain()); + } + } + + private static SignKeyOptionWithKeychain runtimeImageSignOption() { + // Sign the runtime bundle with the key not used in the jpackage command line being tested. + // This way we can test if jpackage keeps or replaces the signature of + // the predefined runtime bundle when backing it in the pkg or dmg installer. + return new SignKeyOptionWithKeychain( + SignKeyOption.Type.SIGN_KEY_USER_SHORT_NAME, + SigningBase.StandardCertificateRequest.CODESIGN_ACME_TECH_LTD, + SigningBase.StandardKeychain.MAIN.keychain()); + } + + private static Path createRuntime(Optional signRuntime, RuntimeType runtimeType) { + if (runtimeType == RuntimeType.IMAGE && signRuntime.isEmpty()) { + return JPackageCommand.createInputRuntimeImage(RUNTIME_TYPE_FAKE); + } else { + Slot runtimeBundle = Slot.createEmpty(); + + MacSign.withKeychain(keychain -> { + var runtimeBundleBuilder = MacHelper.buildRuntimeBundle(); + signRuntime.ifPresent(signingOption -> { + runtimeBundleBuilder.mutator(signingOption::setTo); + }); + runtimeBundle.set(runtimeBundleBuilder.type(RUNTIME_TYPE_FAKE).create()); + }, SigningBase.StandardKeychain.MAIN.keychain()); + + if (runtimeType == RuntimeType.IMAGE) { + return MacBundle.fromPath(runtimeBundle.get()).orElseThrow().homeDir(); + } else { + // Verify the runtime bundle is properly signed/unsigned. + signRuntime.map(SignKeyOptionWithKeychain::certRequest).ifPresentOrElse(certRequest -> { + MacSignVerify.assertSigned(runtimeBundle.get(), certRequest); + var signOrigin = MacSignVerify.findSpctlSignOrigin(SpctlType.EXEC, runtimeBundle.get()).orElse(null); + TKit.assertEquals(certRequest.name(), signOrigin, + String.format("Check [%s] has sign origin as expected", runtimeBundle.get())); + }, () -> { + MacSignVerify.assertAdhocSigned(runtimeBundle.get()); + }); + return runtimeBundle.get(); + } + } } } diff --git a/test/jdk/tools/jpackage/macosx/base/SigningBase.java b/test/jdk/tools/jpackage/macosx/base/SigningBase.java deleted file mode 100644 index b1a709c9cf0..00000000000 --- a/test/jdk/tools/jpackage/macosx/base/SigningBase.java +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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.nio.file.Path; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.stream.Stream; -import jdk.jpackage.test.JPackageCommand; -import jdk.jpackage.test.MacSign; -import jdk.jpackage.test.MacSign.CertificateRequest; -import jdk.jpackage.test.MacSign.CertificateType; -import jdk.jpackage.test.MacSign.KeychainWithCertsSpec; -import jdk.jpackage.test.MacSign.ResolvedKeychain; -import jdk.jpackage.test.MacSignVerify; -import jdk.jpackage.test.TKit; - - -/* - * @test - * @summary Setup the environment for jpackage macos signing tests. - * Creates required keychains and signing identities. - * Does NOT run any jpackag tests. - * @library /test/jdk/tools/jpackage/helpers - * @build jdk.jpackage.test.* - * @compile -Xlint:all -Werror SigningBase.java - * @requires (jpackage.test.MacSignTests == "setup") - * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main - * --jpt-run=SigningBase.setUp - */ - -/* - * @test - * @summary Tear down the environment for jpackage macos signing tests. - * Deletes required keychains and signing identities. - * Does NOT run any jpackag tests. - * @library /test/jdk/tools/jpackage/helpers - * @build jdk.jpackage.test.* - * @compile -Xlint:all -Werror SigningBase.java - * @requires (jpackage.test.MacSignTests == "teardown") - * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main - * --jpt-run=SigningBase.tearDown - */ - -public class SigningBase { - - public enum StandardCertificateRequest { - CODESIGN(cert().userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), - CODESIGN_COPY(cert().days(100).userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), - CODESIGN_ACME_TECH_LTD(cert().days(100).userName("ACME Technologies Limited (ABC12345)")), - PKG(cert().type(CertificateType.INSTALLER).userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), - PKG_COPY(cert().type(CertificateType.INSTALLER).days(100).userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), - CODESIGN_UNICODE(cert().userName(DEV_NAMES[CertIndex.UNICODE_INDEX.value()])), - PKG_UNICODE(cert().type(CertificateType.INSTALLER).userName(DEV_NAMES[CertIndex.UNICODE_INDEX.value()])), - CODESIGN_EXPIRED(cert().expired().userName("expired jpackage test")), - PKG_EXPIRED(cert().expired().type(CertificateType.INSTALLER).userName("expired jpackage test")); - - StandardCertificateRequest(CertificateRequest.Builder specBuilder) { - this.spec = specBuilder.create(); - } - - public CertificateRequest spec() { - return spec; - } - - private static CertificateRequest.Builder cert() { - return new CertificateRequest.Builder(); - } - - private final CertificateRequest spec; - } - - /** - * Standard keychains used in signing tests. - */ - public enum StandardKeychain { - /** - * The primary keychain with good certificates. - */ - MAIN("jpackagerTest.keychain", - StandardCertificateRequest.CODESIGN, - StandardCertificateRequest.PKG, - StandardCertificateRequest.CODESIGN_UNICODE, - StandardCertificateRequest.PKG_UNICODE, - StandardCertificateRequest.CODESIGN_ACME_TECH_LTD), - /** - * A keychain with some good and some expired certificates. - */ - EXPIRED("jpackagerTest-expired.keychain", - StandardCertificateRequest.CODESIGN, - StandardCertificateRequest.PKG, - StandardCertificateRequest.CODESIGN_EXPIRED, - StandardCertificateRequest.PKG_EXPIRED), - /** - * A keychain with duplicated certificates. - */ - DUPLICATE("jpackagerTest-duplicate.keychain", - StandardCertificateRequest.CODESIGN, - StandardCertificateRequest.PKG, - StandardCertificateRequest.CODESIGN_COPY, - StandardCertificateRequest.PKG_COPY); - - StandardKeychain(String keychainName, StandardCertificateRequest... certs) { - this(keychainName, certs[0].spec(), Stream.of(certs).skip(1).map(StandardCertificateRequest::spec).toArray(CertificateRequest[]::new)); - } - - StandardKeychain(String keychainName, CertificateRequest cert, CertificateRequest... otherCerts) { - final var builder = keychain(keychainName).addCert(cert); - List.of(otherCerts).forEach(builder::addCert); - this.keychain = new ResolvedKeychain(builder.create()); - } - - public ResolvedKeychain keychain() { - return keychain; - } - - public X509Certificate mapCertificateRequest(CertificateRequest certRequest) { - return Objects.requireNonNull(keychain.mapCertificateRequests().get(certRequest)); - } - - private static KeychainWithCertsSpec.Builder keychain(String name) { - return new KeychainWithCertsSpec.Builder().name(name); - } - - private static List signingEnv() { - return Stream.of(values()).map(StandardKeychain::keychain).map(ResolvedKeychain::spec).toList(); - } - - private final ResolvedKeychain keychain; - } - - public static void setUp() { - MacSign.setUp(StandardKeychain.signingEnv()); - } - - public static void tearDown() { - MacSign.tearDown(StandardKeychain.signingEnv()); - } - - public static void verifySignTestEnvReady() { - if (!Inner.SIGN_ENV_READY) { - TKit.throwSkippedException(new IllegalStateException("Misconfigured signing test environment")); - } - } - - private final class Inner { - private static final boolean SIGN_ENV_READY = MacSign.isDeployed(StandardKeychain.signingEnv()); - } - - enum CertIndex { - ASCII_INDEX(0), - UNICODE_INDEX(1), - INVALID_INDEX(-1); - - CertIndex(int value) { - this.value = value; - } - - int value() { - return value; - } - - private final int value; - } - - public static int DEFAULT_INDEX = 0; - private static String [] DEV_NAMES = { - "jpackage.openjdk.java.net", - "jpackage.openjdk.java.net (ö)", - }; - - public static String getDevName(int certIndex) { - // Always use values from system properties if set - String value = System.getProperty("jpackage.mac.signing.key.user.name"); - if (value != null) { - return value; - } - - return DEV_NAMES[certIndex]; - } - - public static int getDevNameIndex(String devName) { - return Arrays.binarySearch(DEV_NAMES, devName); - } - - public static String getAppCert(int certIndex) { - return "Developer ID Application: " + getDevName(certIndex); - } - - public static String getInstallerCert(int certIndex) { - return "Developer ID Installer: " + getDevName(certIndex); - } - - public static void verifyCodesign(Path target, boolean signed, int certIndex) { - if (signed) { - final var certRequest = getCertRequest(certIndex); - MacSignVerify.assertSigned(target, certRequest); - } else { - MacSignVerify.assertAdhocSigned(target); - } - } - - // Since we no longer have unsigned app image, but we need to check - // DMG which is not adhoc or certificate signed and we cannot use verifyCodesign - // for this. verifyDMG() is introduced to check that DMG is unsigned. - // Should not be used to validated anything else. - public static void verifyDMG(Path target) { - if (!target.toString().toLowerCase().endsWith(".dmg")) { - throw new IllegalArgumentException("Unexpected target: " + target); - } - - MacSignVerify.assertUnsigned(target); - } - - public static void verifySpctl(Path target, String type, int certIndex) { - final var standardCertIndex = Stream.of(CertIndex.values()).filter(v -> { - return v.value() == certIndex; - }).findFirst().orElseThrow(); - - final var standardType = Stream.of(MacSignVerify.SpctlType.values()).filter(v -> { - return v.value().equals(type); - }).findFirst().orElseThrow(); - - final String expectedSignOrigin; - if (standardCertIndex == CertIndex.INVALID_INDEX) { - expectedSignOrigin = null; - } else if (standardType == MacSignVerify.SpctlType.EXEC) { - expectedSignOrigin = getCertRequest(certIndex).name(); - } else if (standardType == MacSignVerify.SpctlType.INSTALL) { - expectedSignOrigin = getPkgCertRequest(certIndex).name(); - } else { - throw new IllegalArgumentException(); - } - - final var signOrigin = MacSignVerify.findSpctlSignOrigin(standardType, target).orElse(null); - - TKit.assertEquals(signOrigin, expectedSignOrigin, - String.format("Check [%s] has sign origin as expected", target)); - } - - public static void verifyPkgutil(Path target, boolean signed, int certIndex) { - if (signed) { - final var certRequest = getPkgCertRequest(certIndex); - MacSignVerify.assertPkgSigned(target, certRequest, StandardKeychain.MAIN.mapCertificateRequest(certRequest)); - } else { - MacSignVerify.assertUnsigned(target); - } - } - - public static void verifyAppImageSignature(JPackageCommand appImageCmd, - boolean isSigned, String... launchers) throws Exception { - Path launcherPath = appImageCmd.appLauncherPath(); - SigningBase.verifyCodesign(launcherPath, isSigned, SigningBase.DEFAULT_INDEX); - - final List launchersList = List.of(launchers); - launchersList.forEach(launcher -> { - Path testALPath = launcherPath.getParent().resolve(launcher); - SigningBase.verifyCodesign(testALPath, isSigned, SigningBase.DEFAULT_INDEX); - }); - - Path appImage = appImageCmd.outputBundle(); - SigningBase.verifyCodesign(appImage, isSigned, SigningBase.DEFAULT_INDEX); - if (isSigned) { - SigningBase.verifySpctl(appImage, "exec", SigningBase.DEFAULT_INDEX); - } - } - - private static CertificateRequest getCertRequest(int certIndex) { - switch (CertIndex.values()[certIndex]) { - case ASCII_INDEX -> { - return StandardCertificateRequest.CODESIGN.spec(); - } - case UNICODE_INDEX -> { - return StandardCertificateRequest.CODESIGN_UNICODE.spec(); - } - default -> { - throw new IllegalArgumentException(); - } - } - } - - private static CertificateRequest getPkgCertRequest(int certIndex) { - switch (CertIndex.values()[certIndex]) { - case ASCII_INDEX -> { - return StandardCertificateRequest.PKG.spec(); - } - case UNICODE_INDEX -> { - return StandardCertificateRequest.PKG_UNICODE.spec(); - } - default -> { - throw new IllegalArgumentException(); - } - } - } -} From 0dd5b59194f32f54c2ec6572833f45e1402515ba Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Sat, 17 Jan 2026 04:30:02 +0000 Subject: [PATCH 068/328] 8375370: XRBackendNative.c reported variable uninitialized by clang23 Reviewed-by: prr --- .../unix/native/libawt_xawt/java2d/x11/XRBackendNative.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c b/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c index 0ea86e3e9b3..ebb3e32890e 100644 --- a/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c +++ b/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, 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 @@ -339,7 +339,7 @@ Java_sun_java2d_xr_XRBackendNative_createPixmap(JNIEnv *env, jobject this, JNIEXPORT jint JNICALL Java_sun_java2d_xr_XRBackendNative_createPictureNative (JNIEnv *env, jclass cls, jint drawable, jlong formatPtr) { - XRenderPictureAttributes pict_attr; + XRenderPictureAttributes pict_attr = {0}; return XRenderCreatePicture(awt_display, (Drawable) drawable, (XRenderPictFormat *) jlong_to_ptr(formatPtr), 0, &pict_attr); From 436c62afd285a3ce2be9aef59876df4b9f0955ff Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Sat, 17 Jan 2026 06:24:31 +0000 Subject: [PATCH 069/328] 8373867: Improve robustness of Attach API for finding tmp directory Reviewed-by: sspitsyn, amenkov --- .../sun/tools/attach/VirtualMachineImpl.java | 55 +++++++--- .../attach/AttachNotSupportedException.java | 13 ++- .../attach/TestWithoutDumpableProcess.java | 102 ++++++++++++++++++ 3 files changed, 154 insertions(+), 16 deletions(-) create mode 100644 test/jdk/com/sun/tools/attach/TestWithoutDumpableProcess.java diff --git a/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java index af8870ecf64..998e8d037b4 100644 --- a/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,8 @@ import java.util.regex.Pattern; import static java.nio.charset.StandardCharsets.UTF_8; +import sun.jvmstat.monitor.MonitoredHost; + /* * Linux implementation of HotSpotVirtualMachine */ @@ -228,7 +230,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { // Return the socket file for the given process. private File findSocketFile(long pid, long ns_pid) throws AttachNotSupportedException, IOException { - return new File(findTargetProcessTmpDirectory(pid, ns_pid), ".java_pid" + ns_pid); + return new File(findTargetProcessTmpDirectory(pid), ".java_pid" + ns_pid); } // On Linux a simple handshake is used to start the attach mechanism @@ -243,14 +245,14 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { // Do not canonicalize the file path, or we will fail to attach to a VM in a container. f.createNewFile(); } catch (IOException _) { - f = new File(findTargetProcessTmpDirectory(pid, ns_pid), fn.toString()); + f = new File(findTargetProcessTmpDirectory(pid), fn.toString()); f.createNewFile(); } return f; } - private String findTargetProcessTmpDirectory(long pid, long ns_pid) throws AttachNotSupportedException, IOException { - final var procPidRoot = PROC.resolve(Long.toString(pid)).resolve(ROOT_TMP); + private String findTargetProcessTmpDirectory(long pid) throws AttachNotSupportedException { + final var tmpOnProcPidRoot = PROC.resolve(Long.toString(pid)).resolve(ROOT_TMP); /* We need to handle at least 4 different cases: * 1. Caller and target processes share PID namespace and root filesystem (host to host or container to @@ -261,21 +263,44 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { * 4. Caller and target processes share neither PID namespace nor root filesystem (host to container) * * if target is elevated, we cant use /proc//... so we have to fallback to /tmp, but that may not be shared - * with the target/attachee process, we can try, except in the case where the ns_pid also exists in this pid ns - * which is ambiguous, if we share /tmp with the intended target, the attach will succeed, if we do not, - * then we will potentially attempt to attach to some arbitrary process with the same pid (in this pid ns) - * as that of the intended target (in its * pid ns). + * with the target/attachee process, so we should check whether /tmp on both is same. This method would throw + * AttachNotSupportedException if they are different because we cannot make a connection with target VM. * - * so in that case we should prehaps throw - or risk sending SIGQUIT to some arbitrary process... which could kill it - * - * however we can also check the target pid's signal masks to see if it catches SIGQUIT and only do so if in + * In addition, we can also check the target pid's signal masks to see if it catches SIGQUIT and only do so if in * fact it does ... this reduces the risk of killing an innocent process in the current ns as opposed to * attaching to the actual target JVM ... c.f: checkCatchesAndSendQuitTo() below. - * - * note that if pid == ns_pid we are in a shared pid ns with the target and may (potentially) share /tmp */ - return (Files.isWritable(procPidRoot) ? procPidRoot : TMPDIR).toString(); + try { + if (Files.isWritable(tmpOnProcPidRoot)) { + return tmpOnProcPidRoot.toString(); + } else if (Files.isSameFile(tmpOnProcPidRoot, TMPDIR)) { + return TMPDIR.toString(); + } else { + throw new AttachNotSupportedException("Unable to access the filesystem of the target process"); + } + } catch (IOException ioe) { + try { + boolean found = MonitoredHost.getMonitoredHost("//localhost") + .activeVms() + .stream() + .anyMatch(i -> pid == i.intValue()); + if (found) { + // We can use /tmp because target process is on same host + // even if we cannot access /proc//root. + // The process with capsh/setcap would fall this pattern. + return TMPDIR.toString(); + } else { + throw new AttachNotSupportedException("Unable to access the filesystem of the target process", ioe); + } + } catch (AttachNotSupportedException e) { + // AttachNotSupportedException happened in above should go through + throw e; + } catch (Exception e) { + // Other exceptions would be wrapped with AttachNotSupportedException + throw new AttachNotSupportedException("Unable to access the filesystem of the target process", e); + } + } } // Return the inner most namespaced PID if there is one, diff --git a/src/jdk.attach/share/classes/com/sun/tools/attach/AttachNotSupportedException.java b/src/jdk.attach/share/classes/com/sun/tools/attach/AttachNotSupportedException.java index 382c8a57b26..9d62badb94c 100644 --- a/src/jdk.attach/share/classes/com/sun/tools/attach/AttachNotSupportedException.java +++ b/src/jdk.attach/share/classes/com/sun/tools/attach/AttachNotSupportedException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,4 +62,15 @@ public class AttachNotSupportedException extends Exception { super(s); } + /** + * Constructs an AttachNotSupportedException with + * the specified cause. + * + * @param message the detail message. + * @param cause the cause of this exception. + */ + public AttachNotSupportedException(String message, Throwable cause) { + super(message, cause); + } + } diff --git a/test/jdk/com/sun/tools/attach/TestWithoutDumpableProcess.java b/test/jdk/com/sun/tools/attach/TestWithoutDumpableProcess.java new file mode 100644 index 00000000000..be9d0c8790c --- /dev/null +++ b/test/jdk/com/sun/tools/attach/TestWithoutDumpableProcess.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, NTT DATA + * 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.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.ValueLayout; + +import com.sun.tools.attach.VirtualMachine; + +import jdk.test.lib.Asserts; +import jdk.test.lib.thread.ProcessThread; +import jdk.test.lib.process.ProcessTools; + +/* + * @test + * @bug 8226919 8373867 + * @summary Test to make sure attach target process which is not dumpable. + * @library /test/lib + * @modules jdk.attach + * @requires os.family == "linux" + * + * @run main/timeout=200 TestWithoutDumpableProcess + */ +public class TestWithoutDumpableProcess { + + private static final String EXPECTED_PROP_KEY = "attach.test"; + private static final String EXPECTED_PROP_VALUE = "true"; + + public static class Debuggee { + + // Disable dumpable attribute via prctl(2) + private static void disableDumpable() throws Throwable { + var linker = Linker.nativeLinker(); + var prctl = linker.downcallHandle(linker.defaultLookup().findOrThrow("prctl"), + FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.JAVA_INT, ValueLayout.JAVA_LONG), + Linker.Option.firstVariadicArg(1), Linker.Option.captureCallState("errno")); + var errnoSeg = Arena.global().allocate(Linker.Option.captureStateLayout()); + final int PR_SET_DUMPABLE = 4; // from linux/prctl.h + + int ret = (int)prctl.invoke(errnoSeg, PR_SET_DUMPABLE, 0L); + if (ret == -1){ + var hndErrno = Linker.Option + .captureStateLayout() + .varHandle(MemoryLayout.PathElement.groupElement("errno")); + int errno = (int)hndErrno.get(errnoSeg, 0L); + throw new RuntimeException("prctl: errno=" + errno); + } + } + + public static void main(String[] args) throws Throwable { + disableDumpable(); + IO.println(Application.READY_MSG); + + while (IO.readln().equals(Application.SHUTDOWN_MSG)); + } + + public static ProcessThread start() { + var args = new String[]{ + "--enable-native-access=ALL-UNNAMED", + String.format("-D%s=%s", EXPECTED_PROP_KEY, EXPECTED_PROP_VALUE), Debuggee.class.getName() + }; + var pb = ProcessTools.createLimitedTestJavaProcessBuilder(args); + var pt = new ProcessThread("runApplication", Application.READY_MSG::equals, pb); + pt.start(); + return pt; + } + + } + + public static void main(String[] args) throws Exception { + var pt = Debuggee.start(); + var vm = VirtualMachine.attach(Long.toString(pt.getPid())); + var val = vm.getSystemProperties().getProperty(EXPECTED_PROP_KEY); + + Asserts.assertNotNull(val, "Expected sysprop not found"); + Asserts.assertEquals(val, "true", "Unexpected sysprop value"); + } + +} From a0e6f028a8952f61d9115f7bdf04b8a87f8ebba4 Mon Sep 17 00:00:00 2001 From: Shawn M Emery Date: Sat, 17 Jan 2026 11:08:30 +0000 Subject: [PATCH 070/328] 8360934: Add AVX-512 intrinsics for ML-KEM - enhancement on AVX512_VBMI Co-authored-by: Sandhya Viswanathan Reviewed-by: jbhateja, vpaprotski --- .../cpu/x86/stubGenerator_x86_64_kyber.cpp | 92 ++++++++++++++++++- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp index 3e5593322d5..7d5dee6a5df 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -64,6 +64,39 @@ static address kyberAvx512ConstsAddr(int offset) { const Register scratch = r10; +ATTRIBUTE_ALIGNED(64) static const uint8_t kyberAvx512_12To16Dup[] = { +// 0 - 63 + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11, 12, 13, 13, 14, 15, 16, + 16, 17, 18, 19, 19, 20, 21, 22, 22, 23, 24, 25, 25, 26, 27, 28, 28, 29, 30, + 31, 31, 32, 33, 34, 34, 35, 36, 37, 37, 38, 39, 40, 40, 41, 42, 43, 43, 44, + 45, 46, 46, 47 + }; + +static address kyberAvx512_12To16DupAddr() { + return (address) kyberAvx512_12To16Dup; +} + +ATTRIBUTE_ALIGNED(64) static const uint16_t kyberAvx512_12To16Shift[] = { +// 0 - 31 + 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, + 4, 0, 4, 0, 4, 0, 4 + }; + +static address kyberAvx512_12To16ShiftAddr() { + return (address) kyberAvx512_12To16Shift; +} + +ATTRIBUTE_ALIGNED(64) static const uint64_t kyberAvx512_12To16And[] = { +// 0 - 7 + 0x0FFF0FFF0FFF0FFF, 0x0FFF0FFF0FFF0FFF, 0x0FFF0FFF0FFF0FFF, + 0x0FFF0FFF0FFF0FFF, 0x0FFF0FFF0FFF0FFF, 0x0FFF0FFF0FFF0FFF, + 0x0FFF0FFF0FFF0FFF, 0x0FFF0FFF0FFF0FFF + }; + +static address kyberAvx512_12To16AndAddr() { + return (address) kyberAvx512_12To16And; +} + ATTRIBUTE_ALIGNED(64) static const uint16_t kyberAvx512NttPerms[] = { // 0 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, @@ -822,10 +855,65 @@ address generate_kyber12To16_avx512(StubGenerator *stubgen, const Register perms = r11; - Label Loop; + Label Loop, VBMILoop; __ addptr(condensed, condensedOffs); + if (VM_Version::supports_avx512_vbmi()) { + // mask load for the first 48 bytes of each vector + __ mov64(rax, 0x0000FFFFFFFFFFFF); + __ kmovql(k1, rax); + + __ lea(perms, ExternalAddress(kyberAvx512_12To16DupAddr())); + __ evmovdqub(xmm20, Address(perms), Assembler::AVX_512bit); + + __ lea(perms, ExternalAddress(kyberAvx512_12To16ShiftAddr())); + __ evmovdquw(xmm21, Address(perms), Assembler::AVX_512bit); + + __ lea(perms, ExternalAddress(kyberAvx512_12To16AndAddr())); + __ evmovdquq(xmm22, Address(perms), Assembler::AVX_512bit); + + __ align(OptoLoopAlignment); + __ BIND(VBMILoop); + + __ evmovdqub(xmm0, k1, Address(condensed, 0), false, + Assembler::AVX_512bit); + __ evmovdqub(xmm1, k1, Address(condensed, 48), false, + Assembler::AVX_512bit); + __ evmovdqub(xmm2, k1, Address(condensed, 96), false, + Assembler::AVX_512bit); + __ evmovdqub(xmm3, k1, Address(condensed, 144), false, + Assembler::AVX_512bit); + + __ evpermb(xmm4, k0, xmm20, xmm0, false, Assembler::AVX_512bit); + __ evpermb(xmm5, k0, xmm20, xmm1, false, Assembler::AVX_512bit); + __ evpermb(xmm6, k0, xmm20, xmm2, false, Assembler::AVX_512bit); + __ evpermb(xmm7, k0, xmm20, xmm3, false, Assembler::AVX_512bit); + + __ evpsrlvw(xmm4, xmm4, xmm21, Assembler::AVX_512bit); + __ evpsrlvw(xmm5, xmm5, xmm21, Assembler::AVX_512bit); + __ evpsrlvw(xmm6, xmm6, xmm21, Assembler::AVX_512bit); + __ evpsrlvw(xmm7, xmm7, xmm21, Assembler::AVX_512bit); + + __ evpandq(xmm0, xmm22, xmm4, Assembler::AVX_512bit); + __ evpandq(xmm1, xmm22, xmm5, Assembler::AVX_512bit); + __ evpandq(xmm2, xmm22, xmm6, Assembler::AVX_512bit); + __ evpandq(xmm3, xmm22, xmm7, Assembler::AVX_512bit); + + store4regs(parsed, 0, xmm0_3, _masm); + + __ addptr(condensed, 192); + __ addptr(parsed, 256); + __ subl(parsedLength, 128); + __ jcc(Assembler::greater, VBMILoop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; + } + __ lea(perms, ExternalAddress(kyberAvx512_12To16PermsAddr())); load4regs(xmm24_27, perms, 0, _masm); From 1cdb8174220e52c055406e0e927bc982c91ac595 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Sun, 18 Jan 2026 07:35:12 +0000 Subject: [PATCH 071/328] 8375575: AttachNotSupportedException constructor missing @since 27 Reviewed-by: liach --- .../com/sun/tools/attach/AttachNotSupportedException.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/jdk.attach/share/classes/com/sun/tools/attach/AttachNotSupportedException.java b/src/jdk.attach/share/classes/com/sun/tools/attach/AttachNotSupportedException.java index 9d62badb94c..725db3e7732 100644 --- a/src/jdk.attach/share/classes/com/sun/tools/attach/AttachNotSupportedException.java +++ b/src/jdk.attach/share/classes/com/sun/tools/attach/AttachNotSupportedException.java @@ -68,6 +68,8 @@ public class AttachNotSupportedException extends Exception { * * @param message the detail message. * @param cause the cause of this exception. + * + * @since 27 */ public AttachNotSupportedException(String message, Throwable cause) { super(message, cause); From a67979c4e6dcea70e63cc79a105be12a9306c660 Mon Sep 17 00:00:00 2001 From: Guanqiang Han Date: Mon, 19 Jan 2026 02:33:18 +0000 Subject: [PATCH 072/328] 8375125: assert(false) failed: "Attempting to acquire lock NativeHeapTrimmer_lock/nosafepoint out of order with lock ConcurrentHashTableResize_lock/nosafepoint-2 -- possible deadlock" when using native heap trimmer Reviewed-by: dholmes, stuefe --- src/hotspot/share/classfile/stringTable.cpp | 7 +- src/hotspot/share/classfile/symbolTable.cpp | 7 +- ...stTrimNativeHeapIntervalTablesCleanup.java | 107 ++++++++++++++++++ 3 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/os/TestTrimNativeHeapIntervalTablesCleanup.java diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index c775014cfac..20dfad0d980 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -614,6 +614,10 @@ struct StringTableDeleteCheck : StackObj { }; void StringTable::clean_dead_entries(JavaThread* jt) { + // BulkDeleteTask::prepare() may take ConcurrentHashTableResize_lock (nosafepoint-2). + // When NativeHeapTrimmer is enabled, SuspendMark may take NativeHeapTrimmer::_lock (nosafepoint). + // Take SuspendMark first to keep lock order and avoid deadlock. + NativeHeapTrimmer::SuspendMark sm("stringtable"); StringTableHash::BulkDeleteTask bdt(_local_table); if (!bdt.prepare(jt)) { return; @@ -621,7 +625,6 @@ void StringTable::clean_dead_entries(JavaThread* jt) { StringTableDeleteCheck stdc; StringTableDoDelete stdd; - NativeHeapTrimmer::SuspendMark sm("stringtable"); { TraceTime timer("Clean", TRACETIME_LOG(Debug, stringtable, perf)); while(bdt.do_task(jt, stdc, stdd)) { diff --git a/src/hotspot/share/classfile/symbolTable.cpp b/src/hotspot/share/classfile/symbolTable.cpp index ec639a2b4d3..c49aa10fa0d 100644 --- a/src/hotspot/share/classfile/symbolTable.cpp +++ b/src/hotspot/share/classfile/symbolTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -763,6 +763,10 @@ struct SymbolTableDeleteCheck : StackObj { }; void SymbolTable::clean_dead_entries(JavaThread* jt) { + // BulkDeleteTask::prepare() may take ConcurrentHashTableResize_lock (nosafepoint-2). + // When NativeHeapTrimmer is enabled, SuspendMark may take NativeHeapTrimmer::_lock (nosafepoint). + // Take SuspendMark first to keep lock order and avoid deadlock. + NativeHeapTrimmer::SuspendMark sm("symboltable"); SymbolTableHash::BulkDeleteTask bdt(_local_table); if (!bdt.prepare(jt)) { return; @@ -770,7 +774,6 @@ void SymbolTable::clean_dead_entries(JavaThread* jt) { SymbolTableDeleteCheck stdc; SymbolTableDoDelete stdd; - NativeHeapTrimmer::SuspendMark sm("symboltable"); { TraceTime timer("Clean", TRACETIME_LOG(Debug, symboltable, perf)); while (bdt.do_task(jt, stdc, stdd)) { diff --git a/test/hotspot/jtreg/runtime/os/TestTrimNativeHeapIntervalTablesCleanup.java b/test/hotspot/jtreg/runtime/os/TestTrimNativeHeapIntervalTablesCleanup.java new file mode 100644 index 00000000000..3ced98b616d --- /dev/null +++ b/test/hotspot/jtreg/runtime/os/TestTrimNativeHeapIntervalTablesCleanup.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2026, 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 8375125 + * @summary Trigger StringTable::clean_dead_entries or SymbolTable::clean_dead_entries + * with -XX:TrimNativeHeapInterval enabled,should not violate lock ordering. + * @requires vm.debug + * @requires vm.gc != "Epsilon" + * @library /test/lib + * @modules java.compiler + * @run main/othervm -Xms128m -Xmx128m + * -XX:TrimNativeHeapInterval=300000 + * TestTrimNativeHeapIntervalTablesCleanup string + * @run main/othervm -Xms128m -Xmx128m + * -XX:TrimNativeHeapInterval=300000 + * TestTrimNativeHeapIntervalTablesCleanup symbol + */ + +import java.util.LinkedList; +import jdk.test.lib.compiler.InMemoryJavaCompiler; + +public class TestTrimNativeHeapIntervalTablesCleanup { + + public static void main(String[] args) throws Exception{ + if (args.length != 1) { + throw new IllegalArgumentException("Expected 1 argument: string|symbol"); + } + switch (args[0]) { + case "string": + testStringTableCleanup(); + break; + case "symbol": + testSymbolTableCleanup(); + break; + default: + throw new IllegalArgumentException("Unknown mode: " + args[0]); + } + System.out.println("passed: " + args[0]); + } + + static void testStringTableCleanup() throws Exception{ + final int rounds = 30; + final int maxSize = 200_000; + final int pruneEvery = 50_000; + final int pruneCount = 25_000; + long stringNum = 0; + + for (int round = 0; round < rounds; round++) { + LinkedList list = new LinkedList<>(); + for (int i = 0; i < maxSize; i++, stringNum++) { + if (i != 0 && (i % pruneEvery) == 0) { + int toRemove = Math.min(pruneCount, list.size()); + list.subList(0, toRemove).clear(); + } + list.push(Long.toString(stringNum).intern()); + } + System.gc(); + Thread.sleep(1000); + } + } + + static void testSymbolTableCleanup() throws Exception { + final int rounds = 10; + final int classesPerRound = 100; + + for (int r = 0; r < rounds; r++) { + for (int i = 0; i < classesPerRound; i++) { + String cn = "C" + r + "_" + i; + byte[] bytes = InMemoryJavaCompiler.compile( + cn, + "public class " + cn + " { int m" + i + "() { return " + i + "; } }" + ); + new ClassLoader(null) { + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (!name.equals(cn)) throw new ClassNotFoundException(name); + return defineClass(name, bytes, 0, bytes.length); + } + }.loadClass(cn).getDeclaredConstructor().newInstance(); + } + System.gc(); + Thread.sleep(1000); + } + } +} \ No newline at end of file From f8fb78042639d4c436fdad7f501ca4ca28dfe9e3 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Fri, 18 Jul 2025 23:49:30 +0000 Subject: [PATCH 073/328] 8265429: Improve GCM encryption Co-authored-by: Daniel Jelinski Reviewed-by: rhalade, pkumaraswamy, ahgross, jnimeh, djelinski --- .../share/native/libj2pkcs11/p11_crypt.c | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_crypt.c b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_crypt.c index d969fabffd0..052c7011860 100644 --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_crypt.c +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_crypt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -184,9 +184,12 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1Encrypt if (directIn != 0) { inBufP = (CK_BYTE_PTR) jlong_to_ptr(directIn); - } else { + } else if (jIn != NULL) { inBufP = (*env)->GetPrimitiveArrayCritical(env, jIn, NULL); + // may happen if out of memory if (inBufP == NULL) { return 0; } + } else { + inBufP = NULL; } if (directOut != 0) { @@ -194,7 +197,7 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1Encrypt } else { outBufP = (*env)->GetPrimitiveArrayCritical(env, jOut, NULL); if (outBufP == NULL) { - if (directIn == 0) { + if (directIn == 0 && inBufP != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, jIn, inBufP, JNI_ABORT); } return 0; @@ -208,7 +211,7 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1Encrypt (CK_BYTE_PTR)(outBufP + jOutOfs), &ckEncryptedLen); - if (directIn == 0) { + if (directIn == 0 && inBufP != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, jIn, inBufP, JNI_ABORT); } if (directOut == 0) { @@ -251,9 +254,12 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1EncryptUpdate if (directIn != 0) { inBufP = (CK_BYTE_PTR) jlong_to_ptr(directIn); - } else { + } else if (jIn != NULL) { inBufP = (*env)->GetPrimitiveArrayCritical(env, jIn, NULL); + // may happen if out of memory if (inBufP == NULL) { return 0; } + } else { + inBufP = NULL; } if (directOut != 0) { @@ -261,7 +267,7 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1EncryptUpdate } else { outBufP = (*env)->GetPrimitiveArrayCritical(env, jOut, NULL); if (outBufP == NULL) { - if (directIn == 0) { + if (directIn == 0 && inBufP != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, jIn, inBufP, JNI_ABORT); } return 0; @@ -275,7 +281,7 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1EncryptUpdate (CK_BYTE_PTR)(outBufP + jOutOfs), &ckEncryptedPartLen); - if (directIn == 0) { + if (directIn == 0 && inBufP != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, jIn, inBufP, JNI_ABORT); } if (directOut == 0) { @@ -462,9 +468,12 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1Decrypt if (directIn != 0) { inBufP = (CK_BYTE_PTR) jlong_to_ptr(directIn); - } else { + } else if (jIn != NULL) { inBufP = (*env)->GetPrimitiveArrayCritical(env, jIn, NULL); + // may happen if out of memory if (inBufP == NULL) { return 0; } + } else { + inBufP = NULL; } if (directOut != 0) { @@ -472,7 +481,7 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1Decrypt } else { outBufP = (*env)->GetPrimitiveArrayCritical(env, jOut, NULL); if (outBufP == NULL) { - if (directIn == 0) { + if (directIn == 0 && inBufP != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, jIn, inBufP, JNI_ABORT); } return 0; @@ -485,7 +494,7 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1Decrypt (CK_BYTE_PTR)(outBufP + jOutOfs), &ckOutLen); - if (directIn == 0) { + if (directIn == 0 && inBufP != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, jIn, inBufP, JNI_ABORT); } if (directOut == 0) { @@ -528,9 +537,12 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptUpdate if (directIn != 0) { inBufP = (CK_BYTE_PTR) jlong_to_ptr(directIn); - } else { + } else if (jIn != NULL) { inBufP = (*env)->GetPrimitiveArrayCritical(env, jIn, NULL); + // may happen if out of memory if (inBufP == NULL) { return 0; } + } else { + inBufP = NULL; } if (directOut != 0) { @@ -538,7 +550,7 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptUpdate } else { outBufP = (*env)->GetPrimitiveArrayCritical(env, jOut, NULL); if (outBufP == NULL) { - if (directIn == 0) { + if (directIn == 0 && inBufP != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, jIn, inBufP, JNI_ABORT); } return 0; @@ -551,7 +563,7 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptUpdate (CK_BYTE_PTR)(outBufP + jOutOfs), &ckDecryptedPartLen); - if (directIn == 0) { + if (directIn == 0 && inBufP != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, jIn, inBufP, JNI_ABORT); } if (directOut == 0) { From 9f3f960b364bad96bfcd469d7993d2aedbc020a4 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Mon, 18 Aug 2025 10:25:12 +0000 Subject: [PATCH 074/328] 8364214: Enhance polygon data support Reviewed-by: rhalade, psadhukhan, mschoene, prr --- .../share/classes/sun/java2d/SunGraphics2D.java | 6 +++--- .../share/classes/sun/java2d/pipe/SpanClipRenderer.java | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java b/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java index 1bebf379997..e92c485a363 100644 --- a/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java +++ b/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1901,9 +1901,9 @@ public final class SunGraphics2D if (usrClip == null) { clipState = CLIP_DEVICE; clipRegion = devClip; - } else if (usrClip instanceof Rectangle2D) { + } else if (usrClip instanceof Rectangle2D clip) { clipState = CLIP_RECTANGULAR; - clipRegion = devClip.getIntersection((Rectangle2D) usrClip); + clipRegion = devClip.getIntersection(clip); } else { PathIterator cpi = usrClip.getPathIterator(null); int[] box = new int[4]; diff --git a/src/java.desktop/share/classes/sun/java2d/pipe/SpanClipRenderer.java b/src/java.desktop/share/classes/sun/java2d/pipe/SpanClipRenderer.java index 62d1f119f33..69c4954cac4 100644 --- a/src/java.desktop/share/classes/sun/java2d/pipe/SpanClipRenderer.java +++ b/src/java.desktop/share/classes/sun/java2d/pipe/SpanClipRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,8 @@ package sun.java2d.pipe; import java.awt.Rectangle; import java.awt.Shape; + +import sun.java2d.InvalidPipeException; import sun.java2d.SunGraphics2D; /** @@ -67,7 +69,9 @@ public class SpanClipRenderer implements CompositePipe public Object startSequence(SunGraphics2D sg, Shape s, Rectangle devR, int[] abox) { RegionIterator ri = sg.clipRegion.getIterator(); - + if (ri.region.isRectangular()) { + throw new InvalidPipeException("Invalid clip data"); + } return new SCRcontext(ri, outpipe.startSequence(sg, s, devR, abox)); } From 3b6ac2af9c8637891092955474b27e5400650dfc Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Wed, 20 Aug 2025 03:17:34 +0000 Subject: [PATCH 075/328] 8362308: Enhance Bitmap operations Reviewed-by: mschoene, rhalade, psadhukhan, prr --- .../libmlib_image/mlib_ImageConvMxN_Fp.c | 9 +++++++- .../libmlib_image/mlib_ImageConvMxN_ext.c | 6 ++++- .../libmlib_image/mlib_ImageConv_16ext.c | 23 ++++++++++++++++++- .../libmlib_image/mlib_ImageConv_16nw.c | 7 +++++- .../libmlib_image/mlib_ImageConv_32nw.c | 7 +++++- .../libmlib_image/mlib_ImageConv_8ext.c | 23 ++++++++++++++++++- .../native/libmlib_image/mlib_ImageConv_8nw.c | 7 +++++- .../libmlib_image/mlib_ImageConv_u16ext.c | 23 ++++++++++++++++++- .../libmlib_image/mlib_ImageConv_u16nw.c | 7 +++++- .../libmlib_image/mlib_ImageLookUp_Bit.c | 12 +++++++++- .../native/libmlib_image/mlib_ImageScanPoly.c | 11 ++++++++- 11 files changed, 124 insertions(+), 11 deletions(-) diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_Fp.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_Fp.c index fa9a186d6d7..bc2df9b0b1a 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_Fp.c +++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_Fp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,6 +76,7 @@ #include "mlib_ImageCheck.h" #include "mlib_SysMath.h" #include "mlib_ImageConv.h" +#include "safe_math.h" /***************************************************************/ static void mlib_ImageConvMxNMulAdd_F32(mlib_f32 *dst, @@ -272,6 +273,9 @@ mlib_status mlib_convMxNext_f32(mlib_image *dst, mlib_s32 nch = mlib_ImageGetChannels(dst); mlib_s32 i, j, j1, k; + if (!SAFE_TO_MULT(3, wid_e) || !SAFE_TO_ADD(3 * wid_e, m)) { + return MLIB_FAILURE; + } if (3 * wid_e + m > 1024) { dsa = mlib_malloc((3 * wid_e + m) * sizeof(mlib_d64)); @@ -629,6 +633,9 @@ mlib_status mlib_convMxNext_d64(mlib_image *dst, mlib_s32 nch = mlib_ImageGetChannels(dst); mlib_s32 i, j, j1, k; + if (!SAFE_TO_MULT(3, wid_e) || !SAFE_TO_ADD(3 * wid_e, m)) { + return MLIB_FAILURE; + } if (3 * wid_e + m > 1024) { dsa = mlib_malloc((3 * wid_e + m) * sizeof(mlib_d64)); diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_ext.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_ext.c index ee15935dcfe..5869b0a54af 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_ext.c +++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_ext.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,6 +82,7 @@ #include "mlib_image.h" #include "mlib_ImageConv.h" +#include "safe_math.h" /***************************************************************/ static void mlib_ImageConvMxNMulAdd_S32(mlib_d64 *dst, @@ -229,6 +230,9 @@ mlib_status mlib_convMxNext_s32(mlib_image *dst, /* internal buffer */ + if (!SAFE_TO_MULT(3, wid_e) || !SAFE_TO_ADD(3 * wid_e, m)) { + return MLIB_FAILURE; + } if (3 * wid_e + m > 1024) { dsa = mlib_malloc((3 * wid_e + m) * sizeof(mlib_d64)); diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_16ext.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_16ext.c index 57486b1cae5..00469d25719 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_16ext.c +++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_16ext.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ #include "mlib_image.h" #include "mlib_ImageConv.h" #include "mlib_c_ImageConv.h" +#include "safe_math.h" /* * This define switches between functions of different data types @@ -260,8 +261,14 @@ static mlib_status mlib_ImageConv1xN_ext(mlib_image *dst, if (max_hsize > hgt) max_hsize = hgt; shgt = hgt + (n - 1); + if (!SAFE_TO_ADD(max_hsize, (n - 1))) { + return MLIB_FAILURE; + } smax_hsize = max_hsize + (n - 1); + if (!SAFE_TO_ADD(smax_hsize, 1) || !SAFE_TO_MULT(2, (smax_hsize + 1))) { + return MLIB_FAILURE; + } bsize = 2 * (smax_hsize + 1); if (bsize > BUFF_SIZE) { @@ -509,8 +516,16 @@ mlib_status CONV_FUNC_MxN FREE_AND_RETURN_STATUS; } + if (!SAFE_TO_ADD(wid, (m - 1))) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } swid = wid + (m - 1); + if (!SAFE_TO_MULT((n + 3), swid)) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } bsize = (n + 3)*swid; if ((bsize > BUFF_SIZE) || (n > MAX_N)) { @@ -919,8 +934,14 @@ mlib_status CONV_FUNC_MxN_I chan1 = nchannel; chan2 = chan1 + chan1; + if (!SAFE_TO_ADD(wid, (m - 1))) { + return MLIB_FAILURE; + } swid = wid + (m - 1); + if (!SAFE_TO_MULT((n + 2), swid)) { + return MLIB_FAILURE; + } bsize = (n + 2)*swid; if ((bsize > BUFF_SIZE) || (n > MAX_N)) { diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_16nw.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_16nw.c index 3b6985b7876..2e035d12453 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_16nw.c +++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_16nw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ #include "mlib_image.h" #include "mlib_c_ImageConv.h" +#include "safe_math.h" /* This define switches between functions of different data types @@ -466,6 +467,10 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, FREE_AND_RETURN_STATUS; } + if (!SAFE_TO_MULT((n + 3), wid)) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } bsize = (n + 3)*wid; if ((bsize > BUFF_SIZE) || (n > MAX_N)) { diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_32nw.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_32nw.c index 380ed044878..bb264d9dcd2 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_32nw.c +++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_32nw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ #include "mlib_image.h" #include "mlib_ImageConv.h" +#include "safe_math.h" /***************************************************************/ #define CACHE_SIZE (64*1024) @@ -335,6 +336,10 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, FREE_AND_RETURN_STATUS; } + if (!SAFE_TO_MULT((n + 2), wid)) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } bsize = (n + 2)*wid; if ((bsize > BUFF_SIZE) || (n > MAX_N)) { diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_8ext.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_8ext.c index c8b58e6f138..136d5a2b814 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_8ext.c +++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_8ext.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ #include "mlib_image.h" #include "mlib_ImageConv.h" #include "mlib_c_ImageConv.h" +#include "safe_math.h" /* * This define switches between functions of different data types @@ -245,8 +246,14 @@ static mlib_status mlib_ImageConv1xN_ext(mlib_image *dst, if (max_hsize > hgt) max_hsize = hgt; shgt = hgt + (n - 1); + if (!SAFE_TO_ADD(max_hsize, (n - 1))) { + return MLIB_FAILURE; + } smax_hsize = max_hsize + (n - 1); + if (!SAFE_TO_ADD(smax_hsize, 1) || !SAFE_TO_MULT(2, (smax_hsize + 1))) { + return MLIB_FAILURE; + } bsize = 2 * (smax_hsize + 1); if (bsize > BUFF_SIZE) { @@ -494,8 +501,16 @@ mlib_status CONV_FUNC_MxN FREE_AND_RETURN_STATUS; } + if (!SAFE_TO_ADD(wid, (m - 1))) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } swid = wid + (m - 1); + if (!SAFE_TO_MULT((n + 3), swid)) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } bsize = (n + 3)*swid; if ((bsize > BUFF_SIZE) || (n > MAX_N)) { @@ -904,8 +919,14 @@ mlib_status CONV_FUNC_MxN_I chan1 = nchannel; chan2 = chan1 + chan1; + if (!SAFE_TO_ADD(wid, (m - 1))) { + return MLIB_FAILURE; + } swid = wid + (m - 1); + if (!SAFE_TO_MULT((n + 2), swid)) { + return MLIB_FAILURE; + } bsize = (n + 2)*swid; if ((bsize > BUFF_SIZE) || (n > MAX_N)) { diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_8nw.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_8nw.c index f65fda45c58..c144404b0f4 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_8nw.c +++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_8nw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ #include "mlib_image.h" #include "mlib_ImageConv.h" #include "mlib_c_ImageConv.h" +#include "safe_math.h" /* This define switches between functions of different data types @@ -467,6 +468,10 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, FREE_AND_RETURN_STATUS; } + if (!SAFE_TO_MULT((n + 3), wid)) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } bsize = (n + 3)*wid; if ((bsize > BUFF_SIZE) || (n > MAX_N)) { diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_u16ext.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_u16ext.c index b2757979a84..81a06f2fc28 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_u16ext.c +++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_u16ext.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ #include "mlib_image.h" #include "mlib_ImageConv.h" #include "mlib_c_ImageConv.h" +#include "safe_math.h" /* * This define switches between functions of different data types @@ -270,8 +271,14 @@ static mlib_status mlib_ImageConv1xN_ext(mlib_image *dst, if (max_hsize > hgt) max_hsize = hgt; shgt = hgt + (n - 1); + if (!SAFE_TO_ADD(max_hsize, (n - 1))) { + return MLIB_FAILURE; + } smax_hsize = max_hsize + (n - 1); + if (!SAFE_TO_ADD(smax_hsize, 1) || !SAFE_TO_MULT(2, (smax_hsize + 1))) { + return MLIB_FAILURE; + } bsize = 2 * (smax_hsize + 1); if (bsize > BUFF_SIZE) { @@ -519,8 +526,16 @@ mlib_status CONV_FUNC_MxN FREE_AND_RETURN_STATUS; } + if (!SAFE_TO_ADD(wid, (m - 1))) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } swid = wid + (m - 1); + if (!SAFE_TO_MULT((n + 3), swid)) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } bsize = (n + 3)*swid; if ((bsize > BUFF_SIZE) || (n > MAX_N)) { @@ -927,8 +942,14 @@ mlib_status CONV_FUNC_MxN_I chan1 = nchannel; chan2 = chan1 + chan1; + if (!SAFE_TO_ADD(wid, (m - 1))) { + return MLIB_FAILURE; + } swid = wid + (m - 1); + if (!SAFE_TO_MULT((n + 2), swid)) { + return MLIB_FAILURE; + } bsize = (n + 2)*swid; if ((bsize > BUFF_SIZE) || (n > MAX_N)) { diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_u16nw.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_u16nw.c index a3234cf8959..49412c7d7ef 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_u16nw.c +++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_u16nw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ #include "mlib_image.h" #include "mlib_c_ImageConv.h" +#include "safe_math.h" /* This define switches between functions of different data types @@ -466,6 +467,10 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, FREE_AND_RETURN_STATUS; } + if (!SAFE_TO_MULT((n + 3), wid)) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } bsize = (n + 3)*wid; if ((bsize > BUFF_SIZE) || (n > MAX_N)) { diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageLookUp_Bit.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageLookUp_Bit.c index 2e77c20aa57..cfd5e3e671e 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageLookUp_Bit.c +++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageLookUp_Bit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,6 +50,7 @@ #include "mlib_image.h" #include "mlib_ImageLookUp.h" +#include "safe_math.h" /***************************************************************/ #define MAX_WIDTH 512 @@ -302,6 +303,9 @@ mlib_status mlib_ImageLookUp_Bit_U8_2(const mlib_u8 *src, mlib_u8 *buff = (mlib_u8*)buff_lcl, *buffs; mlib_u32 val0, val1; + if (!SAFE_TO_MULT(xsize, 2)) { + return MLIB_FAILURE; + } size = xsize * 2; if (size > MAX_WIDTH) { @@ -440,6 +444,9 @@ mlib_status mlib_ImageLookUp_Bit_U8_3(const mlib_u8 *src, mlib_u8 *buff = (mlib_u8*)buff_lcl, *buffs; mlib_u32 l0, h0, v0, l1, h1, v1, l2, h2, v2; + if (!SAFE_TO_MULT(3, xsize)) { + return MLIB_FAILURE; + } size = 3 * xsize; if (size > MAX_WIDTH) { @@ -583,6 +590,9 @@ mlib_status mlib_ImageLookUp_Bit_U8_4(const mlib_u8 *src, mlib_u8 *buff = (mlib_u8*)buff_lcl, *buffs; mlib_u32 l, h; + if (!SAFE_TO_MULT(xsize, 4)) { + return MLIB_FAILURE; + } size = xsize * 4; if (size > MAX_WIDTH) { diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageScanPoly.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageScanPoly.c index a6f4cfdd36e..72adc212af6 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageScanPoly.c +++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageScanPoly.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,6 +101,11 @@ mlib_status mlib_AffineEdges(mlib_affine_param *param, return MLIB_FAILURE; } + int intSize = sizeof(mlib_s32); + if (!SAFE_TO_MULT(dstHeight, intSize) || + !SAFE_TO_ADD(dstHeight * intSize, 7)) { + return MLIB_FAILURE; + } bsize0 = (dstHeight * sizeof(mlib_s32) + 7) & ~7; if (lineAddr == NULL) { @@ -109,6 +114,10 @@ mlib_status mlib_AffineEdges(mlib_affine_param *param, param->buff_malloc = NULL; + if (!SAFE_TO_MULT(4, bsize0) || !SAFE_TO_ADD(4 * bsize0, bsize1)) { + return MLIB_FAILURE; + } + if ((4 * bsize0 + bsize1) > buff_size) { buff = param->buff_malloc = mlib_malloc(4 * bsize0 + bsize1); From 97bd4458416dffd901ad07be028a08b3d6dc4881 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 26 Aug 2025 03:07:27 +0000 Subject: [PATCH 076/328] 8365271: Improve Swing supports Reviewed-by: tr, prr, rhalade, aivanov --- .../classes/javax/swing/plaf/basic/BasicOptionPaneUI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java index a6d2a448186..8ab31b1a2ad 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java @@ -466,12 +466,12 @@ public class BasicOptionPaneUI extends OptionPaneUI { str = s.substring(index2 + "".length()); s = s.substring(index1, index2 + + "".length()); } - JLabel label; - label = new JLabel(s, JLabel.LEADING); + JLabel label = new JLabel(); if (Boolean.TRUE.equals( this.optionPane.getClientProperty("html.disable"))) { label.putClientProperty("html.disable", true); } + label.setText(s); label.setName("OptionPane.label"); configureMessageLabel(label); addMessageComponents(container, cons, label, maxll, true); From dc46a17f1e569e2ae6857eaed4b1365b6cab02e1 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 3 Sep 2025 17:23:16 +0000 Subject: [PATCH 077/328] 8365058: Enhance CopyOnWriteArraySet Reviewed-by: rhalade, skoivu, vklang, rriggs --- .../util/concurrent/CopyOnWriteArraySet.java | 41 +++++++++ .../SerializationTest.java | 84 +++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 test/jdk/java/util/concurrent/CopyOnWriteArraySet/SerializationTest.java diff --git a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArraySet.java b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArraySet.java index cef1682b0b1..abc9fdb348c 100644 --- a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArraySet.java +++ b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArraySet.java @@ -35,6 +35,13 @@ package java.util.concurrent; +import jdk.internal.misc.Unsafe; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamException; +import java.io.Serial; +import java.io.StreamCorruptedException; import java.util.AbstractSet; import java.util.Collection; import java.util.Iterator; @@ -445,4 +452,38 @@ public class CopyOnWriteArraySet extends AbstractSet return Spliterators.spliterator (al.getArray(), Spliterator.IMMUTABLE | Spliterator.DISTINCT); } + + /** + * De-serialization without data not supported for this class. + */ + @Serial + private void readObjectNoData() throws ObjectStreamException { + throw new StreamCorruptedException("Deserialized CopyOnWriteArraySet requires data"); + } + + /** + * Reconstitutes the {@code CopyOnWriteArraySet} instance from a stream + * (that is, deserializes it). + * @throws StreamCorruptedException if the object read from the stream is invalid. + */ + @Serial + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + CopyOnWriteArrayList newAl; // Set during the duplicate check + + @SuppressWarnings("unchecked") + CopyOnWriteArrayList inAl = (CopyOnWriteArrayList) in.readFields().get("al", null); + + if (inAl == null + || inAl.getClass() != CopyOnWriteArrayList.class + || (newAl = new CopyOnWriteArrayList<>()).addAllAbsent(inAl) != inAl.size()) { + throw new StreamCorruptedException("Content is invalid"); + } + + final Unsafe U = Unsafe.getUnsafe(); + U.putReference( + this, + U.objectFieldOffset(CopyOnWriteArraySet.class, "al"), + newAl + ); + } } diff --git a/test/jdk/java/util/concurrent/CopyOnWriteArraySet/SerializationTest.java b/test/jdk/java/util/concurrent/CopyOnWriteArraySet/SerializationTest.java new file mode 100644 index 00000000000..7700eda6cd6 --- /dev/null +++ b/test/jdk/java/util/concurrent/CopyOnWriteArraySet/SerializationTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8365058 + * @summary Check basic correctness of de-serialization + * @run junit SerializationTest + */ + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class SerializationTest { + + // Ensure basic serialization round trip correctness + @ParameterizedTest + @MethodSource + void roundTripTest(CopyOnWriteArraySet expected) { + var bytes = ser(expected); + var actual = deSer(bytes); + assertEquals(CopyOnWriteArraySet.class, actual.getClass()); + assertEquals(expected, actual); + } + + private static Stream> roundTripTest() { + return Stream.of( + new CopyOnWriteArraySet<>(), + new CopyOnWriteArraySet<>(List.of(1, 2, 3)), + new CopyOnWriteArraySet<>(Set.of("Foo", "Bar", "Baz")) + ); + } + + private static byte[] ser(Object obj) { + return assertDoesNotThrow(() -> { + try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream)) { + oos.writeObject(obj); + return byteArrayOutputStream.toByteArray(); + } + }, "Unexpected error during serialization"); + } + + private static Object deSer(byte[] bytes) { + return assertDoesNotThrow(() -> { + try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); + ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream)) { + return ois.readObject(); + } + }, "Unexpected error during de-serialization"); + } +} From 3afb831ae45182e4219decacc355fae100a41b05 Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Thu, 4 Sep 2025 18:11:37 +0000 Subject: [PATCH 078/328] 8341496: Improve JMX connections Co-authored-by: Daniel Fuchs Reviewed-by: skoivu, rhalade, coffeys, dfuchs, kevinw, jnimeh --- .../rmi/ssl/SslRMIClientSocketFactory.java | 13 +++++++++- .../management/security/SecurityTest.java | 2 ++ .../rmi/ssl/SSLSocketParametersTest.java | 1 + .../bootstrap/JMXInterfaceBindingTest.java | 24 +++++++++++++++++++ .../jmxremote/bootstrap/RmiBootstrapTest.java | 3 ++- .../bootstrap/RmiRegistrySslTest.java | 1 + 6 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/java.rmi/share/classes/javax/rmi/ssl/SslRMIClientSocketFactory.java b/src/java.rmi/share/classes/javax/rmi/ssl/SslRMIClientSocketFactory.java index ab6664b9d8f..a4475c8bd1e 100644 --- a/src/java.rmi/share/classes/javax/rmi/ssl/SslRMIClientSocketFactory.java +++ b/src/java.rmi/share/classes/javax/rmi/ssl/SslRMIClientSocketFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ import java.net.Socket; import java.rmi.server.RMIClientSocketFactory; import java.util.StringTokenizer; import javax.net.SocketFactory; +import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; @@ -119,6 +120,16 @@ public class SslRMIClientSocketFactory // final SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(host, port); + + if (Boolean.parseBoolean( + System.getProperty("jdk.rmi.ssl.client.enableEndpointIdentification", "true"))) { + SSLParameters params = sslSocket.getSSLParameters(); + if (params == null) { + params = new SSLParameters(); + } + params.setEndpointIdentificationAlgorithm("HTTPS"); + sslSocket.setSSLParameters(params); + } // Set the SSLSocket Enabled Cipher Suites // final String enabledCipherSuites = diff --git a/test/jdk/javax/management/security/SecurityTest.java b/test/jdk/javax/management/security/SecurityTest.java index 7212aea883f..b46bbfa759f 100644 --- a/test/jdk/javax/management/security/SecurityTest.java +++ b/test/jdk/javax/management/security/SecurityTest.java @@ -402,6 +402,8 @@ public class SecurityTest { opts.add(JDKToolFinder.getJDKTool("java")); opts.addAll(Arrays.asList(jdk.test.lib.Utils.getTestJavaOpts())); + opts.add("-Djdk.rmi.ssl.client.enableEndpointIdentification=false"); + // We need to forward some properties to the client side opts.add("-Dtest.src=" + System.getProperty("test.src")); diff --git a/test/jdk/javax/rmi/ssl/SSLSocketParametersTest.java b/test/jdk/javax/rmi/ssl/SSLSocketParametersTest.java index 3aa7a98c394..7616b112e39 100644 --- a/test/jdk/javax/rmi/ssl/SSLSocketParametersTest.java +++ b/test/jdk/javax/rmi/ssl/SSLSocketParametersTest.java @@ -137,6 +137,7 @@ public class SSLSocketParametersTest extends SSLContextTemplate { } public static void main(String[] args) throws Exception { + System.setProperty("jdk.rmi.ssl.client.enableEndpointIdentification", "false"); SSLSocketParametersTest test = new SSLSocketParametersTest(); test.runTest(Integer.parseInt(args[0])); } diff --git a/test/jdk/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java b/test/jdk/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java index 61359084297..c331cb9050c 100644 --- a/test/jdk/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java +++ b/test/jdk/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java @@ -21,6 +21,29 @@ * questions. */ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + import java.io.File; import java.io.PrintWriter; import java.net.InetAddress; @@ -205,6 +228,7 @@ public class JMXInterfaceBindingTest { // This is needed for testing on loopback args.add("-Djava.rmi.server.hostname=" + address); if (useSSL) { + args.add("-Djdk.rmi.ssl.client.enableEndpointIdentification=false"); args.add("-Dcom.sun.management.jmxremote.registry.ssl=true"); args.add("-Djavax.net.ssl.keyStore=" + KEYSTORE_LOC); args.add("-Djavax.net.ssl.trustStore=" + TRUSTSTORE_LOC); diff --git a/test/jdk/sun/management/jmxremote/bootstrap/RmiBootstrapTest.java b/test/jdk/sun/management/jmxremote/bootstrap/RmiBootstrapTest.java index 2a99c5e7d52..b62d3f1bbd7 100644 --- a/test/jdk/sun/management/jmxremote/bootstrap/RmiBootstrapTest.java +++ b/test/jdk/sun/management/jmxremote/bootstrap/RmiBootstrapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -169,6 +169,7 @@ public class RmiBootstrapTest extends RmiTestBase { final List credentialFiles = prepareTestFiles(args[0]); Security.setProperty("jdk.tls.disabledAlgorithms", ""); + System.setProperty("jdk.rmi.ssl.client.enableEndpointIdentification", "false"); try { MAX_GET_FREE_PORT_TRIES = Integer.parseInt(System.getProperty("test.getfreeport.max.tries", "10")); diff --git a/test/jdk/sun/management/jmxremote/bootstrap/RmiRegistrySslTest.java b/test/jdk/sun/management/jmxremote/bootstrap/RmiRegistrySslTest.java index 1aa20937962..b4ef5e224f8 100644 --- a/test/jdk/sun/management/jmxremote/bootstrap/RmiRegistrySslTest.java +++ b/test/jdk/sun/management/jmxremote/bootstrap/RmiRegistrySslTest.java @@ -179,6 +179,7 @@ public class RmiRegistrySslTest { initTestEnvironment(); List command = new ArrayList<>(); + command.add("-Djdk.rmi.ssl.client.enableEndpointIdentification=false"); command.add("-Dtest.src=" + TEST_SRC); command.add("-Dtest.rmi.port=" + port); command.addAll(Arrays.asList(args)); From 84ee4f976b1580944bd77bdbd8ccd23569bce3ac Mon Sep 17 00:00:00 2001 From: Renjith Kannath Pariyangad Date: Wed, 10 Sep 2025 11:56:45 +0000 Subject: [PATCH 079/328] 8366446: Test java/awt/geom/ConcurrentDrawPolygonTest.java fails intermittently Reviewed-by: jdv, aivanov, prr, rhalade --- .../share/classes/sun/java2d/SunGraphics2D.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java b/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java index e92c485a363..9815d657eee 100644 --- a/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java +++ b/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java @@ -1898,14 +1898,16 @@ public final class SunGraphics2D protected void validateCompClip() { int origClipState = clipState; - if (usrClip == null) { + final Shape clip = usrClip; + + if (clip == null) { clipState = CLIP_DEVICE; clipRegion = devClip; - } else if (usrClip instanceof Rectangle2D clip) { + } else if (clip instanceof Rectangle2D rect2d) { clipState = CLIP_RECTANGULAR; - clipRegion = devClip.getIntersection(clip); + clipRegion = devClip.getIntersection(rect2d); } else { - PathIterator cpi = usrClip.getPathIterator(null); + PathIterator cpi = clip.getPathIterator(null); int[] box = new int[4]; ShapeSpanIterator sr = LoopPipe.getFillSSI(this); try { From 7e3e35abef13ddf38d4268e1269c1d18566149ab Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Wed, 10 Sep 2025 16:40:58 +0000 Subject: [PATCH 080/328] 8367277: Fix copyright header in JMXInterfaceBindingTest.java Reviewed-by: dfuchs, rhalade, iris, coffeys --- .../bootstrap/JMXInterfaceBindingTest.java | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/test/jdk/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java b/test/jdk/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java index c331cb9050c..1f4707fab3b 100644 --- a/test/jdk/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java +++ b/test/jdk/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java @@ -1,27 +1,5 @@ /* * Copyright (c) 2015, Red Hat Inc - * 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. - */ - -/* * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * From f24fadc6240e2dcb5bcd732c91ccc03d1aa19e8a Mon Sep 17 00:00:00 2001 From: Michael McMahon Date: Mon, 15 Sep 2025 13:31:30 +0000 Subject: [PATCH 081/328] 8362632: Improve HttpServer Request handling Reviewed-by: djelinski, dfuchs --- .../com/sun/net/httpserver/Headers.java | 37 +++++-------------- .../sun/net/httpserver/ExchangeImpl.java | 19 +++++++--- .../classes/sun/net/httpserver/Utils.java | 33 +++++++++++++++++ 3 files changed, 57 insertions(+), 32 deletions(-) diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java index 2decd48c806..9389aae8691 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java @@ -36,6 +36,7 @@ import java.util.Set; import java.util.function.BiFunction; import java.util.stream.Collectors; import sun.net.httpserver.UnmodifiableHeaders; +import sun.net.httpserver.Utils; /** * HTTP request and response headers are represented by this class which @@ -216,8 +217,13 @@ public class Headers implements Map> { @Override public List put(String key, List value) { + // checkHeader is called in this class to fail fast + // It also must be called in sendResponseHeaders because + // Headers instances internal state can be modified + // external to these methods. + Utils.checkHeader(key, false); for (String v : value) - checkValue(v); + Utils.checkHeader(v, true); return map.put(normalize(key), value); } @@ -229,7 +235,8 @@ public class Headers implements Map> { * @param value the value to add to the header */ public void add(String key, String value) { - checkValue(value); + Utils.checkHeader(key, false); + Utils.checkHeader(value, true); String k = normalize(key); List l = map.get(k); if (l == null) { @@ -239,30 +246,6 @@ public class Headers implements Map> { l.add(value); } - private static void checkValue(String value) { - int len = value.length(); - for (int i=0; i= len - 2) { - throw new IllegalArgumentException("Illegal CR found in header"); - } - char c1 = value.charAt(i+1); - char c2 = value.charAt(i+2); - if (c1 != '\n') { - throw new IllegalArgumentException("Illegal char found after CR in header"); - } - if (c2 != ' ' && c2 != '\t') { - throw new IllegalArgumentException("No whitespace found after CRLF in header"); - } - i+=2; - } else if (c == '\n') { - throw new IllegalArgumentException("Illegal LF found in header"); - } - } - } - /** * Sets the given {@code value} as the sole header value for the given * {@code key}. If the mapping does not already exist, then it is created. @@ -304,7 +287,7 @@ public class Headers implements Map> { public void replaceAll(BiFunction, ? extends List> function) { var f = function.andThen(values -> { Objects.requireNonNull(values); - values.forEach(Headers::checkValue); + values.forEach(value -> Utils.checkHeader(value, true)); return values; }); Map.super.replaceAll(f); diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java index 8da98cdcfa5..ad6805938a2 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java @@ -207,6 +207,8 @@ class ExchangeImpl { return uos_orig; } + private static final byte[] CRLF = new byte[] {0x0D, 0x0A}; + public void sendResponseHeaders(int rCode, long contentLen) throws IOException { @@ -215,10 +217,11 @@ class ExchangeImpl { throw new IOException("headers already sent"); } this.rcode = rCode; - String statusLine = "HTTP/1.1 " + rCode + Code.msg(rCode) + "\r\n"; + String statusLine = "HTTP/1.1 " + rCode + Code.msg(rCode); ByteArrayOutputStream tmpout = new ByteArrayOutputStream(); PlaceholderOutputStream o = getPlaceholderResponseBody(); - tmpout.write(bytes(statusLine, 0), 0, statusLine.length()); + tmpout.write(bytes(statusLine, false, 0), 0, statusLine.length()); + tmpout.write(CRLF); boolean noContentToSend = false; // assume there is content boolean noContentLengthHeader = false; // must not send Content-length is set rspHdrs.set("Date", FORMATTER.format(Instant.now())); @@ -305,11 +308,11 @@ class ExchangeImpl { List values = entry.getValue(); for (String val : values) { int i = key.length(); - buf = bytes(key, 2); + buf = bytes(key, true, 2); buf[i++] = ':'; buf[i++] = ' '; os.write(buf, 0, i); - buf = bytes(val, 2); + buf = bytes(val, false, 2); i = val.length(); buf[i++] = '\r'; buf[i++] = '\n'; @@ -327,8 +330,14 @@ class ExchangeImpl { * Make sure that at least "extra" bytes are free at end * of rspbuf. Reallocate rspbuf if not big enough. * caller must check return value to see if rspbuf moved + * + * Header values are supposed to be limited to 7-bit ASCII + * but 8-bit has to be allowed (for ISO_8859_1). For efficiency + * we just down cast 16 bit Java chars to byte. We don't allow + * any character that can't be encoded in 8 bits. */ - private byte[] bytes(String s, int extra) { + private byte[] bytes(String s, boolean isKey, int extra) throws IOException { + Utils.checkHeader(s, !isKey); int slen = s.length(); if (slen+extra > rspbuf.length) { int diff = slen + extra - rspbuf.length; diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/Utils.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/Utils.java index 43dadb84a90..41834172f27 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/Utils.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/Utils.java @@ -88,4 +88,37 @@ public class Utils { } return true; } + + /* Throw IAE if illegal character found. isValue is true if String is + * a value. Otherwise it is header name + */ + public static void checkHeader(String str, boolean isValue) { + int len = str.length(); + for (int i=0; i= len - 2) { + throw new IllegalArgumentException("Illegal CR found in header"); + } + char c1 = str.charAt(i+1); + char c2 = str.charAt(i+2); + if (c1 != '\n') { + throw new IllegalArgumentException("Illegal char found after CR in header"); + } + if (c2 != ' ' && c2 != '\t') { + throw new IllegalArgumentException("No whitespace found after CRLF in header"); + } + i+=2; + } else if (c == '\n') { + throw new IllegalArgumentException("Illegal LF found in header"); + } else if (c > 255) { + throw new IllegalArgumentException("Illegal character found in header"); + } + } + } + } From eddbd359654cf6e2a437367461231ba37ee76918 Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Wed, 24 Sep 2025 18:05:45 +0000 Subject: [PATCH 082/328] 8359501: Enhance Handling of URIs Reviewed-by: rhalade, ahgross, azvegint, prr --- .../sun/lwawt/macosx/CDesktopPeer.java | 57 ++++++-- .../native/libawt_lwawt/awt/CDesktopPeer.m | 124 ++++++++++++++---- .../classes/sun/awt/windows/WDesktopPeer.java | 53 +++++++- .../native/libawt/windows/awt_Desktop.cpp | 49 ++++++- test/jdk/java/awt/Desktop/BrowseTest.java | 26 +++- .../EditAndPrintTest/EditAndPrintTest.java | 2 +- 6 files changed, 258 insertions(+), 53 deletions(-) diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDesktopPeer.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDesktopPeer.java index a4ec0767298..cc0e253f23b 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDesktopPeer.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDesktopPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,10 @@ import java.awt.peer.DesktopPeer; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.lang.annotation.Native; import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; /** @@ -44,6 +47,12 @@ import java.net.URI; */ public final class CDesktopPeer implements DesktopPeer { + @Native private static final int OPEN = 0; + @Native private static final int BROWSE = 1; + @Native private static final int EDIT = 2; + @Native private static final int PRINT = 3; + @Native private static final int MAIL = 4; + @Override public boolean isSupported(Action action) { return true; @@ -51,27 +60,27 @@ public final class CDesktopPeer implements DesktopPeer { @Override public void open(File file) throws IOException { - this.lsOpenFile(file, false); + this.lsOpenFile(file, OPEN); } @Override public void edit(File file) throws IOException { - this.lsOpenFile(file, false); + this.lsOpenFile(file, EDIT); } @Override public void print(File file) throws IOException { - this.lsOpenFile(file, true); + this.lsOpenFile(file, PRINT); } @Override public void mail(URI uri) throws IOException { - this.lsOpen(uri); + this.lsOpen(uri, MAIL); } @Override public void browse(URI uri) throws IOException { - this.lsOpen(uri); + this.lsOpen(uri, BROWSE); } @Override @@ -162,24 +171,44 @@ public final class CDesktopPeer implements DesktopPeer { } } - private void lsOpen(URI uri) throws IOException { - int status = _lsOpenURI(uri.toString()); + private void lsOpen(URI uri, int action) throws IOException { + int status = _lsOpenURI(uri.toString(), action); if (status != 0 /* noErr */) { - throw new IOException("Failed to mail or browse " + uri + ". Error code: " + status); + String actionString = (action == MAIL) ? "mail" : "browse"; + throw new IOException("Failed to " + actionString + " " + uri + + ". Error code: " + status); } } - private void lsOpenFile(File file, boolean print) throws IOException { - int status = _lsOpenFile(file.getCanonicalPath(), print); + private void lsOpenFile(File file, int action) throws IOException { + int status = -1; + Path tmpFile = null; + String tmpTxtPath = null; + try { + if (action == EDIT) { + tmpFile = Files.createTempFile("TmpFile", ".txt"); + tmpTxtPath = tmpFile.toAbsolutePath().toString(); + } + status = _lsOpenFile(file.getCanonicalPath(), action, tmpTxtPath); + } catch (Exception e) { + throw new IOException("Failed to create tmp file: ", e); + } finally { + if (tmpFile != null) { + Files.deleteIfExists(tmpFile); + } + } if (status != 0 /* noErr */) { - throw new IOException("Failed to open, edit or print " + file + ". Error code: " + status); + String actionString = (action == OPEN) ? "open" + : (action == EDIT) ? "edit" : "print"; + throw new IOException("Failed to " + actionString + " " + file + + ". Error code: " + status); } } - private static native int _lsOpenURI(String uri); + private static native int _lsOpenURI(String uri, int action); - private static native int _lsOpenFile(String path, boolean print); + private static native int _lsOpenFile(String path, int action, String tmpTxtPath); } diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CDesktopPeer.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/CDesktopPeer.m index 7555c7990c4..e1841c9398c 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CDesktopPeer.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CDesktopPeer.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,27 +27,60 @@ #import "JNIUtilities.h" #import #import +#import "sun_lwawt_macosx_CDesktopPeer.h" /* * Class: sun_lwawt_macosx_CDesktopPeer * Method: _lsOpenURI - * Signature: (Ljava/lang/String;)I; + * Signature: (Ljava/lang/String;I)I */ JNIEXPORT jint JNICALL Java_sun_lwawt_macosx_CDesktopPeer__1lsOpenURI -(JNIEnv *env, jclass clz, jstring uri) +(JNIEnv *env, jclass clz, jstring uri, jint action) { - OSStatus status = noErr; + __block OSStatus status = noErr; JNI_COCOA_ENTER(env); - // I would love to use NSWorkspace here, but it's not thread safe. Why? I don't know. - // So we use LaunchServices directly. + NSURL *urlToOpen = [NSURL URLWithString:JavaStringToNSString(env, uri)]; + NSURL *appURI = nil; - NSURL *url = [NSURL URLWithString:JavaStringToNSString(env, uri)]; + if (action == sun_lwawt_macosx_CDesktopPeer_BROWSE) { + // To get the defaultBrowser + NSURL *httpsURL = [NSURL URLWithString:@"https://"]; + NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; + appURI = [workspace URLForApplicationToOpenURL:httpsURL]; + } else if (action == sun_lwawt_macosx_CDesktopPeer_MAIL) { + // To get the default mailer + NSURL *mailtoURL = [NSURL URLWithString:@"mailto://"]; + NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; + appURI = [workspace URLForApplicationToOpenURL:mailtoURL]; + } - LSLaunchFlags flags = kLSLaunchDefaults; + if (appURI == nil) { + return -1; + } - LSApplicationParameters params = {0, flags, NULL, NULL, NULL, NULL, NULL}; - status = LSOpenURLsWithRole((CFArrayRef)[NSArray arrayWithObject:url], kLSRolesAll, NULL, ¶ms, NULL, 0); + // Prepare NSOpenConfig object + NSArray *urls = @[urlToOpen]; + NSWorkspaceOpenConfiguration *configuration = [NSWorkspaceOpenConfiguration configuration]; + configuration.activates = YES; // To bring app to foreground + configuration.promptsUserIfNeeded = YES; // To allow macOS desktop prompts + + // dispatch semaphores used to wait for the completion handler to update and return status + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(NSEC_PER_SEC)); // 1 second timeout + + // Asynchronous call to openURL + [[NSWorkspace sharedWorkspace] openURLs:urls + withApplicationAtURL:appURI + configuration:configuration + completionHandler:^(NSRunningApplication *app, NSError *error) { + if (error) { + status = (OSStatus) error.code; + } + dispatch_semaphore_signal(semaphore); + }]; + + dispatch_semaphore_wait(semaphore, timeout); JNI_COCOA_EXIT(env); return status; @@ -56,32 +89,73 @@ JNI_COCOA_EXIT(env); /* * Class: sun_lwawt_macosx_CDesktopPeer * Method: _lsOpenFile - * Signature: (Ljava/lang/String;Z)I; + * Signature: (Ljava/lang/String;I;Ljava/lang/String;)I; */ JNIEXPORT jint JNICALL Java_sun_lwawt_macosx_CDesktopPeer__1lsOpenFile -(JNIEnv *env, jclass clz, jstring jpath, jboolean print) +(JNIEnv *env, jclass clz, jstring jpath, jint action, jstring jtmpTxtPath) { - OSStatus status = noErr; + __block OSStatus status = noErr; JNI_COCOA_ENTER(env); - // I would love to use NSWorkspace here, but it's not thread safe. Why? I don't know. - // So we use LaunchServices directly. - NSString *path = NormalizedPathNSStringFromJavaString(env, jpath); - - NSURL *url = [NSURL fileURLWithPath:(NSString *)path]; + NSURL *urlToOpen = [NSURL fileURLWithPath:(NSString *)path]; // This byzantine workaround is necessary, or else directories won't open in Finder - url = (NSURL *)CFURLCreateWithFileSystemPath(NULL, (CFStringRef)[url path], kCFURLPOSIXPathStyle, false); + urlToOpen = (NSURL *)CFURLCreateWithFileSystemPath(NULL, (CFStringRef)[urlToOpen path], + kCFURLPOSIXPathStyle, false); - LSLaunchFlags flags = kLSLaunchDefaults; - if (print) flags |= kLSLaunchAndPrint; + NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; + NSURL *appURI = [workspace URLForApplicationToOpenURL:urlToOpen]; + NSURL *defaultTerminalApp = [workspace URLForApplicationToOpenURL:[NSURL URLWithString:@"file:///bin/sh"]]; - LSApplicationParameters params = {0, flags, NULL, NULL, NULL, NULL, NULL}; - status = LSOpenURLsWithRole((CFArrayRef)[NSArray arrayWithObject:url], kLSRolesAll, NULL, ¶ms, NULL, 0); - [url release]; + // Prepare NSOpenConfig object + NSArray *urls = @[urlToOpen]; + NSWorkspaceOpenConfiguration *configuration = [NSWorkspaceOpenConfiguration configuration]; + configuration.activates = YES; // To bring app to foreground + configuration.promptsUserIfNeeded = YES; // To allow macOS desktop prompts + + // pre-checks for open/print/edit before calling openURLs API + if (action == sun_lwawt_macosx_CDesktopPeer_OPEN + || action == sun_lwawt_macosx_CDesktopPeer_PRINT) { + if (appURI == nil + || [[urlToOpen absoluteString] containsString:[appURI absoluteString]] + || [[defaultTerminalApp absoluteString] containsString:[appURI absoluteString]]) { + return -1; + } + // Additionally set forPrinting=TRUE for print + if (action == sun_lwawt_macosx_CDesktopPeer_PRINT) { + configuration.forPrinting = YES; + } + } else if (action == sun_lwawt_macosx_CDesktopPeer_EDIT) { + if (appURI == nil + || [[urlToOpen absoluteString] containsString:[appURI absoluteString]]) { + return -1; + } + // for EDIT: if (defaultApp = TerminalApp) then set appURI = DefaultTextEditor + if ([[defaultTerminalApp absoluteString] containsString:[appURI absoluteString]]) { + NSString *path = NormalizedPathNSStringFromJavaString(env, jtmpTxtPath); + NSURL *tempFilePath = [NSURL fileURLWithPath:(NSString *)path]; + appURI = [workspace URLForApplicationToOpenURL:tempFilePath]; + } + } + + // dispatch semaphores used to wait for the completion handler to update and return status + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(NSEC_PER_SEC)); // 1 second timeout + + // Asynchronous call - openURLs:withApplicationAtURL + [[NSWorkspace sharedWorkspace] openURLs:urls + withApplicationAtURL:appURI + configuration:configuration + completionHandler:^(NSRunningApplication *app, NSError *error) { + if (error) { + status = (OSStatus) error.code; + } + dispatch_semaphore_signal(semaphore); + }]; + + dispatch_semaphore_wait(semaphore, timeout); JNI_COCOA_EXIT(env); return status; } - diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WDesktopPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WDesktopPeer.java index 788c1477265..e5b628dd74b 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WDesktopPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WDesktopPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,9 @@ import java.io.File; import java.io.IOException; import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import javax.swing.event.EventListenerList; import sun.awt.shell.ShellFolder; @@ -50,9 +53,11 @@ import sun.awt.shell.ShellFolder; */ final class WDesktopPeer implements DesktopPeer { /* Constants for the operation verbs */ - private static String ACTION_OPEN_VERB = "open"; - private static String ACTION_EDIT_VERB = "edit"; - private static String ACTION_PRINT_VERB = "print"; + private static final String ACTION_OPEN_VERB = "open"; + private static final String ACTION_EDIT_VERB = "edit"; + private static final String ACTION_PRINT_VERB = "print"; + private static final String ACTION_BROWSE_VERB = "browse"; + private static final String ACTION_MAIL_VERB = "mail"; private static native void init(); @@ -95,12 +100,12 @@ final class WDesktopPeer implements DesktopPeer { @Override public void mail(URI uri) throws IOException { - this.ShellExecute(uri, ACTION_OPEN_VERB); + this.ShellExecute(uri, ACTION_MAIL_VERB); } @Override public void browse(URI uri) throws IOException { - this.ShellExecute(uri, ACTION_OPEN_VERB); + this.launchUriInBrowser(uri); } private void ShellExecute(File file, String verb) throws IOException { @@ -121,6 +126,42 @@ final class WDesktopPeer implements DesktopPeer { } } + private void launchUriInBrowser(URI uri) throws IOException { + String defaultBrowser = getDefaultBrowser(); + if (defaultBrowser == null) { + throw new IOException("Failed to get default browser"); + } + + List cmdLineTokens = getCmdLineTokens(uri, defaultBrowser); + try { + ProcessBuilder pb = new ProcessBuilder(cmdLineTokens); + pb.start(); + } catch (Exception e) { + throw new IOException("Error launching Browser: ", e); + } + } + + private static List getCmdLineTokens(URI uri, String defaultBrowser) { + if (defaultBrowser.contains("%1")) { + defaultBrowser = defaultBrowser.replace("%1", uri.toString()); + } else { + defaultBrowser = defaultBrowser + " " + uri.toString(); + } + + List cmdLineTokens = new ArrayList<>(); + int firstIndex = defaultBrowser.indexOf("\""); + int secondIndex = defaultBrowser.indexOf("\"", firstIndex + 1); + + if (firstIndex == 0 && secondIndex != firstIndex) { + cmdLineTokens.add(defaultBrowser.substring(firstIndex, secondIndex + 1)); + defaultBrowser = defaultBrowser.substring(secondIndex + 1).trim(); + } + cmdLineTokens.addAll(Arrays.asList(defaultBrowser.split(" "))); + return cmdLineTokens; + } + + private static native String getDefaultBrowser(); + private static native String ShellExecute(String fileOrUri, String verb); private static final EventListenerList listenerList = new EventListenerList(); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Desktop.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Desktop.cpp index ba79523249c..ebb43b2f078 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Desktop.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Desktop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,12 @@ #include #include #include "awt_Toolkit.h" +#include +#include // for AssocQueryStringW +#include +#include +#include +#include // for SaferiIsExecutableFileType #define BUFFER_LIMIT MAX_PATH+1 @@ -78,14 +84,23 @@ JNIEXPORT jstring JNICALL Java_sun_awt_windows_WDesktopPeer_ShellExecute LPCWSTR fileOrUri_c = JNU_GetStringPlatformChars(env, fileOrUri_j, NULL); CHECK_NULL_RETURN(fileOrUri_c, NULL); LPCWSTR verb_c = JNU_GetStringPlatformChars(env, verb_j, NULL); + if (verb_c == NULL) { JNU_ReleaseStringPlatformChars(env, fileOrUri_j, fileOrUri_c); return NULL; } + if (wcscmp(verb_c, L"open") == 0) { + BOOL isExecutable = SaferiIsExecutableFileType(fileOrUri_c, FALSE); + if (isExecutable) { + return env->NewStringUTF("Unsupported URI content"); + } + } + // set action verb for mail() to open before calling ShellExecute + LPCWSTR actionVerb = wcscmp(verb_c, L"mail") == 0 ? L"open" : verb_c; // 6457572: ShellExecute possibly changes FPU control word - saving it here unsigned oldcontrol87 = _control87(0, 0); - HINSTANCE retval = ::ShellExecute(NULL, verb_c, fileOrUri_c, NULL, NULL, + HINSTANCE retval = ::ShellExecute(NULL, actionVerb, fileOrUri_c, NULL, NULL, SW_SHOWNORMAL); DWORD error = ::GetLastError(); _control87(oldcontrol87, 0xffffffff); @@ -113,10 +128,38 @@ JNIEXPORT jstring JNICALL Java_sun_awt_windows_WDesktopPeer_ShellExecute return errmsg; } } - return NULL; } +/* + * Class: sun_awt_windows_WDesktopPeer + * Method: getDefaultBrowser + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_sun_awt_windows_WDesktopPeer_getDefaultBrowser +(JNIEnv *env, jclass cls) +{ + LPCWSTR fileExtension = L"https"; + WCHAR defaultBrowser_c [MAX_PATH]; + DWORD cchBuffer = MAX_PATH; + + // Use AssocQueryString to get the default browser + HRESULT hr = AssocQueryStringW( + ASSOCF_NONE, // No special flags + ASSOCSTR_COMMAND, // Request the command string + fileExtension, // File extension + NULL, // pszExtra (optional) + defaultBrowser_c, // Output buffer - result + &cchBuffer // Size of the output buffer + ); + + if (FAILED(hr)) { + return NULL; + } + + return JNU_NewStringPlatform(env, defaultBrowser_c); +} + /* * Class: sun_awt_windows_WDesktopPeer * Method: moveToTrash diff --git a/test/jdk/java/awt/Desktop/BrowseTest.java b/test/jdk/java/awt/Desktop/BrowseTest.java index 33de1ecdca7..28e08fe16c7 100644 --- a/test/jdk/java/awt/Desktop/BrowseTest.java +++ b/test/jdk/java/awt/Desktop/BrowseTest.java @@ -40,10 +40,27 @@ import jtreg.SkippedException; public class BrowseTest extends JPanel { static final String INSTRUCTIONS = """ - This test could launch default file manager to open user's home - directory, and default web browser to show the URL of java vendor. - After test execution close the native file manager and web browser + Set your default browser as per the test platform. + macOS - Safari + windows - MS Edge + linux - Firefox + + This test checks 2 cases: + + 1) Directory URI: + On macOS and windows, verify that a browser window opens and + EITHER the browser OR native file manager shows the user's + home directory. + + On Linux verify that the user's home directory is shown by the + default file manager. + + 2) Web URI: + Verify that the Web URI (URL of java vendor) opens in the browser. + + After test execution close the native file manager and any web browser windows if they were launched by test. + Also check output for any unexpected EXCEPTIONS, if you see any failure messages press Fail otherwise press Pass. """; @@ -53,7 +70,7 @@ public class BrowseTest extends JPanel { URI dirURI = new File(System.getProperty("user.home")).toURI(); URI webURI = URI.create(System.getProperty("java.vendor.url", "http://www.java.com")); - boolean failed = false; + PassFailJFrame.log("Testing 1st case: Directory URI ..."); try { PassFailJFrame.log("Try to browse " + dirURI + " ..."); desktop.browse(dirURI); @@ -62,6 +79,7 @@ public class BrowseTest extends JPanel { PassFailJFrame.log("EXCEPTION: " + e.getMessage()); } + PassFailJFrame.log("Testing 2nd case: Web URI ..."); try { PassFailJFrame.log("Try to browse " + webURI + " ..."); desktop.browse(webURI); diff --git a/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java b/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java index b2d7ef28df1..77d86ceb42a 100644 --- a/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java +++ b/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java @@ -48,7 +48,7 @@ public class EditAndPrintTest extends JPanel { This test tries to edit and print a directory, which will expectedly raise IOException. Then this test would edit and print a .txt file, which should be successful. After test execution close the editor if it was launched by test. - If you see any EXCEPTION messages in the output press FAIL. + If you see any EXCEPTION messages in case of .txt file in the output press FAIL. """; static Desktop desktop; From 82e5771b0be205c2ef9500ffa750bf97da21823c Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 9 Oct 2025 04:40:38 +0000 Subject: [PATCH 083/328] 8365280: Enhance JOptionPane Reviewed-by: rhalade, prr, tr, aivanov --- .../swing/plaf/basic/BasicOptionPaneUI.java | 102 +++++++----------- .../swing/JOptionPane/TestJOptionHTMLTag.java | 68 ------------ 2 files changed, 39 insertions(+), 131 deletions(-) delete mode 100644 test/jdk/javax/swing/JOptionPane/TestJOptionHTMLTag.java diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java index 8ab31b1a2ad..8c7ac94b04e 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java @@ -452,78 +452,54 @@ public class BasicOptionPaneUI extends OptionPaneUI { } else if ((nl = s.indexOf('\n')) >= 0) { nll = 1; } - if (s.contains("")) { - /* line break in html text is done by
tag - * and not by /n so it's incorrect to address newline - * same as non-html text. - * Text between tags are extracted - * and rendered as JLabel text - */ - int index1 = s.indexOf(""); - int index2 = s.indexOf(""); - String str = ""; - if (index2 >= 0) { - str = s.substring(index2 + "".length()); - s = s.substring(index1, index2 + + "".length()); + if (nl >= 0) { + // break up newlines + if (nl == 0) { + JPanel breakPanel = new JPanel() { + public Dimension getPreferredSize() { + Font f = getFont(); + + if (f != null) { + return new Dimension(1, f.getSize() + 2); + } + return new Dimension(0, 0); + } + }; + breakPanel.setName("OptionPane.break"); + addMessageComponents(container, cons, breakPanel, maxll, + true); + } else { + addMessageComponents(container, cons, s.substring(0, nl), + maxll, false); } + // Prevent recursion of more than + // 200 successive newlines in a message + // and indicate message is truncated via ellipsis + if (recursionCount++ > 200) { + recursionCount = 0; + addMessageComponents(container, cons, new String("..."), + maxll, false); + return; + } + addMessageComponents(container, cons, s.substring(nl + nll), maxll, + false); + + } else if (len > maxll) { + Container c = Box.createVerticalBox(); + c.setName("OptionPane.verticalBox"); + burstStringInto(c, s, maxll); + addMessageComponents(container, cons, c, maxll, true); + + } else { JLabel label = new JLabel(); if (Boolean.TRUE.equals( - this.optionPane.getClientProperty("html.disable"))) { + optionPane.getClientProperty("html.disable"))) { label.putClientProperty("html.disable", true); } label.setText(s); label.setName("OptionPane.label"); configureMessageLabel(label); addMessageComponents(container, cons, label, maxll, true); - if (!str.isEmpty()) { - addMessageComponents(container, cons, str, maxll, false); - } - } else { - if (nl >= 0) { - // break up newlines - if (nl == 0) { - JPanel breakPanel = new JPanel() { - public Dimension getPreferredSize() { - Font f = getFont(); - - if (f != null) { - return new Dimension(1, f.getSize() + 2); - } - return new Dimension(0, 0); - } - }; - breakPanel.setName("OptionPane.break"); - addMessageComponents(container, cons, breakPanel, maxll, - true); - } else { - addMessageComponents(container, cons, s.substring(0, nl), - maxll, false); - } - // Prevent recursion of more than - // 200 successive newlines in a message - // and indicate message is truncated via ellipsis - if (recursionCount++ > 200) { - recursionCount = 0; - addMessageComponents(container, cons, new String("..."), - maxll, false); - return; - } - addMessageComponents(container, cons, s.substring(nl + nll), maxll, - false); - - } else if (len > maxll) { - Container c = Box.createVerticalBox(); - c.setName("OptionPane.verticalBox"); - burstStringInto(c, s, maxll); - addMessageComponents(container, cons, c, maxll, true); - - } else { - JLabel label; - label = new JLabel(s, JLabel.LEADING); - label.setName("OptionPane.label"); - configureMessageLabel(label); - addMessageComponents(container, cons, label, maxll, true); - } } } } diff --git a/test/jdk/javax/swing/JOptionPane/TestJOptionHTMLTag.java b/test/jdk/javax/swing/JOptionPane/TestJOptionHTMLTag.java deleted file mode 100644 index 94318492bd9..00000000000 --- a/test/jdk/javax/swing/JOptionPane/TestJOptionHTMLTag.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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 5074006 - * @key headful - * @library /java/awt/regtesthelpers - * @build PassFailJFrame - * @summary Swing JOptionPane shows tag as a string after newline - * @run main/manual TestJOptionHTMLTag -*/ - -import javax.swing.JDialog; -import javax.swing.JOptionPane; -import javax.swing.SwingUtilities; - -public class TestJOptionHTMLTag { - static String instructions - = """ - INSTRUCTIONS: - A dialog will be shown. - If it does not contain string, press Pass else press Fail. - """; - static PassFailJFrame passFailJFrame; - - public static void main(String[] args) throws Exception { - - SwingUtilities.invokeAndWait(() -> { - try { - String message = "" + "This is a test\n" + ""; - JOptionPane optionPane = new JOptionPane(); - optionPane.setMessage(message); - optionPane.setMessageType(JOptionPane.INFORMATION_MESSAGE); - JDialog dialog = new JDialog(); - dialog.setContentPane(optionPane); - dialog.pack(); - dialog.setVisible(true); - - passFailJFrame = new PassFailJFrame(instructions); - PassFailJFrame.addTestWindow(dialog); - PassFailJFrame.positionTestWindow(dialog, PassFailJFrame.Position.HORIZONTAL); - } catch (Exception e) { - e.printStackTrace(); - } - }); - passFailJFrame.awaitAndCheck(); - } -} - From 07f981f6b0bb8a7e444fd744791f73853e9fa325 Mon Sep 17 00:00:00 2001 From: Jamil Nimeh Date: Mon, 3 Nov 2025 14:53:21 +0000 Subject: [PATCH 084/328] 8368032: Enhance Certificate Checking Reviewed-by: ahgross, coffeys, rhalade, mullan, abarashev --- .../provider/certpath/URICertStore.java | 358 +++++++++++++++++- .../share/conf/security/java.security | 45 +++ .../x509/URICertStore/AIACertTimeout.java | 2 + .../x509/URICertStore/ExtensionsWithLDAP.java | 94 ++--- 4 files changed, 452 insertions(+), 47 deletions(-) diff --git a/src/java.base/share/classes/sun/security/provider/certpath/URICertStore.java b/src/java.base/share/classes/sun/security/provider/certpath/URICertStore.java index 28729a56dbd..3e1fc8db164 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/URICertStore.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/URICertStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.io.InputStream; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URI; +import java.net.URISyntaxException; import java.net.URLConnection; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; @@ -48,8 +49,11 @@ import java.security.cert.X509CRL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; +import java.util.Optional; +import java.util.Set; import sun.security.x509.AccessDescription; import sun.security.x509.GeneralNameInterface; @@ -58,6 +62,8 @@ import sun.security.util.Cache; import sun.security.util.Debug; import sun.security.util.SecurityProperties; +import javax.security.auth.x500.X500Principal; + /** * A CertStore that retrieves Certificates or * CRLs from a URI, for example, as specified in an X.509 @@ -182,6 +188,166 @@ class URICertStore extends CertStoreSpi { return timeoutVal; } + /** + * Enumeration for the allowed schemes we support when following a + * URI from an authorityInfoAccess extension on a certificate. + */ + private enum AllowedScheme { + HTTP(HttpFtpRuleMatcher.HTTP), + HTTPS(HttpFtpRuleMatcher.HTTPS), + LDAP(LdapRuleMatcher.LDAP), + LDAPS(LdapRuleMatcher.LDAPS), + FTP(HttpFtpRuleMatcher.FTP); + + final URIRuleMatcher ruleMatcher; + + AllowedScheme(URIRuleMatcher matcher) { + ruleMatcher = matcher; + } + + /** + * Return an {@code AllowedScheme} based on a case-insensitive match + * @param name the scheme name to be matched + * @return the {@code AllowedScheme} that corresponds to the + * {@code name} provided, or null if there is no match. + */ + static AllowedScheme nameOf(String name) { + if (name == null) { + return null; + } + + try { + return AllowedScheme.valueOf(name.toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException _) { + return null; + } + } + } + + private static Set CA_ISS_URI_FILTERS = null; + private static final boolean CA_ISS_ALLOW_ANY; + + static { + boolean allowAny = false; + try { + if (Builder.USE_AIA) { + CA_ISS_URI_FILTERS = new LinkedHashSet<>(); + String aiaPropVal = Optional.ofNullable( + SecurityProperties.getOverridableProperty( + "com.sun.security.allowedAIALocations")). + map(String::trim).orElse(""); + if (aiaPropVal.equalsIgnoreCase("any")) { + allowAny = true; + if (debug != null) { + debug.println("allowedAIALocations: Warning: " + + "Allow-All URI filtering enabled!"); + } + } else { + // Load all the valid rules from the Security property + if (!aiaPropVal.isEmpty()) { + String[] aiaUriStrs = aiaPropVal.trim().split("\\s+"); + addCaIssUriFilters(aiaUriStrs); + } + + if (CA_ISS_URI_FILTERS.isEmpty()) { + if (debug != null) { + debug.println("allowedAIALocations: Warning: " + + "No valid filters found. Deny-all URI " + + "filtering is active."); + } + } + } + } + } finally { + CA_ISS_ALLOW_ANY = allowAny; + } + } + + /** + * Populate the filter collection from the list of AIA CA issuer URIs + * found in the {@code com.sun.security.allowedAIALocations} security + * or system property. + * + * @param aiaUriStrs array containing String URI filters + */ + private static void addCaIssUriFilters(String[] aiaUriStrs) { + for (String aiaStr : aiaUriStrs) { + if (aiaStr != null && !aiaStr.isEmpty()) { + try { + AllowedScheme scheme; + URI aiaUri = new URI(aiaStr).normalize(); + // It must be absolute and non-opaque + if (!aiaUri.isAbsolute() || aiaUri.isOpaque()) { + if (debug != null) { + debug.println("allowedAIALocations: Skipping " + + "non-absolute or opaque URI " + aiaUri); + } + } else if (aiaUri.getHost() == null) { + // We do not allow rules with URIs that omit a hostname + // or address. + if (debug != null) { + debug.println("allowedAIALocations: Skipping " + + "URI rule with no hostname or address: " + + aiaUri); + } + } else if ((scheme = AllowedScheme.nameOf( + aiaUri.getScheme())) != null) { + // When it is an LDAP type, we can check the path + // portion (the DN) for proper structure and reject + // the rule early if it isn't correct. + if (scheme == AllowedScheme.LDAP || + scheme == AllowedScheme.LDAPS) { + try { + new X500Principal(aiaUri.getPath(). + replaceFirst("^/+", "")); + } catch (IllegalArgumentException iae) { + if (debug != null) { + debug.println("allowedAIALocations: " + + "Skipping LDAP rule: " + iae); + } + continue; + } + } + + // When a URI has a non-null query or fragment + // warn the user upon adding the rule that those + // components will be ignored + if (aiaUri.getQuery() != null) { + if (debug != null) { + debug.println("allowedAIALocations: " + + "Rule will ignore non-null query"); + } + } + if (aiaUri.getFragment() != null) { + if (debug != null) { + debug.println("allowedAIALocations: " + + "Rule will ignore non-null fragment"); + } + } + + CA_ISS_URI_FILTERS.add(aiaUri); + if (debug != null) { + debug.println("allowedAIALocations: Added " + + aiaUri + " to URI filters"); + } + } else { + if (debug != null) { + debug.println("allowedAIALocations: Disallowed " + + "filter URI scheme: " + + aiaUri.getScheme()); + } + } + } catch (URISyntaxException urise) { + if (debug != null) { + debug.println("allowedAIALocations: Skipping " + + "filter URI entry " + aiaStr + + ": parse failure at index " + urise.getIndex()); + } + } + } + } + } + /** * Creates a URICertStore. * @@ -244,6 +410,39 @@ class URICertStore extends CertStoreSpi { return null; } URI uri = ((URIName) gn).getURI(); + + // Before performing any instantiation make sure that + // the URI passes any filtering rules. This processing should + // only occur if the com.sun.security.enableAIAcaIssuers is true + // and the "any" rule has not been specified. + if (Builder.USE_AIA && !CA_ISS_ALLOW_ANY) { + URI normAIAUri = uri.normalize(); + AllowedScheme scheme = AllowedScheme.nameOf(normAIAUri.getScheme()); + + if (scheme == null) { + if (debug != null) { + debug.println("allowedAIALocations: No matching ruleset " + + "for scheme " + normAIAUri.getScheme()); + } + return null; + } + + // Go through each of the filter rules and see if any will + // make a positive match against the caIssuer URI. If nothing + // matches then we won't instantiate a URICertStore. + if (CA_ISS_URI_FILTERS.stream().noneMatch(rule -> + scheme.ruleMatcher.matchRule(rule, normAIAUri))) { + if (debug != null) { + debug.println("allowedAIALocations: Warning - " + + "The caIssuer URI " + normAIAUri + + " in the AuthorityInfoAccess extension is denied " + + "access. Use the com.sun.security.allowedAIALocations" + + " security/system property to allow access."); + } + return null; + } + } + try { return URICertStore.getInstance(new URICertStoreParameters(uri)); } catch (Exception ex) { @@ -270,7 +469,7 @@ class URICertStore extends CertStoreSpi { @Override @SuppressWarnings("unchecked") public synchronized Collection engineGetCertificates - (CertSelector selector) throws CertStoreException { + (CertSelector selector) throws CertStoreException { if (ldap) { // caching mechanism, see the class description for more info. @@ -462,4 +661,159 @@ class URICertStore extends CertStoreSpi { super(spi, p, type, params); } } + + /** + * URIRuleMatcher - abstract base class for the rule sets used for + * various URI schemes. + */ + static abstract class URIRuleMatcher { + protected final int wellKnownPort; + + protected URIRuleMatcher(int port) { + wellKnownPort = port; + } + + /** + * Attempt to match the scheme, host and port between a filter + * rule URI and a URI coming from an AIA extension. + * + * @param filterRule the filter rule to match against + * @param caIssuer the AIA URI being compared + * @return true if the scheme, host and port numbers match, false if + * any of the components do not match. If a port number is omitted in + * either the filter rule or AIA URI, the well-known port for that + * scheme is used in the comparison. + */ + boolean schemeHostPortCheck(URI filterRule, URI caIssuer) { + if (!filterRule.getScheme().equalsIgnoreCase( + caIssuer.getScheme())) { + return false; + } else if (!filterRule.getHost().equalsIgnoreCase( + caIssuer.getHost())) { + return false; + } else { + try { + // Check for port matching, taking into consideration + // default ports + int fPort = (filterRule.getPort() == -1) ? wellKnownPort : + filterRule.getPort(); + int caiPort = (caIssuer.getPort() == -1) ? wellKnownPort : + caIssuer.getPort(); + if (fPort != caiPort) { + return false; + } + } catch (IllegalArgumentException iae) { + return false; + } + } + return true; + } + + /** + * Attempt to match an AIA URI against a specific filter rule. The + * specific rules to apply are implementation dependent. + * + * @param filterRule the filter rule to match against + * @param caIssuer the AIA URI being compared + * @return true if all matching rules pass, false if any fail. + */ + abstract boolean matchRule(URI filterRule, URI caIssuer); + } + + static class HttpFtpRuleMatcher extends URIRuleMatcher { + static final HttpFtpRuleMatcher HTTP = new HttpFtpRuleMatcher(80); + static final HttpFtpRuleMatcher HTTPS = new HttpFtpRuleMatcher(443); + static final HttpFtpRuleMatcher FTP = new HttpFtpRuleMatcher(21); + + private HttpFtpRuleMatcher(int port) { + super(port); + } + + @Override + boolean matchRule(URI filterRule, URI caIssuer) { + // Check for scheme/host/port matching + if (!schemeHostPortCheck(filterRule, caIssuer)) { + return false; + } + + // Check the path component to make sure the filter is at + // least a root of the AIA caIssuer URI's path. It must be + // a case-sensitive match for all platforms. + if (!isRootOf(filterRule, caIssuer)) { + if (debug != null) { + debug.println("allowedAIALocations: Match failed: " + + "AIA URI is not within the rule's path hierarchy."); + } + return false; + } + return true; + } + + /** + * Performs a hierarchical containment check, ensuring that the + * base URI's path is a root component of the candidate path. The + * path comparison is case-sensitive. If the base path ends in a + * slash (/) then all candidate paths that begin with the base + * path are allowed. If it does not end in a slash, then it is + * assumed that the leaf node in the base path is a file component + * and both paths must match exactly. + * + * @param base the URI that contains the root path + * @param candidate the URI that contains the path being evaluated + * @return true if {@code candidate} is a child path of {@code base}, + * false otherwise. + */ + private static boolean isRootOf(URI base, URI candidate) { + // Note: The URIs have already been normalized at this point and + // HTTP URIs cannot have null paths. If it's an empty path + // then consider the path to be "/". + String basePath = Optional.of(base.getPath()). + filter(p -> !p.isEmpty()).orElse("/"); + String candPath = Optional.of(candidate.getPath()). + filter(p -> !p.isEmpty()).orElse("/"); + return (basePath.endsWith("/")) ? candPath.startsWith(basePath) : + candPath.equals(basePath); + } + } + + static class LdapRuleMatcher extends URIRuleMatcher { + static final LdapRuleMatcher LDAP = new LdapRuleMatcher(389); + static final LdapRuleMatcher LDAPS = new LdapRuleMatcher(636); + + private LdapRuleMatcher(int port) { + super(port); + } + + @Override + boolean matchRule(URI filterRule, URI caIssuer) { + // Check for scheme/host/port matching + if (!schemeHostPortCheck(filterRule, caIssuer)) { + return false; + } + + // Obtain the base DN component and compare + try { + X500Principal filterBaseDn = new X500Principal( + filterRule.getPath().replaceFirst("^/+", "")); + X500Principal caIssBaseDn = new X500Principal( + caIssuer.getPath().replaceFirst("^/+", "")); + if (!filterBaseDn.equals(caIssBaseDn)) { + if (debug != null) { + debug.println("allowedAIALocations: Match failed: " + + "Base DN mismatch (" + filterBaseDn + " vs " + + caIssBaseDn + ")"); + } + return false; + } + } catch (IllegalArgumentException iae) { + if (debug != null) { + debug.println("allowedAIALocations: Match failed on DN: " + + iae); + } + return false; + } + + return true; + } + } } diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index b5cbce413b2..9a81ba86268 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -1655,3 +1655,48 @@ jdk.tls.alpnCharset=ISO_8859_1 # withEncryption method. # jdk.epkcs8.defaultAlgorithm=PBEWithHmacSHA256AndAES_128 + +# +# X.509 AuthorityInfoAccess caIssuer URI Filtering +# +# This property defines a whitespace-separated list of filters that +# are applied to URIs found in the authorityInfoAccess extension in +# X.509 certificates. Any caIssuers URIs in X.509 certificates are only +# followed when the com.sun.security.enableAIAcaIssuers System property is +# enabled and the filter allows the URI. By default this property imposes a +# deny-all ruleset. This property may be overridden by a System property +# of the same name. +# +# The filters must take the form of absolute, hierarchical URIs as defined by +# the java.net.URI class. Additionally, only the following protocols are +# allowed as filters: http, https, ldap and ftp. +# See RFC 5280, section 4.2.2.1 for details about the types of URIs allowed for +# the extension and their specific requirements. +# The filter matching rules are applied to each CA issuer URI as follows: +# 1. The scheme must match (case-insensitive). +# 2. A hostname or address must be specified in the filter URI. It must match +# the host or address in the caIssuers URI (case-insensitive). No name +# resolution is performed on hostnames to match IP addresses. +# 3. The port number must match. For filter and caIssuer URIs, when a port +# number is omitted, the well-known port for that scheme will be used in the +# comparison. +# 4. For hierarchical filesystem schemes (e.g. http[s], ftp): +# a. The normalized path portion of the filter URI is matched in a +# case-sensitive manner. If the final component of the path does not end +# in a slash (/), it is considered to be a file path component and must +# be an exact match of the caIssuer's URI file path component. If the +# final filter component ends in a slash, then it must either match or be +# a prefix of the caIssuer's URI path component (e.g. a filter path of +# /ab/cd/ will match a caIssuer path of /ab/cd/, /ab/cd/ef and +# /ab/cd/ef/ghi). +# b. Query strings will be ignored in filter rules and caIssuer URIs. +# c. Fragments will be ignored in filter rules and caIssuer URIs. +# 5. For ldap URIs: +# a. The base DN must be an exact match (case-insensitive). +# b. Any query string in the rule, if specified, is ignored. +# 6. A single value "any" (case-insensitive) will create an allow-all rule. +# +# As an example, here is a valid filter policy consisting of two rules: +# com.sun.security.allowedAIALocations=http://some.company.com/cacert \ +# ldap://ldap.company.com/dc=company,dc=com?caCertificate;binary +com.sun.security.allowedAIALocations= diff --git a/test/jdk/sun/security/x509/URICertStore/AIACertTimeout.java b/test/jdk/sun/security/x509/URICertStore/AIACertTimeout.java index cabb225bf1c..5491d7b0d7a 100644 --- a/test/jdk/sun/security/x509/URICertStore/AIACertTimeout.java +++ b/test/jdk/sun/security/x509/URICertStore/AIACertTimeout.java @@ -47,6 +47,7 @@ import com.sun.net.httpserver.*; import java.io.*; import java.math.BigInteger; import java.net.InetSocketAddress; +import java.security.Security; import java.security.cert.*; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -69,6 +70,7 @@ public class AIACertTimeout { private static X509Certificate eeCert; public static void main(String[] args) throws Exception { + Security.setProperty("com.sun.security.allowedAIALocations", "any"); int servTimeoutMsec = (args != null && args.length >= 1) ? Integer.parseInt(args[0]) : -1; boolean expectedPass = args != null && args.length >= 2 && diff --git a/test/jdk/sun/security/x509/URICertStore/ExtensionsWithLDAP.java b/test/jdk/sun/security/x509/URICertStore/ExtensionsWithLDAP.java index 3b598d78d9f..2214e9256c3 100644 --- a/test/jdk/sun/security/x509/URICertStore/ExtensionsWithLDAP.java +++ b/test/jdk/sun/security/x509/URICertStore/ExtensionsWithLDAP.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; +import java.security.Security; import java.security.cert.CertPath; import java.security.cert.CertPathValidator; import java.security.cert.CertPathValidatorException; @@ -47,7 +48,6 @@ import java.security.cert.PKIXParameters; import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -67,25 +67,27 @@ public class ExtensionsWithLDAP { * Not After : Jan 17 18:03:59 2043 GMT * Subject: CN=Root */ - private static final String CA_CERT = "" - + "-----BEGIN CERTIFICATE-----\n" - + "MIIC8TCCAdmgAwIBAgIJAJsSNtj5wdqqMA0GCSqGSIb3DQEBDQUAMA8xDTALBgNV\n" - + "BAMMBFJvb3QwHhcNMTUwOTAxMTgwMzU5WhcNNDMwMTE3MTgwMzU5WjAPMQ0wCwYD\n" - + "VQQDDARSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvj892vPm\n" - + "bB++x9QqqyBveP+ZqQ2B1stV7vh5JmDnOTevkZUOcemp3SXu/esNLSbpL+fARYXH\n" - + "V5ubnrfip6RbvcxPfVIIDJrRTLIIsU6W7M6/LJLbLkEVGy4ZV4IHkOw9W2O92rcv\n" - + "BkoqhzZnOTGR6uT3rRcKx4RevEKBKhZO+OPPf//lnckOybmYL7t7yQrajzHro76b\n" - + "QTXYjAUq/DKhglXfC7vF/JzlAvG2IunGmIfjGcnuDo/9X3Bxef/q5TxCS35fvb7t\n" - + "svC+g2QhTcBkQh4uNW2jSjlTIVp1uErCfP5aCjLaez5mqmb1hxPIlcvsNR23HwU6\n" - + "bQO7z7NBo9Do6QIDAQABo1AwTjAdBgNVHQ4EFgQUmLZNOBBkqdYoElyxklPYHmAb\n" - + "QXIwHwYDVR0jBBgwFoAUmLZNOBBkqdYoElyxklPYHmAbQXIwDAYDVR0TBAUwAwEB\n" - + "/zANBgkqhkiG9w0BAQ0FAAOCAQEAYV4fOhDi5q7+XNXCxO8Eil2frR9jqdP4LaQp\n" - + "3L0evW0gvPX68s2WmkPWzIu4TJcpdGFQqxyQFSXuKBXjthyiln77QItGTHWeafES\n" - + "q5ESrKdSaJZq1bTIrrReCIP74f+fY/F4Tnb3dCqzaljXfzpdbeRsIW6gF71xcOUQ\n" - + "nnPEjGVPLUegN+Wn/jQpeLxxIB7FmNXncdRUfMfZ43xVSKuMCy1UUYqJqTa/pXZj\n" - + "jCMeRPThRjRqHlJ69jStfWUQATbLyj9KN09rUaJxzmUSt61UqJi7sjcGySaCjAJc\n" - + "IcCdVmX/DmRLsdv8W36O3MgrvpT1zR3kaAlv2d8HppnBqcL3xg==\n" - + "-----END CERTIFICATE-----"; + private static final String CA_CERT = + """ + -----BEGIN CERTIFICATE----- + MIIC8TCCAdmgAwIBAgIJAJsSNtj5wdqqMA0GCSqGSIb3DQEBDQUAMA8xDTALBgNV + BAMMBFJvb3QwHhcNMTUwOTAxMTgwMzU5WhcNNDMwMTE3MTgwMzU5WjAPMQ0wCwYD + VQQDDARSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvj892vPm + bB++x9QqqyBveP+ZqQ2B1stV7vh5JmDnOTevkZUOcemp3SXu/esNLSbpL+fARYXH + V5ubnrfip6RbvcxPfVIIDJrRTLIIsU6W7M6/LJLbLkEVGy4ZV4IHkOw9W2O92rcv + BkoqhzZnOTGR6uT3rRcKx4RevEKBKhZO+OPPf//lnckOybmYL7t7yQrajzHro76b + QTXYjAUq/DKhglXfC7vF/JzlAvG2IunGmIfjGcnuDo/9X3Bxef/q5TxCS35fvb7t + svC+g2QhTcBkQh4uNW2jSjlTIVp1uErCfP5aCjLaez5mqmb1hxPIlcvsNR23HwU6 + bQO7z7NBo9Do6QIDAQABo1AwTjAdBgNVHQ4EFgQUmLZNOBBkqdYoElyxklPYHmAb + QXIwHwYDVR0jBBgwFoAUmLZNOBBkqdYoElyxklPYHmAbQXIwDAYDVR0TBAUwAwEB + /zANBgkqhkiG9w0BAQ0FAAOCAQEAYV4fOhDi5q7+XNXCxO8Eil2frR9jqdP4LaQp + 3L0evW0gvPX68s2WmkPWzIu4TJcpdGFQqxyQFSXuKBXjthyiln77QItGTHWeafES + q5ESrKdSaJZq1bTIrrReCIP74f+fY/F4Tnb3dCqzaljXfzpdbeRsIW6gF71xcOUQ + nnPEjGVPLUegN+Wn/jQpeLxxIB7FmNXncdRUfMfZ43xVSKuMCy1UUYqJqTa/pXZj + jCMeRPThRjRqHlJ69jStfWUQATbLyj9KN09rUaJxzmUSt61UqJi7sjcGySaCjAJc + IcCdVmX/DmRLsdv8W36O3MgrvpT1zR3kaAlv2d8HppnBqcL3xg== + -----END CERTIFICATE----- + """; /* * Certificate: @@ -106,39 +108,41 @@ public class ExtensionsWithLDAP { * Authority Information Access: * CA Issuers - URI:ldap://ldap.host.for.aia/dc=Root?cACertificate */ - private static final String EE_CERT = "" - + "-----BEGIN CERTIFICATE-----\n" - + "MIIDHTCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQ0FADAPMQ0wCwYDVQQDDARSb290\n" - + "MB4XDTE1MDkwMTE4MDM1OVoXDTQzMDExNzE4MDM1OVowDTELMAkGA1UEAwwCRUUw\n" - + "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpyz97liuWPDYcLH9TX8Bi\n" - + "T78olCmAfmevvch6ncXUVuCzbdaKuKXwn4EVbDszsVJLoK5zdtP+X3iDhutj+IgK\n" - + "mLhuczF3M9VIcWr+JJUyTH4+3h/RT8cjCDZOmk9iXkb5ifruVsLqzb9g+Vp140Oz\n" - + "7leikne7KmclHvTfvFd0WDI7Gb9vo4f5rT717BXJ/n+M6pNk8DLpLiEu6eziYvXR\n" - + "v5x+t5Go3x0eCXdaxEQUf2j876Wfr2qHRJK7lDfFe1DDsMg/KpKGiILYZ+g2qtVM\n" - + "ZSxtp5BZEtfB5qV/IE5kWO+mCIAGpXSZIdbERR6pZUq8GLEe1T9e+sO6H24w2F19\n" - + "AgMBAAGjgYUwgYIwNAYDVR0fBC0wKzApoCegJYYjbGRhcDovL2xkYXAuaG9zdC5m\n" - + "b3IuY3JsZHAvbWFpbi5jcmwwSgYIKwYBBQUHAQEEPjA8MDoGCCsGAQUFBzAChi5s\n" - + "ZGFwOi8vbGRhcC5ob3N0LmZvci5haWEvZGM9Um9vdD9jQUNlcnRpZmljYXRlMA0G\n" - + "CSqGSIb3DQEBDQUAA4IBAQBWDfZHpuUx0yn5d3+BuztFqoks1MkGdk+USlH0TB1/\n" - + "gWWBd+4S4PCKlpSur0gj2rMW4fP5HQfNlHci8JV8/bG4KuKRAXW56dg1818Hl3pc\n" - + "iIrUSRn8uUjH3p9qb+Rb/u3mmVQRyJjN2t/zceNsO8/+Dd808OB9aEwGs8lMT0nn\n" - + "ZYaaAqYz1GIY/Ecyx1vfEZEQ1ljo6i/r70C3igbypBUShxSiGsleiVTLOGNA+MN1\n" - + "/a/Qh0bkaQyTGqK3bwvzzMeQVqWu2EWTBD/PmND5ExkpRICdv8LBVXfLnpoBr4lL\n" - + "hnxn9+e0Ah+t8dS5EKfn44w5bI5PCu2bqxs6RCTxNjcY\n" - + "-----END CERTIFICATE-----"; + private static final String EE_CERT = + """ + -----BEGIN CERTIFICATE----- + MIIDHTCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQ0FADAPMQ0wCwYDVQQDDARSb290 + MB4XDTE1MDkwMTE4MDM1OVoXDTQzMDExNzE4MDM1OVowDTELMAkGA1UEAwwCRUUw + ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpyz97liuWPDYcLH9TX8Bi + T78olCmAfmevvch6ncXUVuCzbdaKuKXwn4EVbDszsVJLoK5zdtP+X3iDhutj+IgK + mLhuczF3M9VIcWr+JJUyTH4+3h/RT8cjCDZOmk9iXkb5ifruVsLqzb9g+Vp140Oz + 7leikne7KmclHvTfvFd0WDI7Gb9vo4f5rT717BXJ/n+M6pNk8DLpLiEu6eziYvXR + v5x+t5Go3x0eCXdaxEQUf2j876Wfr2qHRJK7lDfFe1DDsMg/KpKGiILYZ+g2qtVM + ZSxtp5BZEtfB5qV/IE5kWO+mCIAGpXSZIdbERR6pZUq8GLEe1T9e+sO6H24w2F19 + AgMBAAGjgYUwgYIwNAYDVR0fBC0wKzApoCegJYYjbGRhcDovL2xkYXAuaG9zdC5m + b3IuY3JsZHAvbWFpbi5jcmwwSgYIKwYBBQUHAQEEPjA8MDoGCCsGAQUFBzAChi5s + ZGFwOi8vbGRhcC5ob3N0LmZvci5haWEvZGM9Um9vdD9jQUNlcnRpZmljYXRlMA0G + CSqGSIb3DQEBDQUAA4IBAQBWDfZHpuUx0yn5d3+BuztFqoks1MkGdk+USlH0TB1/ + gWWBd+4S4PCKlpSur0gj2rMW4fP5HQfNlHci8JV8/bG4KuKRAXW56dg1818Hl3pc + iIrUSRn8uUjH3p9qb+Rb/u3mmVQRyJjN2t/zceNsO8/+Dd808OB9aEwGs8lMT0nn + ZYaaAqYz1GIY/Ecyx1vfEZEQ1ljo6i/r70C3igbypBUShxSiGsleiVTLOGNA+MN1 + /a/Qh0bkaQyTGqK3bwvzzMeQVqWu2EWTBD/PmND5ExkpRICdv8LBVXfLnpoBr4lL + hnxn9+e0Ah+t8dS5EKfn44w5bI5PCu2bqxs6RCTxNjcY + -----END CERTIFICATE-----"""; public static void main(String[] args) throws Exception { String extension = args[0]; String targetHost = args[1]; - + Security.setProperty("com.sun.security.allowedAIALocations", + "ldap://" + targetHost + "/dc=Root"); X509Certificate trustedCert = loadCertificate(CA_CERT); X509Certificate eeCert = loadCertificate(EE_CERT); Set trustedCertsSet = new HashSet<>(); trustedCertsSet.add(new TrustAnchor(trustedCert, null)); - CertPath cp = (CertPath) CertificateFactory.getInstance("X509") - .generateCertPath(Arrays.asList(eeCert)); + CertPath cp = CertificateFactory.getInstance("X509") + .generateCertPath(List.of(eeCert)); // CertPath validator should try to parse CRLDP and AIA extensions, // and load CRLs/certs which they point to. @@ -151,7 +155,7 @@ public class ExtensionsWithLDAP { = (InetSocketAddress) socket.getRemoteSocketAddress(); hosts.add(remoteAddress.getHostName()); }; - try (SocksProxy proxy = SocksProxy.startProxy(socketConsumer)) { + try (SocksProxy _ = SocksProxy.startProxy(socketConsumer)) { CertPathValidator.getInstance("PKIX").validate(cp, new PKIXParameters(trustedCertsSet)); throw new RuntimeException("CertPathValidatorException not thrown"); From 75172e06585060e5efca080a11d8a8a51b40afed Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Mon, 19 Jan 2026 07:45:21 +0000 Subject: [PATCH 085/328] 8374717: Unclear wording in docs for recursion for List, Map and LazyConstant Reviewed-by: rriggs --- src/java.base/share/classes/java/lang/LazyConstant.java | 7 +++---- src/java.base/share/classes/java/util/List.java | 4 ++-- src/java.base/share/classes/java/util/Map.java | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/java.base/share/classes/java/lang/LazyConstant.java b/src/java.base/share/classes/java/lang/LazyConstant.java index 703d67b8abf..85f9d0e82fd 100644 --- a/src/java.base/share/classes/java/lang/LazyConstant.java +++ b/src/java.base/share/classes/java/lang/LazyConstant.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -87,9 +87,8 @@ import java.util.function.Supplier; * is thrown. Hence, a lazy constant can never hold a {@code null} value. Clients who * want to use a nullable constant can wrap the value into an {@linkplain Optional} holder. *

- * If the computing function recursively invokes itself (directly or indirectly via - * the lazy constant), an {@linkplain IllegalStateException} is thrown, and the lazy - * constant is not initialized. + * If the computing function recursively invokes itself via the lazy constant, an + * {@linkplain IllegalStateException} is thrown, and the lazy constant is not initialized. * *

Composing lazy constants

* A lazy constant can depend on other lazy constants, forming a dependency graph diff --git a/src/java.base/share/classes/java/util/List.java b/src/java.base/share/classes/java/util/List.java index 43408de292a..5f9a90e1748 100644 --- a/src/java.base/share/classes/java/util/List.java +++ b/src/java.base/share/classes/java/util/List.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -1224,7 +1224,7 @@ public interface List extends SequencedCollection { * The returned list and its {@link List#subList(int, int) subList()} or * {@link List#reversed()} views implement the {@link RandomAccess} interface. *

- * If the provided computing function recursively calls itself or the returned + * If the provided computing function recursively calls itself via the returned * lazy list for the same index, an {@linkplain IllegalStateException} * will be thrown. *

diff --git a/src/java.base/share/classes/java/util/Map.java b/src/java.base/share/classes/java/util/Map.java index 177f0522b1b..fa16fb89050 100644 --- a/src/java.base/share/classes/java/util/Map.java +++ b/src/java.base/share/classes/java/util/Map.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -1777,7 +1777,7 @@ public interface Map { * The values of any {@link Map#values()} or {@link Map#entrySet()} views of * the returned map are also lazily computed. *

- * If the provided computing function recursively calls itself or + * If the provided computing function recursively calls itself via * the returned lazy map for the same key, an {@linkplain IllegalStateException} * will be thrown. *

From 9d7ecd51d72a1a9f34a19c07813e8b5530e6a944 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 19 Jan 2026 08:32:03 +0000 Subject: [PATCH 086/328] 8375437: G1: Convert G1EvacFailureRegions to use Atomic Reviewed-by: stefank, iwalulya --- src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp | 6 +++--- src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp | 6 ++++-- src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp | 6 +++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp b/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp index ffcb5a0022f..37553e2aa56 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp +++ b/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, 2022, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +29,6 @@ #include "gc/g1/g1EvacFailureRegions.inline.hpp" #include "gc/g1/g1HeapRegion.hpp" #include "memory/allocation.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/bitMap.inline.hpp" G1EvacFailureRegions::G1EvacFailureRegions() : @@ -43,7 +43,7 @@ G1EvacFailureRegions::~G1EvacFailureRegions() { } void G1EvacFailureRegions::pre_collection(uint max_regions) { - AtomicAccess::store(&_num_regions_evac_failed, 0u); + _num_regions_evac_failed.store_relaxed(0u); _regions_evac_failed.resize(max_regions); _regions_pinned.resize(max_regions); _regions_alloc_failed.resize(max_regions); @@ -69,6 +69,6 @@ void G1EvacFailureRegions::par_iterate(G1HeapRegionClosure* closure, G1CollectedHeap::heap()->par_iterate_regions_array(closure, hrclaimer, _evac_failed_regions, - AtomicAccess::load(&_num_regions_evac_failed), + num_regions_evac_failed(), worker_id); } diff --git a/src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp b/src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp index 9d29957b782..f752a3f8ab7 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp +++ b/src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, 2022, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +26,7 @@ #ifndef SHARE_GC_G1_G1EVACFAILUREREGIONS_HPP #define SHARE_GC_G1_G1EVACFAILUREREGIONS_HPP +#include "runtime/atomic.hpp" #include "utilities/bitMap.hpp" class G1AbstractSubTask; @@ -53,14 +55,14 @@ class G1EvacFailureRegions { // Evacuation failed regions (indexes) in the current collection. uint* _evac_failed_regions; // Number of regions evacuation failed in the current collection. - volatile uint _num_regions_evac_failed; + Atomic _num_regions_evac_failed; public: G1EvacFailureRegions(); ~G1EvacFailureRegions(); uint get_region_idx(uint idx) const { - assert(idx < _num_regions_evac_failed, "precondition"); + assert(idx < _num_regions_evac_failed.load_relaxed(), "precondition"); return _evac_failed_regions[idx]; } diff --git a/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp b/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp index 6eec9b63e6b..fb456475b56 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp +++ b/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, 2022, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2026, 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 @@ -29,10 +30,9 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" -#include "runtime/atomicAccess.hpp" uint G1EvacFailureRegions::num_regions_evac_failed() const { - return AtomicAccess::load(&_num_regions_evac_failed); + return _num_regions_evac_failed.load_relaxed(); } bool G1EvacFailureRegions::has_regions_evac_failed() const { @@ -57,7 +57,7 @@ bool G1EvacFailureRegions::record(uint worker_id, uint region_idx, bool cause_pi bool success = _regions_evac_failed.par_set_bit(region_idx, memory_order_relaxed); if (success) { - size_t offset = AtomicAccess::fetch_then_add(&_num_regions_evac_failed, 1u); + size_t offset = _num_regions_evac_failed.fetch_then_add(1u); _evac_failed_regions[offset] = region_idx; G1CollectedHeap* g1h = G1CollectedHeap::heap(); From 30f39d88e5af36bb6db458c03215e9fa6a31d6f3 Mon Sep 17 00:00:00 2001 From: David Briemann Date: Mon, 19 Jan 2026 08:54:18 +0000 Subject: [PATCH 087/328] 8375530: PPC64: incorrect quick verify_method_data_pointer check causes poor performance in debug build Reviewed-by: mdoerr, shade --- src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index fc865be015e..f7bf457f72c 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -1109,11 +1109,11 @@ void InterpreterMacroAssembler::verify_method_data_pointer() { lhz(R11_scratch1, in_bytes(DataLayout::bci_offset()), R28_mdx); ld(R12_scratch2, in_bytes(Method::const_offset()), R19_method); addi(R11_scratch1, R11_scratch1, in_bytes(ConstMethod::codes_offset())); - add(R11_scratch1, R12_scratch2, R12_scratch2); + add(R11_scratch1, R11_scratch1, R12_scratch2); cmpd(CR0, R11_scratch1, R14_bcp); beq(CR0, verify_continue); - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp ), R19_method, R14_bcp, R28_mdx); + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp), R19_method, R14_bcp, R28_mdx); bind(verify_continue); #endif From 3e181485709d108ef3d1e6b595fbd95ecc8ef74a Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 19 Jan 2026 09:02:33 +0000 Subject: [PATCH 088/328] 8375439: G1: Convert G1MonotonicArena class to use Atomic Reviewed-by: stefank, iwalulya --- src/hotspot/share/gc/g1/g1MonotonicArena.cpp | 55 +++++++++---------- src/hotspot/share/gc/g1/g1MonotonicArena.hpp | 47 ++++++++-------- .../share/gc/g1/g1MonotonicArena.inline.hpp | 11 ++-- 3 files changed, 56 insertions(+), 57 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1MonotonicArena.cpp b/src/hotspot/share/gc/g1/g1MonotonicArena.cpp index a9c6462680f..3f97870a67f 100644 --- a/src/hotspot/share/gc/g1/g1MonotonicArena.cpp +++ b/src/hotspot/share/gc/g1/g1MonotonicArena.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ #include "gc/g1/g1MonotonicArena.inline.hpp" #include "memory/allocation.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/vmOperations.hpp" #include "utilities/globalCounter.inline.hpp" @@ -61,13 +60,13 @@ void G1MonotonicArena::SegmentFreeList::bulk_add(Segment& first, size_t num, size_t mem_size) { _list.prepend(first, last); - AtomicAccess::add(&_num_segments, num, memory_order_relaxed); - AtomicAccess::add(&_mem_size, mem_size, memory_order_relaxed); + _num_segments.add_then_fetch(num, memory_order_relaxed); + _mem_size.add_then_fetch(mem_size, memory_order_relaxed); } void G1MonotonicArena::SegmentFreeList::print_on(outputStream* out, const char* prefix) { out->print_cr("%s: segments %zu size %zu", - prefix, AtomicAccess::load(&_num_segments), AtomicAccess::load(&_mem_size)); + prefix, _num_segments.load_relaxed(), _mem_size.load_relaxed()); } G1MonotonicArena::Segment* G1MonotonicArena::SegmentFreeList::get_all(size_t& num_segments, @@ -75,12 +74,12 @@ G1MonotonicArena::Segment* G1MonotonicArena::SegmentFreeList::get_all(size_t& nu GlobalCounter::CriticalSection cs(Thread::current()); Segment* result = _list.pop_all(); - num_segments = AtomicAccess::load(&_num_segments); - mem_size = AtomicAccess::load(&_mem_size); + num_segments = _num_segments.load_relaxed(); + mem_size = _mem_size.load_relaxed(); if (result != nullptr) { - AtomicAccess::sub(&_num_segments, num_segments, memory_order_relaxed); - AtomicAccess::sub(&_mem_size, mem_size, memory_order_relaxed); + _num_segments.sub_then_fetch(num_segments, memory_order_relaxed); + _mem_size.sub_then_fetch(mem_size, memory_order_relaxed); } return result; } @@ -96,8 +95,8 @@ void G1MonotonicArena::SegmentFreeList::free_all() { Segment::delete_segment(cur); } - AtomicAccess::sub(&_num_segments, num_freed, memory_order_relaxed); - AtomicAccess::sub(&_mem_size, mem_size_freed, memory_order_relaxed); + _num_segments.sub_then_fetch(num_freed, memory_order_relaxed); + _mem_size.sub_then_fetch(mem_size_freed, memory_order_relaxed); } G1MonotonicArena::Segment* G1MonotonicArena::new_segment(Segment* const prev) { @@ -115,7 +114,7 @@ G1MonotonicArena::Segment* G1MonotonicArena::new_segment(Segment* const prev) { } // Install it as current allocation segment. - Segment* old = AtomicAccess::cmpxchg(&_first, prev, next); + Segment* old = _first.compare_exchange(prev, next); if (old != prev) { // Somebody else installed the segment, use that one. Segment::delete_segment(next); @@ -126,9 +125,9 @@ G1MonotonicArena::Segment* G1MonotonicArena::new_segment(Segment* const prev) { _last = next; } // Successfully installed the segment into the list. - AtomicAccess::inc(&_num_segments, memory_order_relaxed); - AtomicAccess::add(&_mem_size, next->mem_size(), memory_order_relaxed); - AtomicAccess::add(&_num_total_slots, next->num_slots(), memory_order_relaxed); + _num_segments.add_then_fetch(1u, memory_order_relaxed); + _mem_size.add_then_fetch(next->mem_size(), memory_order_relaxed); + _num_total_slots.add_then_fetch(next->num_slots(), memory_order_relaxed); return next; } } @@ -155,7 +154,7 @@ uint G1MonotonicArena::slot_size() const { } void G1MonotonicArena::drop_all() { - Segment* cur = AtomicAccess::load_acquire(&_first); + Segment* cur = _first.load_acquire(); if (cur != nullptr) { assert(_last != nullptr, "If there is at least one segment, there must be a last one."); @@ -175,25 +174,25 @@ void G1MonotonicArena::drop_all() { cur = next; } #endif - assert(num_segments == _num_segments, "Segment count inconsistent %u %u", num_segments, _num_segments); - assert(mem_size == _mem_size, "Memory size inconsistent"); + assert(num_segments == _num_segments.load_relaxed(), "Segment count inconsistent %u %u", num_segments, _num_segments.load_relaxed()); + assert(mem_size == _mem_size.load_relaxed(), "Memory size inconsistent"); assert(last == _last, "Inconsistent last segment"); - _segment_free_list->bulk_add(*first, *_last, _num_segments, _mem_size); + _segment_free_list->bulk_add(*first, *_last, _num_segments.load_relaxed(), _mem_size.load_relaxed()); } - _first = nullptr; + _first.store_relaxed(nullptr); _last = nullptr; - _num_segments = 0; - _mem_size = 0; - _num_total_slots = 0; - _num_allocated_slots = 0; + _num_segments.store_relaxed(0); + _mem_size.store_relaxed(0); + _num_total_slots.store_relaxed(0); + _num_allocated_slots.store_relaxed(0); } void* G1MonotonicArena::allocate() { assert(slot_size() > 0, "instance size not set."); - Segment* cur = AtomicAccess::load_acquire(&_first); + Segment* cur = _first.load_acquire(); if (cur == nullptr) { cur = new_segment(cur); } @@ -201,7 +200,7 @@ void* G1MonotonicArena::allocate() { while (true) { void* slot = cur->allocate_slot(); if (slot != nullptr) { - AtomicAccess::inc(&_num_allocated_slots, memory_order_relaxed); + _num_allocated_slots.add_then_fetch(1u, memory_order_relaxed); guarantee(is_aligned(slot, _alloc_options->slot_alignment()), "result " PTR_FORMAT " not aligned at %u", p2i(slot), _alloc_options->slot_alignment()); return slot; @@ -213,7 +212,7 @@ void* G1MonotonicArena::allocate() { } uint G1MonotonicArena::num_segments() const { - return AtomicAccess::load(&_num_segments); + return _num_segments.load_relaxed(); } #ifdef ASSERT @@ -238,7 +237,7 @@ uint G1MonotonicArena::calculate_length() const { template void G1MonotonicArena::iterate_segments(SegmentClosure& closure) const { - Segment* cur = AtomicAccess::load_acquire(&_first); + Segment* cur = _first.load_acquire(); assert((cur != nullptr) == (_last != nullptr), "If there is at least one segment, there must be a last one"); diff --git a/src/hotspot/share/gc/g1/g1MonotonicArena.hpp b/src/hotspot/share/gc/g1/g1MonotonicArena.hpp index 211820c5254..d8e658b5a64 100644 --- a/src/hotspot/share/gc/g1/g1MonotonicArena.hpp +++ b/src/hotspot/share/gc/g1/g1MonotonicArena.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -28,6 +28,7 @@ #include "gc/shared/freeListAllocator.hpp" #include "nmt/memTag.hpp" +#include "runtime/atomic.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/lockFreeStack.hpp" @@ -65,27 +66,27 @@ private: // AllocOptions provides parameters for Segment sizing and expansion. const AllocOptions* _alloc_options; - Segment* volatile _first; // The (start of the) list of all segments. - Segment* _last; // The last segment of the list of all segments. - volatile uint _num_segments; // Number of assigned segments to this allocator. - volatile size_t _mem_size; // Memory used by all segments. + Atomic _first; // The (start of the) list of all segments. + Segment* _last; // The last segment of the list of all segments. + Atomic _num_segments; // Number of assigned segments to this allocator. + Atomic _mem_size; // Memory used by all segments. SegmentFreeList* _segment_free_list; // The global free segment list to preferentially // get new segments from. - volatile uint _num_total_slots; // Number of slots available in all segments (allocated + not yet used). - volatile uint _num_allocated_slots; // Number of total slots allocated ever (including free and pending). + Atomic _num_total_slots; // Number of slots available in all segments (allocated + not yet used). + Atomic _num_allocated_slots; // Number of total slots allocated ever (including free and pending). inline Segment* new_segment(Segment* const prev); DEBUG_ONLY(uint calculate_length() const;) public: - const Segment* first_segment() const { return AtomicAccess::load(&_first); } + const Segment* first_segment() const { return _first.load_relaxed(); } - uint num_total_slots() const { return AtomicAccess::load(&_num_total_slots); } + uint num_total_slots() const { return _num_total_slots.load_relaxed(); } uint num_allocated_slots() const { - uint allocated = AtomicAccess::load(&_num_allocated_slots); + uint allocated = _num_allocated_slots.load_relaxed(); assert(calculate_length() == allocated, "Must be"); return allocated; } @@ -116,11 +117,11 @@ static constexpr uint SegmentPayloadMaxAlignment = 8; class alignas(SegmentPayloadMaxAlignment) G1MonotonicArena::Segment { const uint _slot_size; const uint _num_slots; - Segment* volatile _next; + Atomic _next; // Index into the next free slot to allocate into. Full if equal (or larger) // to _num_slots (can be larger because we atomically increment this value and // check only afterwards if the allocation has been successful). - uint volatile _next_allocate; + Atomic _next_allocate; const MemTag _mem_tag; static size_t header_size() { return align_up(sizeof(Segment), SegmentPayloadMaxAlignment); } @@ -139,21 +140,21 @@ class alignas(SegmentPayloadMaxAlignment) G1MonotonicArena::Segment { Segment(uint slot_size, uint num_slots, Segment* next, MemTag mem_tag); ~Segment() = default; public: - Segment* volatile* next_addr() { return &_next; } + Atomic* next_addr() { return &_next; } void* allocate_slot(); uint num_slots() const { return _num_slots; } - Segment* next() const { return _next; } + Segment* next() const { return _next.load_relaxed(); } void set_next(Segment* next) { assert(next != this, " loop condition"); - _next = next; + _next.store_relaxed(next); } void reset(Segment* next) { - _next_allocate = 0; + _next_allocate.store_relaxed(0); assert(next != this, " loop condition"); set_next(next); memset(payload(0), 0, payload_size()); @@ -166,7 +167,7 @@ public: uint length() const { // _next_allocate might grow larger than _num_slots in multi-thread environments // due to races. - return MIN2(_next_allocate, _num_slots); + return MIN2(_next_allocate.load_relaxed(), _num_slots); } static size_t size_in_bytes(uint slot_size, uint num_slots) { @@ -176,7 +177,7 @@ public: static Segment* create_segment(uint slot_size, uint num_slots, Segment* next, MemTag mem_tag); static void delete_segment(Segment* segment); - bool is_full() const { return _next_allocate >= _num_slots; } + bool is_full() const { return _next_allocate.load_relaxed() >= _num_slots; } }; static_assert(alignof(G1MonotonicArena::Segment) >= SegmentPayloadMaxAlignment, "assert alignment of Segment (and indirectly its payload)"); @@ -186,15 +187,15 @@ static_assert(alignof(G1MonotonicArena::Segment) >= SegmentPayloadMaxAlignment, // performed by multiple threads concurrently. // Counts and memory usage are current on a best-effort basis if accessed concurrently. class G1MonotonicArena::SegmentFreeList { - static Segment* volatile* next_ptr(Segment& segment) { + static Atomic* next_ptr(Segment& segment) { return segment.next_addr(); } using SegmentStack = LockFreeStack; SegmentStack _list; - volatile size_t _num_segments; - volatile size_t _mem_size; + Atomic _num_segments; + Atomic _mem_size; public: SegmentFreeList() : _list(), _num_segments(0), _mem_size(0) { } @@ -210,8 +211,8 @@ public: void print_on(outputStream* out, const char* prefix = ""); - size_t num_segments() const { return AtomicAccess::load(&_num_segments); } - size_t mem_size() const { return AtomicAccess::load(&_mem_size); } + size_t num_segments() const { return _num_segments.load_relaxed(); } + size_t mem_size() const { return _mem_size.load_relaxed(); } }; // Configuration for G1MonotonicArena, e.g slot size, slot number of next Segment. diff --git a/src/hotspot/share/gc/g1/g1MonotonicArena.inline.hpp b/src/hotspot/share/gc/g1/g1MonotonicArena.inline.hpp index dd9ccae1849..cf1b35ccead 100644 --- a/src/hotspot/share/gc/g1/g1MonotonicArena.inline.hpp +++ b/src/hotspot/share/gc/g1/g1MonotonicArena.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -28,14 +28,13 @@ #include "gc/g1/g1MonotonicArena.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/globalCounter.inline.hpp" inline void* G1MonotonicArena::Segment::allocate_slot() { - if (_next_allocate >= _num_slots) { + if (_next_allocate.load_relaxed() >= _num_slots) { return nullptr; } - uint result = AtomicAccess::fetch_then_add(&_next_allocate, 1u, memory_order_relaxed); + uint result = _next_allocate.fetch_then_add(1u, memory_order_relaxed); if (result >= _num_slots) { return nullptr; } @@ -48,8 +47,8 @@ inline G1MonotonicArena::Segment* G1MonotonicArena::SegmentFreeList::get() { Segment* result = _list.pop(); if (result != nullptr) { - AtomicAccess::dec(&_num_segments, memory_order_relaxed); - AtomicAccess::sub(&_mem_size, result->mem_size(), memory_order_relaxed); + _num_segments.sub_then_fetch(1u, memory_order_relaxed); + _mem_size.sub_then_fetch(result->mem_size(), memory_order_relaxed); } return result; } From e0edc656240d18b4468212c38f136084a50be301 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 19 Jan 2026 12:57:44 +0000 Subject: [PATCH 089/328] 8375463: G1: Remove AtomicAccess include from files that do not use it Reviewed-by: stefank, iwalulya --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 1 - src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp | 3 +-- src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp | 3 +-- src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp | 1 - src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp | 3 +-- src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp | 3 +-- src/hotspot/share/gc/g1/g1ParScanThreadState.cpp | 3 +-- 7 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 3a0c4a04441..b6c3c0b0907 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -103,7 +103,6 @@ #include "oops/access.inline.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/cpuTimeCounters.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" diff --git a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp index 83c846e84d4..c02b028112b 100644 --- a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,6 @@ #include "gc/shared/weakProcessor.inline.hpp" #include "logging/log.hpp" #include "memory/iterator.inline.hpp" -#include "runtime/atomicAccess.hpp" class G1AdjustLiveClosure : public StackObj { G1AdjustClosure* _adjust_closure; diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp index fae73a2c6bf..13c7a6a8d3e 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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,7 +31,6 @@ #include "memory/allocation.hpp" #include "memory/padded.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/globals_extension.hpp" #include "runtime/java.hpp" #include "runtime/mutexLocker.hpp" diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp index 878d35397aa..950098c706e 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp @@ -30,7 +30,6 @@ #include "gc/g1/g1CodeRootSet.hpp" #include "gc/g1/g1CollectionSetCandidates.hpp" #include "gc/g1/g1FromCardCache.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" #include "utilities/bitMap.hpp" diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp index fbd529cb1d3..f621b1318c1 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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,6 @@ #include "gc/g1/g1CardSet.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/bitMap.inline.hpp" void G1HeapRegionRemSet::set_state_untracked() { diff --git a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp index d7e0c6e394f..529ef62b44d 100644 --- a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp +++ b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ #include "nmt/memTracker.hpp" #include "oops/markWord.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/bitMap.inline.hpp" diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index e7b02ed68e7..75a8ef1a336 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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 @@ -42,7 +42,6 @@ #include "memory/allocation.inline.hpp" #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/prefetch.inline.hpp" #include "utilities/globalDefinitions.hpp" From 6942bb2b313c2d81e95f692dd947733b1149e8b8 Mon Sep 17 00:00:00 2001 From: Andreas Steiner Date: Mon, 19 Jan 2026 13:54:06 +0000 Subject: [PATCH 090/328] 8374802: java/net/DatagramSocket/SendReceiveMaxSize.java fails on AIX due to small default RCVBUF size Reviewed-by: alanb --- test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java b/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java index 3cea9073199..ded087d35e8 100644 --- a/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java +++ b/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ import java.net.MulticastSocket; import java.nio.channels.DatagramChannel; import java.util.Random; +import static java.net.StandardSocketOptions.SO_RCVBUF; +import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertEquals; import static org.testng.Assert.expectThrows; @@ -102,6 +104,10 @@ public class SendReceiveMaxSize { DatagramSocketSupplier supplier, Class exception) throws IOException { try (var receiver = new DatagramSocket(new InetSocketAddress(HOST_ADDR, 0))) { + assertTrue(receiver.getOption(SO_RCVBUF) >= capacity, + receiver.getOption(SO_RCVBUF) + + " for UDP receive buffer too small to hold capacity " + + capacity); var port = receiver.getLocalPort(); var addr = new InetSocketAddress(HOST_ADDR, port); try (var sender = supplier.open()) { From e7f1f16a88ce239f22f86e479a5e806f531fbe31 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Mon, 19 Jan 2026 14:02:02 +0000 Subject: [PATCH 091/328] 8375271: [IR Framework] Rename IREncoding to ApplicableIRRules and driver/flag/test VM to Driver/Flag/Test VM Reviewed-by: dfenacci, thartmann, mhaessig --- .../lib/ir_framework/AbstractInfo.java | 4 +- .../compiler/lib/ir_framework/CompLevel.java | 4 +- .../jtreg/compiler/lib/ir_framework/IR.java | 4 +- .../jtreg/compiler/lib/ir_framework/README.md | 24 +++---- .../compiler/lib/ir_framework/Scenario.java | 8 +-- .../lib/ir_framework/TestFramework.java | 46 ++++++------- .../ir_framework/driver/FlagVMProcess.java | 26 ++++---- .../ir_framework/driver/TestVMException.java | 8 +-- .../ir_framework/driver/TestVMProcess.java | 35 +++++----- ...rser.java => ApplicableIRRulesParser.java} | 65 ++++++++++--------- .../irmatching/parser/IRMethodBuilder.java | 5 +- .../irmatching/parser/TestClassParser.java | 14 ++-- .../driver/irmatching/parser/TestMethod.java | 6 +- .../driver/irmatching/parser/TestMethods.java | 8 +-- .../driver/irmatching/parser/VMInfo.java | 4 +- .../irmatching/parser/VMInfoParser.java | 18 ++--- .../parser/hotspot/CompileQueueMessages.java | 8 +-- .../parser/hotspot/HotSpotPidFileParser.java | 12 ++-- .../flag/CompilePhaseCollector.java | 4 +- .../lib/ir_framework/flag/FlagVM.java | 14 ++-- .../shared/NoTestsRunException.java | 10 +-- .../shared/TestFrameworkSocket.java | 34 +++++----- ...ter.java => ApplicableIRRulesPrinter.java} | 25 +++---- .../lib/ir_framework/test/TestVM.java | 20 +++--- .../lib/ir_framework/test/VMInfoPrinter.java | 4 +- .../ir_framework/tests/TestIRMatching.java | 9 +-- .../tests/TestPhaseIRMatching.java | 4 +- 27 files changed, 213 insertions(+), 210 deletions(-) rename test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/{IREncodingParser.java => ApplicableIRRulesParser.java} (60%) rename test/hotspot/jtreg/compiler/lib/ir_framework/test/{IREncodingPrinter.java => ApplicableIRRulesPrinter.java} (96%) diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/AbstractInfo.java b/test/hotspot/jtreg/compiler/lib/ir_framework/AbstractInfo.java index 20a865b1337..b57b209112c 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/AbstractInfo.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/AbstractInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,7 +103,7 @@ abstract public class AbstractInfo { } /** - * Returns a boolean indicating if the test VM runs with flags that allow C2 compilations. + * Returns a boolean indicating if the Test VM runs with flags that allow C2 compilations. * * @return {@code true} if C2 compilations are allowed; * {@code false} otherwise (run with {@code -XX:TieredStopAtLevel={1,2,3}, -XX:-UseCompiler}). diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/CompLevel.java b/test/hotspot/jtreg/compiler/lib/ir_framework/CompLevel.java index b6e55c0f617..f8760b4dfad 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/CompLevel.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/CompLevel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -51,7 +51,7 @@ public enum CompLevel { * Can only be used at {@link Test#compLevel()}. After the warm-up, the framework keeps invoking the test over a span * of 10s (configurable by setting the property flag {@code -DWaitForCompilationTimeout}) until HotSpot compiles the * {@link Test} method. If the method was not compiled after 10s, an exception is thrown. The framework does not wait - * for the compilation if the test VM is run with {@code -Xcomp}, {@code -XX:-UseCompiler}, or + * for the compilation if the Test VM is run with {@code -Xcomp}, {@code -XX:-UseCompiler}, or * {@code -DExcludeRandom=true}. */ WAIT_FOR_COMPILATION(-4), diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IR.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IR.java index fd2cd69056a..96df71dacd7 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IR.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IR.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,7 +55,7 @@ import java.lang.annotation.RetentionPolicy; * For any other flag specified either by user code (e.g. {@link Scenario#Scenario(int, String...)}, * {@link TestFramework#runWithFlags(String...) etc.} or as part of the JTreg whitelist, IR verification is applied. * To restrict the application of IR rules when certain flags are present that could change the IR, each {@code @IR} - * annotation can specify additional preconditions on the allowed test VM flags that must hold when an IR rule is applied. + * annotation can specify additional preconditions on the allowed Test VM flags that must hold when an IR rule is applied. * If the specified preconditions fail, then the framework does not apply the IR rule. These preconditions can be * set with {@link #applyIf()}, {@link #applyIfNot()}, {@link #applyIfAnd()}, or {@link #applyIfOr()}. *

diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/README.md b/test/hotspot/jtreg/compiler/lib/ir_framework/README.md index c0df8b54658..da59bd61b13 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/README.md +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/README.md @@ -115,7 +115,7 @@ The [@IR](./IR.java) annotation provides two kinds of checks: - `counts`: A list of one or more "IR node/user-defined regex - counter" pairs which specify how often each IR node/user-defined regex should be matched on the compilation output of each compile phase. #### Disable/Enable IR Rules based on VM Flags -One might also want to restrict the application of certain `@IR` rules depending on the used flags in the test VM. These could be flags defined by the user or by JTreg. In the latter case, the flags must be whitelisted in `JTREG_WHITELIST_FLAGS` in [TestFramework](./TestFramework.java) (i.e. have no unexpected impact on the IR except if the flag simulates a specific machine setup like `UseAVX={1,2,3}` etc.) to enable an IR verification by the framework. The `@IR` rules thus have an option to restrict their application: +One might also want to restrict the application of certain `@IR` rules depending on the used flags in the Test VM. These could be flags defined by the user or by JTreg. In the latter case, the flags must be whitelisted in `JTREG_WHITELIST_FLAGS` in [TestFramework](./TestFramework.java) (i.e. have no unexpected impact on the IR except if the flag simulates a specific machine setup like `UseAVX={1,2,3}` etc.) to enable an IR verification by the framework. The `@IR` rules thus have an option to restrict their application: - `applyIf`: Only apply a rule if a flag has the specified value/range of values. - `applyIfNot`: Only apply a rule if a flag has **not** a specified value/range of values @@ -144,7 +144,7 @@ An IR verification cannot always be performed. Certain VM flags explicitly disab More information about IR matching can be found in the Javadocs of [IR](./IR.java). Concrete examples on how to specify IR constraint/rules can be found in [IRExample](../../../testlibrary_tests/ir_framework/examples/IRExample.java), [TestIRMatching](../../../testlibrary_tests/ir_framework/tests/TestIRMatching.java) (internal framework test), and [TestPhaseIRMatching](../../../testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java) (internal framework test). ### 2.3 Test VM Flags and Scenarios -The recommended way to use the framework is by defining a single `@run driver` statement in the JTreg header which, however, does not allow the specification of additional test VM flags. Instead, the user has the possibility to provide VM flags by calling `TestFramework.runWithFlags()` or by creating a `TestFramework` builder object on which `addFlags()` can be called. +The recommended way to use the framework is by defining a single `@run driver` statement in the JTreg header which, however, does not allow the specification of additional Test VM flags. Instead, the user has the possibility to provide VM flags by calling `TestFramework.runWithFlags()` or by creating a `TestFramework` builder object on which `addFlags()` can be called. If a user wants to provide multiple flag combinations for a single test, he or she has the option to provide different scenarios. A scenario based flag will always have precedence over other user defined flags. More information about scenarios can be found in the Javadocs of [Scenario](./Scenario.java). If a user wants to test all combinations of multiple sets of flags, they can use `TestFramework.addCrossProductScenarios()`. @@ -174,16 +174,16 @@ The framework provides various stress and debug flags. They should mainly be use - `-DExclude=test3`: Provide a list of `@Test` method names which should be excluded from execution. - `-DScenarios=1,2`: Provide a list of scenario indexes to specify which scenarios should be executed. - `-DWarmup=200`: Provide a new default value of the number of warm-up iterations (framework default is 2000). This might have an influence on the resulting IR and could lead to matching failures (the user can also set a fixed default warm-up value in a test with `testFrameworkObject.setDefaultWarmup(200)`). -- `-DReportStdout=true`: Print the standard output of the test VM. +- `-DReportStdout=true`: Print the standard output of the Test VM. - `-DVerbose=true`: Enable more fine-grained logging (slows the execution down). -- `-DReproduce=true`: Flag to use when directly running a test VM to bypass dependencies to the driver VM state (for example, when reproducing an issue). +- `-DReproduce=true`: Flag to use when directly running a Test VM to bypass dependencies to the Driver VM state (for example, when reproducing an issue). - `-DPrintTimes=true`: Print the execution time measurements of each executed test. - `-DPrintRuleMatchingTime=true`: Print the time of matching IR rules per method. Slows down the execution as the rules are warmed up before measurement. -- `-DVerifyVM=true`: The framework runs the test VM with additional verification flags (slows the execution down). +- `-DVerifyVM=true`: The framework runs the Test VM with additional verification flags (slows the execution down). - `-DExcludeRandom=true`: The framework randomly excludes some methods from compilation. IR verification is disabled completely with this flag. - `-DFlipC1C2=true`: The framework compiles all `@Test` annotated method with C1 if a C2 compilation would have been applied and vice versa. IR verification is disabled completely with this flag. - `-DShuffleTests=false`: Disables the random execution order of all tests (such a shuffling is always done by default). -- `-DDumpReplay=true`: Add the `DumpReplay` directive to the test VM. +- `-DDumpReplay=true`: Add the `DumpReplay` directive to the Test VM. - `-DGCAfter=true`: Perform `System.gc()` after each test (slows the execution down). - `-DTestCompilationTimeout=20`: Change the default waiting time (default: 10s) for a compilation of a normal `@Test` annotated method. - `-DWaitForCompilationTimeout=20`: Change the default waiting time (default: 10s) for a compilation of a `@Test` annotated method with compilation level [WAIT\_FOR\_COMPILATION](./CompLevel.java). @@ -193,12 +193,12 @@ The framework provides various stress and debug flags. They should mainly be use ## 3. Test Framework Execution This section gives an overview of how the framework is executing a JTreg test that calls the framework from within its `main()` method. -The framework will spawn a new "test VM" to execute the user defined tests. The test VM collects all tests of the test class specified by the user code in `main()` and ensures that there is no violation of the required format by the framework. In a next step, the framework does the following for each test in general: +The framework will spawn a new "Test VM" to execute the user defined tests. The Test VM collects all tests of the test class specified by the user code in `main()` and ensures that there is no violation of the required format by the framework. In a next step, the framework does the following for each test in general: 1. Warm the test up for a predefined number of times (default 2000). This can also be adapted for all tests by using `testFrameworkobject.setDefaultWarmup(100)` or for individual tests with an additional [@Warmup](./Warmup.java) annotation. 2. After the warm-up is finished, the framework compiles the associated `@Test` annotated method at the specified compilation level (default: C2). 3. After the compilation, the test is invoked one more time. -Once the test VM terminates, IR verification (if possible) is performed on the output of the test VM. If any test throws an exception during its execution or if IR matching fails, the failures are collected and reported in a pretty format. Check the standard error and output for more information and how to reproduce these failures. +Once the Test VM terminates, IR verification (if possible) is performed on the output of the Test VM. If any test throws an exception during its execution or if IR matching fails, the failures are collected and reported in a pretty format. Check the standard error and output for more information and how to reproduce these failures. Some of the steps above can be different due to the kind of the test or due to using non-default annotation properties. These details and differences are described in the Javadocs for the three tests (see section 2.1 Different Tests). @@ -212,10 +212,10 @@ Additional testing was performed by converting all compiler Inline Types tests t ## 5. Framework Package Structure A user only needs to import classes from the package `compiler.lib.ir_framework` (e.g. `import compiler.lib.ir_framework.*;`) which represents the interface classes to the framework. The remaining framework internal classes are kept in separate subpackages and should not directly be imported: -- `compiler.lib.ir_framework.driver`: These classes are used while running the driver VM (same VM as the one running the user code's `main()` method of a JTreg test). -- `compiler.lib.ir_framework.flag`: These classes are used while running the flag VM to determine additional flags for the test VM which are required for IR verification. -- `compiler.lib.ir_framework.test`: These classes are used while running the test VM (i.e. the actual execution of the user tests as described in section 3). -- `compiler.lib.ir_framework.shared`: These classes can be called from either the driver, flag, or test VM. +- `compiler.lib.ir_framework.driver`: These classes are used while running the Driver VM (same VM as the one running the user code's `main()` method of a JTreg test). +- `compiler.lib.ir_framework.flag`: These classes are used while running the Flag VM to determine additional flags for the Test VM which are required for IR verification. +- `compiler.lib.ir_framework.test`: These classes are used while running the Test VM (i.e. the actual execution of the user tests as described in section 3). +- `compiler.lib.ir_framework.shared`: These classes can be called from either the driver, flag, or Test VM. ## 6. Summary The initial design and feature set was kept simple and straight forward and serves well for small to medium sized tests. There are a lot of possibilities to further enhance the framework and make it more powerful. This can be tackled in additional RFEs. A few ideas can be found as subtasks of the [initial RFE](https://bugs.openjdk.org/browse/JDK-8254129) for this framework. diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/Scenario.java b/test/hotspot/jtreg/compiler/lib/ir_framework/Scenario.java index 17776f7285c..65f61173e2a 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/Scenario.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/Scenario.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -121,16 +121,16 @@ public class Scenario { } /** - * Get the test VM output (stdout + stderr) of this scenario from the last execution of the framework. + * Get the Test VM output (stdout + stderr) of this scenario from the last execution of the framework. * - * @return the test VM output. + * @return the Test VM output. */ public String getTestVMOutput() { return testVMOutput; } /** - * Set the test VM output, called by the framework. + * Set the Test VM output, called by the framework. */ void setTestVMOutput(String testVMOutput) { this.testVMOutput = testVMOutput; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java index 09e291ce5a4..1fea5da52ef 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -85,19 +85,19 @@ import java.util.stream.Stream; * {@code runXX()} methods of {@link TestFramework}. The second way, which gives more control, is to create a new * {@code TestFramework} builder object on which {@link #start()} needs to be eventually called to start the testing. *

- * The framework is called from the driver VM in which the JTreg test is initially run by specifying {@code + * The framework is called from the Driver VM in which the JTreg test is initially run by specifying {@code * @run driver} in the JTreg header. This strips all additionally specified JTreg VM and Javaoptions. - * The framework creates a new flag VM with all these flags added again in order to figure out which flags are + * The framework creates a new Flag VM with all these flags added again in order to figure out which flags are * required to run the tests specified in the test class (e.g. {@code -XX:+PrintIdeal} and {@code -XX:+PrintOptoAssembly} * for IR matching). *

- * After the flag VM terminates, it starts a new test VM which performs the execution of the specified + * After the Flag VM terminates, it starts a new Test VM which performs the execution of the specified * tests in the test class as described in {@link Test}, {@link Check}, and {@link Run}. *

- * In a last step, once the test VM has terminated without exceptions, IR matching is performed if there are any IR + * In a last step, once the Test VM has terminated without exceptions, IR matching is performed if there are any IR * rules and if no VM flags disable it (e.g. not running with {@code -Xint}, see {@link IR} for more details). * The IR regex matching is done on the output of {@code -XX:+PrintIdeal} and {@code -XX:+PrintOptoAssembly} by parsing - * the hotspot_pid file of the test VM. Failing IR rules are reported by throwing a {@link IRViolationException}. + * the hotspot_pid file of the Test VM. Failing IR rules are reported by throwing a {@link IRViolationException}. * * @see Test * @see Check @@ -166,7 +166,7 @@ public class TestFramework { ############################################################# - To only run the failed tests use -DTest, -DExclude, and/or -DScenarios. - - To also get the standard output of the test VM run with + - To also get the standard output of the Test VM run with -DReportStdout=true or for even more fine-grained logging use -DVerbose=true. ############################################################# @@ -236,10 +236,10 @@ public class TestFramework { } /** - * Tests the class from which this method was invoked from. The test VM is called with the specified {@code flags}. + * Tests the class from which this method was invoked from. The Test VM is called with the specified {@code flags}. *

    *
  • The {@code flags} override any set VM or Javaoptions flags by JTreg by default.

    - * Use {@code -DPreferCommandLineFlags=true} if you want to prefer the JTreg VM and Javaoptions flags over + * Use {@code -DPreferCommandLineFlags=true} if you want to prefer the JTreg VM and Javaoptions flags over * the specified {@code flags} of this method.

  • *
  • If you want to run your entire JTreg test with additional flags, use this method.

  • *
  • If you want to run your entire JTreg test with additional flags but for another test class then the one @@ -248,7 +248,7 @@ public class TestFramework { * {@link #addScenarios(Scenario...)}

  • *
* - * @param flags VM flags to be used for the test VM. + * @param flags VM flags to be used for the Test VM. */ public static void runWithFlags(String... flags) { StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); @@ -258,13 +258,13 @@ public class TestFramework { } /** - * Add VM flags to be used for the test VM. These flags override any VM or Javaoptions set by JTreg by default.

+ * Add VM flags to be used for the Test VM. These flags override any VM or Javaoptions set by JTreg by default.

* Use {@code -DPreferCommandLineFlags=true} if you want to prefer the VM or Javaoptions over the scenario flags. * *

* The testing can be started by invoking {@link #start()} * - * @param flags VM options to be applied to the test VM. + * @param flags VM options to be applied to the Test VM. * @return the same framework instance. */ public TestFramework addFlags(String... flags) { @@ -306,7 +306,7 @@ public class TestFramework { } /** - * Add scenarios to be used for the test VM. A test VM is called for each scenario in {@code scenarios} by using the + * Add scenarios to be used for the Test VM. A Test VM is called for each scenario in {@code scenarios} by using the * specified VM flags in the scenario. The scenario flags override any flags set by {@link #addFlags(String...)} * and thus also override any VM or Javaoptions set by JTreg by default.

* Use {@code -DPreferCommandLineFlags=true} if you want to prefer the VM and Javaoptions over the scenario flags. @@ -314,7 +314,7 @@ public class TestFramework { *

* The testing can be started by invoking {@link #start()} * - * @param scenarios scenarios which specify specific flags for the test VM. + * @param scenarios scenarios which specify specific flags for the Test VM. * @return the same framework instance. */ public TestFramework addScenarios(Scenario... scenarios) { @@ -503,10 +503,10 @@ public class TestFramework { } /** - * Get the VM output of the test VM. Use {@code -DVerbose=true} to enable more debug information. If scenarios + * Get the VM output of the Test VM. Use {@code -DVerbose=true} to enable more debug information. If scenarios * were run, use {@link Scenario#getTestVMOutput()}. * - * @return the last test VM output. + * @return the last Test VM output. */ public static String getLastTestVMOutput() { return TestVMProcess.getLastTestVMOutput(); @@ -796,9 +796,9 @@ public class TestFramework { } /** - * Execute a separate "flag" VM with White Box access to determine all test VM flags. The flag VM sends an encoding of - * all required flags for the test VM to the driver VM over a socket. Once the flag VM exits, this driver VM parses the - * test VM flags, which also determine if IR matching should be done, and then starts the test VM to execute all tests. + * Execute a separate Flag VM with White Box access to determine all Test VM flags. The Flag VM sends an encoding of + * all required flags for the Test VM to the Driver VM over a socket. Once the Flag VM exits, this Driver VM parses the + * Test VM flags, which also determine if IR matching should be done, and then starts the Test VM to execute all tests. */ private void start(Scenario scenario) { if (scenario != null && !scenario.isEnabled()) { @@ -823,12 +823,12 @@ public class TestFramework { "" : " - [" + String.join(", ", additionalFlags) + "]"; if (shouldVerifyIR) { - // Only need to use flag VM if an IR verification is possibly done. + // Only need to use Flag VM if an IR verification is possibly done. System.out.println("Run Flag VM:"); FlagVMProcess flagVMProcess = new FlagVMProcess(testClass, additionalFlags); shouldVerifyIR = flagVMProcess.shouldVerifyIR(); if (shouldVerifyIR) { - // Add more flags for the test VM which are required to do IR verification. + // Add more flags for the Test VM which are required to do IR verification. additionalFlags.addAll(flagVMProcess.getTestVMFlags()); } // else: Flag VM found a reason to not do IR verification. } else { @@ -882,7 +882,7 @@ public class TestFramework { try { TestClassParser testClassParser = new TestClassParser(testClass, isAllowNotCompilable); Matchable testClassMatchable = testClassParser.parse(testVMProcess.getHotspotPidFileName(), - testVMProcess.getIrEncoding()); + testVMProcess.getApplicableIRRules()); IRMatcher matcher = new IRMatcher(testClassMatchable); matcher.match(); } catch (IRViolationException e) { @@ -892,7 +892,7 @@ public class TestFramework { } else { System.out.println("IR verification disabled either due to no @IR annotations, through explicitly setting " + "-DVerify=false, due to not running a debug build, using a non-whitelisted JTreg VM or " + - "Javaopts flag like -Xint, or running the test VM with other VM flags added by user code " + + "Javaopts flag like -Xint, or running the Test VM with other VM flags added by user code " + "that make the IR verification impossible (e.g. -XX:-UseCompile, " + "-XX:TieredStopAtLevel=[1,2,3], etc.)."); } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/FlagVMProcess.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/FlagVMProcess.java index 0b7d1db125c..86eb1935207 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/FlagVMProcess.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/FlagVMProcess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,9 +41,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * This class prepares, creates, and runs the "flag" VM with verification of proper termination. The flag VM determines - * the flags required for the "test" VM. The flag VM writes these flags to a dedicated file which is then parsed by this - * class after the termination of the flag VM. + * This class prepares, creates, and runs the Flag VM with verification of proper termination. The Flag VM determines + * the flags required for the Test VM. The Flag VM writes these flags to a dedicated file which is then parsed by this + * class after the termination of the Flag VM. * * @see FlagVM */ @@ -73,7 +73,7 @@ public class FlagVMProcess { String patternString = "(.*DShouldDoIRVerification=(true|false).*)"; Pattern pattern = Pattern.compile(patternString); Matcher matcher = pattern.matcher(flags); - TestFramework.check(matcher.find(), "Invalid flag encoding emitted by flag VM"); + TestFramework.check(matcher.find(), "Invalid flag encoding emitted by Flag VM"); // Maybe we run with flags that make IR verification impossible shouldVerifyIR = Boolean.parseBoolean(matcher.group(2)); testVMFlags.addAll(Arrays.asList(matcher.group(1).split(FlagVM.TEST_VM_FLAGS_DELIMITER))); @@ -91,8 +91,8 @@ public class FlagVMProcess { } /** - * The flag VM needs White Box access to prepare all test VM flags. The flag VM will write the test VM flags to - * a dedicated file which is afterwards parsed by the driver VM and added as flags to the test VM. + * The Flag VM needs White Box access to prepare all Test VM flags. The Flag VM will write the Test VM flags to + * a dedicated file which is afterwards parsed by the Driver VM and added as flags to the Test VM. */ private void prepareVMFlags(Class testClass, List additionalFlags) { cmds.add("-Dtest.jdk=" + Utils.TEST_JDK); @@ -103,7 +103,7 @@ public class FlagVMProcess { cmds.add("-Xbootclasspath/a:."); cmds.add("-XX:+UnlockDiagnosticVMOptions"); cmds.add("-XX:+WhiteBoxAPI"); - // TestFramework and scenario flags might have an influence on the later used test VM flags. Add them as well. + // TestFramework and scenario flags might have an influence on the later used Test VM flags. Add them as well. cmds.addAll(additionalFlags); cmds.add(FlagVM.class.getCanonicalName()); cmds.add(testClass.getCanonicalName()); @@ -111,10 +111,10 @@ public class FlagVMProcess { private void start() { try { - // Run "flag" VM with White Box access to determine the test VM flags and if IR verification should be done. + // Run Flag VM with White Box access to determine the Test VM flags and if IR verification should be done. oa = ProcessTools.executeTestJava(cmds); } catch (Exception e) { - throw new TestRunException("Failed to execute TestFramework flag VM", e); + throw new TestRunException("Failed to execute TestFramework Flag VM", e); } testVMFlagsFile = FlagVM.TEST_VM_FLAGS_FILE_PREFIX + oa.pid() + FlagVM.FILE_POSTFIX; @@ -125,14 +125,14 @@ public class FlagVMProcess { String flagVMOutput = oa.getOutput(); int exitCode = oa.getExitValue(); if (VERBOSE && exitCode == 0) { - System.out.println("--- OUTPUT TestFramework flag VM ---"); + System.out.println("--- OUTPUT TestFramework Flag VM ---"); System.out.println(flagVMOutput); } if (exitCode != 0) { - System.err.println("--- OUTPUT TestFramework flag VM ---"); + System.err.println("--- OUTPUT TestFramework Flag VM ---"); System.err.println(flagVMOutput); - throw new RuntimeException("TestFramework flag VM exited with " + exitCode); + throw new RuntimeException("TestFramework Flag VM exited with " + exitCode); } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMException.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMException.java index 63b3d522b86..8de9ac8e348 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMException.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ package compiler.lib.ir_framework.driver; import compiler.lib.ir_framework.shared.TestFormatException; /** - * Exception that is thrown if the test VM has thrown any kind of exception (except for {@link TestFormatException}). + * Exception that is thrown if the Test VM has thrown any kind of exception (except for {@link TestFormatException}). */ public class TestVMException extends RuntimeException { private final String exceptionInfo; @@ -37,9 +37,9 @@ public class TestVMException extends RuntimeException { } /** - * Get some more detailed information about the exception thrown in the test VM and how to reproduce it. + * Get some more detailed information about the exception thrown in the Test VM and how to reproduce it. * - * @return a formatted string containing information about the exception of the test VM and how to reproduce it. + * @return a formatted string containing information about the exception of the Test VM and how to reproduce it. */ public String getExceptionInfo() { return exceptionInfo; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java index 2b7fd2a1eea..a172dce1991 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,9 +41,9 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; /** - * This class prepares, creates, and runs the "test" VM with verification of proper termination. The class also stores - * information about the test VM which is later queried for IR matching. The communication between this driver VM - * and the test VM is done over a dedicated socket. + * This class prepares, creates, and runs the Test VM with verification of proper termination. The class also stores + * information about the Test VM which is later queried for IR matching. The communication between this Driver VM + * and the Test VM is done over a dedicated socket. * * @see TestVM * @see TestFrameworkSocket @@ -62,7 +62,7 @@ public class TestVMProcess { private String hotspotPidFileName; private String commandLine; private OutputAnalyzer oa; - private String irEncoding; + private String applicableIRRules; public TestVMProcess(List additionalFlags, Class testClass, Set> helperClasses, int defaultWarmup, boolean allowNotCompilable, boolean testClassesOnBootClassPath) { @@ -81,8 +81,8 @@ public class TestVMProcess { return commandLine; } - public String getIrEncoding() { - return irEncoding; + public String getApplicableIRRules() { + return applicableIRRules; } public String getHotspotPidFileName() { @@ -98,7 +98,7 @@ public class TestVMProcess { boolean testClassesOnBootClassPath) { // Set java.library.path so JNI tests which rely on jtreg nativepath setting work cmds.add("-Djava.library.path=" + Utils.TEST_NATIVE_PATH); - // Need White Box access in test VM. + // Need White Box access in Test VM. String bootClassPath = "-Xbootclasspath/a:."; if (testClassesOnBootClassPath) { // Add test classes themselves to boot classpath to make them privileged. @@ -112,7 +112,8 @@ public class TestVMProcess { if (!PREFER_COMMAND_LINE_FLAGS) { cmds.addAll(jtregVMFlags); } - // Add server property flag that enables test VM to print encoding for IR verification last and debug messages. + // Add server property flag that enables the Test VM to print the Applicable IR Rules for IR verification and + // debug messages. cmds.add(socket.getPortPropertyFlag()); cmds.addAll(additionalFlags); cmds.addAll(Arrays.asList(getDefaultFlags())); @@ -142,7 +143,7 @@ public class TestVMProcess { } /** - * Default flags that are added used for the test VM. + * Default flags that are added used for the Test VM. */ private static String[] getDefaultFlags() { return new String[] {"-XX:-BackgroundCompilation", "-XX:CompileCommand=quiet"}; @@ -169,7 +170,7 @@ public class TestVMProcess { throw new TestFrameworkException("Error while executing Test VM", e); } - process.command().add(1, "-DReproduce=true"); // Add after "/path/to/bin/java" in order to rerun the test VM directly + process.command().add(1, "-DReproduce=true"); // Add after "/path/to/bin/java" in order to rerun the Test VM directly commandLine = "Command Line:" + System.lineSeparator() + String.join(" ", process.command()) + System.lineSeparator(); hotspotPidFileName = String.format("hotspot_pid%d.log", oa.pid()); @@ -178,7 +179,7 @@ public class TestVMProcess { /** * Process the socket output: All prefixed lines are dumped to the standard output while the remaining lines - * represent the IR encoding used for IR matching later. + * represent the Applicable IR Rules used for IR matching later. */ private void processSocketOutput(TestFrameworkSocket socket) { String output = socket.getOutput(); @@ -215,16 +216,16 @@ public class TestVMProcess { System.out.println("---------------------"); System.out.println(messagesBuilder); } - irEncoding = nonStdOutBuilder.toString(); + applicableIRRules = nonStdOutBuilder.toString(); } else { - irEncoding = output; + applicableIRRules = output; } } private void checkTestVMExitCode() { final int exitCode = oa.getExitValue(); if (EXCLUDE_RANDOM || REPORT_STDOUT || (VERBOSE && exitCode == 0)) { - System.out.println("--- OUTPUT TestFramework test VM ---"); + System.out.println("--- OUTPUT TestFramework Test VM ---"); System.out.println(oa.getOutput()); } @@ -234,7 +235,7 @@ public class TestVMProcess { } /** - * Exit code was non-zero of test VM. Check the stderr to determine what kind of exception that should be thrown to + * Exit code was non-zero of Test VM. Check the stderr to determine what kind of exception that should be thrown to * react accordingly later. */ private void throwTestVMException() { @@ -266,7 +267,7 @@ public class TestVMProcess { stdOut = System.lineSeparator() + System.lineSeparator() + "Standard Output" + System.lineSeparator() + "---------------" + System.lineSeparator() + oa.getOutput(); } - return "TestFramework test VM exited with code " + exitCode + System.lineSeparator() + stdOut + return "TestFramework Test VM exited with code " + exitCode + System.lineSeparator() + stdOut + System.lineSeparator() + commandLine + System.lineSeparator() + System.lineSeparator() + "Error Output" + System.lineSeparator() + "------------" + System.lineSeparator() + stdErr + System.lineSeparator() + System.lineSeparator(); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IREncodingParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/ApplicableIRRulesParser.java similarity index 60% rename from test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IREncodingParser.java rename to test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/ApplicableIRRulesParser.java index 28c4213f82d..7aaf0c2b285 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IREncodingParser.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/ApplicableIRRulesParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ import compiler.lib.ir_framework.TestFramework; import compiler.lib.ir_framework.driver.irmatching.parser.hotspot.HotSpotPidFileParser; import compiler.lib.ir_framework.shared.TestFormat; import compiler.lib.ir_framework.shared.TestFrameworkException; -import compiler.lib.ir_framework.test.IREncodingPrinter; +import compiler.lib.ir_framework.test.ApplicableIRRulesPrinter; import java.lang.reflect.Method; import java.util.HashMap; @@ -37,34 +37,34 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * Class to parse the IR encoding emitted by the test VM and creating {@link TestMethod} objects for each entry. + * Class to parse the Applicable IR Rules emitted by the Test VM and creating {@link TestMethod} objects for each entry. * * @see TestMethod */ -public class IREncodingParser { +public class ApplicableIRRulesParser { - private static final boolean PRINT_IR_ENCODING = Boolean.parseBoolean(System.getProperty("PrintIREncoding", "false")); - private static final Pattern IR_ENCODING_PATTERN = - Pattern.compile("(?<=" + IREncodingPrinter.START + "\r?\n).*\\R([\\s\\S]*)(?=" + IREncodingPrinter.END + ")"); + private static final boolean PRINT_APPLICABLE_IR_RULES = Boolean.parseBoolean(System.getProperty("PrintApplicableIRRules", "false")); + private static final Pattern APPLICABLE_IR_RULES_PATTERN = + Pattern.compile("(?<=" + ApplicableIRRulesPrinter.START + "\r?\n).*\\R([\\s\\S]*)(?=" + ApplicableIRRulesPrinter.END + ")"); private final Map testMethods; private final Class testClass; - public IREncodingParser(Class testClass) { + public ApplicableIRRulesParser(Class testClass) { this.testClass = testClass; this.testMethods = new HashMap<>(); } /** - * Parse the IR encoding passed as parameter and return a "test name" -> TestMethod map that contains an entry - * for each method that needs to be IR matched on. + * Parse the Applicable IR rules passed as parameter and return a "test name" -> TestMethod map that contains an + * entry for each method that needs to be IR matched on. */ - public TestMethods parse(String irEncoding) { - if (TestFramework.VERBOSE || PRINT_IR_ENCODING) { - System.out.println("Read IR encoding from test VM:"); - System.out.println(irEncoding); + public TestMethods parse(String applicableIRRules) { + if (TestFramework.VERBOSE || PRINT_APPLICABLE_IR_RULES) { + System.out.println("Read Applicable IR Rules from Test VM:"); + System.out.println(applicableIRRules); } - createTestMethodMap(irEncoding, testClass); + createTestMethodMap(applicableIRRules, testClass); // We could have found format errors in @IR annotations. Report them now with an exception. TestFormat.throwIfAnyFailures(); return new TestMethods(testMethods); @@ -74,22 +74,22 @@ public class IREncodingParser { * Sets up a map testname -> TestMethod map. The TestMethod object will later be filled with the ideal and opto * assembly output in {@link HotSpotPidFileParser}. */ - private void createTestMethodMap(String irEncoding, Class testClass) { - Map irRulesMap = parseIREncoding(irEncoding); - createTestMethodsWithEncoding(testClass, irRulesMap); + private void createTestMethodMap(String applicableIRRules, Class testClass) { + Map irRulesMap = parseApplicableIRRules(applicableIRRules); + createTestMethodsWithApplicableIRRules(testClass, irRulesMap); } /** - * Read the IR encoding emitted by the test VM to decide if an @IR rule must be checked for a method. + * Read the Applicable IR Rules emitted by the Test VM to decide if an @IR rule must be checked for a method. */ - private Map parseIREncoding(String irEncoding) { + private Map parseApplicableIRRules(String applicableIRRules) { Map irRulesMap = new HashMap<>(); - String[] irEncodingLines = getIREncodingLines(irEncoding); - for (String s : irEncodingLines) { + String[] applicableIRRulesLines = getApplicableIRRulesLines(applicableIRRules); + for (String s : applicableIRRulesLines) { String line = s.trim(); String[] splitLine = line.split(","); if (splitLine.length < 2) { - throw new TestFrameworkException("Invalid IR match rule encoding. No comma found: " + splitLine[0]); + throw new TestFrameworkException("Invalid Applicable IR Rules format. No comma found: " + splitLine[0]); } String testName = splitLine[0]; int[] irRulesIdx = getRuleIndexes(splitLine); @@ -99,11 +99,12 @@ public class IREncodingParser { } /** - * Parse the IR encoding lines without header, explanation line and footer and return them in an array. + * Parse the Applicable IR Rules lines without header, explanation line and footer and return them in an array. */ - private String[] getIREncodingLines(String irEncoding) { - Matcher matcher = IR_ENCODING_PATTERN.matcher(irEncoding); - TestFramework.check(matcher.find(), "Did not find IR encoding in:" + System.lineSeparator() + irEncoding); + private String[] getApplicableIRRulesLines(String applicableIRRules) { + Matcher matcher = APPLICABLE_IR_RULES_PATTERN.matcher(applicableIRRules); + TestFramework.check(matcher.find(), "Did not find Applicable IR Rules in:" + + System.lineSeparator() + applicableIRRules); String lines = matcher.group(1).trim(); if (lines.isEmpty()) { // Nothing to IR match. @@ -113,7 +114,7 @@ public class IREncodingParser { } /** - * Parse rule indexes from IR encoding line of the format: + * Parse rule indexes from a single line of the Applicable IR Rules in the format: */ private int[] getRuleIndexes(String[] splitLine) { int[] irRulesIdx = new int[splitLine.length - 1]; @@ -121,13 +122,13 @@ public class IREncodingParser { try { irRulesIdx[i - 1] = Integer.parseInt(splitLine[i]); } catch (NumberFormatException e) { - throw new TestFrameworkException("Invalid IR match rule encoding. No number found: " + splitLine[i]); + throw new TestFrameworkException("Invalid Applicable IR Rules format. No number found: " + splitLine[i]); } } return irRulesIdx; } - private void createTestMethodsWithEncoding(Class testClass, Map irRulesMap) { + private void createTestMethodsWithApplicableIRRules(Class testClass, Map irRulesMap) { for (Method m : testClass.getDeclaredMethods()) { IR[] irAnnos = m.getAnnotationsByType(IR.class); if (irAnnos.length > 0) { @@ -144,7 +145,7 @@ public class IREncodingParser { private void validateIRRuleIds(Method m, IR[] irAnnos, int[] ids) { TestFramework.check(ids != null, "Should find method name in validIrRulesMap for " + m); TestFramework.check(ids.length > 0, "Did not find any rule indices for " + m); - TestFramework.check((ids[0] >= 1 || ids[0] == IREncodingPrinter.NO_RULE_APPLIED) + TestFramework.check((ids[0] >= 1 || ids[0] == ApplicableIRRulesPrinter.NO_RULE_APPLIED) && ids[ids.length - 1] <= irAnnos.length, "Invalid IR rule index found in validIrRulesMap for " + m); } @@ -153,6 +154,6 @@ public class IREncodingParser { * Does the list of IR rules contain any applicable IR rules for the given conditions? */ private boolean hasAnyApplicableIRRules(int[] irRuleIds) { - return irRuleIds[0] != IREncodingPrinter.NO_RULE_APPLIED; + return irRuleIds[0] != ApplicableIRRulesPrinter.NO_RULE_APPLIED; } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodBuilder.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodBuilder.java index 538680496e7..d7a10acd1cd 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodBuilder.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ package compiler.lib.ir_framework.driver.irmatching.parser; import compiler.lib.ir_framework.Test; -import compiler.lib.ir_framework.TestFramework; import compiler.lib.ir_framework.driver.irmatching.Compilation; import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod; import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethodMatchable; @@ -53,7 +52,7 @@ class IRMethodBuilder { } /** - * Create IR methods for all test methods identified by {@link IREncodingParser} by combining them with the parsed + * Create IR methods for all test methods identified by {@link ApplicableIRRulesParser} by combining them with the parsed * compilation output from {@link HotSpotPidFileParser}. */ public SortedSet build(VMInfo vmInfo) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestClassParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestClassParser.java index b6c9920c2d1..2329b41afbe 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestClassParser.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestClassParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, 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 @@ -50,13 +50,13 @@ public class TestClassParser { } /** - * Parse the IR encoding and hotspot_pid* file to create a collection of {@link IRMethod} objects. + * Parse the Applicable IR Rules and hotspot_pid* file to create a collection of {@link IRMethod} objects. * Return a default/empty TestClass object if there are no applicable @IR rules in any method of the test class. */ - public Matchable parse(String hotspotPidFileName, String irEncoding) { - IREncodingParser irEncodingParser = new IREncodingParser(testClass); - TestMethods testMethods = irEncodingParser.parse(irEncoding); - VMInfo vmInfo = VMInfoParser.parseVMInfo(irEncoding); + public Matchable parse(String hotspotPidFileName, String applicableIRRules) { + ApplicableIRRulesParser applicableIRRulesParser = new ApplicableIRRulesParser(testClass); + TestMethods testMethods = applicableIRRulesParser.parse(applicableIRRules); + VMInfo vmInfo = VMInfoParser.parseVMInfo(applicableIRRules); if (testMethods.hasTestMethods()) { HotSpotPidFileParser hotSpotPidFileParser = new HotSpotPidFileParser(testClass.getName(), testMethods); LoggedMethods loggedMethods = hotSpotPidFileParser.parse(hotspotPidFileName); @@ -66,7 +66,7 @@ public class TestClassParser { } /** - * Create test class with IR methods for all test methods identified by {@link IREncodingParser} by combining them + * Create test class with IR methods for all test methods identified by {@link ApplicableIRRulesParser} by combining them * with the parsed compilation output from {@link HotSpotPidFileParser}. */ private Matchable createTestClass(TestMethods testMethods, LoggedMethods loggedMethods, VMInfo vmInfo) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethod.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethod.java index 8491b8d61eb..43f27c80ac6 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethod.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, 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,10 +30,10 @@ import compiler.lib.ir_framework.driver.irmatching.parser.hotspot.LoggedMethod; import java.lang.reflect.Method; /** - * This class represents a test method parsed by {@link IREncodingParser}. In combination with the associated + * This class represents a test method parsed by {@link ApplicableIRRulesParser}. In combination with the associated * {@link LoggedMethod}, a new {@link IRMethod} is created to IR match on later. * - * @see IREncodingParser + * @see ApplicableIRRulesParser * @see LoggedMethod * @see IRMethod */ diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethods.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethods.java index ecc8fb4e0b9..d1edfb08fdf 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethods.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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 @@ -29,15 +29,15 @@ import compiler.lib.ir_framework.driver.irmatching.parser.hotspot.HotSpotPidFile import java.util.Map; /** - * This class stores all test methods that need to be IR matched as identified by {@link IREncodingParser}. + * This class stores all test methods that need to be IR matched as identified by {@link ApplicableIRRulesParser}. * - * @see IREncodingParser + * @see ApplicableIRRulesParser * @see HotSpotPidFileParser * @see IRMethod */ public class TestMethods { /** - * "Method name" -> TestMethod map created by {@link IREncodingParser} which contains an entry for each method that + * "Method name" -> TestMethod map created by {@link ApplicableIRRulesParser} which contains an entry for each method that * needs to be IR matched on. */ private final Map testMethods; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfo.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfo.java index db70e7892a2..89b6d610496 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfo.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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 @@ -33,7 +33,7 @@ import java.util.regex.Pattern; /** * This class stores the key value mapping from the VMInfo. * - * @see IREncodingParser + * @see ApplicableIRRulesParser */ public class VMInfo { /** diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfoParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfoParser.java index a8e6782ab12..2b17303f1a7 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfoParser.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfoParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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 @@ -33,7 +33,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * Class to parse the VMInfo emitted by the test VM and creating {@link VMInfo} objects for each entry. + * Class to parse the VMInfo emitted by the Test VM and creating {@link VMInfo} objects for each entry. * * @see VMInfo */ @@ -43,11 +43,11 @@ public class VMInfoParser { Pattern.compile("(?<=" + VMInfoPrinter.START_VM_INFO + "\r?\n).*\\R([\\s\\S]*)(?=" + VMInfoPrinter.END_VM_INFO + ")"); /** - * Extract VMInfo from the irEncoding. + * Extract VMInfo from the applicableIRRules. */ - public static VMInfo parseVMInfo(String irEncoding) { + public static VMInfo parseVMInfo(String applicableIRRules) { Map map = new HashMap<>(); - String[] lines = getVMInfoLines(irEncoding); + String[] lines = getVMInfoLines(applicableIRRules); for (String s : lines) { String line = s.trim(); String[] splitLine = line.split(":", 2); @@ -62,11 +62,11 @@ public class VMInfoParser { } /** - * Extract the VMInfo from the irEncoding string, strip away the header and return the individual key-value lines. + * Extract the VMInfo from the applicableIRRules string, strip away the header and return the individual key-value lines. */ - private static String[] getVMInfoLines(String irEncoding) { - Matcher matcher = VM_INFO_PATTERN.matcher(irEncoding); - TestFramework.check(matcher.find(), "Did not find VMInfo in:" + System.lineSeparator() + irEncoding); + private static String[] getVMInfoLines(String applicableIRRules) { + Matcher matcher = VM_INFO_PATTERN.matcher(applicableIRRules); + TestFramework.check(matcher.find(), "Did not find VMInfo in:" + System.lineSeparator() + applicableIRRules); String lines = matcher.group(1).trim(); if (lines.isEmpty()) { // Nothing to IR match. diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/CompileQueueMessages.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/CompileQueueMessages.java index 9ccb78ea892..f9fa0d1433e 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/CompileQueueMessages.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/CompileQueueMessages.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ package compiler.lib.ir_framework.driver.irmatching.parser.hotspot; import compiler.lib.ir_framework.TestFramework; -import compiler.lib.ir_framework.driver.irmatching.parser.IREncodingParser; +import compiler.lib.ir_framework.driver.irmatching.parser.ApplicableIRRulesParser; import compiler.lib.ir_framework.driver.irmatching.parser.TestMethods; import java.util.HashMap; @@ -34,9 +34,9 @@ import java.util.regex.Pattern; /** * This class parses compile queue messages found in the hotspot_pid* files and keeps track of those that need to be - * IR matched (i.e. identified by {@link IREncodingParser}. + * IR matched (i.e. identified by {@link ApplicableIRRulesParser}. * - * @see IREncodingParser + * @see ApplicableIRRulesParser */ class CompileQueueMessages { private static final Pattern COMPILE_ID_PATTERN = Pattern.compile("compile_id='(\\d+)'"); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/HotSpotPidFileParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/HotSpotPidFileParser.java index a5a5a0b20a9..f39f7cc9a83 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/HotSpotPidFileParser.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/HotSpotPidFileParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ package compiler.lib.ir_framework.driver.irmatching.parser.hotspot; import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod; -import compiler.lib.ir_framework.driver.irmatching.parser.IREncodingParser; +import compiler.lib.ir_framework.driver.irmatching.parser.ApplicableIRRulesParser; import compiler.lib.ir_framework.driver.irmatching.parser.TestMethods; import compiler.lib.ir_framework.shared.TestFrameworkException; @@ -34,10 +34,10 @@ import java.nio.file.Paths; /** * Class to parse the ideal compile phases and PrintOptoAssembly outputs of the test class from the hotspot_pid* file - * of all methods identified by {@link IREncodingParser}. + * of all methods identified by {@link ApplicableIRRulesParser}. * * @see IRMethod - * @see IREncodingParser + * @see ApplicableIRRulesParser */ public class HotSpotPidFileParser { private final State state; @@ -47,8 +47,8 @@ public class HotSpotPidFileParser { } /** - * Parse the hotspot_pid*.log file from the test VM. Read the ideal compile phase and PrintOptoAssembly outputs for - * all methods defined by the IR encoding. + * Parse the hotspot_pid*.log file from the Test VM. Read the ideal compile phase and PrintOptoAssembly outputs for + * all methods defined by the Applicable IR Rules. */ public LoggedMethods parse(String hotspotPidFileName) { try (var reader = Files.newBufferedReader(Paths.get(hotspotPidFileName))) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/flag/CompilePhaseCollector.java b/test/hotspot/jtreg/compiler/lib/ir_framework/flag/CompilePhaseCollector.java index 86ef31c6277..0488b3f58e6 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/flag/CompilePhaseCollector.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/flag/CompilePhaseCollector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ class CompilePhaseCollector { collectCompilePhases(method)); } } catch (TestFormatException e) { - // Create default map and let the IR matcher report the format failures later in the driver VM. + // Create default map and let the IR matcher report the format failures later in the Driver VM. return createDefaultMap(testClass); } return methodNameToCompilePhasesMap; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/flag/FlagVM.java b/test/hotspot/jtreg/compiler/lib/ir_framework/flag/FlagVM.java index 42e4c85a499..4b033eb2c0e 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/flag/FlagVM.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/flag/FlagVM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -38,8 +38,8 @@ import java.util.ArrayList; import java.util.Arrays; /** - * This class' main method is called from {@link TestFramework} and represents the so-called "flag VM". It uses the - * Whitebox API to determine the necessary additional flags to run the test VM (e.g. to do IR matching). It returns + * This class' main method is called from {@link TestFramework} and represents the so-called "Flag VM". It uses the + * Whitebox API to determine the necessary additional flags to run the Test VM (e.g. to do IR matching). It returns * the flags over the dedicated TestFramework socket. */ public class FlagVM { @@ -79,12 +79,12 @@ public class FlagVM { private static final boolean VERIFY_IR = REQUESTED_VERIFY_IR && USE_COMPILER && !EXCLUDE_RANDOM && !FLIP_C1_C2 && !TEST_C1 && Platform.isServer(); /** - * Main entry point of the flag VM. + * Main entry point of the Flag VM. */ public static void main(String[] args) { String testClassName = args[0]; if (VERBOSE) { - System.out.println("FlagVM main() called. Prepare test VM flags to run class " + testClassName); + System.out.println("FlagVM main() called. Prepare Test VM flags to run class " + testClassName); } Class testClass; try { @@ -96,8 +96,8 @@ public class FlagVM { } /** - * Emit test VM flags to the dedicated test VM flags file to parse them from the TestFramework "driver" VM again - * which adds them to the test VM. + * Emit Test VM flags to the dedicated Test VM flags file to parse them from the TestFramework Driver VM again + * which adds them to the Test VM. */ private static void emitTestVMFlags(ArrayList flags) { try (var bw = Files.newBufferedWriter(Paths.get(TEST_VM_FLAGS_FILE))) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/NoTestsRunException.java b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/NoTestsRunException.java index 02afdd4ee4f..4b616f53e4d 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/NoTestsRunException.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/NoTestsRunException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,17 +24,17 @@ package compiler.lib.ir_framework.shared; /** - * Exception that is thrown by the test VM if no tests are run as a result of specifying {@code -DTest} and/or - * {@code -DExclude} defining an empty set with the used test VM flags. + * Exception that is thrown by the Test VM if no tests are run as a result of specifying {@code -DTest} and/or + * {@code -DExclude} defining an empty set with the used Test VM flags. */ public class NoTestsRunException extends RuntimeException { /** - * Default constructor used by test VM + * Default constructor used by Test VM */ public NoTestsRunException() {} /** - * Constructor used to eventually throw the exception in the driver VM. + * Constructor used to eventually throw the exception in the Driver VM. */ public NoTestsRunException(String message) { super(message); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFrameworkSocket.java b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFrameworkSocket.java index 1fdcb34a6b8..f10540ebc5b 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFrameworkSocket.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFrameworkSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** - * Dedicated socket to send data from the flag and test VM back to the driver VM. + * Dedicated socket to send data from the flag and Test VM back to the Driver VM. */ public class TestFrameworkSocket implements AutoCloseable { public static final String STDOUT_PREFIX = "[STDOUT]"; @@ -46,7 +46,7 @@ public class TestFrameworkSocket implements AutoCloseable { public static final String PRINT_TIMES_TAG = "[PRINT_TIMES]"; public static final String NOT_COMPILABLE_TAG = "[NOT_COMPILABLE]"; - // Static fields used for test VM only. + // Static fields used for Test VM only. private static final String SERVER_PORT_PROPERTY = "ir.framework.server.port"; private static final int SERVER_PORT = Integer.getInteger(SERVER_PORT_PROPERTY, -1); @@ -85,7 +85,7 @@ public class TestFrameworkSocket implements AutoCloseable { } /** - * Waits for a client (created by flag or test VM) to connect. Return the messages received from the client. + * Waits for a client (created by flag or Test VM) to connect. Return the messages received from the client. */ private FutureTask initSocketTask() { return new FutureTask<>(() -> { @@ -117,18 +117,18 @@ public class TestFrameworkSocket implements AutoCloseable { } /** - * Only called by test VM to write to server socket. + * Only called by Test VM to write to server socket. */ public static void write(String msg, String tag) { write(msg, tag, false); } /** - * Only called by test VM to write to server socket. + * Only called by Test VM to write to server socket. *

- * The test VM is spawned by the main jtreg VM. The stdout of the test VM is hidden + * The Test VM is spawned by the main jtreg VM. The stdout of the Test VM is hidden * unless the Verbose or ReportStdout flag is used. TestFrameworkSocket is used by the parent jtreg - * VM and the test VM to communicate. By sending the prints through the TestFrameworkSocket with the + * VM and the Test VM to communicate. By sending the prints through the TestFrameworkSocket with the * parameter stdout set to true, the parent VM will print the received messages to its stdout, making it * visible to the user. */ @@ -137,10 +137,10 @@ public class TestFrameworkSocket implements AutoCloseable { System.out.println("Debugging Test VM: Skip writing due to -DReproduce"); return; } - TestFramework.check(SERVER_PORT != -1, "Server port was not set correctly for flag and/or test VM " - + "or method not called from flag or test VM"); + TestFramework.check(SERVER_PORT != -1, "Server port was not set correctly for flag and/or Test VM " + + "or method not called from flag or Test VM"); try { - // Keep the client socket open until the test VM terminates (calls closeClientSocket before exiting main()). + // Keep the client socket open until the Test VM terminates (calls closeClientSocket before exiting main()). if (clientSocket == null) { clientSocket = new Socket(InetAddress.getLoopbackAddress(), SERVER_PORT); clientWriter = new PrintWriter(clientSocket.getOutputStream(), true); @@ -150,11 +150,11 @@ public class TestFrameworkSocket implements AutoCloseable { } clientWriter.println(msg); } catch (Exception e) { - // When the test VM is directly run, we should ignore all messages that would normally be sent to the - // driver VM. + // When the Test VM is directly run, we should ignore all messages that would normally be sent to the + // Driver VM. String failMsg = System.lineSeparator() + System.lineSeparator() + """ ########################################################### - Did you directly run the test VM (TestVM class) + Did you directly run the Test VM (TestVM class) to reproduce a bug? => Append the flag -DReproduce=true and try again! ########################################################### @@ -169,7 +169,7 @@ public class TestFrameworkSocket implements AutoCloseable { /** * Closes (and flushes) the printer to the socket and the socket itself. Is called as last thing before exiting - * the main() method of the flag and the test VM. + * the main() method of the flag and the Test VM. */ public static void closeClientSocket() { if (clientSocket != null) { @@ -183,7 +183,7 @@ public class TestFrameworkSocket implements AutoCloseable { } /** - * Get the socket output of the flag VM. + * Get the socket output of the Flag VM. */ public String getOutput() { try { @@ -197,7 +197,7 @@ public class TestFrameworkSocket implements AutoCloseable { } /** - * Return whether test VM sent messages to be put on stdout (starting with {@link ::STDOUT_PREFIX}). + * Return whether Test VM sent messages to be put on stdout (starting with {@link ::STDOUT_PREFIX}). */ public boolean hasStdOut() { return receivedStdOut; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java similarity index 96% rename from test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java rename to test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java index a24cfbd3e37..4fa1f8f3fe5 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -39,12 +39,13 @@ import java.util.Objects; import java.util.function.Function; /** - * Prints an encoding to the dedicated test framework socket whether @IR rules of @Test methods should be applied or not. - * This is done during the execution of the test VM by checking the active VM flags. This encoding is eventually parsed - * and checked by the IRMatcher class in the driver VM after the termination of the test VM. IR rule indices start at 1. + * Prints all applicable IR rules to the dedicated test framework socket whether @IR rules of @Test methods should be + * applied or not. This is done during the execution of the Test VM by checking the active VM flags. This + * Applicable IR Rules message is eventually parsed and checked by the IRMatcher class in the Driver VM after the + * termination of the Test VM. IR rule indices start at 1. */ -public class IREncodingPrinter { - public static final String START = "##### IRMatchRulesEncoding - used by TestFramework #####"; +public class ApplicableIRRulesPrinter { + public static final String START = "##### ApplicableIRRules - used by TestFramework #####"; public static final String END = "----- END -----"; public static final int NO_RULE_APPLIED = -1; @@ -60,7 +61,7 @@ public class IREncodingPrinter { // Platforms for use in IR preconditions. Please verify that e.g. there is // a corresponding use in a jtreg @requires annotation before adding new platforms, // as adding non-existent platforms can lead to skipped tests. - private static final List irTestingPlatforms = new ArrayList(Arrays.asList( + private static final List irTestingPlatforms = new ArrayList<>(Arrays.asList( // os.family "aix", "linux", @@ -85,7 +86,7 @@ public class IREncodingPrinter { // Please verify new CPU features before adding them. If we allow non-existent features // on this list, we will ignore tests and never execute them. Consult CPU_FEATURE_FLAGS // in corresponding vm_version_.hpp file to find correct cpu feature's name. - private static final List verifiedCPUFeatures = new ArrayList( Arrays.asList( + private static final List verifiedCPUFeatures = new ArrayList<>( Arrays.asList( // x86 "fma", "f16c", @@ -126,7 +127,7 @@ public class IREncodingPrinter { "zvkn" )); - public IREncodingPrinter() { + public ApplicableIRRulesPrinter() { output.append(START).append(System.lineSeparator()); output.append(",{comma separated applied @IR rule ids}").append(System.lineSeparator()); } @@ -136,7 +137,7 @@ public class IREncodingPrinter { * - indices of all @IR rules that should be applied, separated by a comma * - "-1" if no @IR rule should not be applied */ - public void emitRuleEncoding(Method m, boolean skipped) { + public void emitApplicableIRRules(Method m, boolean skipped) { method = m; int i = 0; ArrayList validRules = new ArrayList<>(); @@ -170,7 +171,7 @@ public class IREncodingPrinter { private void printDisableReason(String method, String reason, String[] apply, int ruleIndex, int ruleMax) { TestFrameworkSocket.write("Disabling IR matching for rule " + ruleIndex + " of " + ruleMax + " in " + method + ": " + reason + ": " + String.join(", ", apply), - "[IREncodingPrinter]", true); + "[ApplicableIRRules]", true); } private boolean shouldApplyIrRule(IR irAnno, String m, int ruleIndex, int ruleMax) { @@ -521,7 +522,7 @@ public class IREncodingPrinter { public void emit() { output.append(END); - TestFrameworkSocket.write(output.toString(), "IR rule application encoding"); + TestFrameworkSocket.write(output.toString(), "ApplicableIRRules"); } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java index 8ccd0faa013..c5ab318d67d 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ import java.util.stream.Stream; import static compiler.lib.ir_framework.shared.TestFrameworkSocket.PRINT_TIMES_TAG; /** - * This class' main method is called from {@link TestFramework} and represents the so-called "test VM". The class is + * This class' main method is called from {@link TestFramework} and represents the so-called "Test VM". The class is * the heart of the framework and is responsible for executing all the specified tests in the test class. It uses the * Whitebox API and reflection to achieve this task. */ @@ -58,7 +58,7 @@ public class TestVM { TestFramework in main() of your test? Make sure to only call setup/run methods and no checks or assertions from main() of your test! - - Are you rerunning the test VM (TestVM class) + - Are you rerunning the Test VM (TestVM class) directly after a JTreg run? Make sure to start it from within JTwork/scratch and with the flag -DReproduce=true! @@ -100,7 +100,7 @@ public class TestVM { private static final boolean DUMP_REPLAY = Boolean.getBoolean("DumpReplay"); private static final boolean GC_AFTER = Boolean.getBoolean("GCAfter"); private static final boolean SHUFFLE_TESTS = Boolean.parseBoolean(System.getProperty("ShuffleTests", "true")); - // Use separate flag as VERIFY_IR could have been set by user but due to other flags it was disabled by flag VM. + // Use separate flag as VERIFY_IR could have been set by user but due to other flags it was disabled by Flag VM. private static final boolean PRINT_VALID_IR_RULES = Boolean.getBoolean("ShouldDoIRVerification"); protected static final long PER_METHOD_TRAP_LIMIT = (Long)WHITE_BOX.getVMFlag("PerMethodTrapLimit"); protected static final boolean PROFILE_INTERPRETER = (Boolean)WHITE_BOX.getVMFlag("ProfileInterpreter"); @@ -114,7 +114,7 @@ public class TestVM { private final List excludeList; private final List testList; private Set> helperClasses = null; // Helper classes that contain framework annotations to be processed. - private final IREncodingPrinter irMatchRulePrinter; + private final ApplicableIRRulesPrinter irMatchRulePrinter; private final Class testClass; private final Map forceCompileMap = new HashMap<>(); @@ -125,7 +125,7 @@ public class TestVM { this.excludeList = createTestFilterList(EXCLUDELIST, testClass); if (PRINT_VALID_IR_RULES) { - irMatchRulePrinter = new IREncodingPrinter(); + irMatchRulePrinter = new ApplicableIRRulesPrinter(); } else { irMatchRulePrinter = null; } @@ -155,7 +155,7 @@ public class TestVM { } /** - * Main entry point of the test VM. + * Main entry point of the Test VM. */ public static void main(String[] args) { try { @@ -293,7 +293,7 @@ public class TestVM { BaseTest baseTest = new BaseTest(test, shouldExcludeTest(m.getName())); allTests.add(baseTest); if (PRINT_VALID_IR_RULES) { - irMatchRulePrinter.emitRuleEncoding(m, baseTest.isSkipped()); + irMatchRulePrinter.emitApplicableIRRules(m, baseTest.isSkipped()); } } catch (TestFormatException e) { // Failure logged. Continue and report later. @@ -687,7 +687,7 @@ public class TestVM { allTests.add(checkedTest); if (PRINT_VALID_IR_RULES) { // Only need to emit IR verification information if IR verification is actually performed. - irMatchRulePrinter.emitRuleEncoding(testMethod, checkedTest.isSkipped()); + irMatchRulePrinter.emitApplicableIRRules(testMethod, checkedTest.isSkipped()); } } @@ -755,7 +755,7 @@ public class TestVM { CustomRunTest customRunTest = new CustomRunTest(m, getAnnotation(m, Warmup.class), runAnno, tests, shouldExcludeTest); allTests.add(customRunTest); if (PRINT_VALID_IR_RULES) { - tests.forEach(test -> irMatchRulePrinter.emitRuleEncoding(test.getTestMethod(), customRunTest.isSkipped())); + tests.forEach(test -> irMatchRulePrinter.emitApplicableIRRules(test.getTestMethod(), customRunTest.isSkipped())); } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/VMInfoPrinter.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/VMInfoPrinter.java index 14636da4cbe..470569122dd 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/VMInfoPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/VMInfoPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ import compiler.lib.ir_framework.shared.TestFrameworkSocket; import jdk.test.whitebox.WhiteBox; /** - * Prints some test VM info to the socket. + * Prints some Test VM info to the socket. */ public class VMInfoPrinter { public static final String START_VM_INFO = "##### IRMatchingVMInfo - used by TestFramework #####"; diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java index 142a30f34a9..07a6a03f2a6 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -38,13 +38,13 @@ import java.util.regex.Pattern; /* * @test * @requires vm.debug == true & vm.compMode != "Xint" & vm.compiler1.enabled & vm.compiler2.enabled & vm.flagless - * @summary Test IR matcher with different default IR node regexes. Use -DPrintIREncoding. + * @summary Test IR matcher with different default IR node regexes. Use -DPrintApplicableIRRules. * Normally, the framework should be called with driver. * @library /test/lib /testlibrary_tests / * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=240 -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -DPrintIREncoding=true ir_framework.tests.TestIRMatching + * -XX:+WhiteBoxAPI -DPrintApplicableIRRules=true ir_framework.tests.TestIRMatching */ public class TestIRMatching { @@ -440,7 +440,8 @@ public class TestIRMatching { } } if (!output.contains(builder.toString())) { - addException(new RuntimeException("Could not find encoding: \"" + builder + System.lineSeparator())); + addException(new RuntimeException("Could not find line in Applicable IR Rules: \"" + builder + + System.lineSeparator())); } } } diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java index fe21dce73b5..70e4c463c55 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -70,7 +70,7 @@ public class TestPhaseIRMatching { TestVMProcess testVMProcess = new TestVMProcess(testVMFlags, testClass, null, -1, false, false); TestClassParser testClassParser = new TestClassParser(testClass, false); Matchable testClassMatchable = testClassParser.parse(testVMProcess.getHotspotPidFileName(), - testVMProcess.getIrEncoding()); + testVMProcess.getApplicableIRRules()); MatchResult result = testClassMatchable.match(); List expectedFails = new ExpectedFailsBuilder().build(testClass); List foundFailures = new FailureBuilder().build(result); From c44a99a758f38ceea84e03905d2ffb9c1fd1987a Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Mon, 19 Jan 2026 14:20:18 +0000 Subject: [PATCH 092/328] 8374180: C2 crash in PhaseCCP::verify_type - fatal error: Not monotonic Reviewed-by: hgreule, bmaillard, epeter --- src/hotspot/share/opto/rangeinference.hpp | 41 ++++++++++---- src/hotspot/share/opto/type.hpp | 8 ++- .../gtest/opto/test_rangeinference.cpp | 8 +-- .../compiler/ccp/TestWrongXorIWiden.java | 54 +++++++++++++++++++ 4 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/ccp/TestWrongXorIWiden.java diff --git a/src/hotspot/share/opto/rangeinference.hpp b/src/hotspot/share/opto/rangeinference.hpp index ebfd98ca4a6..66ea741a2da 100644 --- a/src/hotspot/share/opto/rangeinference.hpp +++ b/src/hotspot/share/opto/rangeinference.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -147,7 +147,7 @@ public: static const Type* int_type_xmeet(const CT* i1, const Type* t2); template - static CTP int_type_union(CTP t1, CTP t2) { + static auto int_type_union(CTP t1, CTP t2) { using CT = std::conditional_t, std::remove_pointer_t, CTP>; using S = std::remove_const_t; using U = std::remove_const_t; @@ -209,7 +209,7 @@ public: KnownBits _bits; int _widen = 0; // dummy field to mimic the same field in TypeInt, useful in testing - static TypeIntMirror make(const TypeIntPrototype& t, int widen) { + static TypeIntMirror make(const TypeIntPrototype& t, int widen = 0) { auto canonicalized_t = t.canonicalize_constraints(); assert(!canonicalized_t.empty(), "must not be empty"); return TypeIntMirror{canonicalized_t._data._srange._lo, canonicalized_t._data._srange._hi, @@ -217,11 +217,15 @@ public: canonicalized_t._data._bits}; } + TypeIntMirror meet(const TypeIntMirror& o) const { + return TypeIntHelper::int_type_union(this, &o); + } + // These allow TypeIntMirror to mimick the behaviors of TypeInt* and TypeLong*, so they can be // passed into RangeInference methods. These are only used in testing, so they are implemented in // the test file. + static TypeIntMirror make(const TypeIntMirror& t, int widen); const TypeIntMirror* operator->() const; - TypeIntMirror meet(const TypeIntMirror& o) const; bool contains(U u) const; bool contains(const TypeIntMirror& o) const; bool operator==(const TypeIntMirror& o) const; @@ -322,7 +326,7 @@ private: // Infer a result given the input types of a binary operation template static CTP infer_binary(CTP t1, CTP t2, Inference infer) { - CTP res; + TypeIntMirror, U> res; bool is_init = false; SimpleIntervalIterable t1_simple_intervals(t1); @@ -330,10 +334,10 @@ private: for (auto& st1 : t1_simple_intervals) { for (auto& st2 : t2_simple_intervals) { - CTP current = infer(st1, st2); + TypeIntMirror, U> current = infer(st1, st2); if (is_init) { - res = res->meet(current)->template cast>(); + res = res.meet(current); } else { is_init = true; res = current; @@ -342,7 +346,22 @@ private: } assert(is_init, "must be initialized"); - return res; + // It is important that widen is computed on the whole result instead of during each step. This + // is because we normalize the widen of small Type instances to 0, so computing the widen value + // for each step and taking the union of them may return a widen value that conflicts with + // other computations, trigerring the monotonicity assert during CCP. + // + // For example, let us consider the operation r = x ^ y: + // - During the first step of CCP, type(x) = {0}, type(y) = [-2, 2], w = 3. + // Since x is a constant that is the identity element of the xor operation, type(r) = type(y) = [-2, 2], w = 3 + // - During the second step, type(x) is widened to [0, 2], w = 0. + // We then compute the range for: + // r1 = x ^ y1, type(x) = [0, 2], w = 0, type(y1) = [0, 2], w = 0 + // r2 = x ^ y2, type(x) = [0, 2], w = 0, type(y2) = [-2, -1], w = 0 + // This results in type(r1) = [0, 3], w = 0, and type(r2) = [-4, -1], w = 0 + // So the union of type(r1) and type(r2) is [-4, 3], w = 0. This widen value is smaller than + // that of the previous step, triggering the monotonicity assert. + return CT::make(res, MAX2(t1->_widen, t2->_widen)); } public: @@ -357,7 +376,7 @@ public: U uhi = MIN2(st1._uhi, st2._uhi); U zeros = st1._bits._zeros | st2._bits._zeros; U ones = st1._bits._ones & st2._bits._ones; - return CT::make(TypeIntPrototype, U>{{lo, hi}, {ulo, uhi}, {zeros, ones}}, MAX2(t1->_widen, t2->_widen)); + return TypeIntMirror, U>::make(TypeIntPrototype, U>{{lo, hi}, {ulo, uhi}, {zeros, ones}}); }); } @@ -372,7 +391,7 @@ public: U uhi = std::numeric_limits>::max(); U zeros = st1._bits._zeros & st2._bits._zeros; U ones = st1._bits._ones | st2._bits._ones; - return CT::make(TypeIntPrototype, U>{{lo, hi}, {ulo, uhi}, {zeros, ones}}, MAX2(t1->_widen, t2->_widen)); + return TypeIntMirror, U>::make(TypeIntPrototype, U>{{lo, hi}, {ulo, uhi}, {zeros, ones}}); }); } @@ -385,7 +404,7 @@ public: U uhi = std::numeric_limits>::max(); U zeros = (st1._bits._zeros & st2._bits._zeros) | (st1._bits._ones & st2._bits._ones); U ones = (st1._bits._zeros & st2._bits._ones) | (st1._bits._ones & st2._bits._zeros); - return CT::make(TypeIntPrototype, U>{{lo, hi}, {ulo, uhi}, {zeros, ones}}, MAX2(t1->_widen, t2->_widen)); + return TypeIntMirror, U>::make(TypeIntPrototype, U>{{lo, hi}, {ulo, uhi}, {zeros, ones}}); }); } }; diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 73e2ba0045a..285b4984cd1 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -799,6 +799,9 @@ public: static const TypeInt* make(jint lo, jint hi, int widen); static const Type* make_or_top(const TypeIntPrototype& t, int widen); static const TypeInt* make(const TypeIntPrototype& t, int widen) { return make_or_top(t, widen)->is_int(); } + static const TypeInt* make(const TypeIntMirror& t, int widen) { + return (new TypeInt(TypeIntPrototype{{t._lo, t._hi}, {t._ulo, t._uhi}, t._bits}, widen, false))->hashcons()->is_int(); + } // Check for single integer bool is_con() const { return _lo == _hi; } @@ -881,6 +884,9 @@ public: static const TypeLong* make(jlong lo, jlong hi, int widen); static const Type* make_or_top(const TypeIntPrototype& t, int widen); static const TypeLong* make(const TypeIntPrototype& t, int widen) { return make_or_top(t, widen)->is_long(); } + static const TypeLong* make(const TypeIntMirror& t, int widen) { + return (new TypeLong(TypeIntPrototype{{t._lo, t._hi}, {t._ulo, t._uhi}, t._bits}, widen, false))->hashcons()->is_long(); + } // Check for single integer bool is_con() const { return _lo == _hi; } diff --git a/test/hotspot/gtest/opto/test_rangeinference.cpp b/test/hotspot/gtest/opto/test_rangeinference.cpp index 42767e9fcab..fd49050d022 100644 --- a/test/hotspot/gtest/opto/test_rangeinference.cpp +++ b/test/hotspot/gtest/opto/test_rangeinference.cpp @@ -216,13 +216,13 @@ TEST_VM(opto, canonicalize_constraints) { // Implementations of TypeIntMirror methods for testing purposes template -const TypeIntMirror* TypeIntMirror::operator->() const { - return this; +TypeIntMirror TypeIntMirror::make(const TypeIntMirror& t, int widen) { + return t; } template -TypeIntMirror TypeIntMirror::meet(const TypeIntMirror& o) const { - return TypeIntHelper::int_type_union(*this, o); +const TypeIntMirror* TypeIntMirror::operator->() const { + return this; } template diff --git a/test/hotspot/jtreg/compiler/ccp/TestWrongXorIWiden.java b/test/hotspot/jtreg/compiler/ccp/TestWrongXorIWiden.java new file mode 100644 index 00000000000..3b058758beb --- /dev/null +++ b/test/hotspot/jtreg/compiler/ccp/TestWrongXorIWiden.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2026, 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.ccp; + +/* + * @test + * @bug 8374180 + * @summary Test that _widen is set correctly in XorI::add_ring() to ensure monotonicity. + * @run main/othervm -XX:CompileCommand=compileonly,${test.main.class}::* -Xcomp ${test.main.class} + */ +public class TestWrongXorIWiden { + static byte byFld; + + public static void main(String[] strArr) { + test(); + } + + static void test() { + int k, i17 = 0; + long lArr[] = new long[400]; + for (int i = 9; i < 54; ++i) { + for (int j = 7; j > 1; j--) { + for (k = 1; k < 2; k++) { + i17 >>= i; + } + byFld += j ^ i17; + for (int a = 1; a < 2; a++) { + i17 = k; + } + } + } + } +} From f2d5290c29b0b832e64ab2b4dc04cd892a627ca2 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Mon, 19 Jan 2026 14:44:37 +0000 Subject: [PATCH 093/328] 8367319: Add os interfaces to get machine and container values separately Reviewed-by: eosterlund, sgehwolf --- src/hotspot/os/aix/os_aix.cpp | 26 +++- src/hotspot/os/bsd/os_bsd.cpp | 26 +++- .../os/linux/cgroupSubsystem_linux.cpp | 22 ++- .../os/linux/cgroupSubsystem_linux.hpp | 23 +-- src/hotspot/os/linux/cgroupUtil_linux.cpp | 27 ++-- src/hotspot/os/linux/cgroupUtil_linux.hpp | 7 +- .../os/linux/cgroupV1Subsystem_linux.cpp | 6 +- .../os/linux/cgroupV1Subsystem_linux.hpp | 10 +- .../os/linux/cgroupV2Subsystem_linux.cpp | 6 +- .../os/linux/cgroupV2Subsystem_linux.hpp | 10 +- src/hotspot/os/linux/osContainer_linux.cpp | 16 +- src/hotspot/os/linux/osContainer_linux.hpp | 7 +- src/hotspot/os/linux/os_linux.cpp | 141 ++++++++++++++---- src/hotspot/os/windows/os_windows.cpp | 26 +++- src/hotspot/share/jfr/jni/jfrJniMethod.cpp | 27 +--- src/hotspot/share/prims/jvm.cpp | 9 +- src/hotspot/share/prims/whitebox.cpp | 9 +- src/hotspot/share/runtime/os.cpp | 55 +++++-- src/hotspot/share/runtime/os.hpp | 48 +++++- .../containers/docker/TestCPUAwareness.java | 12 +- 20 files changed, 356 insertions(+), 157 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index f88729cdc66..d7c1911a914 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -258,10 +258,18 @@ bool os::free_memory(physical_memory_size_type& value) { return Aix::available_memory(value); } +bool os::Machine::free_memory(physical_memory_size_type& value) { + return Aix::available_memory(value); +} + bool os::available_memory(physical_memory_size_type& value) { return Aix::available_memory(value); } +bool os::Machine::available_memory(physical_memory_size_type& value) { + return Aix::available_memory(value); +} + bool os::Aix::available_memory(physical_memory_size_type& value) { os::Aix::meminfo_t mi; if (os::Aix::get_meminfo(&mi)) { @@ -273,6 +281,10 @@ bool os::Aix::available_memory(physical_memory_size_type& value) { } bool os::total_swap_space(physical_memory_size_type& value) { + return Machine::total_swap_space(value); +} + +bool os::Machine::total_swap_space(physical_memory_size_type& value) { perfstat_memory_total_t memory_info; if (libperfstat::perfstat_memory_total(nullptr, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) { return false; @@ -282,6 +294,10 @@ bool os::total_swap_space(physical_memory_size_type& value) { } bool os::free_swap_space(physical_memory_size_type& value) { + return Machine::free_swap_space(value); +} + +bool os::Machine::free_swap_space(physical_memory_size_type& value) { perfstat_memory_total_t memory_info; if (libperfstat::perfstat_memory_total(nullptr, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) { return false; @@ -294,6 +310,10 @@ physical_memory_size_type os::physical_memory() { return Aix::physical_memory(); } +physical_memory_size_type os::Machine::physical_memory() { + return Aix::physical_memory(); +} + size_t os::rss() { return (size_t)0; } // Cpu architecture string @@ -2264,6 +2284,10 @@ int os::active_processor_count() { return ActiveProcessorCount; } + return Machine::active_processor_count(); +} + +int os::Machine::active_processor_count() { int online_cpus = ::sysconf(_SC_NPROCESSORS_ONLN); assert(online_cpus > 0 && online_cpus <= processor_count(), "sanity check"); return online_cpus; diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 61de48bb7fa..667810bd6ca 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, 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 @@ -137,10 +137,18 @@ bool os::available_memory(physical_memory_size_type& value) { return Bsd::available_memory(value); } +bool os::Machine::available_memory(physical_memory_size_type& value) { + return Bsd::available_memory(value); +} + bool os::free_memory(physical_memory_size_type& value) { return Bsd::available_memory(value); } +bool os::Machine::free_memory(physical_memory_size_type& value) { + return Bsd::available_memory(value); +} + // Available here means free. Note that this number is of no much use. As an estimate // for future memory pressure it is far too conservative, since MacOS will use a lot // of unused memory for caches, and return it willingly in case of needs. @@ -181,6 +189,10 @@ void os::Bsd::print_uptime_info(outputStream* st) { } bool os::total_swap_space(physical_memory_size_type& value) { + return Machine::total_swap_space(value); +} + +bool os::Machine::total_swap_space(physical_memory_size_type& value) { #if defined(__APPLE__) struct xsw_usage vmusage; size_t size = sizeof(vmusage); @@ -195,6 +207,10 @@ bool os::total_swap_space(physical_memory_size_type& value) { } bool os::free_swap_space(physical_memory_size_type& value) { + return Machine::free_swap_space(value); +} + +bool os::Machine::free_swap_space(physical_memory_size_type& value) { #if defined(__APPLE__) struct xsw_usage vmusage; size_t size = sizeof(vmusage); @@ -212,6 +228,10 @@ physical_memory_size_type os::physical_memory() { return Bsd::physical_memory(); } +physical_memory_size_type os::Machine::physical_memory() { + return Bsd::physical_memory(); +} + size_t os::rss() { size_t rss = 0; #ifdef __APPLE__ @@ -2189,6 +2209,10 @@ int os::active_processor_count() { return ActiveProcessorCount; } + return Machine::active_processor_count(); +} + +int os::Machine::active_processor_count() { return _processor_count; } diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index f9c6f794ebd..e49d070890e 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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 @@ -631,22 +631,20 @@ void CgroupSubsystemFactory::cleanup(CgroupInfo* cg_infos) { * return: * true if there were no errors. false otherwise. */ -bool CgroupSubsystem::active_processor_count(int& value) { - int cpu_count; - int result = -1; - +bool CgroupSubsystem::active_processor_count(double& value) { // We use a cache with a timeout to avoid performing expensive // computations in the event this function is called frequently. // [See 8227006]. - CachingCgroupController* contrl = cpu_controller(); - CachedMetric* cpu_limit = contrl->metrics_cache(); + CachingCgroupController* contrl = cpu_controller(); + CachedMetric* cpu_limit = contrl->metrics_cache(); if (!cpu_limit->should_check_metric()) { - value = (int)cpu_limit->value(); - log_trace(os, container)("CgroupSubsystem::active_processor_count (cached): %d", value); + value = cpu_limit->value(); + log_trace(os, container)("CgroupSubsystem::active_processor_count (cached): %.2f", value); return true; } - cpu_count = os::Linux::active_processor_count(); + int cpu_count = os::Linux::active_processor_count(); + double result = -1; if (!CgroupUtil::processor_count(contrl->controller(), cpu_count, result)) { return false; } @@ -671,8 +669,8 @@ bool CgroupSubsystem::active_processor_count(int& value) { */ bool CgroupSubsystem::memory_limit_in_bytes(physical_memory_size_type upper_bound, physical_memory_size_type& value) { - CachingCgroupController* contrl = memory_controller(); - CachedMetric* memory_limit = contrl->metrics_cache(); + CachingCgroupController* contrl = memory_controller(); + CachedMetric* memory_limit = contrl->metrics_cache(); if (!memory_limit->should_check_metric()) { value = memory_limit->value(); return true; diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index 522b64f8816..8aafbf49c63 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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 @@ -181,9 +181,10 @@ class CgroupController: public CHeapObj { static bool limit_from_str(char* limit_str, physical_memory_size_type& value); }; +template class CachedMetric : public CHeapObj{ private: - volatile physical_memory_size_type _metric; + volatile MetricType _metric; volatile jlong _next_check_counter; public: CachedMetric() { @@ -193,8 +194,8 @@ class CachedMetric : public CHeapObj{ bool should_check_metric() { return os::elapsed_counter() > _next_check_counter; } - physical_memory_size_type value() { return _metric; } - void set_value(physical_memory_size_type value, jlong timeout) { + MetricType value() { return _metric; } + void set_value(MetricType value, jlong timeout) { _metric = value; // Metric is unlikely to change, but we want to remain // responsive to configuration changes. A very short grace time @@ -205,19 +206,19 @@ class CachedMetric : public CHeapObj{ } }; -template +template class CachingCgroupController : public CHeapObj { private: T* _controller; - CachedMetric* _metrics_cache; + CachedMetric* _metrics_cache; public: CachingCgroupController(T* cont) { _controller = cont; - _metrics_cache = new CachedMetric(); + _metrics_cache = new CachedMetric(); } - CachedMetric* metrics_cache() { return _metrics_cache; } + CachedMetric* metrics_cache() { return _metrics_cache; } T* controller() { return _controller; } }; @@ -277,7 +278,7 @@ class CgroupMemoryController: public CHeapObj { class CgroupSubsystem: public CHeapObj { public: bool memory_limit_in_bytes(physical_memory_size_type upper_bound, physical_memory_size_type& value); - bool active_processor_count(int& value); + bool active_processor_count(double& value); virtual bool pids_max(uint64_t& value) = 0; virtual bool pids_current(uint64_t& value) = 0; @@ -286,8 +287,8 @@ class CgroupSubsystem: public CHeapObj { virtual char * cpu_cpuset_cpus() = 0; virtual char * cpu_cpuset_memory_nodes() = 0; virtual const char * container_type() = 0; - virtual CachingCgroupController* memory_controller() = 0; - virtual CachingCgroupController* cpu_controller() = 0; + virtual CachingCgroupController* memory_controller() = 0; + virtual CachingCgroupController* cpu_controller() = 0; virtual CgroupCpuacctController* cpuacct_controller() = 0; bool cpu_quota(int& value); diff --git a/src/hotspot/os/linux/cgroupUtil_linux.cpp b/src/hotspot/os/linux/cgroupUtil_linux.cpp index 7aa07d53148..570b335940b 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.cpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2024, 2025, Red Hat, Inc. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +26,8 @@ #include "cgroupUtil_linux.hpp" #include "os_linux.hpp" -bool CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int upper_bound, int& value) { +bool CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int upper_bound, double& value) { assert(upper_bound > 0, "upper bound of cpus must be positive"); - int limit_count = upper_bound; int quota = -1; int period = -1; if (!cpu_ctrl->cpu_quota(quota)) { @@ -37,20 +37,15 @@ bool CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int upper_bound, return false; } int quota_count = 0; - int result = upper_bound; + double result = upper_bound; - if (quota > -1 && period > 0) { - quota_count = ceilf((float)quota / (float)period); - log_trace(os, container)("CPU Quota count based on quota/period: %d", quota_count); + if (quota > 0 && period > 0) { // Use quotas + double cpu_quota = static_cast(quota) / period; + log_trace(os, container)("CPU Quota based on quota/period: %.2f", cpu_quota); + result = MIN2(result, cpu_quota); } - // Use quotas - if (quota_count != 0) { - limit_count = quota_count; - } - - result = MIN2(upper_bound, limit_count); - log_trace(os, container)("OSContainer::active_processor_count: %d", result); + log_trace(os, container)("OSContainer::active_processor_count: %.2f", result); value = result; return true; } @@ -73,11 +68,11 @@ physical_memory_size_type CgroupUtil::get_updated_mem_limit(CgroupMemoryControll // Get an updated cpu limit. The return value is strictly less than or equal to the // passed in 'lowest' value. -int CgroupUtil::get_updated_cpu_limit(CgroupCpuController* cpu, +double CgroupUtil::get_updated_cpu_limit(CgroupCpuController* cpu, int lowest, int upper_bound) { assert(lowest > 0 && lowest <= upper_bound, "invariant"); - int cpu_limit_val = -1; + double cpu_limit_val = -1; if (CgroupUtil::processor_count(cpu, upper_bound, cpu_limit_val) && cpu_limit_val != upper_bound) { assert(cpu_limit_val <= upper_bound, "invariant"); if (lowest > cpu_limit_val) { @@ -172,7 +167,7 @@ void CgroupUtil::adjust_controller(CgroupCpuController* cpu) { assert(cg_path[0] == '/', "cgroup path must start with '/'"); int host_cpus = os::Linux::active_processor_count(); int lowest_limit = host_cpus; - int cpus = get_updated_cpu_limit(cpu, lowest_limit, host_cpus); + double cpus = get_updated_cpu_limit(cpu, lowest_limit, host_cpus); int orig_limit = lowest_limit != host_cpus ? lowest_limit : host_cpus; char* limit_cg_path = nullptr; while ((last_slash = strrchr(cg_path, '/')) != cg_path) { diff --git a/src/hotspot/os/linux/cgroupUtil_linux.hpp b/src/hotspot/os/linux/cgroupUtil_linux.hpp index d72bbd1cf1e..1fd2a7d872b 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.hpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.hpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2024, Red Hat, Inc. + * Copyright (c) 2026, 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,7 +32,7 @@ class CgroupUtil: AllStatic { public: - static bool processor_count(CgroupCpuController* cpu, int upper_bound, int& value); + static bool processor_count(CgroupCpuController* cpu, int upper_bound, double& value); // Given a memory controller, adjust its path to a point in the hierarchy // that represents the closest memory limit. static void adjust_controller(CgroupMemoryController* m); @@ -42,9 +43,7 @@ class CgroupUtil: AllStatic { static physical_memory_size_type get_updated_mem_limit(CgroupMemoryController* m, physical_memory_size_type lowest, physical_memory_size_type upper_bound); - static int get_updated_cpu_limit(CgroupCpuController* c, - int lowest, - int upper_bound); + static double get_updated_cpu_limit(CgroupCpuController* c, int lowest, int upper_bound); }; #endif // CGROUP_UTIL_LINUX_HPP diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index 2df604083d2..c8f5a290c99 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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 @@ -328,8 +328,8 @@ CgroupV1Subsystem::CgroupV1Subsystem(CgroupV1Controller* cpuset, _pids(pids) { CgroupUtil::adjust_controller(memory); CgroupUtil::adjust_controller(cpu); - _memory = new CachingCgroupController(memory); - _cpu = new CachingCgroupController(cpu); + _memory = new CachingCgroupController(memory); + _cpu = new CachingCgroupController(cpu); } bool CgroupV1Subsystem::is_containerized() { diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp index f556bc57f26..af8d0efd378 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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 @@ -214,15 +214,15 @@ class CgroupV1Subsystem: public CgroupSubsystem { const char * container_type() override { return "cgroupv1"; } - CachingCgroupController* memory_controller() override { return _memory; } - CachingCgroupController* cpu_controller() override { return _cpu; } + CachingCgroupController* memory_controller() override { return _memory; } + CachingCgroupController* cpu_controller() override { return _cpu; } CgroupCpuacctController* cpuacct_controller() override { return _cpuacct; } private: /* controllers */ - CachingCgroupController* _memory = nullptr; + CachingCgroupController* _memory = nullptr; CgroupV1Controller* _cpuset = nullptr; - CachingCgroupController* _cpu = nullptr; + CachingCgroupController* _cpu = nullptr; CgroupV1CpuacctController* _cpuacct = nullptr; CgroupV1Controller* _pids = nullptr; diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index c61d30e9236..30e1affc646 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2025, Red Hat Inc. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -156,8 +156,8 @@ CgroupV2Subsystem::CgroupV2Subsystem(CgroupV2MemoryController * memory, _unified(unified) { CgroupUtil::adjust_controller(memory); CgroupUtil::adjust_controller(cpu); - _memory = new CachingCgroupController(memory); - _cpu = new CachingCgroupController(cpu); + _memory = new CachingCgroupController(memory); + _cpu = new CachingCgroupController(cpu); _cpuacct = cpuacct; } diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp index 39a4fabe9f6..998145c0ff9 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2024, Red Hat Inc. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -152,8 +152,8 @@ class CgroupV2Subsystem: public CgroupSubsystem { /* One unified controller */ CgroupV2Controller _unified; /* Caching wrappers for cpu/memory metrics */ - CachingCgroupController* _memory = nullptr; - CachingCgroupController* _cpu = nullptr; + CachingCgroupController* _memory = nullptr; + CachingCgroupController* _cpu = nullptr; CgroupCpuacctController* _cpuacct = nullptr; @@ -175,8 +175,8 @@ class CgroupV2Subsystem: public CgroupSubsystem { const char * container_type() override { return "cgroupv2"; } - CachingCgroupController* memory_controller() override { return _memory; } - CachingCgroupController* cpu_controller() override { return _cpu; } + CachingCgroupController* memory_controller() override { return _memory; } + CachingCgroupController* cpu_controller() override { return _cpu; } CgroupCpuacctController* cpuacct_controller() override { return _cpuacct; }; }; diff --git a/src/hotspot/os/linux/osContainer_linux.cpp b/src/hotspot/os/linux/osContainer_linux.cpp index 15a6403d07f..fe1dbc17239 100644 --- a/src/hotspot/os/linux/osContainer_linux.cpp +++ b/src/hotspot/os/linux/osContainer_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -86,8 +86,8 @@ void OSContainer::init() { // 2.) On a physical Linux system with a limit enforced by other means (like systemd slice) physical_memory_size_type mem_limit_val = value_unlimited; (void)memory_limit_in_bytes(mem_limit_val); // discard error and use default - int host_cpus = os::Linux::active_processor_count(); - int cpus = host_cpus; + double host_cpus = os::Linux::active_processor_count(); + double cpus = host_cpus; (void)active_processor_count(cpus); // discard error and use default any_mem_cpu_limit_present = mem_limit_val != value_unlimited || host_cpus != cpus; if (any_mem_cpu_limit_present) { @@ -127,8 +127,7 @@ bool OSContainer::available_memory_in_bytes(physical_memory_size_type& value) { return false; } -bool OSContainer::available_swap_in_bytes(physical_memory_size_type host_free_swap, - physical_memory_size_type& value) { +bool OSContainer::available_swap_in_bytes(physical_memory_size_type& value) { physical_memory_size_type mem_limit = 0; physical_memory_size_type mem_swap_limit = 0; if (memory_limit_in_bytes(mem_limit) && @@ -179,8 +178,7 @@ bool OSContainer::available_swap_in_bytes(physical_memory_size_type host_free_sw assert(num < 25, "buffer too small"); mem_limit_buf[num] = '\0'; log_trace(os,container)("OSContainer::available_swap_in_bytes: container_swap_limit=%s" - " container_mem_limit=%s, host_free_swap: " PHYS_MEM_TYPE_FORMAT, - mem_swap_buf, mem_limit_buf, host_free_swap); + " container_mem_limit=%s", mem_swap_buf, mem_limit_buf); } return false; } @@ -252,7 +250,7 @@ char * OSContainer::cpu_cpuset_memory_nodes() { return cgroup_subsystem->cpu_cpuset_memory_nodes(); } -bool OSContainer::active_processor_count(int& value) { +bool OSContainer::active_processor_count(double& value) { assert(cgroup_subsystem != nullptr, "cgroup subsystem not available"); return cgroup_subsystem->active_processor_count(value); } @@ -291,11 +289,13 @@ template struct metric_fmt; template<> struct metric_fmt { static constexpr const char* fmt = "%llu"; }; template<> struct metric_fmt { static constexpr const char* fmt = "%lu"; }; template<> struct metric_fmt { static constexpr const char* fmt = "%d"; }; +template<> struct metric_fmt { static constexpr const char* fmt = "%.2f"; }; template<> struct metric_fmt { static constexpr const char* fmt = "%s"; }; template void OSContainer::print_container_metric(outputStream*, const char*, unsigned long long int, const char*); template void OSContainer::print_container_metric(outputStream*, const char*, unsigned long int, const char*); template void OSContainer::print_container_metric(outputStream*, const char*, int, const char*); +template void OSContainer::print_container_metric(outputStream*, const char*, double, const char*); template void OSContainer::print_container_metric(outputStream*, const char*, const char*, const char*); template diff --git a/src/hotspot/os/linux/osContainer_linux.hpp b/src/hotspot/os/linux/osContainer_linux.hpp index 11c3e086feb..96b59b98db8 100644 --- a/src/hotspot/os/linux/osContainer_linux.hpp +++ b/src/hotspot/os/linux/osContainer_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -72,8 +72,7 @@ class OSContainer: AllStatic { static const char * container_type(); static bool available_memory_in_bytes(physical_memory_size_type& value); - static bool available_swap_in_bytes(physical_memory_size_type host_free_swap, - physical_memory_size_type& value); + static bool available_swap_in_bytes(physical_memory_size_type& value); static bool memory_limit_in_bytes(physical_memory_size_type& value); static bool memory_and_swap_limit_in_bytes(physical_memory_size_type& value); static bool memory_and_swap_usage_in_bytes(physical_memory_size_type& value); @@ -84,7 +83,7 @@ class OSContainer: AllStatic { static bool rss_usage_in_bytes(physical_memory_size_type& value); static bool cache_usage_in_bytes(physical_memory_size_type& value); - static bool active_processor_count(int& value); + static bool active_processor_count(double& value); static char * cpu_cpuset_cpus(); static char * cpu_cpuset_memory_nodes(); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 6a2a3974a16..48529c6ce17 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -211,15 +211,58 @@ static bool suppress_primordial_thread_resolution = false; // utility functions +bool os::is_containerized() { + return OSContainer::is_containerized(); +} + +bool os::Container::memory_limit(physical_memory_size_type& value) { + physical_memory_size_type result = 0; + if (OSContainer::memory_limit_in_bytes(result) && result != value_unlimited) { + value = result; + return true; + } + return false; +} + +bool os::Container::memory_soft_limit(physical_memory_size_type& value) { + physical_memory_size_type result = 0; + if (OSContainer::memory_soft_limit_in_bytes(result) && result != 0 && result != value_unlimited) { + value = result; + return true; + } + return false; +} + +bool os::Container::memory_throttle_limit(physical_memory_size_type& value) { + physical_memory_size_type result = 0; + if (OSContainer::memory_throttle_limit_in_bytes(result) && result != value_unlimited) { + value = result; + return true; + } + return false; +} + +bool os::Container::used_memory(physical_memory_size_type& value) { + return OSContainer::memory_usage_in_bytes(value); +} + bool os::available_memory(physical_memory_size_type& value) { - if (OSContainer::is_containerized() && OSContainer::available_memory_in_bytes(value)) { + if (is_containerized() && Container::available_memory(value)) { log_trace(os)("available container memory: " PHYS_MEM_TYPE_FORMAT, value); return true; } + return Machine::available_memory(value); +} + +bool os::Machine::available_memory(physical_memory_size_type& value) { return Linux::available_memory(value); } +bool os::Container::available_memory(physical_memory_size_type& value) { + return OSContainer::available_memory_in_bytes(value); +} + bool os::Linux::available_memory(physical_memory_size_type& value) { physical_memory_size_type avail_mem = 0; @@ -251,11 +294,15 @@ bool os::Linux::available_memory(physical_memory_size_type& value) { } bool os::free_memory(physical_memory_size_type& value) { - if (OSContainer::is_containerized() && OSContainer::available_memory_in_bytes(value)) { + if (is_containerized() && Container::available_memory(value)) { log_trace(os)("free container memory: " PHYS_MEM_TYPE_FORMAT, value); return true; } + return Machine::free_memory(value); +} + +bool os::Machine::free_memory(physical_memory_size_type& value) { return Linux::free_memory(value); } @@ -274,21 +321,30 @@ bool os::Linux::free_memory(physical_memory_size_type& value) { } bool os::total_swap_space(physical_memory_size_type& value) { - if (OSContainer::is_containerized()) { - physical_memory_size_type mem_swap_limit = value_unlimited; - physical_memory_size_type memory_limit = value_unlimited; - if (OSContainer::memory_and_swap_limit_in_bytes(mem_swap_limit) && - OSContainer::memory_limit_in_bytes(memory_limit)) { - if (memory_limit != value_unlimited && mem_swap_limit != value_unlimited && - mem_swap_limit >= memory_limit /* ensure swap is >= 0 */) { - value = mem_swap_limit - memory_limit; - return true; - } - } - } // fallback to the host swap space if the container returned unlimited + if (is_containerized() && Container::total_swap_space(value)) { + return true; + } // fallback to the host swap space if the container value fails + return Machine::total_swap_space(value); +} + +bool os::Machine::total_swap_space(physical_memory_size_type& value) { return Linux::host_swap(value); } +bool os::Container::total_swap_space(physical_memory_size_type& value) { + physical_memory_size_type mem_swap_limit = value_unlimited; + physical_memory_size_type memory_limit = value_unlimited; + if (OSContainer::memory_and_swap_limit_in_bytes(mem_swap_limit) && + OSContainer::memory_limit_in_bytes(memory_limit)) { + if (memory_limit != value_unlimited && mem_swap_limit != value_unlimited && + mem_swap_limit >= memory_limit /* ensure swap is >= 0 */) { + value = mem_swap_limit - memory_limit; + return true; + } + } + return false; +} + static bool host_free_swap_f(physical_memory_size_type& value) { struct sysinfo si; int ret = sysinfo(&si); @@ -309,32 +365,45 @@ bool os::free_swap_space(physical_memory_size_type& value) { return false; } physical_memory_size_type host_free_swap_val = MIN2(total_swap_space, host_free_swap); - if (OSContainer::is_containerized()) { - if (OSContainer::available_swap_in_bytes(host_free_swap_val, value)) { + if (is_containerized()) { + if (Container::free_swap_space(value)) { return true; } // Fall through to use host value log_trace(os,container)("os::free_swap_space: containerized value unavailable" " returning host value: " PHYS_MEM_TYPE_FORMAT, host_free_swap_val); } + value = host_free_swap_val; return true; } +bool os::Machine::free_swap_space(physical_memory_size_type& value) { + return host_free_swap_f(value); +} + +bool os::Container::free_swap_space(physical_memory_size_type& value) { + return OSContainer::available_swap_in_bytes(value); +} + physical_memory_size_type os::physical_memory() { - if (OSContainer::is_containerized()) { + if (is_containerized()) { physical_memory_size_type mem_limit = value_unlimited; - if (OSContainer::memory_limit_in_bytes(mem_limit) && mem_limit != value_unlimited) { + if (Container::memory_limit(mem_limit) && mem_limit != value_unlimited) { log_trace(os)("total container memory: " PHYS_MEM_TYPE_FORMAT, mem_limit); return mem_limit; } } - physical_memory_size_type phys_mem = Linux::physical_memory(); + physical_memory_size_type phys_mem = Machine::physical_memory(); log_trace(os)("total system memory: " PHYS_MEM_TYPE_FORMAT, phys_mem); return phys_mem; } +physical_memory_size_type os::Machine::physical_memory() { + return Linux::physical_memory(); +} + // Returns the resident set size (RSS) of the process. // Falls back to using VmRSS from /proc/self/status if /proc/self/smaps_rollup is unavailable. // Note: On kernels with memory cgroups or shared memory, VmRSS may underreport RSS. @@ -2439,20 +2508,21 @@ bool os::Linux::print_container_info(outputStream* st) { OSContainer::print_container_metric(st, "cpu_memory_nodes", p != nullptr ? p : "not supported"); free(p); - int i = -1; - bool supported = OSContainer::active_processor_count(i); + double cpus = -1; + bool supported = OSContainer::active_processor_count(cpus); if (supported) { - assert(i > 0, "must be"); + assert(cpus > 0, "must be"); if (ActiveProcessorCount > 0) { OSContainer::print_container_metric(st, "active_processor_count", ActiveProcessorCount, "(from -XX:ActiveProcessorCount)"); } else { - OSContainer::print_container_metric(st, "active_processor_count", i); + OSContainer::print_container_metric(st, "active_processor_count", cpus); } } else { OSContainer::print_container_metric(st, "active_processor_count", "not supported"); } + int i = -1; supported = OSContainer::cpu_quota(i); if (supported && i > 0) { OSContainer::print_container_metric(st, "cpu_quota", i); @@ -4737,15 +4807,26 @@ int os::active_processor_count() { return ActiveProcessorCount; } - int active_cpus = -1; - if (OSContainer::is_containerized() && OSContainer::active_processor_count(active_cpus)) { - log_trace(os)("active_processor_count: determined by OSContainer: %d", - active_cpus); - } else { - active_cpus = os::Linux::active_processor_count(); + if (is_containerized()) { + double cpu_quota; + if (Container::processor_count(cpu_quota)) { + int active_cpus = ceilf(cpu_quota); // Round fractional CPU quota up. + assert(active_cpus <= Machine::active_processor_count(), "must be"); + log_trace(os)("active_processor_count: determined by OSContainer: %d", + active_cpus); + return active_cpus; + } } - return active_cpus; + return Machine::active_processor_count(); +} + +int os::Machine::active_processor_count() { + return os::Linux::active_processor_count(); +} + +bool os::Container::processor_count(double& value) { + return OSContainer::active_processor_count(value); } static bool should_warn_invalid_processor_id() { diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index efbd1fe7c68..b0b7ae18106 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -839,10 +839,18 @@ bool os::available_memory(physical_memory_size_type& value) { return win32::available_memory(value); } +bool os::Machine::available_memory(physical_memory_size_type& value) { + return win32::available_memory(value); +} + bool os::free_memory(physical_memory_size_type& value) { return win32::available_memory(value); } +bool os::Machine::free_memory(physical_memory_size_type& value) { + return win32::available_memory(value); +} + bool os::win32::available_memory(physical_memory_size_type& value) { // Use GlobalMemoryStatusEx() because GlobalMemoryStatus() may return incorrect // value if total memory is larger than 4GB @@ -858,7 +866,11 @@ bool os::win32::available_memory(physical_memory_size_type& value) { } } -bool os::total_swap_space(physical_memory_size_type& value) { +bool os::total_swap_space(physical_memory_size_type& value) { + return Machine::total_swap_space(value); +} + +bool os::Machine::total_swap_space(physical_memory_size_type& value) { MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); BOOL res = GlobalMemoryStatusEx(&ms); @@ -872,6 +884,10 @@ bool os::total_swap_space(physical_memory_size_type& value) { } bool os::free_swap_space(physical_memory_size_type& value) { + return Machine::free_swap_space(value); +} + +bool os::Machine::free_swap_space(physical_memory_size_type& value) { MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); BOOL res = GlobalMemoryStatusEx(&ms); @@ -888,6 +904,10 @@ physical_memory_size_type os::physical_memory() { return win32::physical_memory(); } +physical_memory_size_type os::Machine::physical_memory() { + return win32::physical_memory(); +} + size_t os::rss() { size_t rss = 0; PROCESS_MEMORY_COUNTERS_EX pmex; @@ -911,6 +931,10 @@ int os::active_processor_count() { return ActiveProcessorCount; } + return Machine::active_processor_count(); +} + +int os::Machine::active_processor_count() { bool schedules_all_processor_groups = win32::is_windows_11_or_greater() || win32::is_windows_server_2022_or_greater(); if (UseAllWindowsProcessorGroups && !schedules_all_processor_groups && !win32::processor_group_warning_displayed()) { win32::set_processor_group_warning_displayed(true); diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index d8a30f9b5ee..885484020bd 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -66,10 +66,6 @@ #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" #include "utilities/debug.hpp" -#ifdef LINUX -#include "os_linux.hpp" -#include "osContainer_linux.hpp" -#endif #define NO_TRANSITION(result_type, header) extern "C" { result_type JNICALL header { #define NO_TRANSITION_END } } @@ -400,35 +396,18 @@ JVM_ENTRY_NO_ENV(jboolean, jfr_is_class_instrumented(JNIEnv* env, jclass jvm, jc JVM_END JVM_ENTRY_NO_ENV(jboolean, jfr_is_containerized(JNIEnv* env, jclass jvm)) -#ifdef LINUX - return OSContainer::is_containerized(); -#else - return false; -#endif + return os::is_containerized(); JVM_END JVM_ENTRY_NO_ENV(jlong, jfr_host_total_memory(JNIEnv* env, jclass jvm)) -#ifdef LINUX - // We want the host memory, not the container limit. - // os::physical_memory() would return the container limit. - return static_cast(os::Linux::physical_memory()); -#else - return static_cast(os::physical_memory()); -#endif + return static_cast(os::Machine::physical_memory()); JVM_END JVM_ENTRY_NO_ENV(jlong, jfr_host_total_swap_memory(JNIEnv* env, jclass jvm)) -#ifdef LINUX - // We want the host swap memory, not the container value. - physical_memory_size_type host_swap = 0; - (void)os::Linux::host_swap(host_swap); // Discard return value and treat as no swap - return static_cast(host_swap); -#else physical_memory_size_type total_swap_space = 0; // Return value ignored - defaulting to 0 on failure. - (void)os::total_swap_space(total_swap_space); + (void)os::Machine::total_swap_space(total_swap_space); return static_cast(total_swap_space); -#endif JVM_END JVM_ENTRY_NO_ENV(void, jfr_emit_data_loss(JNIEnv* env, jclass jvm, jlong bytes)) diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index ef5aca96a57..6d6937a97e9 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -115,9 +115,6 @@ #if INCLUDE_MANAGEMENT #include "services/finalizerService.hpp" #endif -#ifdef LINUX -#include "osContainer_linux.hpp" -#endif #include @@ -500,11 +497,9 @@ JVM_LEAF(jboolean, JVM_IsUseContainerSupport(void)) JVM_END JVM_LEAF(jboolean, JVM_IsContainerized(void)) -#ifdef LINUX - if (OSContainer::is_containerized()) { + if (os::is_containerized()) { return JNI_TRUE; } -#endif return JNI_FALSE; JVM_END diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 1c2f5527ff9..de5bc9ea58f 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, 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 @@ -129,7 +129,6 @@ #ifdef LINUX #include "cgroupSubsystem_linux.hpp" #include "os_linux.hpp" -#include "osContainer_linux.hpp" #endif #define CHECK_JNI_EXCEPTION_(env, value) \ @@ -2582,14 +2581,12 @@ WB_ENTRY(jboolean, WB_CheckLibSpecifiesNoexecstack(JNIEnv* env, jobject o, jstri WB_END WB_ENTRY(jboolean, WB_IsContainerized(JNIEnv* env, jobject o)) - LINUX_ONLY(return OSContainer::is_containerized();) - return false; + return os::is_containerized(); WB_END // Physical memory of the host machine (including containers) WB_ENTRY(jlong, WB_HostPhysicalMemory(JNIEnv* env, jobject o)) - LINUX_ONLY(return static_cast(os::Linux::physical_memory());) - return static_cast(os::physical_memory()); + return static_cast(os::Machine::physical_memory()); WB_END // Available memory of the host machine (container-aware) diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index cf18388c625..1c06bf3c521 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -81,10 +81,6 @@ #include "utilities/permitForbiddenFunctions.hpp" #include "utilities/powerOfTwo.hpp" -#ifdef LINUX -#include "osContainer_linux.hpp" -#endif - #ifndef _WINDOWS # include #endif @@ -2205,11 +2201,14 @@ static void assert_nonempty_range(const char* addr, size_t bytes) { } bool os::used_memory(physical_memory_size_type& value) { -#ifdef LINUX - if (OSContainer::is_containerized()) { - return OSContainer::memory_usage_in_bytes(value); + if (is_containerized()) { + return Container::used_memory(value); } -#endif + + return Machine::used_memory(value); +} + +bool os::Machine::used_memory(physical_memory_size_type& value) { physical_memory_size_type avail_mem = 0; // Return value ignored - defaulting to 0 on failure. (void)os::available_memory(avail_mem); @@ -2218,6 +2217,44 @@ bool os::used_memory(physical_memory_size_type& value) { return true; } +#ifndef LINUX +bool os::is_containerized() { + return false; +} + +bool os::Container::processor_count(double& value) { + return false; +} + +bool os::Container::available_memory(physical_memory_size_type& value) { + return false; +} + +bool os::Container::used_memory(physical_memory_size_type& value) { + return false; +} + +bool os::Container::total_swap_space(physical_memory_size_type& value) { + return false; +} + +bool os::Container::free_swap_space(physical_memory_size_type& value) { + return false; +} + +bool os::Container::memory_limit(physical_memory_size_type& value) { + return false; +} + +bool os::Container::memory_soft_limit(physical_memory_size_type& value) { + return false; +} + +bool os::Container::memory_throttle_limit(physical_memory_size_type& value) { + return false; +} +#endif + bool os::commit_memory(char* addr, size_t bytes, bool executable) { assert_nonempty_range(addr, bytes); diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index d585d3e5fc0..29c872157fd 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -342,6 +342,52 @@ class os: AllStatic { static bool is_server_class_machine(); static size_t rss(); + // On platforms with container support (currently only Linux) we combine machine values with + // potential container values in os:: methods, abstracting which value is actually used. + // The os::Machine and os::Container classes and containing methods are used to get machine + // and container values (when available) separately. + static bool is_containerized(); + + // The os::Machine class reports system resource metrics from the perspective of the operating + // system, without considering container-imposed limits. The values returned by these methods + // reflect the resources visible to the process as reported by the OS, and may already be + // affected by mechanisms such as virtualization, hypervisor limits, or process affinity, + // but do NOT consider further restrictions imposed by container runtimes (e.g., cgroups) + class Machine : AllStatic { + public: + static int active_processor_count(); + + [[nodiscard]] static bool available_memory(physical_memory_size_type& value); + [[nodiscard]] static bool used_memory(physical_memory_size_type& value); + [[nodiscard]] static bool free_memory(physical_memory_size_type& value); + + [[nodiscard]] static bool total_swap_space(physical_memory_size_type& value); + [[nodiscard]] static bool free_swap_space(physical_memory_size_type& value); + + static physical_memory_size_type physical_memory(); + }; + + // The os::Container class reports resource limits as imposed by a supported container runtime + // (currently only cgroup-based Linux runtimes). If the process is running inside a + // containerized environment, methods from this class report the effective limits imposed + // by the container, which may be more restrictive than what os::Machine reports. + // Methods return true and set the out-parameter if a limit is found, + // or false if no limit exists or it cannot be determined. + class Container : AllStatic { + public: + [[nodiscard]] static bool processor_count(double& value); // Returns the core-equivalent CPU quota + + [[nodiscard]] static bool available_memory(physical_memory_size_type& value); + [[nodiscard]] static bool used_memory(physical_memory_size_type& value); + + [[nodiscard]] static bool total_swap_space(physical_memory_size_type& value); + [[nodiscard]] static bool free_swap_space(physical_memory_size_type& value); + + [[nodiscard]] static bool memory_limit(physical_memory_size_type& value); + [[nodiscard]] static bool memory_soft_limit(physical_memory_size_type& value); + [[nodiscard]] static bool memory_throttle_limit(physical_memory_size_type& value); + }; + // Returns the id of the processor on which the calling thread is currently executing. // The returned value is guaranteed to be between 0 and (os::processor_count() - 1). static uint processor_id(); diff --git a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java index 6b0a536e4d4..3064b320c0d 100644 --- a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -143,9 +143,9 @@ public class TestCPUAwareness { // Expected active processor count can not exceed available CPU count - private static int adjustExpectedAPCForAvailableCPUs(int expectedAPC) { - if (expectedAPC > availableCPUs) { - expectedAPC = availableCPUs; + private static double adjustExpectedAPCForAvailableCPUs(double expectedAPC) { + if (expectedAPC > (double)availableCPUs) { + expectedAPC = (double)availableCPUs; System.out.println("Adjusted expectedAPC = " + expectedAPC); } return expectedAPC; @@ -158,7 +158,7 @@ public class TestCPUAwareness { System.out.println("quota = " + quota); System.out.println("period = " + period); - int expectedAPC = (int) Math.ceil((float) quota / (float) period); + double expectedAPC = (double) quota / (double) period; System.out.println("expectedAPC = " + expectedAPC); expectedAPC = adjustExpectedAPCForAvailableCPUs(expectedAPC); @@ -178,7 +178,7 @@ public class TestCPUAwareness { private static void testAPCCombo(String cpuset, int quota, int period, int shares, - int expectedAPC) throws Exception { + double expectedAPC) throws Exception { Common.logNewTestCase("test APC Combo"); System.out.println("cpuset = " + cpuset); System.out.println("quota = " + quota); From 496af3cf4769b78fa0928450a87928d259511c51 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 19 Jan 2026 18:05:22 +0000 Subject: [PATCH 094/328] 8375093: Convert GlobalCounter to use Atomic Reviewed-by: dholmes, iwalulya --- src/hotspot/share/runtime/thread.cpp | 5 +++-- src/hotspot/share/runtime/thread.hpp | 7 ++++--- src/hotspot/share/utilities/globalCounter.cpp | 12 ++++++------ src/hotspot/share/utilities/globalCounter.hpp | 5 +++-- .../share/utilities/globalCounter.inline.hpp | 15 +++++++-------- 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index f3c08ae62f7..bfbd4727e9a 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -36,6 +36,7 @@ #include "memory/resourceArea.hpp" #include "nmt/memTracker.hpp" #include "oops/oop.inline.hpp" +#include "runtime/atomic.hpp" #include "runtime/atomicAccess.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaThread.inline.hpp" @@ -82,7 +83,7 @@ Thread::Thread(MemTag mem_tag) { _threads_hazard_ptr = nullptr; _threads_list_ptr = nullptr; _nested_threads_hazard_ptr_cnt = 0; - _rcu_counter = 0; + _rcu_counter.store_relaxed(0); // the handle mark links itself to last_handle_mark new HandleMark(this); diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 181dfc46f87..dcd6fb2d3fd 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,6 +30,7 @@ #include "gc/shared/threadLocalAllocBuffer.hpp" #include "jni.h" #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" #include "runtime/atomicAccess.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" @@ -238,9 +239,9 @@ class Thread: public ThreadShadow { // Support for GlobalCounter private: - volatile uintx _rcu_counter; + Atomic _rcu_counter; public: - volatile uintx* get_rcu_counter() { + Atomic* get_rcu_counter() { return &_rcu_counter; } diff --git a/src/hotspot/share/utilities/globalCounter.cpp b/src/hotspot/share/utilities/globalCounter.cpp index 7019273d937..114d3b5fed1 100644 --- a/src/hotspot/share/utilities/globalCounter.cpp +++ b/src/hotspot/share/utilities/globalCounter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ */ #include "memory/iterator.hpp" -#include "runtime/atomicAccess.hpp" +#include "runtime/atomic.hpp" #include "runtime/javaThread.hpp" #include "runtime/threadSMR.inline.hpp" #include "runtime/vmThread.hpp" @@ -41,7 +41,7 @@ class GlobalCounter::CounterThreadCheck : public ThreadClosure { SpinYield yield; // Loops on this thread until it has exited the critical read section. while(true) { - uintx cnt = AtomicAccess::load_acquire(thread->get_rcu_counter()); + uintx cnt = thread->get_rcu_counter()->load_acquire(); // This checks if the thread's counter is active. And if so is the counter // for a pre-existing reader (belongs to this grace period). A pre-existing // reader will have a lower counter than the global counter version for this @@ -57,9 +57,9 @@ class GlobalCounter::CounterThreadCheck : public ThreadClosure { }; void GlobalCounter::write_synchronize() { - assert((*Thread::current()->get_rcu_counter() & COUNTER_ACTIVE) == 0x0, "must be outside a critcal section"); - // AtomicAccess::add must provide fence since we have storeload dependency. - uintx gbl_cnt = AtomicAccess::add(&_global_counter._counter, COUNTER_INCREMENT); + assert((Thread::current()->get_rcu_counter()->load_relaxed() & COUNTER_ACTIVE) == 0x0, "must be outside a critcal section"); + // Atomic add must provide fence since we have storeload dependency. + uintx gbl_cnt = _global_counter._counter.add_then_fetch(COUNTER_INCREMENT); // Do all RCU threads. CounterThreadCheck ctc(gbl_cnt); diff --git a/src/hotspot/share/utilities/globalCounter.hpp b/src/hotspot/share/utilities/globalCounter.hpp index c78831acfa5..80fc1b3e94e 100644 --- a/src/hotspot/share/utilities/globalCounter.hpp +++ b/src/hotspot/share/utilities/globalCounter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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,6 +27,7 @@ #include "memory/allStatic.hpp" #include "memory/padded.hpp" +#include "runtime/atomic.hpp" class Thread; @@ -47,7 +48,7 @@ class GlobalCounter : public AllStatic { // counter is on a separate cacheline. struct PaddedCounter { DEFINE_PAD_MINUS_SIZE(0, DEFAULT_PADDING_SIZE, 0); - volatile uintx _counter; + Atomic _counter; DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, sizeof(volatile uintx)); }; diff --git a/src/hotspot/share/utilities/globalCounter.inline.hpp b/src/hotspot/share/utilities/globalCounter.inline.hpp index 9cc746173b8..ed37b8a878d 100644 --- a/src/hotspot/share/utilities/globalCounter.inline.hpp +++ b/src/hotspot/share/utilities/globalCounter.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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,30 +27,29 @@ #include "utilities/globalCounter.hpp" -#include "runtime/atomicAccess.hpp" +#include "runtime/atomic.hpp" #include "runtime/javaThread.hpp" inline GlobalCounter::CSContext GlobalCounter::critical_section_begin(Thread *thread) { assert(thread == Thread::current(), "must be current thread"); - uintx old_cnt = AtomicAccess::load(thread->get_rcu_counter()); + uintx old_cnt = thread->get_rcu_counter()->load_relaxed(); // Retain the old counter value if already active, e.g. nested. // Otherwise, set the counter to the current version + active bit. uintx new_cnt = old_cnt; if ((new_cnt & COUNTER_ACTIVE) == 0) { - new_cnt = AtomicAccess::load(&_global_counter._counter) | COUNTER_ACTIVE; + new_cnt = _global_counter._counter.load_relaxed() | COUNTER_ACTIVE; } - AtomicAccess::release_store_fence(thread->get_rcu_counter(), new_cnt); + thread->get_rcu_counter()->release_store_fence(new_cnt); return static_cast(old_cnt); } inline void GlobalCounter::critical_section_end(Thread *thread, CSContext context) { assert(thread == Thread::current(), "must be current thread"); - assert((*thread->get_rcu_counter() & COUNTER_ACTIVE) == COUNTER_ACTIVE, "must be in critical section"); + assert((thread->get_rcu_counter()->load_relaxed() & COUNTER_ACTIVE) == COUNTER_ACTIVE, "must be in critical section"); // Restore the counter value from before the associated begin. - AtomicAccess::release_store(thread->get_rcu_counter(), - static_cast(context)); + thread->get_rcu_counter()->release_store(static_cast(context)); } class GlobalCounter::CriticalSection { From 303de9a3f2ba93f0bbe42044483a0b48c82b70cb Mon Sep 17 00:00:00 2001 From: Xiaohong Gong Date: Tue, 20 Jan 2026 01:43:40 +0000 Subject: [PATCH 095/328] 8370666: VectorAPI: Add clear comments for vector relative code in c2 Reviewed-by: epeter, jbhateja, qamai --- src/hotspot/share/opto/matcher.hpp | 4 +- src/hotspot/share/opto/node.hpp | 5 +- src/hotspot/share/opto/type.cpp | 8 +- src/hotspot/share/opto/type.hpp | 15 +- src/hotspot/share/opto/vectornode.hpp | 343 ++++++++++++++------------ 5 files changed, 214 insertions(+), 161 deletions(-) diff --git a/src/hotspot/share/opto/matcher.hpp b/src/hotspot/share/opto/matcher.hpp index a071cff9e3c..9579af84f24 100644 --- a/src/hotspot/share/opto/matcher.hpp +++ b/src/hotspot/share/opto/matcher.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -327,6 +327,8 @@ public: // e.g. Op_ vector nodes and other intrinsics while guarding with vlen static bool match_rule_supported_vector(int opcode, int vlen, BasicType bt); + // Returns true if the platform efficiently implements the given masked vector + // operation using predicate features, false otherwise. static bool match_rule_supported_vector_masked(int opcode, int vlen, BasicType bt); // Determines if a vector operation needs to be partially implemented with a mask diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index f1d9785a746..5ddc4236b3e 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, 2025, Alibaba Group Holding Limited. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -845,7 +845,8 @@ public: Flag_has_swapped_edges = 1ULL << 11, Flag_is_scheduled = 1ULL << 12, Flag_is_expensive = 1ULL << 13, - Flag_is_predicated_vector = 1ULL << 14, + Flag_is_predicated_vector = 1ULL << 14, // Marked on a vector node that has an additional + // mask input controlling the lane operations. Flag_for_post_loop_opts_igvn = 1ULL << 15, Flag_for_merge_stores_igvn = 1ULL << 16, Flag_is_removed_by_peephole = 1ULL << 17, diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index ecb8c2c1cd8..d3271e79f2f 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -2443,6 +2443,12 @@ const TypeVect* TypeVect::make(BasicType elem_bt, uint length, bool is_mask) { return nullptr; } +// Create a vector mask type with the given element basic type and length. +// - Returns "TypeVectMask" (PVectMask) for platforms that support the predicate +// feature and it is implemented properly in the backend, allowing the mask to +// be stored in a predicate/mask register. +// - Returns a normal vector type "TypeVectA ~ TypeVectZ" (NVectMask) otherwise, +// where the vector mask is stored in a vector register. const TypeVect* TypeVect::makemask(BasicType elem_bt, uint length) { if (Matcher::has_predicated_vectors() && Matcher::match_rule_supported_vector_masked(Op_VectorLoadMask, length, elem_bt)) { diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 285b4984cd1..7c7ff035a54 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -1018,7 +1018,7 @@ public: }; //------------------------------TypeVect--------------------------------------- -// Class of Vector Types +// Basic class of vector (mask) types. class TypeVect : public Type { const BasicType _elem_bt; // Vector's element type const uint _length; // Elements in vector (power of 2) @@ -1058,6 +1058,16 @@ public: #endif }; +// TypeVect subclasses representing vectors or vector masks with "BVectMask" or "NVectMask" +// layout (see vectornode.hpp for detailed notes on vector mask representations), mapped +// to vector registers and distinguished by vector register size: +// +// - TypeVectA: Scalable vector type (variable size, e.g., AArch64 SVE, RISC-V RVV) +// - TypeVectS: 32-bit vector type +// - TypeVectD: 64-bit vector type +// - TypeVectX: 128-bit vector type +// - TypeVectY: 256-bit vector type +// - TypeVectZ: 512-bit vector type class TypeVectA : public TypeVect { friend class TypeVect; TypeVectA(BasicType elem_bt, uint length) : TypeVect(VectorA, elem_bt, length) {} @@ -1088,6 +1098,9 @@ class TypeVectZ : public TypeVect { TypeVectZ(BasicType elem_bt, uint length) : TypeVect(VectorZ, elem_bt, length) {} }; +// Class of TypeVectMask, representing vector masks with "PVectMask" layout (see +// vectornode.hpp for detailed notes on vector mask representations), mapped to +// dedicated hardware predicate/mask registers. class TypeVectMask : public TypeVect { public: friend class TypeVect; diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp index dc7aa13cf36..b1976d8f0db 100644 --- a/src/hotspot/share/opto/vectornode.hpp +++ b/src/hotspot/share/opto/vectornode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, 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 @@ -33,7 +33,63 @@ #include "opto/opcodes.hpp" #include "prims/vectorSupport.hpp" -//------------------------------VectorNode------------------------------------- +//=======================Notes-for-VectorMask-Representation======================= +// +// There are three distinct representations for vector masks based on platform and +// use scenarios: +// +// - BVectMask: Platform-independent mask stored in a vector register with 8-bit +// lanes containing 1/0 values. The corresponding type is TypeVectA ~ TypeVectZ. +// +// - NVectMask: Platform-specific mask stored in vector registers with N-bit lanes, +// where all bits in each lane are either set (true) or unset (false). Generated +// on architectures without predicate/mask feature, such as AArch64 NEON, x86 +// AVX2, etc. The corresponding type is TypeVectA ~ TypeVectZ. +// +// - PVectMask: Platform-specific mask stored in predicate/mask registers. Generated +// on architectures with predicate/mask feature, such as AArch64 SVE, x86 AVX-512, +// and RISC-V Vector Extension (RVV). The corresponding type is TypeVectMask. +// +// NVectMask and PVectMask encode element data type and vector length information. +// They are the primary mask representations used in most mask and masked vector +// operations. BVectMask primarily represents mask values loaded from or stored to +// Java boolean memory (mask backing storage). VectorLoadMask/VectorStoreMask nodes +// are needed to transform it to/from P/NVectMask. It is also used in certain mask +// operations (e.g. VectorMaskOpNode). +// +//=========================Notes-for-Masked-Vector-Nodes=========================== +// +// Each lane-wise and cross-lane (reduction) ALU node supports both non-masked +// and masked operations. +// +// Currently masked vector nodes are only used to implement the Vector API's masked +// operations (which might also be used for auto-vectorization in future), such as: +// Vector lanewise(VectorOperators.Binary op, Vector v, VectorMask m) +// +// They are generated during intrinsification for Vector API, only on architectures +// that support the relevant predicated instructions. The compiler uses +// "Matcher::match_rule_supported_vector_masked()" to check whether the current +// platform supports the predicated/masked vector instructions for an operation. It +// generates the masked vector node for the operation if supported. Otherwise, it +// generates the unpredicated vector node and implements the masked operation with +// the help of a VectorBlendNode. Please see more details from API intrinsification +// in vectorIntrinsics.cpp. +// +// To differentiate the masked and non-masked nodes, flag "Flag_is_predicated_vector" +// is set for the masked version. Meanwhile, there is an additional mask input for +// the masked nodes. +// +// For example: +// - Non-masked version: +// in1 in2 +// \ / +// AddVBNode +// +// - Masked version (with "Flag_is_predicated_vector" being set): +// in1 in2 mask +// \ | / +// AddVBNode + // Vector Operation class VectorNode : public TypeNode { public: @@ -103,6 +159,8 @@ class VectorNode : public TypeNode { static bool implemented(int opc, uint vlen, BasicType bt); static bool is_shift(Node* n); static bool is_vshift_cnt(Node* n); + // Returns true if the lower vlen bits (bits [0, vlen-1]) of the long value + // are all 1s or all 0s, indicating a "mask all" or "mask none" pattern. static bool is_maskall_type(const TypeLong* type, int vlen); static bool is_muladds2i(const Node* n); static bool is_roundopD(Node* n); @@ -176,7 +234,6 @@ class SaturatingVectorNode : public VectorNode { bool is_unsigned() { return _is_unsigned; } }; -//------------------------------AddVBNode-------------------------------------- // Vector add byte class AddVBNode : public VectorNode { public: @@ -184,7 +241,6 @@ class AddVBNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------AddVSNode-------------------------------------- // Vector add char/short class AddVSNode : public VectorNode { public: @@ -192,7 +248,6 @@ class AddVSNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------AddVINode-------------------------------------- // Vector add int class AddVINode : public VectorNode { public: @@ -200,7 +255,6 @@ class AddVINode : public VectorNode { virtual int Opcode() const; }; -//------------------------------AddVLNode-------------------------------------- // Vector add long class AddVLNode : public VectorNode { public: @@ -208,7 +262,6 @@ public: virtual int Opcode() const; }; -//------------------------------AddVHFNode-------------------------------------- // Vector add float class AddVHFNode : public VectorNode { public: @@ -216,7 +269,6 @@ public: virtual int Opcode() const; }; -//------------------------------AddVFNode-------------------------------------- // Vector add float class AddVFNode : public VectorNode { public: @@ -224,7 +276,6 @@ public: virtual int Opcode() const; }; -//------------------------------AddVDNode-------------------------------------- // Vector add double class AddVDNode : public VectorNode { public: @@ -232,7 +283,6 @@ public: virtual int Opcode() const; }; -//------------------------------ReductionNode------------------------------------ // Perform reduction of a vector class ReductionNode : public Node { private: @@ -294,7 +344,6 @@ class ReductionNode : public Node { #endif }; -//------------------------------AddReductionVINode-------------------------------------- // Vector add byte, short and int as a reduction class AddReductionVINode : public ReductionNode { public: @@ -302,7 +351,6 @@ public: virtual int Opcode() const; }; -//------------------------------AddReductionVLNode-------------------------------------- // Vector add long as a reduction class AddReductionVLNode : public ReductionNode { public: @@ -310,7 +358,6 @@ public: virtual int Opcode() const; }; -//------------------------------AddReductionVFNode-------------------------------------- // Vector add float as a reduction class AddReductionVFNode : public ReductionNode { private: @@ -337,7 +384,6 @@ public: virtual uint size_of() const { return sizeof(*this); } }; -//------------------------------AddReductionVDNode-------------------------------------- // Vector add double as a reduction class AddReductionVDNode : public ReductionNode { private: @@ -364,7 +410,6 @@ public: virtual uint size_of() const { return sizeof(*this); } }; -//------------------------------SubVBNode-------------------------------------- // Vector subtract byte class SubVBNode : public VectorNode { public: @@ -372,7 +417,6 @@ class SubVBNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------SubVSNode-------------------------------------- // Vector subtract short class SubVSNode : public VectorNode { public: @@ -380,7 +424,6 @@ class SubVSNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------SubVINode-------------------------------------- // Vector subtract int class SubVINode : public VectorNode { public: @@ -388,7 +431,6 @@ class SubVINode : public VectorNode { virtual int Opcode() const; }; -//------------------------------SubVLNode-------------------------------------- // Vector subtract long class SubVLNode : public VectorNode { public: @@ -396,7 +438,6 @@ class SubVLNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------SaturatingAddVNode----------------------------- // Vector saturating addition. class SaturatingAddVNode : public SaturatingVectorNode { public: @@ -404,7 +445,6 @@ class SaturatingAddVNode : public SaturatingVectorNode { virtual int Opcode() const; }; -//------------------------------SaturatingSubVNode----------------------------- // Vector saturating subtraction. class SaturatingSubVNode : public SaturatingVectorNode { public: @@ -412,7 +452,6 @@ class SaturatingSubVNode : public SaturatingVectorNode { virtual int Opcode() const; }; -//------------------------------SubVHFNode-------------------------------------- // Vector subtract half float class SubVHFNode : public VectorNode { public: @@ -420,8 +459,6 @@ public: virtual int Opcode() const; }; - -//------------------------------SubVFNode-------------------------------------- // Vector subtract float class SubVFNode : public VectorNode { public: @@ -429,7 +466,6 @@ class SubVFNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------SubVDNode-------------------------------------- // Vector subtract double class SubVDNode : public VectorNode { public: @@ -437,7 +473,6 @@ class SubVDNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------MulVBNode-------------------------------------- // Vector multiply byte class MulVBNode : public VectorNode { public: @@ -445,7 +480,6 @@ class MulVBNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------MulVSNode-------------------------------------- // Vector multiply short class MulVSNode : public VectorNode { public: @@ -453,7 +487,6 @@ class MulVSNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------MulVINode-------------------------------------- // Vector multiply int class MulVINode : public VectorNode { public: @@ -461,7 +494,6 @@ class MulVINode : public VectorNode { virtual int Opcode() const; }; -//------------------------------MulVLNode-------------------------------------- // Vector multiply long class MulVLNode : public VectorNode { public: @@ -473,7 +505,6 @@ public: bool has_uint_inputs() const; }; -//------------------------------MulVFNode-------------------------------------- // Vector multiply half float class MulVHFNode : public VectorNode { public: @@ -481,7 +512,6 @@ public: virtual int Opcode() const; }; -//------------------------------MulVFNode-------------------------------------- // Vector multiply float class MulVFNode : public VectorNode { public: @@ -489,7 +519,6 @@ public: virtual int Opcode() const; }; -//------------------------------MulVDNode-------------------------------------- // Vector multiply double class MulVDNode : public VectorNode { public: @@ -497,7 +526,6 @@ public: virtual int Opcode() const; }; -//------------------------------MulAddVS2VINode-------------------------------- // Vector multiply shorts to int and add adjacent ints. class MulAddVS2VINode : public VectorNode { public: @@ -505,7 +533,6 @@ class MulAddVS2VINode : public VectorNode { virtual int Opcode() const; }; -//------------------------------FmaVNode-------------------------------------- // Vector fused-multiply-add class FmaVNode : public VectorNode { public: @@ -515,7 +542,6 @@ public: virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); }; -//------------------------------FmaVDNode-------------------------------------- // Vector fused-multiply-add double class FmaVDNode : public FmaVNode { public: @@ -523,7 +549,6 @@ public: virtual int Opcode() const; }; -//------------------------------FmaVFNode-------------------------------------- // Vector fused-multiply-add float class FmaVFNode : public FmaVNode { public: @@ -531,7 +556,6 @@ public: virtual int Opcode() const; }; -//------------------------------FmaVHFNode------------------------------------- // Vector fused-multiply-add half-precision float class FmaVHFNode : public FmaVNode { public: @@ -539,7 +563,6 @@ public: virtual int Opcode() const; }; -//------------------------------MulReductionVINode-------------------------------------- // Vector multiply byte, short and int as a reduction class MulReductionVINode : public ReductionNode { public: @@ -547,7 +570,6 @@ public: virtual int Opcode() const; }; -//------------------------------MulReductionVLNode-------------------------------------- // Vector multiply int as a reduction class MulReductionVLNode : public ReductionNode { public: @@ -555,7 +577,6 @@ public: virtual int Opcode() const; }; -//------------------------------MulReductionVFNode-------------------------------------- // Vector multiply float as a reduction class MulReductionVFNode : public ReductionNode { // True if mul reduction operation for floats requires strict ordering. @@ -581,7 +602,6 @@ public: virtual uint size_of() const { return sizeof(*this); } }; -//------------------------------MulReductionVDNode-------------------------------------- // Vector multiply double as a reduction class MulReductionVDNode : public ReductionNode { // True if mul reduction operation for doubles requires strict ordering. @@ -607,7 +627,6 @@ public: virtual uint size_of() const { return sizeof(*this); } }; -//------------------------------DivVHFNode------------------------------------- // Vector divide half float class DivVHFNode : public VectorNode { public: @@ -615,7 +634,6 @@ public: virtual int Opcode() const; }; -//------------------------------DivVFNode-------------------------------------- // Vector divide float class DivVFNode : public VectorNode { public: @@ -623,7 +641,6 @@ class DivVFNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------DivVDNode-------------------------------------- // Vector Divide double class DivVDNode : public VectorNode { public: @@ -631,7 +648,6 @@ class DivVDNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------AbsVBNode-------------------------------------- // Vector Abs byte class AbsVBNode : public VectorNode { public: @@ -639,7 +655,6 @@ public: virtual int Opcode() const; }; -//------------------------------AbsVSNode-------------------------------------- // Vector Abs short class AbsVSNode : public VectorNode { public: @@ -647,7 +662,6 @@ public: virtual int Opcode() const; }; -//------------------------------MinVNode-------------------------------------- // Vector Min class MinVNode : public VectorNode { public: @@ -655,7 +669,6 @@ public: virtual int Opcode() const; }; -//------------------------------MinVHFNode------------------------------------ // Vector Min for half floats class MinVHFNode : public VectorNode { public: @@ -663,7 +676,6 @@ public: virtual int Opcode() const; }; -//------------------------------MaxVHFNode------------------------------------ // Vector Max for half floats class MaxVHFNode : public VectorNode { public: @@ -671,6 +683,7 @@ public: virtual int Opcode() const; }; +// Vector Unsigned Min class UMinVNode : public VectorNode { public: UMinVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2 ,vt) { @@ -681,8 +694,6 @@ class UMinVNode : public VectorNode { virtual int Opcode() const; }; - -//------------------------------MaxVNode-------------------------------------- // Vector Max class MaxVNode : public VectorNode { public: @@ -690,6 +701,7 @@ class MaxVNode : public VectorNode { virtual int Opcode() const; }; +// Vector Unsigned Max class UMaxVNode : public VectorNode { public: UMaxVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) { @@ -700,7 +712,6 @@ class UMaxVNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------AbsVINode-------------------------------------- // Vector Abs int class AbsVINode : public VectorNode { public: @@ -708,7 +719,6 @@ class AbsVINode : public VectorNode { virtual int Opcode() const; }; -//------------------------------AbsVLNode-------------------------------------- // Vector Abs long class AbsVLNode : public VectorNode { public: @@ -716,7 +726,6 @@ public: virtual int Opcode() const; }; -//------------------------------AbsVFNode-------------------------------------- // Vector Abs float class AbsVFNode : public VectorNode { public: @@ -724,7 +733,6 @@ class AbsVFNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------AbsVDNode-------------------------------------- // Vector Abs double class AbsVDNode : public VectorNode { public: @@ -732,7 +740,6 @@ class AbsVDNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------NegVNode--------------------------------------- // Vector Neg parent class (not for code generation). class NegVNode : public VectorNode { public: @@ -746,7 +753,6 @@ class NegVNode : public VectorNode { Node* degenerate_integral_negate(PhaseGVN* phase, bool is_predicated); }; -//------------------------------NegVINode-------------------------------------- // Vector Neg byte/short/int class NegVINode : public NegVNode { public: @@ -754,7 +760,6 @@ class NegVINode : public NegVNode { virtual int Opcode() const; }; -//------------------------------NegVLNode-------------------------------------- // Vector Neg long class NegVLNode : public NegVNode { public: @@ -762,7 +767,6 @@ class NegVLNode : public NegVNode { virtual int Opcode() const; }; -//------------------------------NegVFNode-------------------------------------- // Vector Neg float class NegVFNode : public NegVNode { public: @@ -770,7 +774,6 @@ class NegVFNode : public NegVNode { virtual int Opcode() const; }; -//------------------------------NegVDNode-------------------------------------- // Vector Neg double class NegVDNode : public NegVNode { public: @@ -778,7 +781,6 @@ class NegVDNode : public NegVNode { virtual int Opcode() const; }; -//------------------------------PopCountVINode--------------------------------- // Vector popcount integer bits class PopCountVINode : public VectorNode { public: @@ -786,7 +788,6 @@ class PopCountVINode : public VectorNode { virtual int Opcode() const; }; -//------------------------------PopCountVLNode--------------------------------- // Vector popcount long bits class PopCountVLNode : public VectorNode { public: @@ -796,7 +797,6 @@ class PopCountVLNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------SqrtVHFNode------------------------------------- // Vector Sqrt half-precision float class SqrtVHFNode : public VectorNode { public: @@ -804,14 +804,13 @@ public: virtual int Opcode() const; }; -//------------------------------SqrtVFNode-------------------------------------- // Vector Sqrt float class SqrtVFNode : public VectorNode { public: SqrtVFNode(Node* in, const TypeVect* vt) : VectorNode(in,vt) {} virtual int Opcode() const; }; -//------------------------------RoundDoubleVNode-------------------------------- + // Vector round double class RoundDoubleModeVNode : public VectorNode { public: @@ -819,7 +818,6 @@ class RoundDoubleModeVNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------SqrtVDNode-------------------------------------- // Vector Sqrt double class SqrtVDNode : public VectorNode { public: @@ -827,8 +825,7 @@ class SqrtVDNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------ShiftVNode----------------------------------- -// Class ShiftV functionality. This covers the common behaviors for all kinds +// Class ShiftV functionality. This covers the common behaviors for all kinds // of vector shifts. class ShiftVNode : public VectorNode { private: @@ -848,7 +845,6 @@ class ShiftVNode : public VectorNode { virtual uint size_of() const { return sizeof(ShiftVNode); } }; -//------------------------------LShiftVBNode----------------------------------- // Vector left shift bytes class LShiftVBNode : public ShiftVNode { public: @@ -857,7 +853,6 @@ class LShiftVBNode : public ShiftVNode { virtual int Opcode() const; }; -//------------------------------LShiftVSNode----------------------------------- // Vector left shift shorts class LShiftVSNode : public ShiftVNode { public: @@ -866,7 +861,6 @@ class LShiftVSNode : public ShiftVNode { virtual int Opcode() const; }; -//------------------------------LShiftVINode----------------------------------- // Vector left shift ints class LShiftVINode : public ShiftVNode { public: @@ -875,7 +869,6 @@ class LShiftVINode : public ShiftVNode { virtual int Opcode() const; }; -//------------------------------LShiftVLNode----------------------------------- // Vector left shift longs class LShiftVLNode : public ShiftVNode { public: @@ -884,7 +877,6 @@ class LShiftVLNode : public ShiftVNode { virtual int Opcode() const; }; -//------------------------------RShiftVBNode----------------------------------- // Vector right arithmetic (signed) shift bytes class RShiftVBNode : public ShiftVNode { public: @@ -893,7 +885,6 @@ class RShiftVBNode : public ShiftVNode { virtual int Opcode() const; }; -//------------------------------RShiftVSNode----------------------------------- // Vector right arithmetic (signed) shift shorts class RShiftVSNode : public ShiftVNode { public: @@ -902,7 +893,6 @@ class RShiftVSNode : public ShiftVNode { virtual int Opcode() const; }; -//------------------------------RShiftVINode----------------------------------- // Vector right arithmetic (signed) shift ints class RShiftVINode : public ShiftVNode { public: @@ -911,7 +901,6 @@ class RShiftVINode : public ShiftVNode { virtual int Opcode() const; }; -//------------------------------RShiftVLNode----------------------------------- // Vector right arithmetic (signed) shift longs class RShiftVLNode : public ShiftVNode { public: @@ -920,7 +909,6 @@ class RShiftVLNode : public ShiftVNode { virtual int Opcode() const; }; -//------------------------------URShiftVBNode---------------------------------- // Vector right logical (unsigned) shift bytes class URShiftVBNode : public ShiftVNode { public: @@ -929,7 +917,6 @@ class URShiftVBNode : public ShiftVNode { virtual int Opcode() const; }; -//------------------------------URShiftVSNode---------------------------------- // Vector right logical (unsigned) shift shorts class URShiftVSNode : public ShiftVNode { public: @@ -938,7 +925,6 @@ class URShiftVSNode : public ShiftVNode { virtual int Opcode() const; }; -//------------------------------URShiftVINode---------------------------------- // Vector right logical (unsigned) shift ints class URShiftVINode : public ShiftVNode { public: @@ -947,7 +933,6 @@ class URShiftVINode : public ShiftVNode { virtual int Opcode() const; }; -//------------------------------URShiftVLNode---------------------------------- // Vector right logical (unsigned) shift longs class URShiftVLNode : public ShiftVNode { public: @@ -956,7 +941,6 @@ class URShiftVLNode : public ShiftVNode { virtual int Opcode() const; }; -//------------------------------LShiftCntVNode--------------------------------- // Vector left shift count class LShiftCntVNode : public VectorNode { public: @@ -964,7 +948,6 @@ class LShiftCntVNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------RShiftCntVNode--------------------------------- // Vector right shift count class RShiftCntVNode : public VectorNode { public: @@ -972,7 +955,6 @@ class RShiftCntVNode : public VectorNode { virtual int Opcode() const; }; -//------------------------------AndVNode--------------------------------------- // Vector and integer class AndVNode : public VectorNode { public: @@ -981,7 +963,6 @@ class AndVNode : public VectorNode { virtual Node* Identity(PhaseGVN* phase); }; -//------------------------------AndReductionVNode-------------------------------------- // Vector and byte, short, int, long as a reduction class AndReductionVNode : public ReductionNode { public: @@ -989,8 +970,7 @@ class AndReductionVNode : public ReductionNode { virtual int Opcode() const; }; -//------------------------------OrVNode--------------------------------------- -// Vector or byte, short, int, long as a reduction +// Vector or integer class OrVNode : public VectorNode { public: OrVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1,in2,vt) {} @@ -998,15 +978,13 @@ class OrVNode : public VectorNode { virtual Node* Identity(PhaseGVN* phase); }; -//------------------------------OrReductionVNode-------------------------------------- -// Vector xor byte, short, int, long as a reduction +// Vector or byte, short, int, long as a reduction class OrReductionVNode : public ReductionNode { public: OrReductionVNode(Node* ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} virtual int Opcode() const; }; -//------------------------------XorVNode--------------------------------------- // Vector xor integer class XorVNode : public VectorNode { public: @@ -1016,15 +994,13 @@ class XorVNode : public VectorNode { Node* Ideal_XorV_VectorMaskCmp(PhaseGVN* phase, bool can_reshape); }; -//------------------------------XorReductionVNode-------------------------------------- -// Vector and int, long as a reduction +// Vector xor byte, short, int, long as a reduction class XorReductionVNode : public ReductionNode { public: XorReductionVNode(Node* ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} virtual int Opcode() const; }; -//------------------------------MinReductionVNode-------------------------------------- // Vector min byte, short, int, long, float, double as a reduction class MinReductionVNode : public ReductionNode { public: @@ -1032,15 +1008,13 @@ public: virtual int Opcode() const; }; -//------------------------------MaxReductionVNode-------------------------------------- -// Vector min byte, short, int, long, float, double as a reduction +// Vector max byte, short, int, long, float, double as a reduction class MaxReductionVNode : public ReductionNode { public: MaxReductionVNode(Node* ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} virtual int Opcode() const; }; -//------------------------------CompressVNode-------------------------------------- // Vector compress class CompressVNode: public VectorNode { public: @@ -1051,6 +1025,7 @@ class CompressVNode: public VectorNode { virtual int Opcode() const; }; +// Vector mask compress class CompressMNode: public VectorNode { public: CompressMNode(Node* mask, const TypeVect* vt) : @@ -1060,7 +1035,6 @@ class CompressMNode: public VectorNode { virtual int Opcode() const; }; -//------------------------------ExpandVNode-------------------------------------- // Vector expand class ExpandVNode: public VectorNode { public: @@ -1073,7 +1047,6 @@ class ExpandVNode: public VectorNode { //================================= M E M O R Y =============================== -//------------------------------LoadVectorNode--------------------------------- // Load Vector from memory class LoadVectorNode : public LoadNode { private: @@ -1115,7 +1088,6 @@ class LoadVectorNode : public LoadNode { #endif }; -//------------------------------LoadVectorGatherNode------------------------------ // Load Vector from memory via index map class LoadVectorGatherNode : public LoadVectorNode { public: @@ -1138,7 +1110,6 @@ class LoadVectorGatherNode : public LoadVectorNode { } }; -//------------------------------StoreVectorNode-------------------------------- // Store Vector to memory class StoreVectorNode : public StoreNode { private: @@ -1180,9 +1151,7 @@ class StoreVectorNode : public StoreNode { #endif }; -//------------------------------StoreVectorScatterNode------------------------------ // Store Vector into memory via index map - class StoreVectorScatterNode : public StoreVectorNode { public: enum { Indices = 4 }; @@ -1200,7 +1169,6 @@ class StoreVectorNode : public StoreNode { virtual Node* indices() const { return in(Indices); } }; -//------------------------------StoreVectorMaskedNode-------------------------------- // Store Vector to memory under the influence of a predicate register(mask). class StoreVectorMaskedNode : public StoreVectorNode { public: @@ -1221,7 +1189,6 @@ class StoreVectorMaskedNode : public StoreVectorNode { virtual Node* mask() const { return in(Mask); } }; -//------------------------------LoadVectorMaskedNode-------------------------------- // Load Vector from memory under the influence of a predicate register(mask). class LoadVectorMaskedNode : public LoadVectorNode { public: @@ -1245,7 +1212,6 @@ class LoadVectorMaskedNode : public LoadVectorNode { } }; -//-------------------------------LoadVectorGatherMaskedNode--------------------------------- // Load Vector from memory via index map under the influence of a predicate register(mask). class LoadVectorGatherMaskedNode : public LoadVectorNode { public: @@ -1268,7 +1234,6 @@ class LoadVectorGatherMaskedNode : public LoadVectorNode { } }; -//------------------------------StoreVectorScatterMaskedNode-------------------------------- // Store Vector into memory via index map under the influence of a predicate register(mask). class StoreVectorScatterMaskedNode : public StoreVectorNode { public: @@ -1312,7 +1277,6 @@ public: virtual const Type *bottom_type() const { return in(1)->bottom_type(); } }; -//------------------------------VectorCmpMaskedNode-------------------------------- // Vector Comparison under the influence of a predicate register(mask). class VectorCmpMaskedNode : public TypeNode { public: @@ -1325,7 +1289,8 @@ class VectorCmpMaskedNode : public TypeNode { virtual int Opcode() const; }; -//------------------------------VectorMaskGenNode---------------------------------- +// Generate a vector mask based on the given length. Lanes with indices in +// [0, length) are set to true, while the remaining lanes are set to false. class VectorMaskGenNode : public TypeNode { public: VectorMaskGenNode(Node* length, const Type* ty): TypeNode(ty, 2) { @@ -1338,7 +1303,8 @@ class VectorMaskGenNode : public TypeNode { static Node* make(Node* length, BasicType vmask_bt, int vmask_len); }; -//------------------------------VectorMaskOpNode----------------------------------- +// Base class for certain vector mask operations. The supported input mask can +// be either "BVectMask" or "PVectMask" depending on the platform. class VectorMaskOpNode : public TypeNode { private: int _mopc; @@ -1359,6 +1325,7 @@ class VectorMaskOpNode : public TypeNode { static Node* make(Node* mask, const Type* ty, int mopc); }; +// Count the number of true (set) lanes in the vector mask. class VectorMaskTrueCountNode : public VectorMaskOpNode { public: VectorMaskTrueCountNode(Node* mask, const Type* ty): @@ -1366,6 +1333,8 @@ class VectorMaskTrueCountNode : public VectorMaskOpNode { virtual int Opcode() const; }; +// Returns the index of the first true (set) lane in the vector mask. +// If no lanes are set, returns the vector length. class VectorMaskFirstTrueNode : public VectorMaskOpNode { public: VectorMaskFirstTrueNode(Node* mask, const Type* ty): @@ -1373,6 +1342,8 @@ class VectorMaskFirstTrueNode : public VectorMaskOpNode { virtual int Opcode() const; }; +// Returns the index of the last true (set) lane in the vector mask. +// If no lanes are set, returns -1 . class VectorMaskLastTrueNode : public VectorMaskOpNode { public: VectorMaskLastTrueNode(Node* mask, const Type* ty): @@ -1380,6 +1351,10 @@ class VectorMaskLastTrueNode : public VectorMaskOpNode { virtual int Opcode() const; }; +// Pack the mask lane values into a long value, supporting at most the +// first 64 lanes. Each mask lane is packed into one bit in the long +// value, ordered from the least significant bit to the most significant +// bit. class VectorMaskToLongNode : public VectorMaskOpNode { public: VectorMaskToLongNode(Node* mask, const Type* ty): @@ -1391,6 +1366,9 @@ class VectorMaskToLongNode : public VectorMaskOpNode { virtual Node* Identity(PhaseGVN* phase); }; +// Unpack bits from a long value into vector mask lane values. Each bit +// in the long value is unpacked into one mask lane, ordered from the +// least significant bit to the sign bit. class VectorLongToMaskNode : public VectorNode { public: VectorLongToMaskNode(Node* mask, const TypeVect* ty): @@ -1400,36 +1378,40 @@ class VectorLongToMaskNode : public VectorNode { virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); }; -//-------------------------- Vector mask broadcast ----------------------------------- +// Broadcast a scalar value to all lanes of a vector mask. All lanes are set +// to true if the input value is non-zero, or false if the input value is +// zero. This node is only used to generate a mask with "PVectMask" layout. class MaskAllNode : public VectorNode { public: MaskAllNode(Node* in, const TypeVect* vt) : VectorNode(in, vt) {} virtual int Opcode() const; }; -//--------------------------- Vector mask logical and -------------------------------- +// Perform a bitwise AND operation between two vector masks. This node is +// only used for vector masks with "PVectMask" layout. class AndVMaskNode : public AndVNode { public: AndVMaskNode(Node* in1, Node* in2, const TypeVect* vt) : AndVNode(in1, in2, vt) {} virtual int Opcode() const; }; -//--------------------------- Vector mask logical or --------------------------------- +// Perform a bitwise OR operation between two vector masks. This node is +// only used for vector masks with "PVectMask" layout. class OrVMaskNode : public OrVNode { public: OrVMaskNode(Node* in1, Node* in2, const TypeVect* vt) : OrVNode(in1, in2, vt) {} virtual int Opcode() const; }; -//--------------------------- Vector mask logical xor -------------------------------- +// Perform a bitwise XOR operation between two vector masks. This node is +// only used for vector masks with "PVectMask" layout. class XorVMaskNode : public XorVNode { public: XorVMaskNode(Node* in1, Node* in2, const TypeVect* vt) : XorVNode(in1, in2, vt) {} virtual int Opcode() const; }; -//=========================Promote_Scalar_to_Vector============================ - +// Replicate a scalar value to all lanes of a vector. class ReplicateNode : public VectorNode { public: ReplicateNode(Node* in1, const TypeVect* vt) : VectorNode(in1, vt) { @@ -1439,7 +1421,7 @@ class ReplicateNode : public VectorNode { virtual int Opcode() const; }; -//======================Populate_Indices_into_a_Vector========================= +// Populate indices into a vector. class PopulateIndexNode : public VectorNode { public: PopulateIndexNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {} @@ -1448,7 +1430,6 @@ class PopulateIndexNode : public VectorNode { //========================Pack_Scalars_into_a_Vector=========================== -//------------------------------PackNode--------------------------------------- // Pack parent class (not for code generation). class PackNode : public VectorNode { public: @@ -1466,7 +1447,6 @@ class PackNode : public VectorNode { static PackNode* make(Node* s, uint vlen, BasicType bt); }; -//------------------------------PackBNode-------------------------------------- // Pack byte scalars into vector class PackBNode : public PackNode { public: @@ -1474,7 +1454,6 @@ class PackBNode : public PackNode { virtual int Opcode() const; }; -//------------------------------PackSNode-------------------------------------- // Pack short scalars into a vector class PackSNode : public PackNode { public: @@ -1483,7 +1462,6 @@ class PackSNode : public PackNode { virtual int Opcode() const; }; -//------------------------------PackINode-------------------------------------- // Pack integer scalars into a vector class PackINode : public PackNode { public: @@ -1492,7 +1470,6 @@ class PackINode : public PackNode { virtual int Opcode() const; }; -//------------------------------PackLNode-------------------------------------- // Pack long scalars into a vector class PackLNode : public PackNode { public: @@ -1501,7 +1478,6 @@ class PackLNode : public PackNode { virtual int Opcode() const; }; -//------------------------------Pack2LNode------------------------------------- // Pack 2 long scalars into a vector class Pack2LNode : public PackNode { public: @@ -1509,7 +1485,6 @@ class Pack2LNode : public PackNode { virtual int Opcode() const; }; -//------------------------------PackFNode-------------------------------------- // Pack float scalars into vector class PackFNode : public PackNode { public: @@ -1518,7 +1493,6 @@ class PackFNode : public PackNode { virtual int Opcode() const; }; -//------------------------------PackDNode-------------------------------------- // Pack double scalars into a vector class PackDNode : public PackNode { public: @@ -1527,7 +1501,6 @@ class PackDNode : public PackNode { virtual int Opcode() const; }; -//------------------------------Pack2DNode------------------------------------- // Pack 2 double scalars into a vector class Pack2DNode : public PackNode { public: @@ -1535,7 +1508,10 @@ class Pack2DNode : public PackNode { virtual int Opcode() const; }; - +// Load the IOTA constant vector containing sequential indices starting from 0 +// and incrementing by 1 up to "VLENGTH - 1". So far, the first input is an int +// constant 0. For example, a 128-bit vector with int (32-bit) elements produces +// a vector like "[0, 1, 2, 3]". class VectorLoadConstNode : public VectorNode { public: VectorLoadConstNode(Node* in1, const TypeVect* vt) : VectorNode(in1, vt) {} @@ -1544,8 +1520,7 @@ class VectorLoadConstNode : public VectorNode { //========================Extract_Scalar_from_Vector=========================== -//------------------------------ExtractNode------------------------------------ -// Extract a scalar from a vector at position "pos" +// The base class for all extract nodes. class ExtractNode : public Node { public: ExtractNode(Node* src, Node* pos) : Node(nullptr, src, pos) {} @@ -1554,8 +1529,7 @@ class ExtractNode : public Node { static int opcode(BasicType bt); }; -//------------------------------ExtractBNode----------------------------------- -// Extract a byte from a vector at position "pos" +// Extract a byte from a vector at position "pos". class ExtractBNode : public ExtractNode { public: ExtractBNode(Node* src, Node* pos) : ExtractNode(src, pos) {} @@ -1564,8 +1538,7 @@ class ExtractBNode : public ExtractNode { virtual uint ideal_reg() const { return Op_RegI; } }; -//------------------------------ExtractUBNode---------------------------------- -// Extract a boolean from a vector at position "pos" +// Extract a boolean from a vector at position "pos". class ExtractUBNode : public ExtractNode { public: ExtractUBNode(Node* src, Node* pos) : ExtractNode(src, pos) {} @@ -1574,8 +1547,7 @@ class ExtractUBNode : public ExtractNode { virtual uint ideal_reg() const { return Op_RegI; } }; -//------------------------------ExtractCNode----------------------------------- -// Extract a char from a vector at position "pos" +// Extract a char from a vector at position "pos". class ExtractCNode : public ExtractNode { public: ExtractCNode(Node* src, Node* pos) : ExtractNode(src, pos) {} @@ -1584,8 +1556,7 @@ class ExtractCNode : public ExtractNode { virtual uint ideal_reg() const { return Op_RegI; } }; -//------------------------------ExtractSNode----------------------------------- -// Extract a short from a vector at position "pos" +// Extract a short from a vector at position "pos". class ExtractSNode : public ExtractNode { public: ExtractSNode(Node* src, Node* pos) : ExtractNode(src, pos) {} @@ -1594,8 +1565,7 @@ class ExtractSNode : public ExtractNode { virtual uint ideal_reg() const { return Op_RegI; } }; -//------------------------------ExtractINode----------------------------------- -// Extract an int from a vector at position "pos" +// Extract an int from a vector at position "pos". class ExtractINode : public ExtractNode { public: ExtractINode(Node* src, Node* pos) : ExtractNode(src, pos) {} @@ -1604,8 +1574,7 @@ class ExtractINode : public ExtractNode { virtual uint ideal_reg() const { return Op_RegI; } }; -//------------------------------ExtractLNode----------------------------------- -// Extract a long from a vector at position "pos" +// Extract a long from a vector at position "pos". class ExtractLNode : public ExtractNode { public: ExtractLNode(Node* src, Node* pos) : ExtractNode(src, pos) {} @@ -1614,8 +1583,7 @@ class ExtractLNode : public ExtractNode { virtual uint ideal_reg() const { return Op_RegL; } }; -//------------------------------ExtractFNode----------------------------------- -// Extract a float from a vector at position "pos" +// Extract a float from a vector at position "pos". class ExtractFNode : public ExtractNode { public: ExtractFNode(Node* src, Node* pos) : ExtractNode(src, pos) {} @@ -1624,8 +1592,7 @@ class ExtractFNode : public ExtractNode { virtual uint ideal_reg() const { return Op_RegF; } }; -//------------------------------ExtractDNode----------------------------------- -// Extract a double from a vector at position "pos" +// Extract a double from a vector at position "pos". class ExtractDNode : public ExtractNode { public: ExtractDNode(Node* src, Node* pos) : ExtractNode(src, pos) {} @@ -1634,7 +1601,6 @@ class ExtractDNode : public ExtractNode { virtual uint ideal_reg() const { return Op_RegD; } }; -//------------------------------MacroLogicVNode------------------------------- // Vector logical operations packing node. class MacroLogicVNode : public VectorNode { private: @@ -1653,6 +1619,8 @@ public: Node* mask, uint truth_table, const TypeVect* vt); }; +// Compare two vectors lane-wise using the specified predicate and produce a +// vector mask. class VectorMaskCmpNode : public VectorNode { private: BoolTest::mask _predicate; @@ -1697,6 +1665,8 @@ class VectorMaskWrapperNode : public VectorNode { Node* vector_mask() const { return in(2); } }; +// Test whether all or any lanes in the first input vector mask is true, +// based on the specified predicate. class VectorTestNode : public CmpNode { private: BoolTest::mask _predicate; @@ -1719,6 +1689,9 @@ class VectorTestNode : public CmpNode { } }; +// Blend two vectors based on a vector mask. For each lane, select the value +// from the first input vector (vec1) if the corresponding mask lane is set, +// otherwise select from the second input vector (vec2). class VectorBlendNode : public VectorNode { public: VectorBlendNode(Node* vec1, Node* vec2, Node* mask) @@ -1732,11 +1705,14 @@ class VectorBlendNode : public VectorNode { Node* vec_mask() const { return in(3); } }; +// Rearrange lane elements from a source vector under the control of a shuffle +// (indexes) vector. Each lane in the shuffle vector specifies which lane from +// the source vector to select for the corresponding output lane. All indexes +// are in the range [0, VLENGTH). class VectorRearrangeNode : public VectorNode { public: VectorRearrangeNode(Node* vec1, Node* shuffle) : VectorNode(vec1, shuffle, vec1->bottom_type()->is_vect()) { - // assert(mask->is_VectorMask(), "VectorBlendNode requires that third argument be a mask"); } virtual int Opcode() const; @@ -1744,9 +1720,12 @@ class VectorRearrangeNode : public VectorNode { Node* vec_shuffle() const { return in(2); } }; - -// Select elements from two source vectors based on the wrapped indexes held in -// the first vector. +// Select lane elements from two source vectors ("src1" and "src2") under the +// control of an "indexes" vector. The two source vectors are logically concatenated +// to form a table of 2*VLENGTH elements, where src1 occupies indices [0, VLENGTH) +// and src2 occupies indices [VLENGTH, 2*VLENGTH). Each lane in the "indexes" +// vector specifies which element from this table to select for the corresponding +// output lane. class SelectFromTwoVectorNode : public VectorNode { public: SelectFromTwoVectorNode(Node* indexes, Node* src1, Node* src2, const TypeVect* vt) @@ -1758,13 +1737,19 @@ public: virtual int Opcode() const; }; -// The target may not directly support the rearrange operation for an element type. In those cases, -// we can transform the rearrange into a different element type. For example, on x86 before AVX512, -// there is no rearrange instruction for short elements, what we will then do is to transform the -// shuffle vector into one that we can do byte rearrange such that it would provide the same -// result. This could have been done in VectorRearrangeNode during code emission but we eagerly -// expand this out because it is often the case that an index vector is reused in many rearrange -// operations. This allows the index preparation to be GVN-ed as well as hoisted out of loops, etc. +// Transform a shuffle vector when the target does not directly support rearrange +// operations for the original element type. In such cases, the rearrange can be +// transformed to use a different element type. +// +// For example, on x86 before AVX512, there are no rearrange instructions for short +// elements. The shuffle vector is transformed into one suitable for byte rearrange +// that produces the same result. This could have been done in VectorRearrangeNode +// during code emission, but we eagerly expand it out because shuffle vectors are +// often reused in many rearrange operations. This allows the transformation to be +// GVN-ed and hoisted out of loops. +// +// Input: Original shuffle vector (indices for the desired element type) +// Output: Transformed shuffle vector (indices for the supported element type) class VectorLoadShuffleNode : public VectorNode { public: VectorLoadShuffleNode(Node* in, const TypeVect* vt) @@ -1773,6 +1758,8 @@ class VectorLoadShuffleNode : public VectorNode { virtual int Opcode() const; }; +// Convert a "BVectMask" into a platform-specific vector mask (either "NVectMask" +// or "PVectMask"). class VectorLoadMaskNode : public VectorNode { public: VectorLoadMaskNode(Node* in, const TypeVect* vt) : VectorNode(in, vt) { @@ -1784,6 +1771,8 @@ class VectorLoadMaskNode : public VectorNode { Node* Ideal(PhaseGVN* phase, bool can_reshape); }; +// Convert a platform-specific vector mask (either "NVectMask" or "PVectMask") +// into a "BVectMask". class VectorStoreMaskNode : public VectorNode { protected: VectorStoreMaskNode(Node* in1, ConINode* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {} @@ -1795,6 +1784,8 @@ class VectorStoreMaskNode : public VectorNode { static VectorStoreMaskNode* make(PhaseGVN& gvn, Node* in, BasicType in_type, uint num_elem); }; +// Lane-wise type cast a vector mask to the given vector type. The vector length +// of the input and output must be the same. class VectorMaskCastNode : public VectorNode { public: VectorMaskCastNode(Node* in, const TypeVect* vt) : VectorNode(in, vt) { @@ -1831,6 +1822,8 @@ class VectorReinterpretNode : public VectorNode { virtual int Opcode() const; }; +// Lane-wise type cast a vector to the given vector type. This is the base +// class for all vector type cast operations. class VectorCastNode : public VectorNode { public: VectorCastNode(Node* in, const TypeVect* vt) : VectorNode(in, vt) {} @@ -1843,6 +1836,7 @@ class VectorCastNode : public VectorNode { virtual Node* Identity(PhaseGVN* phase); }; +// Cast a byte vector to the given vector type. class VectorCastB2XNode : public VectorCastNode { public: VectorCastB2XNode(Node* in, const TypeVect* vt) : VectorCastNode(in, vt) { @@ -1851,6 +1845,7 @@ class VectorCastB2XNode : public VectorCastNode { virtual int Opcode() const; }; +// Cast a short vector to the given vector type. class VectorCastS2XNode : public VectorCastNode { public: VectorCastS2XNode(Node* in, const TypeVect* vt) : VectorCastNode(in, vt) { @@ -1859,6 +1854,7 @@ class VectorCastS2XNode : public VectorCastNode { virtual int Opcode() const; }; +// Cast an int vector to the given vector type. class VectorCastI2XNode : public VectorCastNode { public: VectorCastI2XNode(Node* in, const TypeVect* vt) : VectorCastNode(in, vt) { @@ -1867,6 +1863,7 @@ class VectorCastI2XNode : public VectorCastNode { virtual int Opcode() const; }; +// Cast a long vector to the given vector type. class VectorCastL2XNode : public VectorCastNode { public: VectorCastL2XNode(Node* in, const TypeVect* vt) : VectorCastNode(in, vt) { @@ -1875,6 +1872,7 @@ class VectorCastL2XNode : public VectorCastNode { virtual int Opcode() const; }; +// Cast a float vector to the given vector type. class VectorCastF2XNode : public VectorCastNode { public: VectorCastF2XNode(Node* in, const TypeVect* vt) : VectorCastNode(in, vt) { @@ -1883,6 +1881,7 @@ class VectorCastF2XNode : public VectorCastNode { virtual int Opcode() const; }; +// Cast a double vector to the given vector type. class VectorCastD2XNode : public VectorCastNode { public: VectorCastD2XNode(Node* in, const TypeVect* vt) : VectorCastNode(in, vt) { @@ -1891,6 +1890,7 @@ class VectorCastD2XNode : public VectorCastNode { virtual int Opcode() const; }; +// Cast a half float vector to float vector type. class VectorCastHF2FNode : public VectorCastNode { public: VectorCastHF2FNode(Node* in, const TypeVect* vt) : VectorCastNode(in, vt) { @@ -1899,6 +1899,7 @@ class VectorCastHF2FNode : public VectorCastNode { virtual int Opcode() const; }; +// Cast a float vector to a half float vector type. class VectorCastF2HFNode : public VectorCastNode { public: VectorCastF2HFNode(Node* in, const TypeVect* vt) : VectorCastNode(in, vt) { @@ -1907,8 +1908,12 @@ class VectorCastF2HFNode : public VectorCastNode { virtual int Opcode() const; }; -// So far, VectorUCastNode can only be used in Vector API unsigned extensions -// between integral types. E.g., extending byte to float is not supported now. +// Unsigned vector cast operations can only be used in unsigned (zero) +// extensions between integral types so far. E.g., extending byte to +// float is not supported now. + +// Unsigned cast a byte vector to the given vector type with short, int, +// or long element type. class VectorUCastB2XNode : public VectorCastNode { public: VectorUCastB2XNode(Node* in, const TypeVect* vt) : VectorCastNode(in, vt) { @@ -1920,6 +1925,8 @@ class VectorUCastB2XNode : public VectorCastNode { virtual int Opcode() const; }; +// Unsigned cast a short vector to the given vector type with int or long +// element type. class VectorUCastS2XNode : public VectorCastNode { public: VectorUCastS2XNode(Node* in, const TypeVect* vt) : VectorCastNode(in, vt) { @@ -1930,6 +1937,7 @@ class VectorUCastS2XNode : public VectorCastNode { virtual int Opcode() const; }; +// Unsigned cast an int vector to the given vector type with long element type. class VectorUCastI2XNode : public VectorCastNode { public: VectorUCastI2XNode(Node* in, const TypeVect* vt) : VectorCastNode(in, vt) { @@ -1939,6 +1947,7 @@ class VectorUCastI2XNode : public VectorCastNode { virtual int Opcode() const; }; +// Vector round float to nearest integer. class RoundVFNode : public VectorNode { public: RoundVFNode(Node* in, const TypeVect* vt) :VectorNode(in, vt) { @@ -1947,6 +1956,7 @@ class RoundVFNode : public VectorNode { virtual int Opcode() const; }; +// Vector round double to nearest integer. class RoundVDNode : public VectorNode { public: RoundVDNode(Node* in, const TypeVect* vt) : VectorNode(in, vt) { @@ -1955,6 +1965,7 @@ class RoundVDNode : public VectorNode { virtual int Opcode() const; }; +// Insert a new value into a vector lane at the specified position. class VectorInsertNode : public VectorNode { public: VectorInsertNode(Node* vsrc, Node* new_val, ConINode* pos, const TypeVect* vt) : VectorNode(vsrc, new_val, (Node*)pos, vt) { @@ -1968,6 +1979,9 @@ class VectorInsertNode : public VectorNode { static Node* make(Node* vec, Node* new_val, int position, PhaseGVN& gvn); }; +// Box a vector value into a Vector API object (e.g., IntMaxVector). +// This is a macro node that gets expanded during vector optimization +// phase. class VectorBoxNode : public Node { private: const TypeInstPtr* const _box_type; @@ -1995,6 +2009,8 @@ class VectorBoxNode : public Node { static const TypeFunc* vec_box_type(const TypeInstPtr* box_type); }; +// Allocate storage for boxing a vector value. This is used during vector +// box expansion. class VectorBoxAllocateNode : public CallStaticJavaNode { public: VectorBoxAllocateNode(Compile* C, const TypeInstPtr* vbox_type) @@ -2009,6 +2025,9 @@ class VectorBoxAllocateNode : public CallStaticJavaNode { #endif // !PRODUCT }; +// Unbox a Vector API object (e.g., IntMaxVector) to extract the underlying +// vector value. This is a macro node expanded during vector optimization +// phase. class VectorUnboxNode : public VectorNode { protected: uint size_of() const { return sizeof(*this); } @@ -2027,6 +2046,7 @@ class VectorUnboxNode : public VectorNode { Node* Ideal(PhaseGVN* phase, bool can_reshape); }; +// Lane-wise right rotation of the first input by the second input. class RotateRightVNode : public VectorNode { public: RotateRightVNode(Node* in1, Node* in2, const TypeVect* vt) @@ -2036,6 +2056,7 @@ public: Node* Ideal(PhaseGVN* phase, bool can_reshape); }; +// Lane-wise left rotation of the first input by the second input. class RotateLeftVNode : public VectorNode { public: RotateLeftVNode(Node* in1, Node* in2, const TypeVect* vt) @@ -2045,6 +2066,7 @@ public: Node* Ideal(PhaseGVN* phase, bool can_reshape); }; +// Count the number of leading zeros in each lane of the input. class CountLeadingZerosVNode : public VectorNode { public: CountLeadingZerosVNode(Node* in, const TypeVect* vt) @@ -2056,6 +2078,7 @@ class CountLeadingZerosVNode : public VectorNode { virtual int Opcode() const; }; +// Count the number of trailing zeros in each lane of the input. class CountTrailingZerosVNode : public VectorNode { public: CountTrailingZerosVNode(Node* in, const TypeVect* vt) @@ -2067,6 +2090,7 @@ class CountTrailingZerosVNode : public VectorNode { virtual int Opcode() const; }; +// Reverse the bits within each lane (e.g., 0b10110010 becomes 0b01001101). class ReverseVNode : public VectorNode { public: ReverseVNode(Node* in, const TypeVect* vt) @@ -2076,6 +2100,7 @@ public: virtual int Opcode() const; }; +// Reverse the byte order within each lane (e.g., 0x12345678 becomes 0x78563412). class ReverseBytesVNode : public VectorNode { public: ReverseBytesVNode(Node* in, const TypeVect* vt) @@ -2085,6 +2110,7 @@ public: virtual int Opcode() const; }; +// Vector signum float. class SignumVFNode : public VectorNode { public: SignumVFNode(Node* in1, Node* zero, Node* one, const TypeVect* vt) @@ -2093,6 +2119,7 @@ public: virtual int Opcode() const; }; +// Vector signum double. class SignumVDNode : public VectorNode { public: SignumVDNode(Node* in1, Node* zero, Node* one, const TypeVect* vt) @@ -2101,6 +2128,8 @@ public: virtual int Opcode() const; }; +// Compress (extract and pack) bits in each lane of the first input +// based on the mask input. class CompressBitsVNode : public VectorNode { public: CompressBitsVNode(Node* in, Node* mask, const TypeVect* vt) @@ -2108,6 +2137,8 @@ public: virtual int Opcode() const; }; +// Expand (deposit) bits in each lane of the first input based on the +// mask input. class ExpandBitsVNode : public VectorNode { public: ExpandBitsVNode(Node* in, Node* mask, const TypeVect* vt) From ca6925ec6bf44cf7d4704becc194389e4c87b74f Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 20 Jan 2026 06:18:07 +0000 Subject: [PATCH 096/328] 8370112: Remove VM_Version::supports_fast_class_init_checks() in platform-specific code Reviewed-by: shade, fyang --- .../cpu/aarch64/sharedRuntime_aarch64.cpp | 29 ++++++++------- .../cpu/aarch64/templateTable_aarch64.cpp | 9 ++--- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 35 +++++++++--------- src/hotspot/cpu/ppc/templateTable_ppc_64.cpp | 9 ++--- src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp | 29 ++++++++------- src/hotspot/cpu/riscv/templateTable_riscv.cpp | 9 ++--- src/hotspot/cpu/s390/sharedRuntime_s390.cpp | 31 ++++++++-------- src/hotspot/cpu/s390/templateTable_s390.cpp | 9 ++--- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 36 +++++++++---------- src/hotspot/cpu/x86/templateTable_x86.cpp | 9 ++--- 10 files changed, 102 insertions(+), 103 deletions(-) diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 89ae6bc10e0..73b631029a0 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -722,22 +722,20 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, // Class initialization barrier for static methods entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr; - if (VM_Version::supports_fast_class_init_checks()) { - Label L_skip_barrier; + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); + Label L_skip_barrier; - { // Bypass the barrier for non-static methods - __ ldrh(rscratch1, Address(rmethod, Method::access_flags_offset())); - __ andsw(zr, rscratch1, JVM_ACC_STATIC); - __ br(Assembler::EQ, L_skip_barrier); // non-static - } + // Bypass the barrier for non-static methods + __ ldrh(rscratch1, Address(rmethod, Method::access_flags_offset())); + __ andsw(zr, rscratch1, JVM_ACC_STATIC); + __ br(Assembler::EQ, L_skip_barrier); // non-static - __ load_method_holder(rscratch2, rmethod); - __ clinit_barrier(rscratch2, rscratch1, &L_skip_barrier); - __ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); + __ load_method_holder(rscratch2, rmethod); + __ clinit_barrier(rscratch2, rscratch1, &L_skip_barrier); + __ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); - __ bind(L_skip_barrier); - entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc(); - } + __ bind(L_skip_barrier); + entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc(); BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); bs->c2i_entry_barrier(masm); @@ -1508,7 +1506,8 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // SVC, HVC, or SMC. Make it a NOP. __ nop(); - if (VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) { + if (method->needs_clinit_barrier()) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); Label L_skip_barrier; __ mov_metadata(rscratch2, method->method_holder()); // InstanceKlass* __ clinit_barrier(rscratch2, rscratch1, &L_skip_barrier); diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp index cde142b39ac..07b469650f0 100644 --- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -2290,7 +2290,8 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no, __ subs(zr, temp, (int) code); // have we resolved this bytecode? // Class initialization barrier for static methods - if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) { + if (bytecode() == Bytecodes::_invokestatic) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); __ br(Assembler::NE, L_clinit_barrier_slow); __ ldr(temp, Address(Rcache, in_bytes(ResolvedMethodEntry::method_offset()))); __ load_method_holder(temp, temp); @@ -2340,8 +2341,8 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no, __ subs(zr, temp, (int) code); // have we resolved this bytecode? // Class initialization barrier for static fields - if (VM_Version::supports_fast_class_init_checks() && - (bytecode() == Bytecodes::_getstatic || bytecode() == Bytecodes::_putstatic)) { + if (bytecode() == Bytecodes::_getstatic || bytecode() == Bytecodes::_putstatic) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); const Register field_holder = temp; __ br(Assembler::NE, L_clinit_barrier_slow); diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 4e427ace404..4eb2028f529 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1237,26 +1237,24 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, // Class initialization barrier for static methods entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr; - if (VM_Version::supports_fast_class_init_checks()) { - Label L_skip_barrier; + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); + Label L_skip_barrier; - { // Bypass the barrier for non-static methods - __ lhz(R0, in_bytes(Method::access_flags_offset()), R19_method); - __ andi_(R0, R0, JVM_ACC_STATIC); - __ beq(CR0, L_skip_barrier); // non-static - } + // Bypass the barrier for non-static methods + __ lhz(R0, in_bytes(Method::access_flags_offset()), R19_method); + __ andi_(R0, R0, JVM_ACC_STATIC); + __ beq(CR0, L_skip_barrier); // non-static - Register klass = R11_scratch1; - __ load_method_holder(klass, R19_method); - __ clinit_barrier(klass, R16_thread, &L_skip_barrier /*L_fast_path*/); + Register klass = R11_scratch1; + __ load_method_holder(klass, R19_method); + __ clinit_barrier(klass, R16_thread, &L_skip_barrier /*L_fast_path*/); - __ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub(), R0); - __ mtctr(klass); - __ bctr(); + __ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub(), R0); + __ mtctr(klass); + __ bctr(); - __ bind(L_skip_barrier); - entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc(); - } + __ bind(L_skip_barrier); + entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc(); BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); bs->c2i_entry_barrier(masm, /* tmp register*/ ic_klass, /* tmp register*/ receiver_klass, /* tmp register*/ code); @@ -2210,7 +2208,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // -------------------------------------------------------------------------- vep_start_pc = (intptr_t)__ pc(); - if (VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) { + if (method->needs_clinit_barrier()) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); Label L_skip_barrier; Register klass = r_temp_1; // Notify OOP recorder (don't need the relocation) diff --git a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp index 8d61ba1b2d7..8a3af748fa1 100644 --- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -2199,7 +2199,8 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no, Register Rca __ isync(); // Order load wrt. succeeding loads. // Class initialization barrier for static methods - if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) { + if (bytecode() == Bytecodes::_invokestatic) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); const Register method = Rscratch; const Register klass = Rscratch; @@ -2244,8 +2245,8 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no, Register Rcac __ isync(); // Order load wrt. succeeding loads. // Class initialization barrier for static fields - if (VM_Version::supports_fast_class_init_checks() && - (bytecode() == Bytecodes::_getstatic || bytecode() == Bytecodes::_putstatic)) { + if (bytecode() == Bytecodes::_getstatic || bytecode() == Bytecodes::_putstatic) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); const Register field_holder = R4_ARG2; // InterpreterRuntime::resolve_get_put sets field_holder and finally release-stores put_code. diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index eeb6fad1b59..44a6f6c0dc0 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -637,22 +637,20 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, // Class initialization barrier for static methods entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr; - if (VM_Version::supports_fast_class_init_checks()) { - Label L_skip_barrier; + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); + Label L_skip_barrier; - { // Bypass the barrier for non-static methods - __ load_unsigned_short(t0, Address(xmethod, Method::access_flags_offset())); - __ test_bit(t1, t0, exact_log2(JVM_ACC_STATIC)); - __ beqz(t1, L_skip_barrier); // non-static - } + // Bypass the barrier for non-static methods + __ load_unsigned_short(t0, Address(xmethod, Method::access_flags_offset())); + __ test_bit(t1, t0, exact_log2(JVM_ACC_STATIC)); + __ beqz(t1, L_skip_barrier); // non-static - __ load_method_holder(t1, xmethod); - __ clinit_barrier(t1, t0, &L_skip_barrier); - __ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); + __ load_method_holder(t1, xmethod); + __ clinit_barrier(t1, t0, &L_skip_barrier); + __ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); - __ bind(L_skip_barrier); - entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc(); - } + __ bind(L_skip_barrier); + entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc(); BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); bs->c2i_entry_barrier(masm); @@ -1443,7 +1441,8 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ nop(); // 4 bytes } - if (VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) { + if (method->needs_clinit_barrier()) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); Label L_skip_barrier; __ mov_metadata(t1, method->method_holder()); // InstanceKlass* __ clinit_barrier(t1, t0, &L_skip_barrier); diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp index ca41583e4bc..5a3644f70bb 100644 --- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -2192,7 +2192,8 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no, __ mv(t0, (int) code); // Class initialization barrier for static methods - if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) { + if (bytecode() == Bytecodes::_invokestatic) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); __ bne(temp, t0, L_clinit_barrier_slow); // have we resolved this bytecode? __ ld(temp, Address(Rcache, in_bytes(ResolvedMethodEntry::method_offset()))); __ load_method_holder(temp, temp); @@ -2243,8 +2244,8 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no, __ mv(t0, (int) code); // have we resolved this bytecode? // Class initialization barrier for static fields - if (VM_Version::supports_fast_class_init_checks() && - (bytecode() == Bytecodes::_getstatic || bytecode() == Bytecodes::_putstatic)) { + if (bytecode() == Bytecodes::_getstatic || bytecode() == Bytecodes::_putstatic) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); const Register field_holder = temp; __ bne(temp, t0, L_clinit_barrier_slow); diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 5b6f7dcd984..00a830a80cd 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1567,7 +1567,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, //--------------------------------------------------------------------- wrapper_VEPStart = __ offset(); - if (VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) { + if (method->needs_clinit_barrier()) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); Label L_skip_barrier; Register klass = Z_R1_scratch; // Notify OOP recorder (don't need the relocation) @@ -2378,24 +2379,22 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, // Class initialization barrier for static methods entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr; - if (VM_Version::supports_fast_class_init_checks()) { - Label L_skip_barrier; + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); + Label L_skip_barrier; - { // Bypass the barrier for non-static methods - __ testbit_ushort(Address(Z_method, Method::access_flags_offset()), JVM_ACC_STATIC_BIT); - __ z_bfalse(L_skip_barrier); // non-static - } + // Bypass the barrier for non-static methods + __ testbit_ushort(Address(Z_method, Method::access_flags_offset()), JVM_ACC_STATIC_BIT); + __ z_bfalse(L_skip_barrier); // non-static - Register klass = Z_R11; - __ load_method_holder(klass, Z_method); - __ clinit_barrier(klass, Z_thread, &L_skip_barrier /*L_fast_path*/); + Register klass = Z_R11; + __ load_method_holder(klass, Z_method); + __ clinit_barrier(klass, Z_thread, &L_skip_barrier /*L_fast_path*/); - __ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub()); - __ z_br(klass); + __ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub()); + __ z_br(klass); - __ bind(L_skip_barrier); - entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc(); - } + __ bind(L_skip_barrier); + entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc(); gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup); return; diff --git a/src/hotspot/cpu/s390/templateTable_s390.cpp b/src/hotspot/cpu/s390/templateTable_s390.cpp index 4e8fdf275e4..647915ef4fa 100644 --- a/src/hotspot/cpu/s390/templateTable_s390.cpp +++ b/src/hotspot/cpu/s390/templateTable_s390.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -2377,7 +2377,8 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no, __ z_cli(Address(Rcache, bc_offset), code); // Class initialization barrier for static methods - if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) { + if (bytecode() == Bytecodes::_invokestatic) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); const Register method = Z_R1_scratch; const Register klass = Z_R1_scratch; __ z_brne(L_clinit_barrier_slow); @@ -2427,8 +2428,8 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no, __ z_cli(Address(cache, code_offset), code); // Class initialization barrier for static fields - if (VM_Version::supports_fast_class_init_checks() && - (bytecode() == Bytecodes::_getstatic || bytecode() == Bytecodes::_putstatic)) { + if (bytecode() == Bytecodes::_getstatic || bytecode() == Bytecodes::_putstatic) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); const Register field_holder = index; __ z_brne(L_clinit_barrier_slow); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index 5a4a5b1809e..bbd43c1a0e8 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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 @@ -1043,26 +1043,24 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, // Class initialization barrier for static methods entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr; - if (VM_Version::supports_fast_class_init_checks()) { - Label L_skip_barrier; - Register method = rbx; + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); + Label L_skip_barrier; + Register method = rbx; - { // Bypass the barrier for non-static methods - Register flags = rscratch1; - __ load_unsigned_short(flags, Address(method, Method::access_flags_offset())); - __ testl(flags, JVM_ACC_STATIC); - __ jcc(Assembler::zero, L_skip_barrier); // non-static - } + // Bypass the barrier for non-static methods + Register flags = rscratch1; + __ load_unsigned_short(flags, Address(method, Method::access_flags_offset())); + __ testl(flags, JVM_ACC_STATIC); + __ jcc(Assembler::zero, L_skip_barrier); // non-static - Register klass = rscratch1; - __ load_method_holder(klass, method); - __ clinit_barrier(klass, &L_skip_barrier /*L_fast_path*/); + Register klass = rscratch1; + __ load_method_holder(klass, method); + __ clinit_barrier(klass, &L_skip_barrier /*L_fast_path*/); - __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path + __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path - __ bind(L_skip_barrier); - entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc(); - } + __ bind(L_skip_barrier); + entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc(); BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); bs->c2i_entry_barrier(masm); @@ -1904,7 +1902,8 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, int vep_offset = ((intptr_t)__ pc()) - start; - if (VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) { + if (method->needs_clinit_barrier()) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); Label L_skip_barrier; Register klass = r10; __ mov_metadata(klass, method->method_holder()); // InstanceKlass* @@ -3602,4 +3601,3 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { } #endif // INCLUDE_JFR - diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp index 42392b84833..db7749ec482 100644 --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -2216,7 +2216,8 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no, __ cmpl(temp, code); // have we resolved this bytecode? // Class initialization barrier for static methods - if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) { + if (bytecode() == Bytecodes::_invokestatic) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); const Register method = temp; const Register klass = temp; @@ -2264,8 +2265,8 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no, __ cmpl(temp, code); // have we resolved this bytecode? // Class initialization barrier for static fields - if (VM_Version::supports_fast_class_init_checks() && - (bytecode() == Bytecodes::_getstatic || bytecode() == Bytecodes::_putstatic)) { + if (bytecode() == Bytecodes::_getstatic || bytecode() == Bytecodes::_putstatic) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); const Register field_holder = temp; __ jcc(Assembler::notEqual, L_clinit_barrier_slow); From e45f5656bc90421c9acb0cbf87164162039ddf81 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 20 Jan 2026 07:10:46 +0000 Subject: [PATCH 097/328] 8373650: Test "javax/swing/JMenuItem/6458123/ManualBug6458123.java" fails because the check icons are not aligned properly as expected Reviewed-by: tr, dnguyen --- .../plaf/windows/WindowsIconFactory.java | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java index 915a361a3a1..91c2cbcd61d 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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 @@ -905,10 +905,46 @@ public final class WindowsIconFactory implements Serializable XPStyle xp = XPStyle.getXP(); if (xp != null) { Skin skin = xp.getSkin(c, part); - if (icon == null || icon.getIconHeight() <= 16) { - skin.paintSkin(g, x + OFFSET, y + OFFSET, state); + if (WindowsGraphicsUtils.isLeftToRight(c)) { + if (icon == null || icon.getIconHeight() <= 16) { + skin.paintSkin(g, x + OFFSET, y + OFFSET, state); + } else { + skin.paintSkin(g, x + OFFSET, y + icon.getIconHeight() / 2, state); + } } else { - skin.paintSkin(g, x + OFFSET, y + icon.getIconHeight() / 2, state); + if (icon == null) { + skin.paintSkin(g, x + 4 * OFFSET, y + OFFSET, state); + } else { + int ycoord = (icon.getIconHeight() <= 16) + ? y + OFFSET + : (y + icon.getIconHeight() / 2); + if (icon.getIconWidth() <= 8) { + skin.paintSkin(g, x + OFFSET, ycoord, state); + } else if (icon.getIconWidth() <= 16) { + if (menuItem.getText().isEmpty()) { + skin.paintSkin(g, + (menuItem.getAccelerator() != null) + ? (x + 2 * OFFSET) : (x + 3 * OFFSET), + ycoord, state); + } else { + skin.paintSkin(g, + (type == JRadioButtonMenuItem.class) + ? (x + 4 * OFFSET) : (x + 3 * OFFSET), + ycoord, state); + } + } else { + if (menuItem.getText().isEmpty() + || menuItem.getAccelerator() != null) { + skin.paintSkin(g, + (type == JRadioButtonMenuItem.class) + ? (x + 3 * OFFSET) : (x + 4 * OFFSET), + ycoord, state); + } else { + skin.paintSkin(g, x + 7 * OFFSET, + ycoord, state); + } + } + } } } } From d9db4fb36e4f90546dc3fc19b5923b8be6a2f518 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 20 Jan 2026 08:01:54 +0000 Subject: [PATCH 098/328] 8373894: G1: Count evacuation-failed garbage collections in gc cpu usage Reviewed-by: iwalulya, kbarrett --- src/hotspot/share/gc/g1/g1Policy.cpp | 11 ++++------- src/hotspot/share/gc/g1/g1Policy.hpp | 5 ++--- .../jtreg/gc/stress/TestMultiThreadStressRSet.java | 6 +++--- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 6eef6cbfa87..2847a25c5b4 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -943,7 +943,7 @@ void G1Policy::record_young_collection_end(bool concurrent_operation_is_full_mar phase_times()->sum_thread_work_items(G1GCPhaseTimes::MergePSS, G1GCPhaseTimes::MergePSSToYoungGenCards)); } - record_pause(this_pause, start_time_sec, end_time_sec, allocation_failure); + record_pause(this_pause, start_time_sec, end_time_sec); if (G1GCPauseTypeHelper::is_last_young_pause(this_pause)) { assert(!G1GCPauseTypeHelper::is_concurrent_start_pause(this_pause), @@ -1389,16 +1389,13 @@ void G1Policy::update_gc_pause_time_ratios(G1GCPauseType gc_type, double start_t void G1Policy::record_pause(G1GCPauseType gc_type, double start, - double end, - bool allocation_failure) { + double end) { // Manage the MMU tracker. For some reason it ignores Full GCs. if (gc_type != G1GCPauseType::FullGC) { _mmu_tracker->add_pause(start, end); } - if (!allocation_failure) { - update_gc_pause_time_ratios(gc_type, start, end); - } + update_gc_pause_time_ratios(gc_type, start, end); update_time_to_mixed_tracking(gc_type, start, end); diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 72fdc6deb5b..cf12a7a8027 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -275,8 +275,7 @@ private: // Record the given STW pause with the given start and end times (in s). void record_pause(G1GCPauseType gc_type, double start, - double end, - bool allocation_failure = false); + double end); void update_gc_pause_time_ratios(G1GCPauseType gc_type, double start_sec, double end_sec); diff --git a/test/hotspot/jtreg/gc/stress/TestMultiThreadStressRSet.java b/test/hotspot/jtreg/gc/stress/TestMultiThreadStressRSet.java index a323ebd945a..ffd5203dfb8 100644 --- a/test/hotspot/jtreg/gc/stress/TestMultiThreadStressRSet.java +++ b/test/hotspot/jtreg/gc/stress/TestMultiThreadStressRSet.java @@ -44,15 +44,15 @@ import jdk.test.lib.Utils; * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=1 -Xlog:gc + * -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=1 -Xlog:gc -XX:-UseGCOverheadLimit * -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 gc.stress.TestMultiThreadStressRSet 10 4 * * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc + * -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc -XX:-UseGCOverheadLimit * -Xmx1G -XX:G1HeapRegionSize=8m -XX:MaxGCPauseMillis=1000 gc.stress.TestMultiThreadStressRSet 60 16 * * @run main/othervm/timeout=1200 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc + * -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc -XX:-UseGCOverheadLimit * -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 gc.stress.TestMultiThreadStressRSet 600 32 */ public class TestMultiThreadStressRSet { From c5f288e2ae2ebe6ee4a0d39d91348f746bd0e353 Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Tue, 20 Jan 2026 09:30:12 +0000 Subject: [PATCH 099/328] 8373253: Re-work InjectGCWorkerCreationFailure for future changes Reviewed-by: stefank, tschatzl, iwalulya, sjohanss --- src/hotspot/share/gc/shared/workerThread.cpp | 16 +++++++++++++++- src/hotspot/share/gc/shared/workerThread.hpp | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shared/workerThread.cpp b/src/hotspot/share/gc/shared/workerThread.cpp index 7a9404a195a..e4831d25d26 100644 --- a/src/hotspot/share/gc/shared/workerThread.cpp +++ b/src/hotspot/share/gc/shared/workerThread.cpp @@ -96,8 +96,22 @@ void WorkerThreads::initialize_workers() { } } +bool WorkerThreads::allow_inject_creation_failure() const { + if (!is_init_completed()) { + // Never allow creation failures during VM init + return false; + } + + if (_created_workers == 0) { + // Never allow creation failures of the first worker, it will cause the VM to exit + return false; + } + + return true; +} + WorkerThread* WorkerThreads::create_worker(uint name_suffix) { - if (is_init_completed() && InjectGCWorkerCreationFailure) { + if (InjectGCWorkerCreationFailure && allow_inject_creation_failure()) { return nullptr; } diff --git a/src/hotspot/share/gc/shared/workerThread.hpp b/src/hotspot/share/gc/shared/workerThread.hpp index a1f7282abe4..003ce8a2959 100644 --- a/src/hotspot/share/gc/shared/workerThread.hpp +++ b/src/hotspot/share/gc/shared/workerThread.hpp @@ -104,6 +104,7 @@ public: WorkerThreads(const char* name, uint max_workers); void initialize_workers(); + bool allow_inject_creation_failure() const; uint max_workers() const { return _max_workers; } uint created_workers() const { return _created_workers; } From afbb3a041545ea11ee1514d329c1a6cc4cb969d2 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 20 Jan 2026 10:31:22 +0000 Subject: [PATCH 100/328] 8375620: G1: Convert G1CardTableClaimTable to use Atomic Reviewed-by: kbarrett, shade --- src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp | 8 ++++---- src/hotspot/share/gc/g1/g1CardTableClaimTable.hpp | 5 +++-- .../share/gc/g1/g1CardTableClaimTable.inline.hpp | 11 +++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp b/src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp index e0cadbdd907..d8cabaa00a4 100644 --- a/src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp +++ b/src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -44,20 +44,20 @@ G1CardTableClaimTable::~G1CardTableClaimTable() { void G1CardTableClaimTable::initialize(uint max_reserved_regions) { assert(_card_claims == nullptr, "Must not be initialized twice"); - _card_claims = NEW_C_HEAP_ARRAY(uint, max_reserved_regions, mtGC); + _card_claims = NEW_C_HEAP_ARRAY(Atomic, max_reserved_regions, mtGC); _max_reserved_regions = max_reserved_regions; reset_all_to_unclaimed(); } void G1CardTableClaimTable::reset_all_to_unclaimed() { for (uint i = 0; i < _max_reserved_regions; i++) { - _card_claims[i] = 0; + _card_claims[i].store_relaxed(0); } } void G1CardTableClaimTable::reset_all_to_claimed() { for (uint i = 0; i < _max_reserved_regions; i++) { - _card_claims[i] = (uint)G1HeapRegion::CardsPerRegion; + _card_claims[i].store_relaxed((uint)G1HeapRegion::CardsPerRegion); } } diff --git a/src/hotspot/share/gc/g1/g1CardTableClaimTable.hpp b/src/hotspot/share/gc/g1/g1CardTableClaimTable.hpp index 4f524b83f97..822ef45c722 100644 --- a/src/hotspot/share/gc/g1/g1CardTableClaimTable.hpp +++ b/src/hotspot/share/gc/g1/g1CardTableClaimTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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,6 +27,7 @@ #include "gc/g1/g1CardTable.hpp" #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" class G1HeapRegionClosure; @@ -45,7 +46,7 @@ class G1CardTableClaimTable : public CHeapObj { // Card table iteration claim values for every heap region, from 0 (completely unclaimed) // to (>=) G1HeapRegion::CardsPerRegion (completely claimed). - uint volatile* _card_claims; + Atomic* _card_claims; uint _cards_per_chunk; // For conversion between card index and chunk index. diff --git a/src/hotspot/share/gc/g1/g1CardTableClaimTable.inline.hpp b/src/hotspot/share/gc/g1/g1CardTableClaimTable.inline.hpp index d682f0d17ae..35b2484982c 100644 --- a/src/hotspot/share/gc/g1/g1CardTableClaimTable.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardTableClaimTable.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -29,26 +29,25 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" -#include "runtime/atomicAccess.hpp" bool G1CardTableClaimTable::has_unclaimed_cards(uint region) { assert(region < _max_reserved_regions, "Tried to access invalid region %u", region); - return AtomicAccess::load(&_card_claims[region]) < G1HeapRegion::CardsPerRegion; + return _card_claims[region].load_relaxed() < G1HeapRegion::CardsPerRegion; } void G1CardTableClaimTable::reset_to_unclaimed(uint region) { assert(region < _max_reserved_regions, "Tried to access invalid region %u", region); - AtomicAccess::store(&_card_claims[region], 0u); + _card_claims[region].store_relaxed(0u); } uint G1CardTableClaimTable::claim_cards(uint region, uint increment) { assert(region < _max_reserved_regions, "Tried to access invalid region %u", region); - return AtomicAccess::fetch_then_add(&_card_claims[region], increment, memory_order_relaxed); + return _card_claims[region].fetch_then_add(increment, memory_order_relaxed); } uint G1CardTableClaimTable::claim_chunk(uint region) { assert(region < _max_reserved_regions, "Tried to access invalid region %u", region); - return AtomicAccess::fetch_then_add(&_card_claims[region], cards_per_chunk(), memory_order_relaxed); + return _card_claims[region].fetch_then_add(cards_per_chunk(), memory_order_relaxed); } uint G1CardTableClaimTable::claim_all_cards(uint region) { From 8c615190e69ee6e521990595fc23197f38ad6f14 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 20 Jan 2026 10:34:00 +0000 Subject: [PATCH 101/328] 8375624: G1: Convert G1JavaThreadsListClaimer to use Atomic Reviewed-by: kbarrett, shade --- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 5 +++-- src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp | 7 +++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index aff7166d391..a0104d04f4f 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -54,6 +54,7 @@ #include "memory/allocation.hpp" #include "memory/iterator.hpp" #include "memory/memRegion.hpp" +#include "runtime/atomic.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/threadSMR.hpp" #include "utilities/bitMap.hpp" @@ -124,7 +125,7 @@ class G1JavaThreadsListClaimer : public StackObj { ThreadsListHandle _list; uint _claim_step; - volatile uint _cur_claim; + Atomic _cur_claim; // Attempts to claim _claim_step JavaThreads, returning an array of claimed // JavaThread* with count elements. Returns null (and a zero count) if there diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp index abd61e72d57..577450b3be9 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,6 @@ #include "gc/shared/markBitMap.inline.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "oops/stackChunkOop.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/threadSMR.inline.hpp" #include "utilities/bitMap.inline.hpp" @@ -53,10 +52,10 @@ inline bool G1STWIsAliveClosure::do_object_b(oop p) { inline JavaThread* const* G1JavaThreadsListClaimer::claim(uint& count) { count = 0; - if (AtomicAccess::load(&_cur_claim) >= _list.length()) { + if (_cur_claim.load_relaxed() >= _list.length()) { return nullptr; } - uint claim = AtomicAccess::fetch_then_add(&_cur_claim, _claim_step); + uint claim = _cur_claim.fetch_then_add(_claim_step); if (claim >= _list.length()) { return nullptr; } From fe102918dd4f33ba030c4c4301a676ac8497fd90 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 20 Jan 2026 10:34:16 +0000 Subject: [PATCH 102/328] 8375630: G1: Convert G1ConcurrentMark to use Atomic Reviewed-by: kbarrett, shade --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 27 ++++++++++---------- src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 9 ++++--- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 456d543fa10..1077939f953 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -67,7 +67,6 @@ #include "nmt/memTracker.hpp" #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" @@ -148,25 +147,25 @@ bool G1CMMarkStack::initialize() { } G1CMMarkStack::TaskQueueEntryChunk* G1CMMarkStack::ChunkAllocator::allocate_new_chunk() { - if (_size >= _max_capacity) { + if (_size.load_relaxed() >= _max_capacity) { return nullptr; } - size_t cur_idx = AtomicAccess::fetch_then_add(&_size, 1u); + size_t cur_idx = _size.fetch_then_add(1u); if (cur_idx >= _max_capacity) { return nullptr; } size_t bucket = get_bucket(cur_idx); - if (AtomicAccess::load_acquire(&_buckets[bucket]) == nullptr) { + if (_buckets[bucket].load_acquire() == nullptr) { if (!_should_grow) { // Prefer to restart the CM. return nullptr; } MutexLocker x(G1MarkStackChunkList_lock, Mutex::_no_safepoint_check_flag); - if (AtomicAccess::load_acquire(&_buckets[bucket]) == nullptr) { + if (_buckets[bucket].load_acquire() == nullptr) { size_t desired_capacity = bucket_size(bucket) * 2; if (!try_expand_to(desired_capacity)) { return nullptr; @@ -175,7 +174,7 @@ G1CMMarkStack::TaskQueueEntryChunk* G1CMMarkStack::ChunkAllocator::allocate_new_ } size_t bucket_idx = get_bucket_index(cur_idx); - TaskQueueEntryChunk* result = ::new (&_buckets[bucket][bucket_idx]) TaskQueueEntryChunk; + TaskQueueEntryChunk* result = ::new (&_buckets[bucket].load_relaxed()[bucket_idx]) TaskQueueEntryChunk; result->next = nullptr; return result; } @@ -197,10 +196,10 @@ bool G1CMMarkStack::ChunkAllocator::initialize(size_t initial_capacity, size_t m _max_capacity = max_capacity; _num_buckets = get_bucket(_max_capacity) + 1; - _buckets = NEW_C_HEAP_ARRAY(TaskQueueEntryChunk*, _num_buckets, mtGC); + _buckets = NEW_C_HEAP_ARRAY(Atomic, _num_buckets, mtGC); for (size_t i = 0; i < _num_buckets; i++) { - _buckets[i] = nullptr; + _buckets[i].store_relaxed(nullptr); } size_t new_capacity = bucket_size(0); @@ -240,9 +239,9 @@ G1CMMarkStack::ChunkAllocator::~ChunkAllocator() { } for (size_t i = 0; i < _num_buckets; i++) { - if (_buckets[i] != nullptr) { - MmapArrayAllocator::free(_buckets[i], bucket_size(i)); - _buckets[i] = nullptr; + if (_buckets[i].load_relaxed() != nullptr) { + MmapArrayAllocator::free(_buckets[i].load_relaxed(), bucket_size(i)); + _buckets[i].store_relaxed(nullptr); } } @@ -259,7 +258,7 @@ bool G1CMMarkStack::ChunkAllocator::reserve(size_t new_capacity) { // and the new capacity (new_capacity). This step ensures that there are no gaps in the // array and that the capacity accurately reflects the reserved memory. for (; i <= highest_bucket; i++) { - if (AtomicAccess::load_acquire(&_buckets[i]) != nullptr) { + if (_buckets[i].load_acquire() != nullptr) { continue; // Skip over already allocated buckets. } @@ -279,7 +278,7 @@ bool G1CMMarkStack::ChunkAllocator::reserve(size_t new_capacity) { return false; } _capacity += bucket_capacity; - AtomicAccess::release_store(&_buckets[i], bucket_base); + _buckets[i].release_store(bucket_base); } return true; } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 752082ce629..1a0cfcd8caa 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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,6 +37,7 @@ #include "gc/shared/workerThread.hpp" #include "gc/shared/workerUtils.hpp" #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" #include "utilities/compilerWarnings.hpp" #include "utilities/numberSeq.hpp" @@ -172,9 +173,9 @@ private: size_t _capacity; size_t _num_buckets; bool _should_grow; - TaskQueueEntryChunk* volatile* _buckets; + Atomic* _buckets; char _pad0[DEFAULT_PADDING_SIZE]; - volatile size_t _size; + Atomic _size; char _pad4[DEFAULT_PADDING_SIZE - sizeof(size_t)]; size_t bucket_size(size_t bucket) { @@ -212,7 +213,7 @@ private: bool initialize(size_t initial_capacity, size_t max_capacity); void reset() { - _size = 0; + _size.store_relaxed(0); _should_grow = false; } From 3cc713fa296dfb59bbc03f2cfd4fc7d8f4b44be2 Mon Sep 17 00:00:00 2001 From: Jonas Norlinder Date: Tue, 20 Jan 2026 11:40:19 +0000 Subject: [PATCH 103/328] 8374945: Avoid fstat in os::open Reviewed-by: dholmes, jsjolen, redestad --- src/hotspot/os/linux/os_linux.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 48529c6ce17..7190845a8ba 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4963,9 +4963,14 @@ int os::open(const char *path, int oflag, int mode) { oflag |= O_CLOEXEC; int fd = ::open(path, oflag, mode); - if (fd == -1) return -1; + // No further checking is needed if open() returned an error or + // access mode is not read only. + if (fd == -1 || (oflag & O_ACCMODE) != O_RDONLY) { + return fd; + } - //If the open succeeded, the file might still be a directory + // If the open succeeded and is read only, the file might be a directory + // which the JVM doesn't allow to be read. { struct stat buf; int ret = ::fstat(fd, &buf); From 037040129e82958bd023e0b24d962627e8653710 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 20 Jan 2026 13:22:25 +0000 Subject: [PATCH 104/328] 8375643: G1: Convert G1RegionMarkStatsCache to use Atomic Reviewed-by: shade, kbarrett --- src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 8 +++---- src/hotspot/share/gc/g1/g1FullCollector.hpp | 4 ++-- .../share/gc/g1/g1RegionMarkStatsCache.hpp | 24 ++++++++++++------- .../gc/g1/g1RegionMarkStatsCache.inline.hpp | 12 ++++------ 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 1a0cfcd8caa..7ea9151c6f1 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -557,14 +557,14 @@ public: // mark_in_bitmap call. Updates various statistics data. void add_to_liveness(uint worker_id, oop const obj, size_t size); // Did the last marking find a live object between bottom and TAMS? - bool contains_live_object(uint region) const { return _region_mark_stats[region]._live_words != 0; } + bool contains_live_object(uint region) const { return _region_mark_stats[region].live_words() != 0; } // Live bytes in the given region as determined by concurrent marking, i.e. the amount of // live bytes between bottom and TAMS. - size_t live_bytes(uint region) const { return _region_mark_stats[region]._live_words * HeapWordSize; } + size_t live_bytes(uint region) const { return _region_mark_stats[region].live_words() * HeapWordSize; } // Set live bytes for concurrent marking. - void set_live_bytes(uint region, size_t live_bytes) { _region_mark_stats[region]._live_words = live_bytes / HeapWordSize; } + void set_live_bytes(uint region, size_t live_bytes) { _region_mark_stats[region]._live_words.store_relaxed(live_bytes / HeapWordSize); } // Approximate number of incoming references found during marking. - size_t incoming_refs(uint region) const { return _region_mark_stats[region]._incoming_refs; } + size_t incoming_refs(uint region) const { return _region_mark_stats[region].incoming_refs(); } // Update the TAMS for the given region to the current top. inline void update_top_at_mark_start(G1HeapRegion* r); diff --git a/src/hotspot/share/gc/g1/g1FullCollector.hpp b/src/hotspot/share/gc/g1/g1FullCollector.hpp index ed8225fc004..1fb3af17032 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.hpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -122,7 +122,7 @@ public: ReferenceProcessor* reference_processor(); size_t live_words(uint region_index) const { assert(region_index < _heap->max_num_regions(), "sanity"); - return _live_stats[region_index]._live_words; + return _live_stats[region_index].live_words(); } void before_marking_update_attribute_table(G1HeapRegion* hr); diff --git a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.hpp b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.hpp index 3c1a6ed4667..4dcdd33846e 100644 --- a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.hpp +++ b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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,6 +27,7 @@ #include "memory/allocation.hpp" #include "oops/oop.hpp" +#include "runtime/atomic.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/pair.hpp" @@ -40,20 +41,23 @@ // * the number of incoming references found during marking. This is an approximate // value because we do not mark through all objects. struct G1RegionMarkStats { - size_t _live_words; - size_t _incoming_refs; + Atomic _live_words; + Atomic _incoming_refs; // Clear all members. void clear() { - _live_words = 0; - _incoming_refs = 0; + _live_words.store_relaxed(0); + _incoming_refs.store_relaxed(0); } // Clear all members after a marking overflow. Only needs to clear the number of // incoming references as all objects will be rescanned, while the live words are // gathered whenever a thread can mark an object, which is synchronized. void clear_during_overflow() { - _incoming_refs = 0; + _incoming_refs.store_relaxed(0); } + + size_t live_words() const { return _live_words.load_relaxed(); } + size_t incoming_refs() const { return _incoming_refs.load_relaxed(); } }; // Per-marking thread cache for the region mark statistics. @@ -112,12 +116,16 @@ public: void add_live_words(oop obj); void add_live_words(uint region_idx, size_t live_words) { G1RegionMarkStatsCacheEntry* const cur = find_for_add(region_idx); - cur->_stats._live_words += live_words; + // This method is only ever called single-threaded, so we do not need atomic + // update here. + cur->_stats._live_words.store_relaxed(cur->_stats.live_words() + live_words); } void inc_incoming_refs(uint region_idx) { G1RegionMarkStatsCacheEntry* const cur = find_for_add(region_idx); - cur->_stats._incoming_refs++; + // This method is only ever called single-threaded, so we do not need atomic + // update here. + cur->_stats._incoming_refs.store_relaxed(cur->_stats.incoming_refs() + 1u); } void reset(uint region_idx) { diff --git a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.inline.hpp b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.inline.hpp index 6b0ebb34e0d..71cd33e71ae 100644 --- a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.inline.hpp +++ b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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,6 @@ #include "gc/g1/g1RegionMarkStatsCache.hpp" -#include "runtime/atomicAccess.hpp" - inline G1RegionMarkStatsCache::G1RegionMarkStatsCacheEntry* G1RegionMarkStatsCache::find_for_add(uint region_idx) { uint const cache_idx = hash(region_idx); @@ -46,12 +44,12 @@ inline G1RegionMarkStatsCache::G1RegionMarkStatsCacheEntry* G1RegionMarkStatsCac inline void G1RegionMarkStatsCache::evict(uint idx) { G1RegionMarkStatsCacheEntry* cur = &_cache[idx]; - if (cur->_stats._live_words != 0) { - AtomicAccess::add(&_target[cur->_region_idx]._live_words, cur->_stats._live_words); + if (cur->_stats.live_words() != 0) { + _target[cur->_region_idx]._live_words.add_then_fetch(cur->_stats.live_words()); } - if (cur->_stats._incoming_refs != 0) { - AtomicAccess::add(&_target[cur->_region_idx]._incoming_refs, cur->_stats._incoming_refs); + if (cur->_stats.incoming_refs() != 0) { + _target[cur->_region_idx]._incoming_refs.add_then_fetch(cur->_stats.incoming_refs()); } cur->clear(); From 5ba91fed345b078a67ad6bead1d8893bd9289f58 Mon Sep 17 00:00:00 2001 From: Christian Heilmann Date: Tue, 20 Jan 2026 15:00:14 +0000 Subject: [PATCH 105/328] 8297191: [macos] Printing a page range with starting page > 1 results in missing pages Reviewed-by: aivanov, prr --- .../classes/sun/lwawt/macosx/CPrinterJob.java | 24 +++++-------------- .../native/libawt_lwawt/awt/CPrinterJob.m | 8 +++---- .../native/libawt_lwawt/awt/PrinterView.h | 6 ++--- .../native/libawt_lwawt/awt/PrinterView.m | 13 +++++----- .../java/awt/print/PrinterJob/PageRanges.java | 4 ++-- 5 files changed, 21 insertions(+), 34 deletions(-) diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java index 979eeb36239..508b1a843ef 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, 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 @@ -355,20 +355,9 @@ public final class CPrinterJob extends RasterPrinterJob { validateDestination(destinationAttr); } - /* Get the range of pages we are to print. If the - * last page to print is unknown, then we print to - * the end of the document. Note that firstPage - * and lastPage are 0 based page indices. - */ - + // Note that firstPage is 0 based page index. int firstPage = getFirstPage(); - int lastPage = getLastPage(); - if(lastPage == Pageable.UNKNOWN_NUMBER_OF_PAGES) { - int totalPages = mDocument.getNumberOfPages(); - if (totalPages != Pageable.UNKNOWN_NUMBER_OF_PAGES) { - lastPage = mDocument.getNumberOfPages() - 1; - } - } + int totalPages = mDocument.getNumberOfPages(); try { synchronized (this) { @@ -393,7 +382,7 @@ public final class CPrinterJob extends RasterPrinterJob { try { // Fire off the print rendering loop on the AppKit thread, and don't have // it wait and block this thread. - if (printLoop(false, firstPage, lastPage)) { + if (printLoop(false, firstPage, totalPages)) { // Start a secondary loop on EDT until printing operation is finished or cancelled printingLoop.enter(); } @@ -407,7 +396,7 @@ public final class CPrinterJob extends RasterPrinterJob { onEventThread = false; try { - printLoop(true, firstPage, lastPage); + printLoop(true, firstPage, totalPages); } catch (Exception e) { e.printStackTrace(); } @@ -417,7 +406,6 @@ public final class CPrinterJob extends RasterPrinterJob { } if (++loopi < prMembers.length) { firstPage = prMembers[loopi][0]-1; - lastPage = prMembers[loopi][1] -1; } } while (loopi < prMembers.length); } finally { @@ -693,7 +681,7 @@ public final class CPrinterJob extends RasterPrinterJob { } } - private native boolean printLoop(boolean waitUntilDone, int firstPage, int lastPage) throws PrinterException; + private native boolean printLoop(boolean waitUntilDone, int firstPage, int totalPages) throws PrinterException; private PageFormat getPageFormat(int pageIndex) { // This is called from the native side. diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m index 9cc0a18564f..555a2746f43 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, 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 @@ -656,7 +656,7 @@ JNI_COCOA_EXIT(env); * Signature: ()V */ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPrinterJob_printLoop - (JNIEnv *env, jobject jthis, jboolean blocks, jint firstPage, jint lastPage) + (JNIEnv *env, jobject jthis, jboolean blocks, jint firstPage, jint totalPages) { AWT_ASSERT_NOT_APPKIT_THREAD; @@ -672,14 +672,14 @@ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPrinterJob_printLoop JNI_COCOA_ENTER(env); // Get the first page's PageFormat for setting things up (This introduces // and is a facet of the same problem in Radar 2818593/2708932). - jobject page = (*env)->CallObjectMethod(env, jthis, jm_getPageFormat, 0); // AWT_THREADING Safe (!appKit) + jobject page = (*env)->CallObjectMethod(env, jthis, jm_getPageFormat, firstPage); // AWT_THREADING Safe (!appKit) CHECK_EXCEPTION(); if (page != NULL) { jobject pageFormatArea = (*env)->CallObjectMethod(env, jthis, jm_getPageFormatArea, page); // AWT_THREADING Safe (!appKit) CHECK_EXCEPTION(); PrinterView* printerView = [[PrinterView alloc] initWithFrame:JavaToNSRect(env, pageFormatArea) withEnv:env withPrinterJob:jthis]; - [printerView setFirstPage:firstPage lastPage:lastPage]; + [printerView setTotalPages:totalPages]; GET_NSPRINTINFO_METHOD_RETURN(NO) NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr((*env)->CallLongMethod(env, jthis, sjm_getNSPrintInfo)); // AWT_THREADING Safe (known object) diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/PrinterView.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/PrinterView.h index 43472bee920..95a8055cdb0 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/PrinterView.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/PrinterView.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,12 +32,12 @@ jobject fCurPainter; jobject fCurPeekGraphics; - jint fFirstPage, fLastPage; + jint fTotalPages; } - (id)initWithFrame:(NSRect)aRect withEnv:(JNIEnv*)env withPrinterJob:(jobject)printerJob; -- (void)setFirstPage:(jint)firstPage lastPage:(jint)lastPage; +- (void)setTotalPages:(jint)totalPages; - (void)releaseReferences:(JNIEnv*)env; diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/PrinterView.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/PrinterView.m index d19948d9f0f..f219e8082b4 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/PrinterView.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/PrinterView.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, 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 @@ -72,9 +72,8 @@ static jclass sjc_PAbortEx = NULL; } } -- (void)setFirstPage:(jint)firstPage lastPage:(jint)lastPage { - fFirstPage = firstPage; - fLastPage = lastPage; +- (void)setTotalPages:(jint)totalPages { + fTotalPages = totalPages; } - (void)drawRect:(NSRect)aRect @@ -156,15 +155,15 @@ static jclass sjc_PAbortEx = NULL; return NO; } - aRange->location = fFirstPage + 1; + aRange->location = 1; - if (fLastPage == java_awt_print_Pageable_UNKNOWN_NUMBER_OF_PAGES) + if (fTotalPages == java_awt_print_Pageable_UNKNOWN_NUMBER_OF_PAGES) { aRange->length = NSIntegerMax; } else { - aRange->length = (fLastPage + 1) - fFirstPage; + aRange->length = fTotalPages; } return YES; diff --git a/test/jdk/java/awt/print/PrinterJob/PageRanges.java b/test/jdk/java/awt/print/PrinterJob/PageRanges.java index e80330bae6c..aea60516f78 100644 --- a/test/jdk/java/awt/print/PrinterJob/PageRanges.java +++ b/test/jdk/java/awt/print/PrinterJob/PageRanges.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 6575331 + * @bug 6575331 8297191 * @key printer * @summary The specified pages should be printed. * @library /java/awt/regtesthelpers From 21dc41f744edd138e77970d4e25e3a7eda41621f Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Tue, 20 Jan 2026 16:16:38 +0000 Subject: [PATCH 106/328] 8314323: Implement JEP 527: TLS 1.3 Hybrid Key Exchange Co-authored-by: Jamil Nimeh Co-authored-by: Weijun Wang Reviewed-by: wetmore, mullan --- .../classes/sun/security/ssl/DHasKEM.java | 254 ++++++++++ .../classes/sun/security/ssl/Hybrid.java | 474 ++++++++++++++++++ .../sun/security/ssl/HybridProvider.java | 130 +++++ .../sun/security/ssl/KAKeyDerivation.java | 127 ++++- .../sun/security/ssl/KEMKeyExchange.java | 223 ++++++++ .../sun/security/ssl/KeyShareExtension.java | 113 +++-- .../classes/sun/security/ssl/NamedGroup.java | 131 ++++- .../sun/security/ssl/SSLKeyExchange.java | 6 +- .../classes/sun/security/ssl/ServerHello.java | 51 +- .../classes/sun/security/x509/X509Key.java | 4 + .../net/ssl/SSLParameters/NamedGroups.java | 57 ++- .../javax/net/ssl/TLSCommon/NamedGroup.java | 8 +- .../net/ssl/TLSv13/ClientHelloKeyShares.java | 15 +- .../javax/net/ssl/TLSv13/HRRKeyShares.java | 25 +- .../security/pkcs11/tls/fips/FipsModeTLS.java | 8 +- .../ssl/CipherSuite/DisabledCurve.java | 49 +- .../NamedGroupsWithCipherSuite.java | 76 ++- .../ssl/CipherSuite/RestrictNamedGroup.java | 7 +- .../ssl/CipherSuite/SupportedGroups.java | 32 +- .../bench/java/security/SSLHandshake.java | 25 +- .../bench/javax/crypto/full/KEMBench.java | 110 +++- .../crypto/full/KeyPairGeneratorBench.java | 34 +- 22 files changed, 1839 insertions(+), 120 deletions(-) create mode 100644 src/java.base/share/classes/sun/security/ssl/DHasKEM.java create mode 100644 src/java.base/share/classes/sun/security/ssl/Hybrid.java create mode 100644 src/java.base/share/classes/sun/security/ssl/HybridProvider.java create mode 100644 src/java.base/share/classes/sun/security/ssl/KEMKeyExchange.java diff --git a/src/java.base/share/classes/sun/security/ssl/DHasKEM.java b/src/java.base/share/classes/sun/security/ssl/DHasKEM.java new file mode 100644 index 00000000000..763013f280c --- /dev/null +++ b/src/java.base/share/classes/sun/security/ssl/DHasKEM.java @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import sun.security.util.ArrayUtil; +import sun.security.util.CurveDB; +import sun.security.util.ECUtil; +import sun.security.util.NamedCurve; + +import javax.crypto.DecapsulateException; +import javax.crypto.KEM; +import javax.crypto.KEMSpi; +import javax.crypto.KeyAgreement; +import javax.crypto.SecretKey; +import java.io.IOException; +import java.math.BigInteger; +import java.security.*; +import java.security.interfaces.ECKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.XECKey; +import java.security.interfaces.XECPublicKey; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.NamedParameterSpec; +import java.security.spec.XECPublicKeySpec; +import java.util.Arrays; + +/** + * The DHasKEM class presents a KEM abstraction layer over traditional + * DH-based key exchange, which can be used for either straight + * ECDH/XDH or TLS hybrid key exchanges. + * + * This class can be alongside standard full post-quantum KEMs + * when hybrid implementations are required. + */ +public class DHasKEM implements KEMSpi { + + @Override + public EncapsulatorSpi engineNewEncapsulator( + PublicKey publicKey, AlgorithmParameterSpec spec, + SecureRandom secureRandom) throws InvalidKeyException { + return new Handler(publicKey, null, secureRandom); + } + + @Override + public DecapsulatorSpi engineNewDecapsulator(PrivateKey privateKey, + AlgorithmParameterSpec spec) throws InvalidKeyException { + return new Handler(null, privateKey, null); + } + + private static final class Handler + implements KEMSpi.EncapsulatorSpi, KEMSpi.DecapsulatorSpi { + private final PublicKey pkR; + private final PrivateKey skR; + private final SecureRandom sr; + private final Params params; + + Handler(PublicKey pk, PrivateKey sk, SecureRandom sr) + throws InvalidKeyException { + this.pkR = pk; + this.skR = sk; + this.sr = sr; + this.params = paramsFromKey(pk == null ? sk : pk); + } + + @Override + public KEM.Encapsulated engineEncapsulate(int from, int to, + String algorithm) { + KeyPair kpE = params.generateKeyPair(sr); + PrivateKey skE = kpE.getPrivate(); + PublicKey pkE = kpE.getPublic(); + byte[] pkEm = params.SerializePublicKey(pkE); + try { + SecretKey dh = params.DH(algorithm, skE, pkR); + return new KEM.Encapsulated( + sub(dh, from, to), + pkEm, null); + } catch (Exception e) { + throw new ProviderException("internal error", e); + } + } + + @Override + public int engineSecretSize() { + return params.secretLen; + } + + @Override + public int engineEncapsulationSize() { + return params.publicKeyLen; + } + + @Override + public SecretKey engineDecapsulate(byte[] encapsulation, int from, + int to, String algorithm) throws DecapsulateException { + if (encapsulation.length != params.publicKeyLen) { + throw new DecapsulateException("incorrect encapsulation size"); + } + try { + PublicKey pkE = params.DeserializePublicKey(encapsulation); + SecretKey dh = params.DH(algorithm, skR, pkE); + return sub(dh, from, to); + } catch (IOException | InvalidKeyException e) { + throw new DecapsulateException("Cannot decapsulate", e); + } catch (Exception e) { + throw new ProviderException("internal error", e); + } + } + + private SecretKey sub(SecretKey key, int from, int to) { + if (from == 0 && to == params.secretLen) { + return key; + } + + // Key slicing should never happen. Otherwise, there might be + // a programming error. + throw new AssertionError( + "Unexpected key slicing: from=" + from + ", to=" + to); + } + + // This KEM is designed to be able to represent every ECDH and XDH + private Params paramsFromKey(Key k) throws InvalidKeyException { + if (k instanceof ECKey eckey) { + if (ECUtil.equals(eckey.getParams(), CurveDB.P_256)) { + return Params.P256; + } else if (ECUtil.equals(eckey.getParams(), CurveDB.P_384)) { + return Params.P384; + } else if (ECUtil.equals(eckey.getParams(), CurveDB.P_521)) { + return Params.P521; + } + } else if (k instanceof XECKey xkey + && xkey.getParams() instanceof NamedParameterSpec ns) { + if (ns.getName().equalsIgnoreCase( + NamedParameterSpec.X25519.getName())) { + return Params.X25519; + } else if (ns.getName().equalsIgnoreCase( + NamedParameterSpec.X448.getName())) { + return Params.X448; + } + } + throw new InvalidKeyException("Unsupported key"); + } + } + + private enum Params { + + P256(32, 2 * 32 + 1, + "ECDH", "EC", CurveDB.P_256), + + P384(48, 2 * 48 + 1, + "ECDH", "EC", CurveDB.P_384), + + P521(66, 2 * 66 + 1, + "ECDH", "EC", CurveDB.P_521), + + X25519(32, 32, + "XDH", "XDH", NamedParameterSpec.X25519), + + X448(56, 56, + "XDH", "XDH", NamedParameterSpec.X448); + + private final int secretLen; + private final int publicKeyLen; + private final String kaAlgorithm; + private final String keyAlgorithm; + private final AlgorithmParameterSpec spec; + + Params(int secretLen, int publicKeyLen, String kaAlgorithm, + String keyAlgorithm, AlgorithmParameterSpec spec) { + this.spec = spec; + this.secretLen = secretLen; + this.publicKeyLen = publicKeyLen; + this.kaAlgorithm = kaAlgorithm; + this.keyAlgorithm = keyAlgorithm; + } + + private boolean isEC() { + return this == P256 || this == P384 || this == P521; + } + + private KeyPair generateKeyPair(SecureRandom sr) { + try { + KeyPairGenerator g = KeyPairGenerator.getInstance(keyAlgorithm); + g.initialize(spec, sr); + return g.generateKeyPair(); + } catch (Exception e) { + throw new ProviderException("internal error", e); + } + } + + private byte[] SerializePublicKey(PublicKey k) { + if (isEC()) { + ECPoint w = ((ECPublicKey) k).getW(); + return ECUtil.encodePoint(w, ((NamedCurve) spec).getCurve()); + } else { + byte[] uArray = ((XECPublicKey) k).getU().toByteArray(); + ArrayUtil.reverse(uArray); + return Arrays.copyOf(uArray, publicKeyLen); + } + } + + private PublicKey DeserializePublicKey(byte[] data) throws + IOException, NoSuchAlgorithmException, + InvalidKeySpecException { + KeySpec keySpec; + if (isEC()) { + NamedCurve curve = (NamedCurve) this.spec; + keySpec = new ECPublicKeySpec( + ECUtil.decodePoint(data, curve.getCurve()), curve); + } else { + data = data.clone(); + ArrayUtil.reverse(data); + keySpec = new XECPublicKeySpec( + this.spec, new BigInteger(1, data)); + } + return KeyFactory.getInstance(keyAlgorithm). + generatePublic(keySpec); + } + + private SecretKey DH(String alg, PrivateKey skE, PublicKey pkR) + throws NoSuchAlgorithmException, InvalidKeyException { + KeyAgreement ka = KeyAgreement.getInstance(kaAlgorithm); + ka.init(skE); + ka.doPhase(pkR, true); + return ka.generateSecret(alg); + } + } +} diff --git a/src/java.base/share/classes/sun/security/ssl/Hybrid.java b/src/java.base/share/classes/sun/security/ssl/Hybrid.java new file mode 100644 index 00000000000..e3e2cfa0b23 --- /dev/null +++ b/src/java.base/share/classes/sun/security/ssl/Hybrid.java @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import sun.security.util.ArrayUtil; +import sun.security.util.CurveDB; +import sun.security.util.ECUtil; +import sun.security.util.RawKeySpec; +import sun.security.x509.X509Key; + +import javax.crypto.DecapsulateException; +import javax.crypto.KEM; +import javax.crypto.KEMSpi; +import javax.crypto.SecretKey; +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyFactorySpi; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyPairGeneratorSpi; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.ProviderException; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.*; +import java.util.Arrays; +import java.util.Locale; + +// The Hybrid class wraps two underlying algorithms (left and right sides) +// in a single TLS hybrid named group. +// It implements: +// - Hybrid KeyPair generation +// - Hybrid KeyFactory for decoding concatenated hybrid public keys +// - Hybrid KEM implementation for performing encapsulation and +// decapsulation over two underlying algorithms (traditional +// algorithm and post-quantum KEM algorithm) + +public class Hybrid { + + public static final NamedParameterSpec X25519_MLKEM768 = + new NamedParameterSpec("X25519MLKEM768"); + + public static final NamedParameterSpec SECP256R1_MLKEM768 = + new NamedParameterSpec("SecP256r1MLKEM768"); + + public static final NamedParameterSpec SECP384R1_MLKEM1024 = + new NamedParameterSpec("SecP384r1MLKEM1024"); + + private static AlgorithmParameterSpec getSpec(String name) { + if (name.startsWith("secp")) { + return new ECGenParameterSpec(name); + } else { + return new NamedParameterSpec(name); + } + } + + private static KeyPairGenerator getKeyPairGenerator(String name) throws + NoSuchAlgorithmException { + if (name.startsWith("secp")) { + name = "EC"; + } + return KeyPairGenerator.getInstance(name); + } + + private static KeyFactory getKeyFactory(String name) throws + NoSuchAlgorithmException { + if (name.startsWith("secp")) { + name = "EC"; + } + return KeyFactory.getInstance(name); + } + + /** + * Returns a KEM instance for each side of the hybrid algorithm. + * For traditional key exchange algorithms, we use the DH-based KEM + * implementation provided by DHasKEM class. + * For ML-KEM post-quantum algorithms, we obtain a KEM instance + * with "ML-KEM". This is done to work with 3rd-party providers that + * only have "ML-KEM" KEM algorithm. + */ + private static KEM getKEM(String name) throws NoSuchAlgorithmException { + if (name.startsWith("secp") || name.equals("X25519")) { + return KEM.getInstance("DH", HybridProvider.PROVIDER); + } else { + return KEM.getInstance("ML-KEM"); + } + } + + public static class KeyPairGeneratorImpl extends KeyPairGeneratorSpi { + private final KeyPairGenerator left; + private final KeyPairGenerator right; + private final AlgorithmParameterSpec leftSpec; + private final AlgorithmParameterSpec rightSpec; + + public KeyPairGeneratorImpl(String leftAlg, String rightAlg) + throws NoSuchAlgorithmException { + left = getKeyPairGenerator(leftAlg); + right = getKeyPairGenerator(rightAlg); + leftSpec = getSpec(leftAlg); + rightSpec = getSpec(rightAlg); + } + + @Override + public void initialize(AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidAlgorithmParameterException { + left.initialize(leftSpec, random); + right.initialize(rightSpec, random); + } + + @Override + public void initialize(int keysize, SecureRandom random) { + // NO-OP (do nothing) + } + + @Override + public KeyPair generateKeyPair() { + var kp1 = left.generateKeyPair(); + var kp2 = right.generateKeyPair(); + return new KeyPair( + new PublicKeyImpl("Hybrid", kp1.getPublic(), + kp2.getPublic()), + new PrivateKeyImpl("Hybrid", kp1.getPrivate(), + kp2.getPrivate())); + } + } + + public static class KeyFactoryImpl extends KeyFactorySpi { + private final KeyFactory left; + private final KeyFactory right; + private final int leftlen; + private final String leftname; + private final String rightname; + + public KeyFactoryImpl(String left, String right) + throws NoSuchAlgorithmException { + this.left = getKeyFactory(left); + this.right = getKeyFactory(right); + this.leftlen = leftPublicLength(left); + this.leftname = left; + this.rightname = right; + } + + @Override + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException { + if (keySpec == null) { + throw new InvalidKeySpecException("keySpec must not be null"); + } + + if (keySpec instanceof RawKeySpec rks) { + byte[] key = rks.getKeyArr(); + if (key == null) { + throw new InvalidKeySpecException( + "RawkeySpec contains null key data"); + } + if (key.length <= leftlen) { + throw new InvalidKeySpecException( + "Hybrid key length " + key.length + + " is too short and its left key length is " + + leftlen); + } + + byte[] leftKeyBytes = Arrays.copyOfRange(key, 0, leftlen); + byte[] rightKeyBytes = Arrays.copyOfRange(key, leftlen, + key.length); + PublicKey leftKey, rightKey; + + try { + if (leftname.startsWith("secp")) { + var curve = CurveDB.lookup(leftname); + var ecSpec = new ECPublicKeySpec( + ECUtil.decodePoint(leftKeyBytes, + curve.getCurve()), curve); + leftKey = left.generatePublic(ecSpec); + } else if (leftname.startsWith("ML-KEM")) { + leftKey = left.generatePublic(new RawKeySpec( + leftKeyBytes)); + } else { + throw new InvalidKeySpecException("Unsupported left" + + " algorithm" + leftname); + } + + if (rightname.equals("X25519")) { + ArrayUtil.reverse(rightKeyBytes); + var xecSpec = new XECPublicKeySpec( + new NamedParameterSpec(rightname), + new BigInteger(1, rightKeyBytes)); + rightKey = right.generatePublic(xecSpec); + } else if (rightname.startsWith("ML-KEM")) { + rightKey = right.generatePublic(new RawKeySpec( + rightKeyBytes)); + } else { + throw new InvalidKeySpecException("Unsupported right" + + " algorithm: " + rightname); + } + + return new PublicKeyImpl("Hybrid", leftKey, rightKey); + } catch (Exception e) { + throw new InvalidKeySpecException("Failed to decode " + + "hybrid key", e); + } + } + + throw new InvalidKeySpecException( + "KeySpec type:" + + keySpec.getClass().getName() + " not supported"); + } + + private static int leftPublicLength(String name) { + return switch (name.toLowerCase(Locale.ROOT)) { + case "secp256r1" -> 65; + case "secp384r1" -> 97; + case "ml-kem-768" -> 1184; + default -> throw new IllegalArgumentException( + "Unknown named group: " + name); + }; + } + + @Override + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws + InvalidKeySpecException { + throw new UnsupportedOperationException(); + } + + @Override + protected T engineGetKeySpec(Key key, + Class keySpec) throws InvalidKeySpecException { + throw new UnsupportedOperationException(); + } + + @Override + protected Key engineTranslateKey(Key key) throws InvalidKeyException { + throw new UnsupportedOperationException(); + } + } + + public static class KEMImpl implements KEMSpi { + private final KEM left; + private final KEM right; + + public KEMImpl(String left, String right) + throws NoSuchAlgorithmException { + this.left = getKEM(left); + this.right = getKEM(right); + } + + @Override + public EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey, + AlgorithmParameterSpec spec, SecureRandom secureRandom) throws + InvalidAlgorithmParameterException, InvalidKeyException { + if (publicKey instanceof PublicKeyImpl pk) { + return new Handler(left.newEncapsulator(pk.left, secureRandom), + right.newEncapsulator(pk.right, secureRandom), + null, null); + } + throw new InvalidKeyException(); + } + + @Override + public DecapsulatorSpi engineNewDecapsulator(PrivateKey privateKey, + AlgorithmParameterSpec spec) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (privateKey instanceof PrivateKeyImpl pk) { + return new Handler(null, null, left.newDecapsulator(pk.left), + right.newDecapsulator(pk.right)); + } + throw new InvalidKeyException(); + } + } + + private static byte[] concat(byte[]... inputs) { + int outLen = 0; + for (byte[] in : inputs) { + outLen += in.length; + } + byte[] out = new byte[outLen]; + int pos = 0; + for (byte[] in : inputs) { + System.arraycopy(in, 0, out, pos, in.length); + pos += in.length; + } + return out; + } + + private record Handler(KEM.Encapsulator le, KEM.Encapsulator re, + KEM.Decapsulator ld, KEM.Decapsulator rd) + implements KEMSpi.EncapsulatorSpi, KEMSpi.DecapsulatorSpi { + @Override + public KEM.Encapsulated engineEncapsulate(int from, int to, + String algorithm) { + int expectedSecretSize = engineSecretSize(); + if (!(from == 0 && to == expectedSecretSize)) { + throw new IllegalArgumentException( + "Invalid range for encapsulation: from = " + from + + " to = " + to + ", expected total secret size = " + + expectedSecretSize); + } + + var left = le.encapsulate(); + var right = re.encapsulate(); + return new KEM.Encapsulated( + new SecretKeyImpl(left.key(), right.key()), + concat(left.encapsulation(), right.encapsulation()), + null); + } + + @Override + public int engineSecretSize() { + if (le != null) { + return le.secretSize() + re.secretSize(); + } else { + return ld.secretSize() + rd.secretSize(); + } + } + + @Override + public int engineEncapsulationSize() { + if (le != null) { + return le.encapsulationSize() + re.encapsulationSize(); + } else { + return ld.encapsulationSize() + rd.encapsulationSize(); + } + } + + @Override + public SecretKey engineDecapsulate(byte[] encapsulation, int from, + int to, String algorithm) throws DecapsulateException { + int expectedEncSize = engineEncapsulationSize(); + if (encapsulation.length != expectedEncSize) { + throw new IllegalArgumentException( + "Invalid key encapsulation message length: " + + encapsulation.length + + ", expected = " + expectedEncSize); + } + + int expectedSecretSize = engineSecretSize(); + if (!(from == 0 && to == expectedSecretSize)) { + throw new IllegalArgumentException( + "Invalid range for decapsulation: from = " + from + + " to = " + to + ", expected total secret size = " + + expectedSecretSize); + } + + var left = Arrays.copyOf(encapsulation, ld.encapsulationSize()); + var right = Arrays.copyOfRange(encapsulation, + ld.encapsulationSize(), encapsulation.length); + return new SecretKeyImpl( + ld.decapsulate(left), + rd.decapsulate(right) + ); + } + } + + // Package-private + record SecretKeyImpl(SecretKey k1, SecretKey k2) + implements SecretKey { + @Override + public String getAlgorithm() { + return "Generic"; + } + + @Override + public String getFormat() { + return null; + } + + @Override + public byte[] getEncoded() { + return null; + } + } + + /** + * Hybrid public key combines two underlying public keys (left and right). + * Public keys can be transmitted/encoded because the hybrid protocol + * requires the public component to be sent. + */ + // Package-private + record PublicKeyImpl(String algorithm, PublicKey left, + PublicKey right) implements PublicKey { + @Override + public String getAlgorithm() { + return algorithm; + } + + // getFormat() returns "RAW" as hybrid key uses RAW concatenation + // of underlying encodings. + @Override + public String getFormat() { + return "RAW"; + } + + // getEncoded() returns the concatenation of the encoded bytes of the + // left and right public keys. + @Override + public byte[] getEncoded() { + return concat(onlyKey(left), onlyKey(right)); + } + + static byte[] onlyKey(PublicKey key) { + if (key instanceof X509Key xk) { + return xk.getKeyAsBytes(); + } + + // Fallback for 3rd-party providers + if (!"X.509".equalsIgnoreCase(key.getFormat())) { + throw new ProviderException("Invalid public key encoding " + + "format"); + } + var xk = new X509Key(); + try { + xk.decode(key.getEncoded()); + } catch (InvalidKeyException e) { + throw new ProviderException("Invalid public key encoding", e); + } + return xk.getKeyAsBytes(); + } + } + + /** + * Hybrid private key combines two underlying private keys (left and right). + * It is for internal use only. The private keys should never be exported. + */ + private record PrivateKeyImpl(String algorithm, PrivateKey left, + PrivateKey right) implements PrivateKey { + + @Override + public String getAlgorithm() { + return algorithm; + } + + // getFormat() returns null because there is no standard + // format for a hybrid private key. + @Override + public String getFormat() { + return null; + } + + // getEncoded() returns an empty byte array because there is no + // standard encoding format for a hybrid private key. + @Override + public byte[] getEncoded() { + return null; + } + } +} diff --git a/src/java.base/share/classes/sun/security/ssl/HybridProvider.java b/src/java.base/share/classes/sun/security/ssl/HybridProvider.java new file mode 100644 index 00000000000..c77d6f66273 --- /dev/null +++ b/src/java.base/share/classes/sun/security/ssl/HybridProvider.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.security.Provider; +import java.security.NoSuchAlgorithmException; +import java.util.List; +import java.util.Map; + +import static sun.security.util.SecurityConstants.PROVIDER_VER; + +// This is an internal provider used in the JSSE code for DH-as-KEM +// and Hybrid KEM support. It doesn't actually get installed in the +// system's list of security providers that is searched at runtime. +// JSSE loads this provider internally. +// It registers Hybrid KeyPairGenerator, KeyFactory, and KEM +// implementations for hybrid named groups as Provider services. + +public class HybridProvider { + + public static final Provider PROVIDER = new ProviderImpl(); + + private static final class ProviderImpl extends Provider { + @java.io.Serial + private static final long serialVersionUID = 0L; + + ProviderImpl() { + super("HybridAndDHAsKEM", PROVIDER_VER, + "Hybrid and DHAsKEM provider"); + put("KEM.DH", DHasKEM.class.getName()); + + // Hybrid KeyPairGenerator/KeyFactory/KEM + + // The order of shares in the concatenation for group name + // X25519MLKEM768 has been reversed as per the current + // draft RFC. + var attrs = Map.of("name", "X25519MLKEM768", "left", "ML-KEM-768", + "right", "X25519"); + putService(new HybridService(this, "KeyPairGenerator", + "X25519MLKEM768", + "sun.security.ssl.Hybrid$KeyPairGeneratorImpl", + null, attrs)); + putService(new HybridService(this, "KEM", + "X25519MLKEM768", + "sun.security.ssl.Hybrid$KEMImpl", + null, attrs)); + putService(new HybridService(this, "KeyFactory", + "X25519MLKEM768", + "sun.security.ssl.Hybrid$KeyFactoryImpl", + null, attrs)); + + attrs = Map.of("name", "SecP256r1MLKEM768", "left", "secp256r1", + "right", "ML-KEM-768"); + putService(new HybridService(this, "KeyPairGenerator", + "SecP256r1MLKEM768", + "sun.security.ssl.Hybrid$KeyPairGeneratorImpl", + null, attrs)); + putService(new HybridService(this, "KEM", + "SecP256r1MLKEM768", + "sun.security.ssl.Hybrid$KEMImpl", + null, attrs)); + putService(new HybridService(this, "KeyFactory", + "SecP256r1MLKEM768", + "sun.security.ssl.Hybrid$KeyFactoryImpl", + null, attrs)); + + attrs = Map.of("name", "SecP384r1MLKEM1024", "left", "secp384r1", + "right", "ML-KEM-1024"); + putService(new HybridService(this, "KeyPairGenerator", + "SecP384r1MLKEM1024", + "sun.security.ssl.Hybrid$KeyPairGeneratorImpl", + null, attrs)); + putService(new HybridService(this, "KEM", + "SecP384r1MLKEM1024", + "sun.security.ssl.Hybrid$KEMImpl", + null, attrs)); + putService(new HybridService(this, "KeyFactory", + "SecP384r1MLKEM1024", + "sun.security.ssl.Hybrid$KeyFactoryImpl", + null, attrs)); + } + } + + private static class HybridService extends Provider.Service { + + HybridService(Provider p, String type, String algo, String cn, + List aliases, Map attrs) { + super(p, type, algo, cn, aliases, attrs); + } + + @Override + public Object newInstance(Object ctrParamObj) + throws NoSuchAlgorithmException { + String type = getType(); + return switch (type) { + case "KeyPairGenerator" -> new Hybrid.KeyPairGeneratorImpl( + getAttribute("left"), getAttribute("right")); + case "KeyFactory" -> new Hybrid.KeyFactoryImpl( + getAttribute("left"), getAttribute("right")); + case "KEM" -> new Hybrid.KEMImpl( + getAttribute("left"), getAttribute("right")); + default -> throw new NoSuchAlgorithmException( + "Unexpected value: " + type); + }; + } + } +} diff --git a/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java b/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java index 623f83f547a..39e82b50435 100644 --- a/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java @@ -24,7 +24,10 @@ */ package sun.security.ssl; +import sun.security.util.RawKeySpec; + import javax.crypto.KDF; +import javax.crypto.KEM; import javax.crypto.KeyAgreement; import javax.crypto.SecretKey; import javax.crypto.spec.HKDFParameterSpec; @@ -32,9 +35,11 @@ import javax.net.ssl.SSLHandshakeException; import java.io.IOException; import java.security.GeneralSecurityException; +import java.security.KeyFactory; import java.security.PrivateKey; +import java.security.Provider; import java.security.PublicKey; -import java.security.spec.AlgorithmParameterSpec; +import java.security.SecureRandom; import sun.security.util.KeyUtil; /** @@ -46,15 +51,32 @@ public class KAKeyDerivation implements SSLKeyDerivation { private final HandshakeContext context; private final PrivateKey localPrivateKey; private final PublicKey peerPublicKey; + private final byte[] keyshare; + private final Provider provider; + // Constructor called by Key Agreement KAKeyDerivation(String algorithmName, HandshakeContext context, PrivateKey localPrivateKey, PublicKey peerPublicKey) { + this(algorithmName, null, context, localPrivateKey, + peerPublicKey, null); + } + + // When the constructor called by KEM: store the client's public key or the + // encapsulated message in keyshare. + KAKeyDerivation(String algorithmName, + NamedGroup namedGroup, + HandshakeContext context, + PrivateKey localPrivateKey, + PublicKey peerPublicKey, + byte[] keyshare) { this.algorithmName = algorithmName; this.context = context; this.localPrivateKey = localPrivateKey; this.peerPublicKey = peerPublicKey; + this.keyshare = keyshare; + this.provider = (namedGroup != null) ? namedGroup.getProvider() : null; } @Override @@ -94,22 +116,15 @@ public class KAKeyDerivation implements SSLKeyDerivation { } } - /** - * Handle the TLSv1.3 objects, which use the HKDF algorithms. - */ - private SecretKey t13DeriveKey(String type) - throws IOException { - SecretKey sharedSecret = null; + private SecretKey deriveHandshakeSecret(String label, + SecretKey sharedSecret) + throws GeneralSecurityException, IOException { SecretKey earlySecret = null; SecretKey saltSecret = null; - try { - KeyAgreement ka = KeyAgreement.getInstance(algorithmName); - ka.init(localPrivateKey); - ka.doPhase(peerPublicKey, true); - sharedSecret = ka.generateSecret("TlsPremasterSecret"); - CipherSuite.HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg; - SSLKeyDerivation kd = context.handshakeKeyDerivation; + CipherSuite.HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg; + SSLKeyDerivation kd = context.handshakeKeyDerivation; + try { if (kd == null) { // No PSK is in use. // If PSK is not in use, Early Secret will still be // HKDF-Extract(0, 0). @@ -129,12 +144,90 @@ public class KAKeyDerivation implements SSLKeyDerivation { // the handshake secret key derivation (below) as it may not // work with the "sharedSecret" obj. KDF hkdf = KDF.getInstance(hashAlg.hkdfAlgorithm); - return hkdf.deriveKey(type, HKDFParameterSpec.ofExtract() - .addSalt(saltSecret).addIKM(sharedSecret).extractOnly()); + var spec = HKDFParameterSpec.ofExtract().addSalt(saltSecret); + if (sharedSecret instanceof Hybrid.SecretKeyImpl hsk) { + spec = spec.addIKM(hsk.k1()).addIKM(hsk.k2()); + } else { + spec = spec.addIKM(sharedSecret); + } + + return hkdf.deriveKey(label, spec.extractOnly()); + } finally { + KeyUtil.destroySecretKeys(earlySecret, saltSecret); + } + } + /** + * This method is called by the server to perform KEM encapsulation. + * It uses the client's public key (sent by the client as a keyshare) + * to encapsulate a shared secret and returns the encapsulated message. + * + * Package-private, used from KeyShareExtension.SHKeyShareProducer:: + * produce(). + */ + KEM.Encapsulated encapsulate(String algorithm, SecureRandom random) + throws IOException { + SecretKey sharedSecret = null; + + if (keyshare == null) { + throw new IOException("No keyshare available for KEM " + + "encapsulation"); + } + + try { + KeyFactory kf = (provider != null) ? + KeyFactory.getInstance(algorithmName, provider) : + KeyFactory.getInstance(algorithmName); + var pk = kf.generatePublic(new RawKeySpec(keyshare)); + + KEM kem = (provider != null) ? + KEM.getInstance(algorithmName, provider) : + KEM.getInstance(algorithmName); + KEM.Encapsulator e = kem.newEncapsulator(pk, random); + KEM.Encapsulated enc = e.encapsulate(); + sharedSecret = enc.key(); + + SecretKey derived = deriveHandshakeSecret(algorithm, sharedSecret); + + return new KEM.Encapsulated(derived, enc.encapsulation(), null); } catch (GeneralSecurityException gse) { throw new SSLHandshakeException("Could not generate secret", gse); } finally { - KeyUtil.destroySecretKeys(sharedSecret, earlySecret, saltSecret); + KeyUtil.destroySecretKeys(sharedSecret); + } + } + + /** + * Handle the TLSv1.3 objects, which use the HKDF algorithms. + */ + private SecretKey t13DeriveKey(String type) + throws IOException { + SecretKey sharedSecret = null; + + try { + if (keyshare != null) { + // Using KEM: called by the client after receiving the KEM + // ciphertext (keyshare) from the server in ServerHello. + // The client decapsulates it using its private key. + KEM kem = (provider != null) + ? KEM.getInstance(algorithmName, provider) + : KEM.getInstance(algorithmName); + var decapsulator = kem.newDecapsulator(localPrivateKey); + sharedSecret = decapsulator.decapsulate( + keyshare, 0, decapsulator.secretSize(), + "TlsPremasterSecret"); + } else { + // Using traditional DH-style Key Agreement + KeyAgreement ka = KeyAgreement.getInstance(algorithmName); + ka.init(localPrivateKey); + ka.doPhase(peerPublicKey, true); + sharedSecret = ka.generateSecret("TlsPremasterSecret"); + } + + return deriveHandshakeSecret(type, sharedSecret); + } catch (GeneralSecurityException gse) { + throw new SSLHandshakeException("Could not generate secret", gse); + } finally { + KeyUtil.destroySecretKeys(sharedSecret); } } } diff --git a/src/java.base/share/classes/sun/security/ssl/KEMKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/KEMKeyExchange.java new file mode 100644 index 00000000000..fb8de6cb104 --- /dev/null +++ b/src/java.base/share/classes/sun/security/ssl/KEMKeyExchange.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.security.ssl; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.ProviderException; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.NamedParameterSpec; +import javax.crypto.SecretKey; + +import sun.security.ssl.NamedGroup.NamedGroupSpec; +import sun.security.x509.X509Key; + +/** + * Specifics for single or hybrid Key exchanges based on KEM + */ +final class KEMKeyExchange { + + static final SSLKeyAgreementGenerator kemKAGenerator + = new KEMKAGenerator(); + + static final class KEMCredentials implements NamedGroupCredentials { + + final NamedGroup namedGroup; + // Unlike other credentials, we directly store the key share + // value here, no need to convert to a key + private final byte[] keyshare; + + KEMCredentials(byte[] keyshare, NamedGroup namedGroup) { + this.keyshare = keyshare; + this.namedGroup = namedGroup; + } + + // For KEM, server performs encapsulation and the resulting + // encapsulated message becomes the key_share value sent to + // the client. It is not a public key, so no PublicKey object + // to return. + @Override + public PublicKey getPublicKey() { + throw new UnsupportedOperationException( + "KEMCredentials stores raw keyshare, not a PublicKey"); + } + + public byte[] getKeyShare() { + return keyshare; + } + + @Override + public NamedGroup getNamedGroup() { + return namedGroup; + } + + /** + * Instantiates a KEMCredentials object + */ + static KEMCredentials valueOf(NamedGroup namedGroup, + byte[] encodedPoint) { + + if (namedGroup.spec != NamedGroupSpec.NAMED_GROUP_KEM) { + throw new RuntimeException( + "Credentials decoding: Not KEM named group"); + } + + if (encodedPoint == null || encodedPoint.length == 0) { + return null; + } + + return new KEMCredentials(encodedPoint, namedGroup); + } + } + + private static class KEMPossession implements SSLPossession { + private final NamedGroup namedGroup; + + public KEMPossession(NamedGroup ng) { + this.namedGroup = ng; + } + public NamedGroup getNamedGroup() { + return namedGroup; + } + } + + static final class KEMReceiverPossession extends KEMPossession { + + private final PrivateKey privateKey; + private final PublicKey publicKey; + + KEMReceiverPossession(NamedGroup namedGroup, SecureRandom random) { + super(namedGroup); + String algName = null; + try { + // For KEM: This receiver side (client) generates a key pair. + algName = ((NamedParameterSpec)namedGroup.keAlgParamSpec). + getName(); + Provider provider = namedGroup.getProvider(); + KeyPairGenerator kpg = (provider != null) ? + KeyPairGenerator.getInstance(algName, provider) : + KeyPairGenerator.getInstance(algName); + + kpg.initialize(namedGroup.keAlgParamSpec, random); + KeyPair kp = kpg.generateKeyPair(); + privateKey = kp.getPrivate(); + publicKey = kp.getPublic(); + } catch (GeneralSecurityException e) { + throw new RuntimeException( + "Could not generate keypair for algorithm: " + + algName, e); + } + } + + @Override + public byte[] encode() { + if (publicKey instanceof X509Key xk) { + return xk.getKeyAsBytes(); + } else if (publicKey instanceof Hybrid.PublicKeyImpl hk) { + return hk.getEncoded(); + } + throw new ProviderException("Unsupported key type: " + publicKey); + } + + // Package-private + PublicKey getPublicKey() { + return publicKey; + } + + // Package-private + PrivateKey getPrivateKey() { + return privateKey; + } + } + + static final class KEMSenderPossession extends KEMPossession { + + private SecretKey key; + private final SecureRandom random; + + KEMSenderPossession(NamedGroup namedGroup, SecureRandom random) { + super(namedGroup); + this.random = random; + } + + // Package-private + SecureRandom getRandom() { + return random; + } + + // Package-private + SecretKey getKey() { + return key; + } + + // Package-private + void setKey(SecretKey key) { + this.key = key; + } + + @Override + public byte[] encode() { + throw new UnsupportedOperationException("encode() not supported"); + } + } + + private static final class KEMKAGenerator + implements SSLKeyAgreementGenerator { + + // Prevent instantiation of this class. + private KEMKAGenerator() { + // blank + } + + @Override + public SSLKeyDerivation createKeyDerivation( + HandshakeContext context) throws IOException { + for (SSLPossession poss : context.handshakePossessions) { + if (poss instanceof KEMReceiverPossession kposs) { + NamedGroup ng = kposs.getNamedGroup(); + for (SSLCredentials cred : context.handshakeCredentials) { + if (cred instanceof KEMCredentials kcred && + ng.equals(kcred.namedGroup)) { + String name = ((NamedParameterSpec) + ng.keAlgParamSpec).getName(); + return new KAKeyDerivation(name, ng, context, + kposs.getPrivateKey(), null, + kcred.getKeyShare()); + } + } + } + } + context.conContext.fatal(Alert.HANDSHAKE_FAILURE, + "No suitable KEM key agreement " + + "parameters negotiated"); + return null; + } + } +} diff --git a/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java b/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java index 8d785f7515a..0d2cbb8f529 100644 --- a/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java @@ -27,8 +27,11 @@ package sun.security.ssl; import java.io.IOException; import java.nio.ByteBuffer; +import java.security.AlgorithmConstraints; import java.security.CryptoPrimitive; import java.security.GeneralSecurityException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.NamedParameterSpec; import java.text.MessageFormat; import java.util.*; import javax.net.ssl.SSLProtocolException; @@ -297,7 +300,9 @@ final class KeyShareExtension { // update the context chc.handshakePossessions.add(pos); // May need more possession types in the future. - if (pos instanceof NamedGroupPossession) { + if (pos instanceof NamedGroupPossession || + pos instanceof + KEMKeyExchange.KEMReceiverPossession) { return pos.encode(); } } @@ -358,24 +363,16 @@ final class KeyShareExtension { try { SSLCredentials kaCred = ng.decodeCredentials(entry.keyExchange); - if (shc.algorithmConstraints != null && - kaCred instanceof - NamedGroupCredentials namedGroupCredentials) { - if (!shc.algorithmConstraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - namedGroupCredentials.getPublicKey())) { - if (SSLLogger.isOn() && - SSLLogger.isOn("ssl,handshake")) { - SSLLogger.warning( + + if (!isCredentialPermitted(shc.algorithmConstraints, + kaCred)) { + if (SSLLogger.isOn() && + SSLLogger.isOn("ssl,handshake")) { + SSLLogger.warning( "key share entry of " + ng + " does not " + - " comply with algorithm constraints"); - } - - kaCred = null; + "comply with algorithm constraints"); } - } - - if (kaCred != null) { + } else { credentials.add(kaCred); } } catch (GeneralSecurityException ex) { @@ -513,7 +510,8 @@ final class KeyShareExtension { @Override public byte[] produce(ConnectionContext context, HandshakeMessage message) throws IOException { - // The producing happens in client side only. + // The producing happens in server side only. + ServerHandshakeContext shc = (ServerHandshakeContext)context; // In response to key_share request only @@ -571,7 +569,9 @@ final class KeyShareExtension { SSLPossession[] poses = ke.createPossessions(shc); for (SSLPossession pos : poses) { - if (!(pos instanceof NamedGroupPossession)) { + if (!(pos instanceof NamedGroupPossession || + pos instanceof + KEMKeyExchange.KEMSenderPossession)) { // May need more possession types in the future. continue; } @@ -579,7 +579,34 @@ final class KeyShareExtension { // update the context shc.handshakeKeyExchange = ke; shc.handshakePossessions.add(pos); - keyShare = new KeyShareEntry(ng.id, pos.encode()); + + // For KEM, perform encapsulation using the client’s public + // key (KEMCredentials). The resulting encapsulated message + // becomes the key_share value sent to the client. The + // shared secret derived from encapsulation is stored in + // the KEMSenderPossession for later use in the TLS key + // schedule. + + // SSLKeyExchange.createPossessions() returns at most one + // key-agreement possession or one KEMSenderPossession + // per handshake. + if (pos instanceof KEMKeyExchange.KEMSenderPossession xp) { + if (cd instanceof KEMKeyExchange.KEMCredentials kcred + && ng.equals(kcred.namedGroup)) { + String name = ((NamedParameterSpec) + ng.keAlgParamSpec).getName(); + KAKeyDerivation handshakeKD = new KAKeyDerivation( + name, ng, shc, null, null, + kcred.getKeyShare()); + var encaped = handshakeKD.encapsulate( + "TlsHandshakeSecret", xp.getRandom()); + xp.setKey(encaped.key()); + keyShare = new KeyShareEntry(ng.id, + encaped.encapsulation()); + } + } else { + keyShare = new KeyShareEntry(ng.id, pos.encode()); + } break; } @@ -663,19 +690,13 @@ final class KeyShareExtension { try { SSLCredentials kaCred = ng.decodeCredentials(keyShare.keyExchange); - if (chc.algorithmConstraints != null && - kaCred instanceof - NamedGroupCredentials namedGroupCredentials) { - if (!chc.algorithmConstraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - namedGroupCredentials.getPublicKey())) { - chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, - "key share entry of " + ng + " does not " + - " comply with algorithm constraints"); - } - } - if (kaCred != null) { + if (!isCredentialPermitted(chc.algorithmConstraints, + kaCred)) { + chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, + "key share entry of " + ng + " does not " + + "comply with algorithm constraints"); + } else { credentials = kaCred; } } catch (GeneralSecurityException ex) { @@ -696,6 +717,34 @@ final class KeyShareExtension { } } + private static boolean isCredentialPermitted( + AlgorithmConstraints constraints, + SSLCredentials cred) { + + if (constraints == null) return true; + if (cred == null) return false; + + if (cred instanceof NamedGroupCredentials namedGroupCred) { + if (namedGroupCred instanceof KEMKeyExchange.KEMCredentials + kemCred) { + AlgorithmParameterSpec paramSpec = kemCred.getNamedGroup(). + keAlgParamSpec; + String algName = (paramSpec instanceof NamedParameterSpec nps) ? + nps.getName() : null; + return algName != null && constraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + algName, + null); + } else { + return constraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + namedGroupCred.getPublicKey()); + } + } + + return true; + } + /** * The absence processing if the extension is not present in * the ServerHello handshake message. diff --git a/src/java.base/share/classes/sun/security/ssl/NamedGroup.java b/src/java.base/share/classes/sun/security/ssl/NamedGroup.java index 877236ebfad..abf973727f3 100644 --- a/src/java.base/share/classes/sun/security/ssl/NamedGroup.java +++ b/src/java.base/share/classes/sun/security/ssl/NamedGroup.java @@ -214,6 +214,39 @@ enum NamedGroup { ProtocolVersion.PROTOCOLS_TO_13, PredefinedDHParameterSpecs.ffdheParams.get(8192)), + ML_KEM_512(0x0200, "MLKEM512", + NamedGroupSpec.NAMED_GROUP_KEM, + ProtocolVersion.PROTOCOLS_OF_13, + null), + + ML_KEM_768(0x0201, "MLKEM768", + NamedGroupSpec.NAMED_GROUP_KEM, + ProtocolVersion.PROTOCOLS_OF_13, + null), + + ML_KEM_1024(0x0202, "MLKEM1024", + NamedGroupSpec.NAMED_GROUP_KEM, + ProtocolVersion.PROTOCOLS_OF_13, + null), + + X25519MLKEM768(0x11ec, "X25519MLKEM768", + NamedGroupSpec.NAMED_GROUP_KEM, + ProtocolVersion.PROTOCOLS_OF_13, + Hybrid.X25519_MLKEM768, + HybridProvider.PROVIDER), + + SECP256R1MLKEM768(0x11eb, "SecP256r1MLKEM768", + NamedGroupSpec.NAMED_GROUP_KEM, + ProtocolVersion.PROTOCOLS_OF_13, + Hybrid.SECP256R1_MLKEM768, + HybridProvider.PROVIDER), + + SECP384R1MLKEM1024(0x11ed, "SecP384r1MLKEM1024", + NamedGroupSpec.NAMED_GROUP_KEM, + ProtocolVersion.PROTOCOLS_OF_13, + Hybrid.SECP384R1_MLKEM1024, + HybridProvider.PROVIDER), + // Elliptic Curves (RFC 4492) // // arbitrary prime and characteristic-2 curves @@ -234,22 +267,33 @@ enum NamedGroup { final AlgorithmParameterSpec keAlgParamSpec; final AlgorithmParameters keAlgParams; final boolean isAvailable; + final Provider defaultProvider; // performance optimization private static final Set KEY_AGREEMENT_PRIMITIVE_SET = Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.KEY_AGREEMENT)); - // Constructor used for all NamedGroup types NamedGroup(int id, String name, NamedGroupSpec namedGroupSpec, ProtocolVersion[] supportedProtocols, AlgorithmParameterSpec keAlgParamSpec) { + this(id, name, namedGroupSpec, supportedProtocols, keAlgParamSpec, + null); + } + + // Constructor used for all NamedGroup types + NamedGroup(int id, String name, + NamedGroupSpec namedGroupSpec, + ProtocolVersion[] supportedProtocols, + AlgorithmParameterSpec keAlgParamSpec, + Provider defaultProvider) { this.id = id; this.name = name; this.spec = namedGroupSpec; this.algorithm = namedGroupSpec.algorithm; this.supportedProtocols = supportedProtocols; this.keAlgParamSpec = keAlgParamSpec; + this.defaultProvider = defaultProvider; // Check if it is a supported named group. AlgorithmParameters algParams = null; @@ -266,16 +310,28 @@ enum NamedGroup { // Check the specific algorithm parameters. if (mediator) { try { - algParams = - AlgorithmParameters.getInstance(namedGroupSpec.algorithm); - algParams.init(keAlgParamSpec); + // Skip AlgorithmParameters for KEMs (not supported) + // Check KEM's availability via KeyFactory + if (namedGroupSpec == NamedGroupSpec.NAMED_GROUP_KEM) { + if (defaultProvider == null) { + KeyFactory.getInstance(name); + } else { + KeyFactory.getInstance(name, defaultProvider); + } + } else { + // ECDHE or others: use AlgorithmParameters as before + algParams = AlgorithmParameters.getInstance( + namedGroupSpec.algorithm); + algParams.init(keAlgParamSpec); + } } catch (InvalidParameterSpecException | NoSuchAlgorithmException exp) { if (namedGroupSpec != NamedGroupSpec.NAMED_GROUP_XDH) { mediator = false; if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( - "No AlgorithmParameters for " + name, exp); + "No AlgorithmParameters or KeyFactory for " + name, + exp); } } else { // Please remove the following code if the XDH/X25519/X448 @@ -307,6 +363,10 @@ enum NamedGroup { this.keAlgParams = mediator ? algParams : null; } + Provider getProvider() { + return defaultProvider; + } + // // The next set of methods search & retrieve NamedGroups. // @@ -545,6 +605,10 @@ enum NamedGroup { return spec.decodeCredentials(this, encoded); } + SSLPossession createPossession(boolean isClient, SecureRandom random) { + return spec.createPossession(this, isClient, random); + } + SSLPossession createPossession(SecureRandom random) { return spec.createPossession(this, random); } @@ -566,6 +630,11 @@ enum NamedGroup { SSLKeyDerivation createKeyDerivation( HandshakeContext hc) throws IOException; + + default SSLPossession createPossession(NamedGroup ng, boolean isClient, + SecureRandom random) { + return createPossession(ng, random); + } } enum NamedGroupSpec implements NamedGroupScheme { @@ -578,6 +647,10 @@ enum NamedGroup { // Finite Field Groups (XDH) NAMED_GROUP_XDH("XDH", XDHScheme.instance), + // Post-Quantum Cryptography (PQC) KEM groups + // Currently used for hybrid named groups + NAMED_GROUP_KEM("KEM", KEMScheme.instance), + // arbitrary prime and curves (ECDHE) NAMED_GROUP_ARBITRARY("EC", null), @@ -634,6 +707,15 @@ enum NamedGroup { return null; } + public SSLPossession createPossession( + NamedGroup ng, boolean isClient, SecureRandom random) { + if (scheme != null) { + return scheme.createPossession(ng, isClient, random); + } + + return null; + } + @Override public SSLPossession createPossession( NamedGroup ng, SecureRandom random) { @@ -739,6 +821,42 @@ enum NamedGroup { } } + private static class KEMScheme implements NamedGroupScheme { + private static final KEMScheme instance = new KEMScheme(); + + @Override + public byte[] encodePossessionPublicKey(NamedGroupPossession poss) { + return poss.encode(); + } + + @Override + public SSLCredentials decodeCredentials(NamedGroup ng, + byte[] encoded) throws IOException, GeneralSecurityException { + return KEMKeyExchange.KEMCredentials.valueOf(ng, encoded); + } + + @Override + public SSLPossession createPossession(NamedGroup ng, + SecureRandom random) { + // Must call createPossession with isClient + throw new UnsupportedOperationException(); + } + + @Override + public SSLPossession createPossession( + NamedGroup ng, boolean isClient, SecureRandom random) { + return isClient + ? new KEMKeyExchange.KEMReceiverPossession(ng, random) + : new KEMKeyExchange.KEMSenderPossession(ng, random); + } + + @Override + public SSLKeyDerivation createKeyDerivation( + HandshakeContext hc) throws IOException { + return KEMKeyExchange.kemKAGenerator.createKeyDerivation(hc); + } + } + static final class SupportedGroups { // the supported named groups, non-null immutable list static final String[] namedGroups; @@ -784,6 +902,9 @@ enum NamedGroup { } else { // default groups NamedGroup[] groups = new NamedGroup[] { + // Hybrid key agreement + X25519MLKEM768, + // Primary XDH (RFC 7748) curves X25519, diff --git a/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java index 22a44590ce3..263308f0659 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -570,7 +570,9 @@ final class SSLKeyExchange implements SSLKeyAgreementGenerator, @Override public SSLPossession createPossession(HandshakeContext hc) { - return namedGroup.createPossession(hc.sslContext.getSecureRandom()); + return namedGroup.createPossession( + hc instanceof ClientHandshakeContext, + hc.sslContext.getSecureRandom()); } @Override diff --git a/src/java.base/share/classes/sun/security/ssl/ServerHello.java b/src/java.base/share/classes/sun/security/ssl/ServerHello.java index 76c266a628a..0567c861e18 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerHello.java @@ -565,6 +565,34 @@ final class ServerHello { clientHello); shc.serverHelloRandom = shm.serverRandom; + // For key derivation, we will either use the traditional Key + // Agreement (KA) model or the Key Encapsulation Mechanism (KEM) + // model, depending on what key exchange group is used. + // + // For KA flows, the server first receives the client's share, + // then generates its key share, and finally comes here. + // However, this is changed for KEM: the server + // must perform both actions — derive the secret and generate + // the key encapsulation message at the same time during + // encapsulation in SHKeyShareProducer. + // + // Traditional Key Agreement (KA): + // - Both peers generate a key share and exchange it. + // - Each peer computes a shared secret sometime after + // receiving the other's key share. + // + // Key Encapsulation Mechanism (KEM): + // The client publishes a public key via a KeyShareExtension, + // which the server uses to: + // + // - generate the shared secret + // - encapsulate the message which is sent to the client in + // another KeyShareExtension + // + // The derived shared secret must be stored in a + // KEMSenderPossession so it can be retrieved for handshake + // traffic secret derivation later. + // Produce extensions for ServerHello handshake message. SSLExtension[] serverHelloExtensions = shc.sslConfig.getEnabledExtensions( @@ -590,9 +618,26 @@ final class ServerHello { "Not negotiated key shares"); } - SSLKeyDerivation handshakeKD = ke.createKeyDerivation(shc); - SecretKey handshakeSecret = handshakeKD.deriveKey( - "TlsHandshakeSecret"); + SecretKey handshakeSecret = null; + + // For KEM, the shared secret has already been generated and + // stored in the server’s possession (KEMSenderPossession) + // during encapsulation in SHKeyShareProducer. + // + // Only one key share is selected by the server, so at most one + // possession will contain the pre-derived shared secret. + for (var pos : shc.handshakePossessions) { + if (pos instanceof KEMKeyExchange.KEMSenderPossession xp) { + handshakeSecret = xp.getKey(); + break; + } + } + + if (handshakeSecret == null) { + SSLKeyDerivation handshakeKD = ke.createKeyDerivation(shc); + handshakeSecret = handshakeKD.deriveKey( + "TlsHandshakeSecret"); + } SSLTrafficKeyDerivation kdg = SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol); diff --git a/src/java.base/share/classes/sun/security/x509/X509Key.java b/src/java.base/share/classes/sun/security/x509/X509Key.java index c83e06f651e..1cfe3f9d95d 100644 --- a/src/java.base/share/classes/sun/security/x509/X509Key.java +++ b/src/java.base/share/classes/sun/security/x509/X509Key.java @@ -104,6 +104,10 @@ public class X509Key implements PublicKey, DerEncoder { return (BitArray)bitStringKey.clone(); } + public byte[] getKeyAsBytes() { + return bitStringKey.toByteArray(); + } + /** * Construct X.509 subject public key from a DER value. If * the runtime environment is configured with a specific class for diff --git a/test/jdk/javax/net/ssl/SSLParameters/NamedGroups.java b/test/jdk/javax/net/ssl/SSLParameters/NamedGroups.java index 25f73606b96..786b907b79a 100644 --- a/test/jdk/javax/net/ssl/SSLParameters/NamedGroups.java +++ b/test/jdk/javax/net/ssl/SSLParameters/NamedGroups.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (C) 2022, Tencent. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,7 +27,7 @@ /* * @test - * @bug 8281236 + * @bug 8281236 8314323 * @summary Check TLS connection behaviors for named groups configuration * @library /javax/net/ssl/templates * @run main/othervm NamedGroups @@ -136,6 +137,60 @@ public class NamedGroups extends SSLSocketTemplate { "secp256r1" }, true); + + runTest(new String[] { + "X25519MLKEM768" + }, + new String[] { + "X25519MLKEM768" + }, + false); + + runTest(new String[] { + "SecP256r1MLKEM768" + }, + new String[] { + "SecP256r1MLKEM768" + }, + false); + + runTest(new String[] { + "SecP384r1MLKEM1024" + }, + new String[] { + "SecP384r1MLKEM1024" + }, + false); + + runTest(new String[] { + "X25519MLKEM768" + }, + new String[] { + "SecP256r1MLKEM768" + }, + true); + + runTest(new String[] { + "X25519MLKEM768" + }, + new String[0], + true); + + runTest(new String[] { + "SecP256r1MLKEM768" + }, + null, + true); + + runTest(new String[] { + "X25519MLKEM768", + "x25519" + }, + new String[] { + "X25519MLKEM768", + "x25519" + }, + false); } private static void runTest(String[] serverNamedGroups, diff --git a/test/jdk/javax/net/ssl/TLSCommon/NamedGroup.java b/test/jdk/javax/net/ssl/TLSCommon/NamedGroup.java index ec89fe0d5b5..432a2bd1b0d 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/NamedGroup.java +++ b/test/jdk/javax/net/ssl/TLSCommon/NamedGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,11 @@ public enum NamedGroup { FFDHE3072("ffdhe3072"), FFDHE4096("ffdhe4096"), FFDHE6144("ffdhe6144"), - FFDHE8192("ffdhe8192"); + FFDHE8192("ffdhe8192"), + + X25519MLKEM768("X25519MLKEM768"), + SECP256R1MLKEM768("SecP256r1MLKEM768"), + SECP384R1MLKEM1024("SecP384r1MLKEM1024"); public final String name; diff --git a/test/jdk/javax/net/ssl/TLSv13/ClientHelloKeyShares.java b/test/jdk/javax/net/ssl/TLSv13/ClientHelloKeyShares.java index efb9895b33c..ed26cf90a8c 100644 --- a/test/jdk/javax/net/ssl/TLSv13/ClientHelloKeyShares.java +++ b/test/jdk/javax/net/ssl/TLSv13/ClientHelloKeyShares.java @@ -26,16 +26,21 @@ /* * @test - * @bug 8247630 + * @bug 8247630 8314323 * @summary Use two key share entries - * @run main/othervm ClientHelloKeyShares 29 23 + * @run main/othervm ClientHelloKeyShares 4588 29 * @run main/othervm -Djdk.tls.namedGroups=secp384r1,secp521r1,x448,ffdhe2048 ClientHelloKeyShares 24 30 * @run main/othervm -Djdk.tls.namedGroups=sect163k1,sect163r1,x25519 ClientHelloKeyShares 29 * @run main/othervm -Djdk.tls.namedGroups=sect163k1,sect163r1,secp256r1 ClientHelloKeyShares 23 * @run main/othervm -Djdk.tls.namedGroups=sect163k1,sect163r1,ffdhe2048,ffdhe3072,ffdhe4096 ClientHelloKeyShares 256 * @run main/othervm -Djdk.tls.namedGroups=sect163k1,ffdhe2048,x25519,secp256r1 ClientHelloKeyShares 256 29 * @run main/othervm -Djdk.tls.namedGroups=secp256r1,secp384r1,ffdhe2048,x25519 ClientHelloKeyShares 23 256 - */ + * @run main/othervm -Djdk.tls.namedGroups=X25519MLKEM768 ClientHelloKeyShares 4588 + * @run main/othervm -Djdk.tls.namedGroups=x25519,X25519MLKEM768 ClientHelloKeyShares 29 4588 + * @run main/othervm -Djdk.tls.namedGroups=SecP256r1MLKEM768,x25519 ClientHelloKeyShares 4587 29 + * @run main/othervm -Djdk.tls.namedGroups=SecP384r1MLKEM1024,secp256r1 ClientHelloKeyShares 4589 23 + * @run main/othervm -Djdk.tls.namedGroups=X25519MLKEM768,SecP256r1MLKEM768,X25519,secp256r1 ClientHelloKeyShares 4588 29 +*/ import javax.net.ssl.*; import javax.net.ssl.SSLEngineResult.*; @@ -62,10 +67,6 @@ public class ClientHelloKeyShares { private static final int HELLO_EXT_SUPP_VERS = 43; private static final int HELLO_EXT_KEY_SHARE = 51; private static final int TLS_PROT_VER_13 = 0x0304; - private static final int NG_SECP256R1 = 0x0017; - private static final int NG_SECP384R1 = 0x0018; - private static final int NG_X25519 = 0x001D; - private static final int NG_X448 = 0x001E; public static void main(String args[]) throws Exception { if (debug) { diff --git a/test/jdk/javax/net/ssl/TLSv13/HRRKeyShares.java b/test/jdk/javax/net/ssl/TLSv13/HRRKeyShares.java index 560faf87049..bd14e465e65 100644 --- a/test/jdk/javax/net/ssl/TLSv13/HRRKeyShares.java +++ b/test/jdk/javax/net/ssl/TLSv13/HRRKeyShares.java @@ -26,10 +26,12 @@ /* * @test - * @bug 8247630 + * @bug 8247630 8314323 * @summary Use two key share entries * @library /test/lib - * @run main/othervm -Djdk.tls.namedGroups=x25519,secp256r1,secp384r1 HRRKeyShares + * @run main/othervm + * -Djdk.tls.namedGroups=x25519,secp256r1,secp384r1,X25519MLKEM768,SecP256r1MLKEM768,SecP384r1MLKEM1024 + * HRRKeyShares */ import java.io.ByteArrayOutputStream; @@ -72,6 +74,10 @@ public class HRRKeyShares { private static final int NG_SECP384R1 = 0x0018; private static final int NG_X25519 = 0x001D; private static final int NG_X448 = 0x001E; + private static final int NG_X25519_MLKEM768 = 0x11EC; + private static final int NG_SECP256R1_MLKEM768 = 0x11EB; + private static final int NG_SECP384R1_MLKEM1024 = 0x11ED; + private static final int NG_GC512A = 0x0026; private static final int COMP_NONE = 0; private static final int ALERT_TYPE_FATAL = 2; @@ -238,6 +244,18 @@ public class HRRKeyShares { System.out.println("Test 4: Bad HRR using known / unasserted x448"); hrrKeyShareTest(NG_X448, false); System.out.println(); + + System.out.println("Test 5: Good HRR exchange using X25519MLKEM768"); + hrrKeyShareTest(NG_X25519_MLKEM768, true); + System.out.println(); + + System.out.println("Test 6: Good HRR exchange using SecP256r1MLKEM768"); + hrrKeyShareTest(NG_SECP256R1_MLKEM768, true); + System.out.println(); + + System.out.println("Test 7: Good HRR exchange using SecP384r1MLKEM1024"); + hrrKeyShareTest(NG_SECP384R1_MLKEM1024, true); + System.out.println(); } private static void logResult(String str, SSLEngineResult result) { @@ -348,7 +366,8 @@ public class HRRKeyShares { try { // Now we're expecting to reissue the ClientHello, this time - // with a secp384r1 share. + // with a key share for the HRR requested named + // group (hrrNamedGroup). cTOs.compact(); clientResult = engine.wrap(clientOut, cTOs); logResult("client wrap: ", clientResult); diff --git a/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java b/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java index 8799f2305bf..a54bb501f78 100644 --- a/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java +++ b/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java @@ -34,8 +34,12 @@ * -Djdk.tls.useExtendedMasterSecret=false * -Djdk.tls.client.enableSessionTicketExtension=false FipsModeTLS * @comment SunPKCS11 does not support (TLS1.2) SunTlsExtendedMasterSecret yet. - * Stateless resumption doesn't currently work with NSS-FIPS, see JDK-8368669 - * @run main/othervm/timeout=120 -Djdk.tls.client.protocols=TLSv1.3 FipsModeTLS + * Stateless resumption doesn't currently work with NSS-FIPS, see JDK-8368669. + * NSS-FIPS does not support ML-KEM, so configures the list of named groups. + * @run main/othervm/timeout=120 + * -Djdk.tls.client.protocols=TLSv1.3 + * -Djdk.tls.namedGroups=x25519,secp256r1,secp384r1,secp521r1,x448,ffdhe2048,ffdhe3072,ffdhe4096,ffdhe6144,ffdhe8192 + * FipsModeTLS */ import java.io.File; diff --git a/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java b/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java index 26304c5df95..a13f8570f14 100644 --- a/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java +++ b/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,24 @@ /* * @test - * @bug 8246330 + * @bug 8246330 8314323 * @library /javax/net/ssl/templates /test/lib * @run main/othervm -Djdk.tls.namedGroups="secp384r1" DisabledCurve DISABLE_NONE PASS * @run main/othervm -Djdk.tls.namedGroups="secp384r1" DisabledCurve secp384r1 FAIL + * @run main/othervm -Djdk.tls.namedGroups="X25519MLKEM768" + DisabledCurve DISABLE_NONE PASS + * @run main/othervm -Djdk.tls.namedGroups="X25519MLKEM768" + DisabledCurve X25519MLKEM768 FAIL + * @run main/othervm -Djdk.tls.namedGroups="SecP256r1MLKEM768" + DisabledCurve DISABLE_NONE PASS + * @run main/othervm -Djdk.tls.namedGroups="SecP256r1MLKEM768" + DisabledCurve SecP256r1MLKEM768 FAIL + * @run main/othervm -Djdk.tls.namedGroups="SecP384r1MLKEM1024" + DisabledCurve DISABLE_NONE PASS + * @run main/othervm -Djdk.tls.namedGroups="SecP384r1MLKEM1024" + DisabledCurve SecP384r1MLKEM1024 FAIL */ import java.security.Security; import java.util.Arrays; @@ -45,8 +57,10 @@ public class DisabledCurve extends SSLSocketTemplate { private static final String[][][] protocols = { { { "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1" }, { "TLSv1.2" } }, { { "TLSv1.2" }, { "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1" } }, - { { "TLSv1.2" }, { "TLSv1.2" } }, { { "TLSv1.1" }, { "TLSv1.1" } }, - { { "TLSv1" }, { "TLSv1" } } }; + { { "TLSv1.2" }, { "TLSv1.2" } }, + { { "TLSv1.1" }, { "TLSv1.1" } }, + { { "TLSv1" }, { "TLSv1" } }, + { { "TLSv1.3" }, { "TLSv1.3" } } }; @Override protected SSLContext createClientSSLContext() throws Exception { @@ -94,17 +108,36 @@ public class DisabledCurve extends SSLSocketTemplate { String expected = args[1]; String disabledName = ("DISABLE_NONE".equals(args[0]) ? "" : args[0]); boolean disabled = false; - if (disabledName.equals("")) { + + if (disabledName.isEmpty()) { Security.setProperty("jdk.disabled.namedCurves", ""); + Security.setProperty("jdk.certpath.disabledAlgorithms", ""); } else { disabled = true; - Security.setProperty("jdk.certpath.disabledAlgorithms", "secp384r1"); + Security.setProperty("jdk.certpath.disabledAlgorithms", disabledName); + if (!disabledName.contains("MLKEM")) { + Security.setProperty("jdk.disabled.namedCurves", disabledName); + } else { + Security.setProperty("jdk.disabled.namedCurves", ""); + } } // Re-enable TLSv1 and TLSv1.1 since test depends on it. SecurityUtils.removeFromDisabledTlsAlgs("TLSv1", "TLSv1.1"); + String namedGroups = System.getProperty("jdk.tls.namedGroups", ""); + boolean hybridGroup = namedGroups.contains("MLKEM"); + for (index = 0; index < protocols.length; index++) { + if (hybridGroup) { + String[] clientProtos = protocols[index][0]; + String[] serverProtos = protocols[index][1]; + + if (!(isTLS13(clientProtos) && isTLS13(serverProtos))) { + continue; + } + } + try { (new DisabledCurve()).run(); if (expected.equals("FAIL")) { @@ -123,4 +156,8 @@ public class DisabledCurve extends SSLSocketTemplate { } } + + private static boolean isTLS13(String[] protocols) { + return protocols.length == 1 && "TLSv1.3".equals(protocols[0]); + } } diff --git a/test/jdk/sun/security/ssl/CipherSuite/NamedGroupsWithCipherSuite.java b/test/jdk/sun/security/ssl/CipherSuite/NamedGroupsWithCipherSuite.java index 5732f42982c..9080f549683 100644 --- a/test/jdk/sun/security/ssl/CipherSuite/NamedGroupsWithCipherSuite.java +++ b/test/jdk/sun/security/ssl/CipherSuite/NamedGroupsWithCipherSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,6 +21,8 @@ * questions. */ +import java.util.Arrays; +import java.util.List; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLSocket; @@ -29,7 +31,7 @@ import jdk.test.lib.security.SecurityUtils; /* * @test - * @bug 8224650 8242929 + * @bug 8224650 8242929 8314323 * @library /javax/net/ssl/templates * /javax/net/ssl/TLSCommon * /test/lib @@ -44,17 +46,20 @@ import jdk.test.lib.security.SecurityUtils; * @run main/othervm NamedGroupsWithCipherSuite ffdhe4096 * @run main/othervm NamedGroupsWithCipherSuite ffdhe6144 * @run main/othervm NamedGroupsWithCipherSuite ffdhe8192 + * @run main/othervm NamedGroupsWithCipherSuite X25519MLKEM768 + * @run main/othervm NamedGroupsWithCipherSuite SecP256r1MLKEM768 + * @run main/othervm NamedGroupsWithCipherSuite SecP384r1MLKEM1024 */ public class NamedGroupsWithCipherSuite extends SSLSocketTemplate { - private static final Protocol[] PROTOCOLS = new Protocol[] { + private static final List PROTOCOLS = List.of( Protocol.TLSV1_3, Protocol.TLSV1_2, Protocol.TLSV1_1, Protocol.TLSV1 - }; + ); - private static final CipherSuite[] CIPHER_SUITES = new CipherSuite[] { + private static final List CIPHER_SUITES = List.of( CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_AES_256_GCM_SHA384, CipherSuite.TLS_CHACHA20_POLY1305_SHA256, @@ -75,7 +80,23 @@ public class NamedGroupsWithCipherSuite extends SSLSocketTemplate { CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 - }; + ); + + private static final List HYBRID_NAMEDGROUPS = List.of( + "X25519MLKEM768", + "SecP256r1MLKEM768", + "SecP384r1MLKEM1024" + ); + + private static final List HYBRID_PROTOCOL = List.of( + Protocol.TLSV1_3 + ); + + private static final List HYBRID_CIPHER_SUITES = List.of( + CipherSuite.TLS_AES_128_GCM_SHA256, + CipherSuite.TLS_AES_256_GCM_SHA384, + CipherSuite.TLS_CHACHA20_POLY1305_SHA256 + ); private String protocol; private String cipher; @@ -151,48 +172,59 @@ public class NamedGroupsWithCipherSuite extends SSLSocketTemplate { // Re-enable TLSv1 and TLSv1.1 since test depends on it. SecurityUtils.removeFromDisabledTlsAlgs("TLSv1", "TLSv1.1"); - for (Protocol protocol : PROTOCOLS) { - for (CipherSuite cipherSuite : CIPHER_SUITES) { - // Named group converted to lower case just - // to satisfy Test condition + boolean hybridGroup = HYBRID_NAMEDGROUPS.contains(namedGroup); + List protocolList = hybridGroup ? + HYBRID_PROTOCOL : PROTOCOLS; + List cipherList = hybridGroup ? + HYBRID_CIPHER_SUITES : CIPHER_SUITES; + + // non-Hybrid named group converted to lower case just + // to satisfy Test condition + String normalizedGroup = hybridGroup ? + namedGroup : namedGroup.toLowerCase(); + + for (Protocol protocol : protocolList) { + for (CipherSuite cipherSuite : cipherList) { if (cipherSuite.supportedByProtocol(protocol) - && groupSupportdByCipher(namedGroup.toLowerCase(), - cipherSuite)) { + && groupSupportedByCipher(normalizedGroup, + cipherSuite)) { System.out.printf("Protocol: %s, cipher suite: %s%n", protocol, cipherSuite); - // Named group converted to lower case just - // to satisfy Test condition new NamedGroupsWithCipherSuite(protocol, - cipherSuite, namedGroup.toLowerCase()).run(); + cipherSuite, normalizedGroup).run(); } } } } - private static boolean groupSupportdByCipher(String group, + private static boolean groupSupportedByCipher(String group, CipherSuite cipherSuite) { + if (HYBRID_NAMEDGROUPS.contains(group)) { + return cipherSuite.keyExAlgorithm == null; + } + return (group.startsWith("x") - && xdhGroupSupportdByCipher(cipherSuite)) + && xdhGroupSupportedByCipher(cipherSuite)) || (group.startsWith("secp") - && ecdhGroupSupportdByCipher(cipherSuite)) + && ecdhGroupSupportedByCipher(cipherSuite)) || (group.startsWith("ffdhe") - && ffdhGroupSupportdByCipher(cipherSuite)); + && ffdhGroupSupportedByCipher(cipherSuite)); } - private static boolean xdhGroupSupportdByCipher( + private static boolean xdhGroupSupportedByCipher( CipherSuite cipherSuite) { return cipherSuite.keyExAlgorithm == null || cipherSuite.keyExAlgorithm == KeyExAlgorithm.ECDHE_RSA; } - private static boolean ecdhGroupSupportdByCipher( + private static boolean ecdhGroupSupportedByCipher( CipherSuite cipherSuite) { return cipherSuite.keyExAlgorithm == null || cipherSuite.keyExAlgorithm == KeyExAlgorithm.ECDHE_RSA || cipherSuite.keyExAlgorithm == KeyExAlgorithm.ECDHE_ECDSA; } - private static boolean ffdhGroupSupportdByCipher( + private static boolean ffdhGroupSupportedByCipher( CipherSuite cipherSuite) { return cipherSuite.keyExAlgorithm == null || cipherSuite.keyExAlgorithm == KeyExAlgorithm.DHE_DSS diff --git a/test/jdk/sun/security/ssl/CipherSuite/RestrictNamedGroup.java b/test/jdk/sun/security/ssl/CipherSuite/RestrictNamedGroup.java index c4c343bf84e..4ff0c6e6e15 100644 --- a/test/jdk/sun/security/ssl/CipherSuite/RestrictNamedGroup.java +++ b/test/jdk/sun/security/ssl/CipherSuite/RestrictNamedGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8226374 8242929 + * @bug 8226374 8242929 8314323 * @library /javax/net/ssl/templates * @summary Restrict signature algorithms and named groups * @run main/othervm RestrictNamedGroup x25519 @@ -36,6 +36,9 @@ * @run main/othervm RestrictNamedGroup ffdhe4096 * @run main/othervm RestrictNamedGroup ffdhe6144 * @run main/othervm RestrictNamedGroup ffdhe8192 + * @run main/othervm RestrictNamedGroup X25519MLKEM768 + * @run main/othervm RestrictNamedGroup SecP256r1MLKEM768 + * @run main/othervm RestrictNamedGroup SecP384r1MLKEM1024 */ import java.security.Security; diff --git a/test/jdk/sun/security/ssl/CipherSuite/SupportedGroups.java b/test/jdk/sun/security/ssl/CipherSuite/SupportedGroups.java index 88b0bf2489a..8cf6ee2b5e6 100644 --- a/test/jdk/sun/security/ssl/CipherSuite/SupportedGroups.java +++ b/test/jdk/sun/security/ssl/CipherSuite/SupportedGroups.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8171279 + * @bug 8171279 8314323 * @library /javax/net/ssl/templates * @summary Test TLS connection with each individual supported group * @run main/othervm SupportedGroups x25519 @@ -36,6 +36,9 @@ * @run main/othervm SupportedGroups ffdhe4096 * @run main/othervm SupportedGroups ffdhe6144 * @run main/othervm SupportedGroups ffdhe8192 + * @run main/othervm SupportedGroups X25519MLKEM768 + * @run main/othervm SupportedGroups SecP256r1MLKEM768 + * @run main/othervm SupportedGroups SecP384r1MLKEM1024 */ import java.net.InetAddress; import java.util.Arrays; @@ -45,15 +48,24 @@ import javax.net.ssl.SSLServerSocket; public class SupportedGroups extends SSLSocketTemplate { private static volatile int index; - private static final String[][][] protocols = { + private static final String[][][] protocolsForClassic = { {{"TLSv1.3"}, {"TLSv1.3"}}, {{"TLSv1.3", "TLSv1.2"}, {"TLSv1.2"}}, {{"TLSv1.2"}, {"TLSv1.3", "TLSv1.2"}}, {{"TLSv1.2"}, {"TLSv1.2"}} }; - public SupportedGroups() { + private static final String[][][] protocolsForHybrid = { + {{"TLSv1.3"}, {"TLSv1.3"}}, + {{"TLSv1.3", "TLSv1.2"}, {"TLSv1.3"}}, + {{"TLSv1.3"}, {"TLSv1.3", "TLSv1.2"}} + }; + + private final String[][][] protocols; + + public SupportedGroups(String[][][] protocols) { this.serverAddress = InetAddress.getLoopbackAddress(); + this.protocols = protocols; } // Servers are configured before clients, increment test case after. @@ -85,8 +97,18 @@ public class SupportedGroups extends SSLSocketTemplate { public static void main(String[] args) throws Exception { System.setProperty("jdk.tls.namedGroups", args[0]); + boolean hybridGroup = hybridNamedGroup(args[0]); + String[][][] protocols = hybridGroup ? + protocolsForHybrid : protocolsForClassic; + for (index = 0; index < protocols.length; index++) { - (new SupportedGroups()).run(); + (new SupportedGroups(protocols)).run(); } } + + private static boolean hybridNamedGroup(String namedGroup) { + return namedGroup.equals("X25519MLKEM768") || + namedGroup.equals("SecP256r1MLKEM768") || + namedGroup.equals("SecP384r1MLKEM1024"); + } } diff --git a/test/micro/org/openjdk/bench/java/security/SSLHandshake.java b/test/micro/org/openjdk/bench/java/security/SSLHandshake.java index d8773781b58..b46704a01de 100644 --- a/test/micro/org/openjdk/bench/java/security/SSLHandshake.java +++ b/test/micro/org/openjdk/bench/java/security/SSLHandshake.java @@ -44,6 +44,7 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManagerFactory; @@ -75,8 +76,15 @@ public class SSLHandshake { @Param({"true", "false"}) boolean resume; - @Param({"TLSv1.2", "TLS"}) - String tlsVersion; + @Param({ + "TLSv1.2-secp256r1", + "TLSv1.3-x25519", "TLSv1.3-secp256r1", "TLSv1.3-secp384r1", + "TLSv1.3-X25519MLKEM768", "TLSv1.3-SecP256r1MLKEM768", "TLSv1.3-SecP384r1MLKEM1024" + }) + String versionAndGroup; + + private String tlsVersion; + private String namedGroup; private static SSLContext getServerContext() { try { @@ -96,6 +104,10 @@ public class SSLHandshake { @Setup(Level.Trial) public void init() throws Exception { + String[] components = versionAndGroup.split("-", 2); + tlsVersion = components[0]; + namedGroup = components[1]; + KeyStore ts = TestCertificates.getTrustStore(); TrustManagerFactory tmf = TrustManagerFactory.getInstance( @@ -195,5 +207,14 @@ public class SSLHandshake { */ clientEngine = sslClientCtx.createSSLEngine("client", 80); clientEngine.setUseClientMode(true); + + // Set the key exchange named group in client and server engines + SSLParameters clientParams = clientEngine.getSSLParameters(); + clientParams.setNamedGroups(new String[]{namedGroup}); + clientEngine.setSSLParameters(clientParams); + + SSLParameters serverParams = serverEngine.getSSLParameters(); + serverParams.setNamedGroups(new String[]{namedGroup}); + serverEngine.setSSLParameters(serverParams); } } diff --git a/test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java b/test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java index 3386039c62e..dc6d2060f5e 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java +++ b/test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java @@ -23,34 +23,69 @@ package org.openjdk.bench.javax.crypto.full; import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.OperationsPerInvocation; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.infra.Blackhole; import javax.crypto.DecapsulateException; +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; import javax.crypto.KEM; import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.security.spec.ECGenParameterSpec; -public class KEMBench extends CryptoBase { +public abstract class KEMBench extends CryptoBase { public static final int SET_SIZE = 128; - @Param({"ML-KEM-512", "ML-KEM-768", "ML-KEM-1024" }) + @Param({}) private String algorithm; + @Param({""}) // Used when the KeyPairGenerator Alg != KEM Alg + private String kpgSpec; + private KeyPair[] keys; private byte[][] messages; private KEM kem; @Setup - public void setup() throws NoSuchAlgorithmException, InvalidKeyException { - kem = (prov == null) ? KEM.getInstance(algorithm) : KEM.getInstance(algorithm, prov); - KeyPairGenerator generator = (prov == null) ? KeyPairGenerator.getInstance(algorithm) : KeyPairGenerator.getInstance(algorithm, prov); + public void setup() throws NoSuchAlgorithmException, InvalidKeyException, + InvalidAlgorithmParameterException { + String kpgAlg; + String kpgParams; + kem = (prov == null) ? KEM.getInstance(algorithm) : + KEM.getInstance(algorithm, prov); + + // By default use the same provider for KEM and KPG + Provider kpgProv = prov; + if (kpgSpec.isEmpty()) { + kpgAlg = algorithm; + kpgParams = ""; + } else { + // The key pair generation spec is broken down from a colon- + // delimited string spec into 3 fields: + // [0] - the provider name + // [1] - the algorithm name + // [2] - the parameters (i.e. the name of the curve) + String[] kpgTok = kpgSpec.split(":"); + kpgProv = Security.getProvider(kpgTok[0]); + kpgAlg = kpgTok[1]; + kpgParams = kpgTok[2]; + } + KeyPairGenerator generator = (kpgProv == null) ? + KeyPairGenerator.getInstance(kpgAlg) : + KeyPairGenerator.getInstance(kpgAlg, kpgProv); + if (kpgParams != null && !kpgParams.isEmpty()) { + generator.initialize(new ECGenParameterSpec(kpgParams)); + } keys = new KeyPair[SET_SIZE]; for (int i = 0; i < keys.length; i++) { keys[i] = generator.generateKeyPair(); @@ -63,20 +98,79 @@ public class KEMBench extends CryptoBase { } } + private static Provider getInternalJce() { + try { + Class dhClazz = Class.forName("sun.security.ssl.HybridProvider"); + return (Provider) dhClazz.getField("PROVIDER").get(null); + } catch (ReflectiveOperationException exc) { + throw new RuntimeException(exc); + } + } + @Benchmark @OperationsPerInvocation(SET_SIZE) public void encapsulate(Blackhole bh) throws InvalidKeyException { for (KeyPair kp : keys) { - bh.consume(kem.newEncapsulator(kp.getPublic()).encapsulate().encapsulation()); + bh.consume(kem.newEncapsulator(kp.getPublic()).encapsulate(). + encapsulation()); } } @Benchmark @OperationsPerInvocation(SET_SIZE) - public void decapsulate(Blackhole bh) throws InvalidKeyException, DecapsulateException { + public void decapsulate(Blackhole bh) throws InvalidKeyException, + DecapsulateException { for (int i = 0; i < messages.length; i++) { - bh.consume(kem.newDecapsulator(keys[i].getPrivate()).decapsulate(messages[i])); + bh.consume(kem.newDecapsulator(keys[i].getPrivate()). + decapsulate(messages[i])); } } + public static class MLKEM extends KEMBench { + @Param({"ML-KEM-512", "ML-KEM-768", "ML-KEM-1024" }) + private String algorithm; + + @Param({""}) // ML-KEM uses the same alg for KPG and KEM + private String kpgSpec; + } + + @Fork(value = 5, jvmArgs = {"-XX:+AlwaysPreTouch", "--add-opens", + "java.base/sun.security.ssl=ALL-UNNAMED"}) + public static class JSSE_DHasKEM extends KEMBench { + @Setup + public void init() { + try { + prov = getInternalJce(); + super.setup(); + } catch (GeneralSecurityException gse) { + throw new RuntimeException(gse); + } + } + + @Param({"DH"}) + private String algorithm; + + @Param({"SunEC:XDH:x25519", "SunEC:EC:secp256r1", "SunEC:EC:secp384r1"}) + private String kpgSpec; + } + + @Fork(value = 5, jvmArgs = {"-XX:+AlwaysPreTouch", "--add-opens", + "java.base/sun.security.ssl=ALL-UNNAMED"}) + public static class JSSE_Hybrid extends KEMBench { + @Setup + public void init() { + try { + prov = getInternalJce(); + super.setup(); + } catch (GeneralSecurityException gse) { + throw new RuntimeException(gse); + } + } + + @Param({"X25519MLKEM768", "SecP256r1MLKEM768", "SecP384r1MLKEM1024"}) + private String algorithm; + + @Param({""}) // ML-KEM uses the same alg for KPG and KEM + private String kpgSpec; + } } diff --git a/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java b/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java index 58daff28d88..5a3c72fb263 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java +++ b/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java @@ -22,13 +22,16 @@ */ package org.openjdk.bench.javax.crypto.full; +import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Setup; +import java.security.GeneralSecurityException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; +import java.security.Provider; public class KeyPairGeneratorBench extends CryptoBase { @@ -45,11 +48,21 @@ public class KeyPairGeneratorBench extends CryptoBase { setupProvider(); generator = (prov == null) ? KeyPairGenerator.getInstance(algorithm) : KeyPairGenerator.getInstance(algorithm, prov); - if (keyLength > 0) { // not all key pair generators allow the use of key length + // not all key pair generators allow the use of key length + if (keyLength > 0) { generator.initialize(keyLength); } } + private static Provider getInternalJce() { + try { + Class dhClazz = Class.forName("sun.security.ssl.HybridProvider"); + return (Provider) dhClazz.getField("PROVIDER").get(null); + } catch (ReflectiveOperationException exc) { + throw new RuntimeException(exc); + } + } + @Benchmark public KeyPair generateKeyPair() { return generator.generateKeyPair(); @@ -118,4 +131,23 @@ public class KeyPairGeneratorBench extends CryptoBase { private int keyLength; } + @Fork(value = 5, jvmArgs = {"-XX:+AlwaysPreTouch", "--add-opens", + "java.base/sun.security.ssl=ALL-UNNAMED"}) + public static class JSSE_Hybrid extends KeyPairGeneratorBench { + @Setup + public void init() { + try { + prov = getInternalJce(); + super.setup(); + } catch (GeneralSecurityException gse) { + throw new RuntimeException(gse); + } + } + + @Param({"X25519MLKEM768", "SecP256r1MLKEM768", "SecP384r1MLKEM1024"}) + private String algorithm; + + @Param({"0"}) // Hybrid KPGs don't need key lengths + private int keyLength; + } } From b2b4729ba2dbbb7cecb177612bd08927ccb085f2 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Tue, 20 Jan 2026 16:28:23 +0000 Subject: [PATCH 107/328] 8375015: CompletionAPITest::testDocumentation failed - AssertionFailedError: expected: but was: Reviewed-by: jlahoda --- test/langtools/jdk/jshell/CompletionAPITest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/langtools/jdk/jshell/CompletionAPITest.java b/test/langtools/jdk/jshell/CompletionAPITest.java index ad5dea90a95..932482ce6dc 100644 --- a/test/langtools/jdk/jshell/CompletionAPITest.java +++ b/test/langtools/jdk/jshell/CompletionAPITest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8366691 + * @bug 8366691 8375015 * @summary Test JShell Completion API * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -67,7 +67,7 @@ import org.junit.jupiter.api.Test; public class CompletionAPITest extends KullaTesting { - private static final long TIMEOUT = 2_000; + private static final long TIMEOUT = 20_000; @Test public void testAPI() { @@ -144,7 +144,7 @@ public class CompletionAPITest extends KullaTesting { } @Test - public void testDocumentation() { + public void testDocumentation() throws Exception { waitIndexingFinished(); Path classes = prepareZip(); @@ -171,6 +171,7 @@ public class CompletionAPITest extends KullaTesting { while (clazz.get().get() != null && (System.currentTimeMillis() - start) < TIMEOUT) { System.gc(); + Thread.sleep(100); } assertNull(clazz.get().get()); From 72bf0bb6f6eaf61b3800d885733e23b7b42bf9c9 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Tue, 20 Jan 2026 16:49:02 +0000 Subject: [PATCH 108/328] 8353115: GenShen: mixed evacuation candidate regions need accurate live_data Reviewed-by: wkemper --- .../heuristics/shenandoahHeuristics.hpp | 7 +++++++ .../heuristics/shenandoahOldHeuristics.cpp | 15 +++++++++++++++ .../gc/shenandoah/shenandoahHeapRegion.cpp | 2 ++ .../gc/shenandoah/shenandoahHeapRegion.hpp | 11 +++++++++++ .../shenandoah/shenandoahHeapRegion.inline.hpp | 17 +++++++++++++++++ 5 files changed, 52 insertions(+) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp index fb8cfb36353..e1139765022 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp @@ -129,6 +129,13 @@ protected: #endif } + inline void update_livedata(size_t live) { + _region_union._live_data = live; +#ifdef ASSERT + _union_tag = is_live_data; +#endif + } + inline ShenandoahHeapRegion* get_region() const { assert(_union_tag != is_uninitialized, "Cannot fetch region from uninitialized RegionData"); return _region; diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp index 029a4dd98fb..f2c6e427ea8 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp @@ -89,6 +89,17 @@ bool ShenandoahOldHeuristics::prime_collection_set(ShenandoahCollectionSet* coll return false; } + // Between consecutive mixed-evacuation cycles, the live data within each candidate region may change due to + // promotions and old-gen evacuations. Re-sort the candidate regions in order to first evacuate regions that have + // the smallest amount of live data. These are easiest to evacuate with least effort. Doing these first allows + // us to more quickly replenish free memory with empty regions. + for (uint i = _next_old_collection_candidate; i < _last_old_collection_candidate; i++) { + ShenandoahHeapRegion* r = _region_data[i].get_region(); + _region_data[i].update_livedata(r->get_mixed_candidate_live_data_bytes()); + } + QuickSort::sort(_region_data + _next_old_collection_candidate, unprocessed_old_collection_candidates(), + compare_by_live); + _first_pinned_candidate = NOT_FOUND; uint included_old_regions = 0; @@ -414,6 +425,8 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() { ShenandoahHeapRegion* r = candidates[i].get_region(); size_t region_garbage = r->garbage(); size_t region_free = r->free(); + + r->capture_mixed_candidate_garbage(); candidates_garbage += region_garbage; unfragmented += region_free; } @@ -456,6 +469,8 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() { r->index(), ShenandoahHeapRegion::region_state_to_string(r->state())); const size_t region_garbage = r->garbage(); const size_t region_free = r->free(); + + r->capture_mixed_candidate_garbage(); candidates_garbage += region_garbage; unfragmented += region_free; defrag_count++; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp index 3cd5cdd2ec3..e794a86e473 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp @@ -75,6 +75,7 @@ ShenandoahHeapRegion::ShenandoahHeapRegion(HeapWord* start, size_t index, bool c _plab_allocs(0), _live_data(0), _critical_pins(0), + _mixed_candidate_garbage_words(0), _update_watermark(start), _age(0), #ifdef SHENANDOAH_CENSUS_NOISE @@ -565,6 +566,7 @@ void ShenandoahHeapRegion::recycle_internal() { assert(_recycling.is_set() && is_trash(), "Wrong state"); ShenandoahHeap* heap = ShenandoahHeap::heap(); + _mixed_candidate_garbage_words = 0; set_top(bottom()); clear_live_data(); reset_alloc_metadata(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp index cf0dc5476d0..9da2816e2c9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -43,6 +43,7 @@ class ShenandoahHeapRegion { friend class VMStructs; friend class ShenandoahHeapRegionStateConstant; private: + /* Region state is described by a state machine. Transitions are guarded by heap lock, which allows changing the state of several regions atomically. @@ -259,6 +260,8 @@ private: volatile size_t _live_data; volatile size_t _critical_pins; + size_t _mixed_candidate_garbage_words; + HeapWord* volatile _update_watermark; uint _age; @@ -398,6 +401,14 @@ public: // above TAMS. inline size_t get_live_data_words() const; + inline size_t get_mixed_candidate_live_data_bytes() const; + inline size_t get_mixed_candidate_live_data_words() const; + + inline void capture_mixed_candidate_garbage(); + + // Returns garbage by calculating difference between used and get_live_data_words. The value returned is only + // meaningful immediately following completion of marking. If there have been subsequent allocations in this region, + // use a different approach to determine garbage, such as (used() - get_mixed_candidate_live_data_bytes()) inline size_t garbage() const; void print_on(outputStream* st) const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp index b9304ee9daa..be982433885 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp @@ -163,6 +163,23 @@ inline size_t ShenandoahHeapRegion::get_live_data_bytes() const { return get_live_data_words() * HeapWordSize; } +inline size_t ShenandoahHeapRegion::get_mixed_candidate_live_data_bytes() const { + shenandoah_assert_heaplocked_or_safepoint(); + assert(used() >= _mixed_candidate_garbage_words * HeapWordSize, "used must exceed garbage"); + return used() - _mixed_candidate_garbage_words * HeapWordSize; +} + +inline size_t ShenandoahHeapRegion::get_mixed_candidate_live_data_words() const { + shenandoah_assert_heaplocked_or_safepoint(); + assert(used() >= _mixed_candidate_garbage_words * HeapWordSize, "used must exceed garbage"); + return used() / HeapWordSize - _mixed_candidate_garbage_words; +} + +inline void ShenandoahHeapRegion::capture_mixed_candidate_garbage() { + shenandoah_assert_heaplocked_or_safepoint(); + _mixed_candidate_garbage_words = garbage() / HeapWordSize; +} + inline bool ShenandoahHeapRegion::has_live() const { return get_live_data_words() != 0; } From 5f8cb30fc0296a2b487edf9dee63e810f4861e8e Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 20 Jan 2026 18:16:39 +0000 Subject: [PATCH 109/328] 8375626: G1: Convert G1CollectionSetChooser to use Atomic Reviewed-by: kbarrett, shade --- .../share/gc/g1/g1CollectionSetChooser.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp b/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp index 954ca40a77f..d9496410c12 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ #include "gc/g1/g1CollectionSetChooser.hpp" #include "gc/g1/g1HeapRegionRemSet.inline.hpp" #include "gc/shared/space.hpp" -#include "runtime/atomicAccess.hpp" +#include "runtime/atomic.hpp" #include "utilities/quickSort.hpp" // Determine collection set candidates (from marking): For all regions determine @@ -50,7 +50,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask { G1HeapRegion** _data; - uint volatile _cur_claim_idx; + Atomic _cur_claim_idx; static int compare_region_gc_efficiency(G1HeapRegion** rr1, G1HeapRegion** rr2) { G1HeapRegion* r1 = *rr1; @@ -105,7 +105,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask { // Claim a new chunk, returning its bounds [from, to[. void claim_chunk(uint& from, uint& to) { - uint result = AtomicAccess::add(&_cur_claim_idx, _chunk_size); + uint result = _cur_claim_idx.add_then_fetch(_chunk_size); assert(_max_size > result - 1, "Array too small, is %u should be %u with chunk size %u.", _max_size, result, _chunk_size); @@ -121,14 +121,15 @@ class G1BuildCandidateRegionsTask : public WorkerTask { } void sort_by_gc_efficiency() { - if (_cur_claim_idx == 0) { + uint length = _cur_claim_idx.load_relaxed(); + if (length == 0) { return; } - for (uint i = _cur_claim_idx; i < _max_size; i++) { + for (uint i = length; i < _max_size; i++) { assert(_data[i] == nullptr, "must be"); } - qsort(_data, _cur_claim_idx, sizeof(_data[0]), (_sort_Fn)compare_region_gc_efficiency); - for (uint i = _cur_claim_idx; i < _max_size; i++) { + qsort(_data, length, sizeof(_data[0]), (_sort_Fn)compare_region_gc_efficiency); + for (uint i = length; i < _max_size; i++) { assert(_data[i] == nullptr, "must be"); } } From 42439eb60c4488711f182d0d6ee5165b4972b99d Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 20 Jan 2026 18:30:42 +0000 Subject: [PATCH 110/328] 8374889: C2 VectorAPI: must handle impossible combination of signed cast from float Reviewed-by: dlong, qamai --- src/hotspot/share/opto/graphKit.cpp | 23 +++-- src/hotspot/share/opto/graphKit.hpp | 2 + src/hotspot/share/opto/parse1.cpp | 3 +- src/hotspot/share/opto/vectorIntrinsics.cpp | 18 +++- .../vectorapi/TestCastShapeBadOpc.java | 91 +++++++++++++++++++ 5 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/TestCastShapeBadOpc.java diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 71ae8fe44a7..bc8ebaf1869 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -1489,8 +1489,7 @@ Node* GraphKit::must_be_not_null(Node* value, bool do_replace_in_map) { } Node *if_f = _gvn.transform(new IfFalseNode(iff)); Node *frame = _gvn.transform(new ParmNode(C->start(), TypeFunc::FramePtr)); - Node* halt = _gvn.transform(new HaltNode(if_f, frame, "unexpected null in intrinsic")); - C->root()->add_req(halt); + halt(if_f, frame, "unexpected null in intrinsic"); Node *if_t = _gvn.transform(new IfTrueNode(iff)); set_control(if_t); return cast_not_null(value, do_replace_in_map); @@ -2073,6 +2072,12 @@ void GraphKit::increment_counter(Node* counter_addr) { store_to_memory(ctrl, counter_addr, incr, T_LONG, MemNode::unordered); } +void GraphKit::halt(Node* ctrl, Node* frameptr, const char* reason, bool generate_code_in_product) { + Node* halt = new HaltNode(ctrl, frameptr, reason + PRODUCT_ONLY(COMMA generate_code_in_product)); + halt = _gvn.transform(halt); + root()->add_req(halt); +} //------------------------------uncommon_trap---------------------------------- // Bail out to the interpreter in mid-method. Implemented by calling the @@ -2195,11 +2200,15 @@ Node* GraphKit::uncommon_trap(int trap_request, // The debug info is the only real input to this call. // Halt-and-catch fire here. The above call should never return! - HaltNode* halt = new HaltNode(control(), frameptr(), "uncommon trap returned which should never happen" - PRODUCT_ONLY(COMMA /*reachable*/false)); - _gvn.set_type_bottom(halt); - root()->add_req(halt); - + // We only emit code for the HaltNode in debug, which is enough for + // verifying correctness. In product, we don't want to emit it so + // that we can save on code space. HaltNode often get folded because + // the compiler can prove that the unreachable path is dead. But we + // cannot generally expect that for uncommon traps, which are often + // reachable and occasionally taken. + halt(control(), frameptr(), + "uncommon trap returned which should never happen", + false /* don't emit code in product */); stop_and_kill_map(); return call; } diff --git a/src/hotspot/share/opto/graphKit.hpp b/src/hotspot/share/opto/graphKit.hpp index 56e9a949e6f..0537d31ae36 100644 --- a/src/hotspot/share/opto/graphKit.hpp +++ b/src/hotspot/share/opto/graphKit.hpp @@ -709,6 +709,8 @@ class GraphKit : public Phase { void increment_counter(address counter_addr); // increment a debug counter void increment_counter(Node* counter_addr); // increment a debug counter + void halt(Node* ctrl, Node* frameptr, const char* reason, bool generate_code_in_product = true); + // Bail out to the interpreter right now // The optional klass is the one causing the trap. // The optional reason is debug information written to the compile log. diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index 7aa96d2ace3..6122f7e7bfc 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -1229,8 +1229,7 @@ void Parse::do_method_entry() { Node* not_subtype_ctrl = gen_subtype_check(receiver_obj, holder_klass); assert(!stopped(), "not a subtype"); - Node* halt = _gvn.transform(new HaltNode(not_subtype_ctrl, frameptr(), "failed receiver subtype check")); - C->root()->add_req(halt); + halt(not_subtype_ctrl, frameptr(), "failed receiver subtype check"); } } #endif // ASSERT diff --git a/src/hotspot/share/opto/vectorIntrinsics.cpp b/src/hotspot/share/opto/vectorIntrinsics.cpp index b48b5f2cd05..6dcf4615b10 100644 --- a/src/hotspot/share/opto/vectorIntrinsics.cpp +++ b/src/hotspot/share/opto/vectorIntrinsics.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "ci/ciSymbols.hpp" #include "classfile/vmSymbols.hpp" #include "opto/library_call.hpp" +#include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/vectornode.hpp" #include "prims/vectorSupport.hpp" @@ -2330,6 +2331,21 @@ bool LibraryCallKit::inline_vector_convert() { Node* op = opd1; if (is_cast) { assert(!is_mask || num_elem_from == num_elem_to, "vector mask cast needs the same elem num"); + + // Make sure the precondition of VectorCastNode::opcode holds: we can only have + // unsigned casts for integral types (excluding long). VectorAPI code is not + // expected to violate this at runtime, but we may compile unreachable code + // where such impossible combinations arise. + if (is_ucast && (!is_integral_type(elem_bt_from) || elem_bt_from == T_LONG)) { + // Halt-and-catch fire here. This condition should never happen at runtime. + stringStream ss; + ss.print("impossible combination: unsigned vector cast from %s", type2name(elem_bt_from)); + halt(control(), frameptr(), ss.as_string(C->comp_arena())); + stop_and_kill_map(); + log_if_needed(" ** impossible combination: unsigned cast from %s", type2name(elem_bt_from)); + return true; + } + int cast_vopc = VectorCastNode::opcode(-1, elem_bt_from, !is_ucast); // Make sure that vector cast is implemented to particular type/size combination if it is diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestCastShapeBadOpc.java b/test/hotspot/jtreg/compiler/vectorapi/TestCastShapeBadOpc.java new file mode 100644 index 00000000000..4c20c84bc50 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestCastShapeBadOpc.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2026, 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=all-flags + * @bug 8374889 + * @summary Test case that can compile unexpected code paths in VectorAPI cast intrinsification. + * @modules jdk.incubator.vector + * @library /test/lib / + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:-TieredCompilation -Xbatch + * -XX:StressSeed=1462975402 + * -XX:+StressIncrementalInlining + * -XX:CompileCommand=compileonly,${test.main.class}::test2 + * ${test.main.class} + */ + +/* + * @test id=no-stress-seed + * @bug 8374889 + * @modules jdk.incubator.vector + * @library /test/lib / + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:-TieredCompilation -Xbatch + * -XX:+StressIncrementalInlining + * -XX:CompileCommand=compileonly,${test.main.class}::test2 + * ${test.main.class} + */ + +/* + * @test id=vanilla + * @bug 8374889 + * @modules jdk.incubator.vector + * @library /test/lib / + * @run driver ${test.main.class} + */ + +package compiler.vectorapi; + +import jdk.incubator.vector.*; + +public class TestCastShapeBadOpc { + public static void main(String[] args) { + for (int i = 0; i < 100_000; ++i) { + test1(); + test2(); + } + } + + // This code does not trigger the bug itself, but seems to be important for profiling, + // so that test2 fails. + public static Object test1() { + LongVector v0 = LongVector.broadcast(LongVector.SPECIES_512, -15L); + var v1 = (ByteVector)v0.convertShape(VectorOperators.Conversion.ofReinterpret(long.class, byte.class), ByteVector.SPECIES_128, 0); + var v2 = (ByteVector)v1.castShape(ByteVector.SPECIES_256, 0); + return v2; + } + + public static Object test2() { + var v0 = ShortVector.broadcast(ShortVector.SPECIES_64, (short)7729); + var v1 = (FloatVector)v0.reinterpretShape(FloatVector.SPECIES_64, 0); + // The castShape below should take the "C" path in AbstractVector::convert0, but sometimes + // we also compile the "Z" case because of profiling. This means we attempt to create + // a vector cast from float -> long, but unfortunately with a UCAST (float -> long is signed). + // This triggered an assert in VectorCastNode::opcode. + var v2 = (LongVector)v1.castShape(LongVector.SPECIES_256, 0); + return v2; + } +} From aaca0a2c1f3de06a1349ae9084e9e9dbec991421 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 20 Jan 2026 21:54:56 +0000 Subject: [PATCH 111/328] 8375742: Test java/lang/invoke/MethodHandleProxies/Driver.java does not run Unnamed.java Reviewed-by: jvernee --- test/jdk/java/lang/invoke/MethodHandleProxies/Driver.java | 6 +++--- test/jdk/java/lang/invoke/MethodHandleProxies/Unnamed.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/jdk/java/lang/invoke/MethodHandleProxies/Driver.java b/test/jdk/java/lang/invoke/MethodHandleProxies/Driver.java index 6acd4fb30e1..0e9c708e8e9 100644 --- a/test/jdk/java/lang/invoke/MethodHandleProxies/Driver.java +++ b/test/jdk/java/lang/invoke/MethodHandleProxies/Driver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, 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,12 +21,12 @@ * questions. */ -/** +/* * @test * @bug 8280377 * @build m1/* m2/* Unnamed * @run testng/othervm m1/p1.Main - * @run testng/othervm Unnamed + * @run main/othervm Unnamed * @summary Test MethodHandleProxies::asInterfaceInstance with a default * method with varargs */ diff --git a/test/jdk/java/lang/invoke/MethodHandleProxies/Unnamed.java b/test/jdk/java/lang/invoke/MethodHandleProxies/Unnamed.java index f42071f0427..f60f36ca9de 100644 --- a/test/jdk/java/lang/invoke/MethodHandleProxies/Unnamed.java +++ b/test/jdk/java/lang/invoke/MethodHandleProxies/Unnamed.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, 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 @@ -39,7 +39,7 @@ public class Unnamed { // verify that the caller has no access to the proxy created on an // inaccessible interface - Method m = intf.getMethod("test", Object[].class); - assertFalse(m.canAccess(null)); + Method m = intf.getMethod("test"); + assertFalse(m.canAccess(t)); } } From 4fd7595f1b607588d9854471a701c2992c6bec60 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 20 Jan 2026 22:45:39 +0000 Subject: [PATCH 112/328] 8374905: Clarify ZonedDateTime#toString() documentation regarding omitted zero seconds Reviewed-by: rriggs, bpb --- src/java.base/share/classes/java/time/ZonedDateTime.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/time/ZonedDateTime.java b/src/java.base/share/classes/java/time/ZonedDateTime.java index 57dc98d5c68..b1ffe7b87d6 100644 --- a/src/java.base/share/classes/java/time/ZonedDateTime.java +++ b/src/java.base/share/classes/java/time/ZonedDateTime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, 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 @@ -2207,7 +2207,10 @@ public final class ZonedDateTime * Outputs this date-time as a {@code String}, such as * {@code 2007-12-03T10:15:30+01:00[Europe/Paris]}. *

- * The format consists of the {@code LocalDateTime} followed by the {@code ZoneOffset}. + * The format consists of the output of {@link LocalDateTime#toString()}, + * followed by the output of {@link ZoneOffset#toString()}. + * If the time has zero seconds and/or nanoseconds, they are + * omitted to produce the shortest representation. * If the {@code ZoneId} is not the same as the offset, then the ID is output. * The output is compatible with ISO-8601 if the offset and ID are the same, * and the seconds in the offset are zero. From ca3e6236a28794156cc2acf697755229c47735a8 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Tue, 20 Jan 2026 23:48:42 +0000 Subject: [PATCH 113/328] 8375657: RISC-V: Need to check size in SharedRuntime::is_wide_vector Reviewed-by: fjiang, fyang --- src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index 44a6f6c0dc0..8c343f6ab2b 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -213,7 +213,7 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm) { // Is vector's size (in bytes) bigger than a size saved by default? // riscv does not ovlerlay the floating-point registers on vector registers like aarch64. bool SharedRuntime::is_wide_vector(int size) { - return UseRVV; + return UseRVV && size > 0; } // --------------------------------------------------------------------------- From a2e749572e03dd394d123b701e163e3837472dd0 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Wed, 21 Jan 2026 03:12:18 +0000 Subject: [PATCH 114/328] 8375063: Update Libpng to 1.6.54 Reviewed-by: serb, prr --- src/java.desktop/share/legal/libpng.md | 10 +- .../native/libsplashscreen/libpng/CHANGES | 27 + .../native/libsplashscreen/libpng/LICENSE | 4 +- .../native/libsplashscreen/libpng/README | 2 +- .../share/native/libsplashscreen/libpng/png.c | 21 +- .../share/native/libsplashscreen/libpng/png.h | 1121 ++++++++++------- .../native/libsplashscreen/libpng/pngconf.h | 4 +- .../native/libsplashscreen/libpng/pngerror.c | 17 +- .../native/libsplashscreen/libpng/pngget.c | 13 +- .../libsplashscreen/libpng/pnglibconf.h | 4 +- .../native/libsplashscreen/libpng/pngmem.c | 19 +- .../native/libsplashscreen/libpng/pngpriv.h | 921 ++++++++------ .../native/libsplashscreen/libpng/pngread.c | 188 +-- .../native/libsplashscreen/libpng/pngrtran.c | 5 +- .../native/libsplashscreen/libpng/pngrutil.c | 6 +- .../native/libsplashscreen/libpng/pngtrans.c | 4 +- 16 files changed, 1401 insertions(+), 965 deletions(-) diff --git a/src/java.desktop/share/legal/libpng.md b/src/java.desktop/share/legal/libpng.md index 8899491c6c0..80d12248ec4 100644 --- a/src/java.desktop/share/legal/libpng.md +++ b/src/java.desktop/share/legal/libpng.md @@ -1,4 +1,4 @@ -## libpng v1.6.51 +## libpng v1.6.54 ### libpng License

@@ -9,8 +9,8 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
 PNG Reference Library License version 2
 ---------------------------------------
 
-Copyright (C) 1995-2025 The PNG Reference Library Authors.
-Copyright (C) 2018-2025 Cosmin Truta
+Copyright (C) 1995-2026 The PNG Reference Library Authors.
+Copyright (C) 2018-2026 Cosmin Truta
 Copyright (C) 1998-2018 Glenn Randers-Pehrson
 Copyright (C) 1996-1997 Andreas Dilger
 Copyright (C) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -158,6 +158,7 @@ This is the list of PNG Reference Library ("libpng") Contributing
 Authors, for copyright and licensing purposes.
 
  * Adam Richter
+ * Alexander Smorkalov
  * Andreas Dilger
  * Chris Blume
  * Cosmin Truta
@@ -179,6 +180,7 @@ Authors, for copyright and licensing purposes.
  * Mike Klein
  * Pascal Massimino
  * Paul Schmidt
+ * Petr Simecek
  * Philippe Antoine
  * Qiang Zhou
  * Sam Bushell
@@ -209,6 +211,8 @@ Authors, for copyright and licensing purposes.
     - ZhangLixia (张利霞)
  * Samsung Group
     - Filip Wasil
+ * SpacemiT Hangzhou Technology, Co.
+    - Liang Junzhao (梁俊钊)
 
 The build projects, the build scripts, the test scripts, and other
 files in the "projects", "scripts" and "tests" directories, have
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
index 2478fd0fc08..3bb1baecd23 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
@@ -6304,6 +6304,33 @@ Version 1.6.51 [November 21, 2025]
   Added GitHub Actions workflows for automated testing.
   Performed various refactorings and cleanups.
 
+Version 1.6.52 [December 3, 2025]
+  Fixed CVE-2025-66293 (high severity):
+    Out-of-bounds read in `png_image_read_composite`.
+    (Reported by flyfish101 .)
+  Fixed the Paeth filter handling in the RISC-V RVV implementation.
+    (Reported by Filip Wasil; fixed by Liang Junzhao.)
+  Improved the performance of the RISC-V RVV implementation.
+    (Contributed by Liang Junzhao.)
+  Added allocation failure fuzzing to oss-fuzz.
+    (Contributed by Philippe Antoine.)
+
+Version 1.6.53 [December 5, 2025]
+  Fixed a build failure on RISC-V RVV caused by a misspelled intrinsic.
+    (Contributed by Alexander Smorkalov.)
+  Fixed a build failure with CMake 4.1 or newer, on Windows, when using
+    Visual C++ without MASM installed.
+
+Version 1.6.54 [January 12, 2026]
+  Fixed CVE-2026-22695 (medium severity):
+    Heap buffer over-read in `png_image_read_direct_scaled.
+    (Reported and fixed by Petr Simecek.)
+  Fixed CVE-2026-22801 (medium severity):
+    Integer truncation causing heap buffer over-read in `png_image_write_*`.
+  Implemented various improvements in oss-fuzz.
+    (Contributed by Philippe Antoine.)
+
+
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
 Subscription is required; visit
 https://lists.sourceforge.net/lists/listinfo/png-mng-implement
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/LICENSE b/src/java.desktop/share/native/libsplashscreen/libpng/LICENSE
index ea6df986cb6..1b765ae9f96 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/LICENSE
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/LICENSE
@@ -4,8 +4,8 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
 PNG Reference Library License version 2
 ---------------------------------------
 
- * Copyright (c) 1995-2025 The PNG Reference Library Authors.
- * Copyright (c) 2018-2025 Cosmin Truta.
+ * Copyright (c) 1995-2026 The PNG Reference Library Authors.
+ * Copyright (c) 2018-2026 Cosmin Truta.
  * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
  * Copyright (c) 1996-1997 Andreas Dilger.
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/README b/src/java.desktop/share/native/libsplashscreen/libpng/README
index 5ea329ee3da..63d1376edf7 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/README
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/README
@@ -1,4 +1,4 @@
-README for libpng version 1.6.51
+README for libpng version 1.6.54
 ================================
 
 See the note about version numbers near the top of `png.h`.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.c b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
index 7d85e7c8d5f..5636b4a754e 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/png.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2025 Cosmin Truta
+ * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -42,7 +42,7 @@
 #include "pngpriv.h"
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_51 Your_png_h_is_not_version_1_6_51;
+typedef png_libpng_version_1_6_54 Your_png_h_is_not_version_1_6_54;
 
 /* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the
  * corresponding macro definitions.  This causes a compile time failure if
@@ -130,7 +130,8 @@ png_sig_cmp(png_const_bytep sig, size_t start, size_t num_to_check)
 #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
 /* Function to allocate memory for zlib */
 PNG_FUNCTION(voidpf /* PRIVATE */,
-png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED)
+png_zalloc,(voidpf png_ptr, uInt items, uInt size),
+    PNG_ALLOCATED)
 {
    png_alloc_size_t num_bytes = size;
 
@@ -286,7 +287,8 @@ png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver)
 PNG_FUNCTION(png_structp /* PRIVATE */,
 png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
     png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
-    png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)
+    png_malloc_ptr malloc_fn, png_free_ptr free_fn),
+    PNG_ALLOCATED)
 {
    png_struct create_struct;
 #  ifdef PNG_SETJMP_SUPPORTED
@@ -390,7 +392,8 @@ png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
 
 /* Allocate the memory for an info_struct for the application. */
 PNG_FUNCTION(png_infop,PNGAPI
-png_create_info_struct,(png_const_structrp png_ptr),PNG_ALLOCATED)
+png_create_info_struct,(png_const_structrp png_ptr),
+    PNG_ALLOCATED)
 {
    png_inforp info_ptr;
 
@@ -846,8 +849,8 @@ png_get_copyright(png_const_structrp png_ptr)
    return PNG_STRING_COPYRIGHT
 #else
    return PNG_STRING_NEWLINE \
-      "libpng version 1.6.51" PNG_STRING_NEWLINE \
-      "Copyright (c) 2018-2025 Cosmin Truta" PNG_STRING_NEWLINE \
+      "libpng version 1.6.54" PNG_STRING_NEWLINE \
+      "Copyright (c) 2018-2026 Cosmin Truta" PNG_STRING_NEWLINE \
       "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
       PNG_STRING_NEWLINE \
       "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
@@ -2286,8 +2289,8 @@ PNG_FP_End:
 int
 png_check_fp_string(png_const_charp string, size_t size)
 {
-   int        state=0;
-   size_t char_index=0;
+   int state = 0;
+   size_t char_index = 0;
 
    if (png_check_fp_number(string, size, &state, &char_index) != 0 &&
       (char_index == size || string[char_index] == 0))
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.h b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
index d39ff73552c..ab8876a9626 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/png.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
@@ -29,9 +29,9 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * libpng version 1.6.51
+ * libpng version 1.6.54
  *
- * Copyright (c) 2018-2025 Cosmin Truta
+ * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -43,7 +43,7 @@
  *   libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
  *   libpng versions 0.97, January 1998, through 1.6.35, July 2018:
  *     Glenn Randers-Pehrson
- *   libpng versions 1.6.36, December 2018, through 1.6.51, November 2025:
+ *   libpng versions 1.6.36, December 2018, through 1.6.54, January 2026:
  *     Cosmin Truta
  *   See also "Contributing Authors", below.
  */
@@ -55,8 +55,8 @@
  * PNG Reference Library License version 2
  * ---------------------------------------
  *
- *  * Copyright (c) 1995-2025 The PNG Reference Library Authors.
- *  * Copyright (c) 2018-2025 Cosmin Truta.
+ *  * Copyright (c) 1995-2026 The PNG Reference Library Authors.
+ *  * Copyright (c) 2018-2026 Cosmin Truta.
  *  * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
  *  * Copyright (c) 1996-1997 Andreas Dilger.
  *  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -267,7 +267,7 @@
  *    ...
  *    1.5.30                  15    10530  15.so.15.30[.0]
  *    ...
- *    1.6.51                  16    10651  16.so.16.51[.0]
+ *    1.6.54                  16    10654  16.so.16.54[.0]
  *
  *    Henceforth the source version will match the shared-library major and
  *    minor numbers; the shared-library major version number will be used for
@@ -303,7 +303,7 @@
  */
 
 /* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.51"
+#define PNG_LIBPNG_VER_STRING "1.6.54"
 #define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n"
 
 /* The versions of shared library builds should stay in sync, going forward */
@@ -314,7 +314,7 @@
 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
 #define PNG_LIBPNG_VER_MAJOR   1
 #define PNG_LIBPNG_VER_MINOR   6
-#define PNG_LIBPNG_VER_RELEASE 51
+#define PNG_LIBPNG_VER_RELEASE 54
 
 /* This should be zero for a public release, or non-zero for a
  * development version.
@@ -345,7 +345,7 @@
  * From version 1.0.1 it is:
  * XXYYZZ, where XX=major, YY=minor, ZZ=release
  */
-#define PNG_LIBPNG_VER 10651 /* 1.6.51 */
+#define PNG_LIBPNG_VER 10654 /* 1.6.54 */
 
 /* Library configuration: these options cannot be changed after
  * the library has been built.
@@ -455,7 +455,7 @@ extern "C" {
 /* This triggers a compiler error in png.c, if png.c and png.h
  * do not agree upon the version number.
  */
-typedef char* png_libpng_version_1_6_51;
+typedef char *png_libpng_version_1_6_54;
 
 /* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
  *
@@ -814,17 +814,22 @@ typedef png_row_info * * png_row_infopp;
  * modify the buffer it is passed. The 'read' function, on the other hand, is
  * expected to return the read data in the buffer.
  */
-typedef PNG_CALLBACK(void, *png_error_ptr, (png_structp, png_const_charp));
-typedef PNG_CALLBACK(void, *png_rw_ptr, (png_structp, png_bytep, size_t));
-typedef PNG_CALLBACK(void, *png_flush_ptr, (png_structp));
-typedef PNG_CALLBACK(void, *png_read_status_ptr, (png_structp, png_uint_32,
-    int));
-typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32,
-    int));
+typedef PNG_CALLBACK(void, *png_error_ptr,
+   (png_structp, png_const_charp));
+typedef PNG_CALLBACK(void, *png_rw_ptr,
+   (png_structp, png_bytep, size_t));
+typedef PNG_CALLBACK(void, *png_flush_ptr,
+   (png_structp));
+typedef PNG_CALLBACK(void, *png_read_status_ptr,
+   (png_structp, png_uint_32, int));
+typedef PNG_CALLBACK(void, *png_write_status_ptr,
+   (png_structp, png_uint_32, int));
 
 #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
-typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
+typedef PNG_CALLBACK(void, *png_progressive_info_ptr,
+   (png_structp, png_infop));
+typedef PNG_CALLBACK(void, *png_progressive_end_ptr,
+   (png_structp, png_infop));
 
 /* The following callback receives png_uint_32 row_number, int pass for the
  * png_bytep data of the row.  When transforming an interlaced image the
@@ -836,19 +841,19 @@ typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
  * find the output pixel (x,y) given an interlaced sub-image pixel
  * (row,col,pass).  (See below for these macros.)
  */
-typedef PNG_CALLBACK(void, *png_progressive_row_ptr, (png_structp, png_bytep,
-    png_uint_32, int));
+typedef PNG_CALLBACK(void, *png_progressive_row_ptr,
+   (png_structp, png_bytep, png_uint_32, int));
 #endif
 
 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
     defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
-typedef PNG_CALLBACK(void, *png_user_transform_ptr, (png_structp, png_row_infop,
-    png_bytep));
+typedef PNG_CALLBACK(void, *png_user_transform_ptr,
+   (png_structp, png_row_infop, png_bytep));
 #endif
 
 #ifdef PNG_USER_CHUNKS_SUPPORTED
-typedef PNG_CALLBACK(int, *png_user_chunk_ptr, (png_structp,
-    png_unknown_chunkp));
+typedef PNG_CALLBACK(int, *png_user_chunk_ptr,
+   (png_structp, png_unknown_chunkp));
 #endif
 #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
 /* not used anywhere */
@@ -906,9 +911,10 @@ PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), (jmp_buf, int), typedef);
  * ignores the first argument) should be completely compatible with the
  * following.
  */
-typedef PNG_CALLBACK(png_voidp, *png_malloc_ptr, (png_structp,
-    png_alloc_size_t));
-typedef PNG_CALLBACK(void, *png_free_ptr, (png_structp, png_voidp));
+typedef PNG_CALLBACK(png_voidp, *png_malloc_ptr,
+   (png_structp, png_alloc_size_t));
+typedef PNG_CALLBACK(void, *png_free_ptr,
+   (png_structp, png_voidp));
 
 /* Section 4: exported functions
  * Here are the function definitions most commonly used.  This is not
@@ -940,20 +946,22 @@ typedef PNG_CALLBACK(void, *png_free_ptr, (png_structp, png_voidp));
  */
 
 /* Returns the version number of the library */
-PNG_EXPORT(1, png_uint_32, png_access_version_number, (void));
+PNG_EXPORT(1, png_uint_32, png_access_version_number,
+   (void));
 
 /* Tell lib we have already handled the first  magic bytes.
  * Handling more than 8 bytes from the beginning of the file is an error.
  */
-PNG_EXPORT(2, void, png_set_sig_bytes, (png_structrp png_ptr, int num_bytes));
+PNG_EXPORT(2, void, png_set_sig_bytes,
+   (png_structrp png_ptr, int num_bytes));
 
 /* Check sig[start] through sig[start + num_to_check - 1] to see if it's a
  * PNG file.  Returns zero if the supplied bytes match the 8-byte PNG
  * signature, and non-zero otherwise.  Having num_to_check == 0 or
  * start > 7 will always fail (i.e. return non-zero).
  */
-PNG_EXPORT(3, int, png_sig_cmp, (png_const_bytep sig, size_t start,
-    size_t num_to_check));
+PNG_EXPORT(3, int, png_sig_cmp,
+   (png_const_bytep sig, size_t start, size_t num_to_check));
 
 /* Simple signature checking function.  This is the same as calling
  * png_check_sig(sig, n) := (png_sig_cmp(sig, 0, n) == 0).
@@ -962,21 +970,21 @@ PNG_EXPORT(3, int, png_sig_cmp, (png_const_bytep sig, size_t start,
 
 /* Allocate and initialize png_ptr struct for reading, and any other memory. */
 PNG_EXPORTA(4, png_structp, png_create_read_struct,
-    (png_const_charp user_png_ver, png_voidp error_ptr,
-    png_error_ptr error_fn, png_error_ptr warn_fn),
-    PNG_ALLOCATED);
+   (png_const_charp user_png_ver,
+    png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn),
+   PNG_ALLOCATED);
 
 /* Allocate and initialize png_ptr struct for writing, and any other memory */
 PNG_EXPORTA(5, png_structp, png_create_write_struct,
-    (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,
-    png_error_ptr warn_fn),
-    PNG_ALLOCATED);
+   (png_const_charp user_png_ver,
+    png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn),
+   PNG_ALLOCATED);
 
 PNG_EXPORT(6, size_t, png_get_compression_buffer_size,
-    (png_const_structrp png_ptr));
+   (png_const_structrp png_ptr));
 
-PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structrp png_ptr,
-    size_t size));
+PNG_EXPORT(7, void, png_set_compression_buffer_size,
+   (png_structrp png_ptr, size_t size));
 
 /* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp
  * match up.
@@ -989,8 +997,8 @@ PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structrp png_ptr,
  * allocated by the library - the call will return NULL on a mismatch
  * indicating an ABI mismatch.
  */
-PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structrp png_ptr,
-    png_longjmp_ptr longjmp_fn, size_t jmp_buf_size));
+PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn,
+   (png_structrp png_ptr, png_longjmp_ptr longjmp_fn, size_t jmp_buf_size));
 #  define png_jmpbuf(png_ptr) \
       (*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf))))
 #else
@@ -1002,67 +1010,77 @@ PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structrp png_ptr,
  * will use it; otherwise it will call PNG_ABORT().  This function was
  * added in libpng-1.5.0.
  */
-PNG_EXPORTA(9, void, png_longjmp, (png_const_structrp png_ptr, int val),
-    PNG_NORETURN);
+PNG_EXPORTA(9, void, png_longjmp,
+   (png_const_structrp png_ptr, int val),
+   PNG_NORETURN);
 
 #ifdef PNG_READ_SUPPORTED
 /* Reset the compression stream */
-PNG_EXPORTA(10, int, png_reset_zstream, (png_structrp png_ptr), PNG_DEPRECATED);
+PNG_EXPORTA(10, int, png_reset_zstream,
+   (png_structrp png_ptr),
+   PNG_DEPRECATED);
 #endif
 
 /* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */
 #ifdef PNG_USER_MEM_SUPPORTED
 PNG_EXPORTA(11, png_structp, png_create_read_struct_2,
-    (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,
-    png_error_ptr warn_fn,
+   (png_const_charp user_png_ver,
+    png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn,
     png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),
-    PNG_ALLOCATED);
+   PNG_ALLOCATED);
 PNG_EXPORTA(12, png_structp, png_create_write_struct_2,
-    (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,
-    png_error_ptr warn_fn,
+   (png_const_charp user_png_ver,
+    png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn,
     png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),
-    PNG_ALLOCATED);
+   PNG_ALLOCATED);
 #endif
 
 /* Write the PNG file signature. */
-PNG_EXPORT(13, void, png_write_sig, (png_structrp png_ptr));
+PNG_EXPORT(13, void, png_write_sig,
+   (png_structrp png_ptr));
 
 /* Write a PNG chunk - size, type, (optional) data, CRC. */
-PNG_EXPORT(14, void, png_write_chunk, (png_structrp png_ptr, png_const_bytep
-    chunk_name, png_const_bytep data, size_t length));
+PNG_EXPORT(14, void, png_write_chunk,
+   (png_structrp png_ptr,
+    png_const_bytep chunk_name, png_const_bytep data, size_t length));
 
 /* Write the start of a PNG chunk - length and chunk name. */
-PNG_EXPORT(15, void, png_write_chunk_start, (png_structrp png_ptr,
+PNG_EXPORT(15, void, png_write_chunk_start,
+   (png_structrp png_ptr,
     png_const_bytep chunk_name, png_uint_32 length));
 
 /* Write the data of a PNG chunk started with png_write_chunk_start(). */
-PNG_EXPORT(16, void, png_write_chunk_data, (png_structrp png_ptr,
+PNG_EXPORT(16, void, png_write_chunk_data,
+   (png_structrp png_ptr,
     png_const_bytep data, size_t length));
 
 /* Finish a chunk started with png_write_chunk_start() (includes CRC). */
-PNG_EXPORT(17, void, png_write_chunk_end, (png_structrp png_ptr));
+PNG_EXPORT(17, void, png_write_chunk_end,
+   (png_structrp png_ptr));
 
 /* Allocate and initialize the info structure */
-PNG_EXPORTA(18, png_infop, png_create_info_struct, (png_const_structrp png_ptr),
-    PNG_ALLOCATED);
+PNG_EXPORTA(18, png_infop, png_create_info_struct,
+   (png_const_structrp png_ptr),
+   PNG_ALLOCATED);
 
 /* DEPRECATED: this function allowed init structures to be created using the
  * default allocation method (typically malloc).  Use is deprecated in 1.6.0 and
  * the API will be removed in the future.
  */
-PNG_EXPORTA(19, void, png_info_init_3, (png_infopp info_ptr,
-    size_t png_info_struct_size), PNG_DEPRECATED);
+PNG_EXPORTA(19, void, png_info_init_3,
+   (png_infopp info_ptr, size_t png_info_struct_size),
+   PNG_DEPRECATED);
 
 /* Writes all the PNG information before the image. */
 PNG_EXPORT(20, void, png_write_info_before_PLTE,
-    (png_structrp png_ptr, png_const_inforp info_ptr));
+   (png_structrp png_ptr, png_const_inforp info_ptr));
 PNG_EXPORT(21, void, png_write_info,
-    (png_structrp png_ptr, png_const_inforp info_ptr));
+   (png_structrp png_ptr, png_const_inforp info_ptr));
 
 #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
 /* Read the information before the actual image data. */
 PNG_EXPORT(22, void, png_read_info,
-    (png_structrp png_ptr, png_inforp info_ptr));
+   (png_structrp png_ptr, png_inforp info_ptr));
 #endif
 
 #ifdef PNG_TIME_RFC1123_SUPPORTED
@@ -1072,45 +1090,54 @@ PNG_EXPORT(22, void, png_read_info,
     */
 #if PNG_LIBPNG_VER < 10700
 /* To do: remove this from libpng17 (and from libpng17/png.c and pngstruct.h) */
-PNG_EXPORTA(23, png_const_charp, png_convert_to_rfc1123, (png_structrp png_ptr,
-    png_const_timep ptime),PNG_DEPRECATED);
+PNG_EXPORTA(23, png_const_charp, png_convert_to_rfc1123,
+   (png_structrp png_ptr, png_const_timep ptime),
+   PNG_DEPRECATED);
 #endif
-PNG_EXPORT(241, int, png_convert_to_rfc1123_buffer, (char out[29],
-    png_const_timep ptime));
+PNG_EXPORT(241, int, png_convert_to_rfc1123_buffer,
+   (char out[29], png_const_timep ptime));
 #endif
 
 #ifdef PNG_CONVERT_tIME_SUPPORTED
 /* Convert from a struct tm to png_time */
-PNG_EXPORT(24, void, png_convert_from_struct_tm, (png_timep ptime,
-    const struct tm * ttime));
+PNG_EXPORT(24, void, png_convert_from_struct_tm,
+   (png_timep ptime, const struct tm * ttime));
 
 /* Convert from time_t to png_time.  Uses gmtime() */
-PNG_EXPORT(25, void, png_convert_from_time_t, (png_timep ptime, time_t ttime));
+PNG_EXPORT(25, void, png_convert_from_time_t,
+   (png_timep ptime, time_t ttime));
 #endif /* CONVERT_tIME */
 
 #ifdef PNG_READ_EXPAND_SUPPORTED
 /* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */
-PNG_EXPORT(26, void, png_set_expand, (png_structrp png_ptr));
-PNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8, (png_structrp png_ptr));
-PNG_EXPORT(28, void, png_set_palette_to_rgb, (png_structrp png_ptr));
-PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structrp png_ptr));
+PNG_EXPORT(26, void, png_set_expand,
+   (png_structrp png_ptr));
+PNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8,
+   (png_structrp png_ptr));
+PNG_EXPORT(28, void, png_set_palette_to_rgb,
+   (png_structrp png_ptr));
+PNG_EXPORT(29, void, png_set_tRNS_to_alpha,
+   (png_structrp png_ptr));
 #endif
 
 #ifdef PNG_READ_EXPAND_16_SUPPORTED
 /* Expand to 16-bit channels, forces conversion of palette to RGB and expansion
  * of a tRNS chunk if present.
  */
-PNG_EXPORT(221, void, png_set_expand_16, (png_structrp png_ptr));
+PNG_EXPORT(221, void, png_set_expand_16,
+   (png_structrp png_ptr));
 #endif
 
 #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
 /* Use blue, green, red order for pixels. */
-PNG_EXPORT(30, void, png_set_bgr, (png_structrp png_ptr));
+PNG_EXPORT(30, void, png_set_bgr,
+   (png_structrp png_ptr));
 #endif
 
 #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
 /* Expand the grayscale to 24-bit RGB if necessary. */
-PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structrp png_ptr));
+PNG_EXPORT(31, void, png_set_gray_to_rgb,
+   (png_structrp png_ptr));
 #endif
 
 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
@@ -1120,18 +1147,20 @@ PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structrp png_ptr));
 #define PNG_ERROR_ACTION_ERROR 3
 #define PNG_RGB_TO_GRAY_DEFAULT (-1)/*for red/green coefficients*/
 
-PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structrp png_ptr,
+PNG_FP_EXPORT(32, void, png_set_rgb_to_gray,
+   (png_structrp png_ptr,
     int error_action, double red, double green))
-PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structrp png_ptr,
+PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed,
+   (png_structrp png_ptr,
     int error_action, png_fixed_point red, png_fixed_point green))
 
-PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structrp
-    png_ptr));
+PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status,
+   (png_const_structrp png_ptr));
 #endif
 
 #ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
-PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth,
-    png_colorp palette));
+PNG_EXPORT(35, void, png_build_grayscale_palette,
+   (int bit_depth, png_colorp palette));
 #endif
 
 #ifdef PNG_READ_ALPHA_MODE_SUPPORTED
@@ -1176,10 +1205,10 @@ PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth,
 #define PNG_ALPHA_OPTIMIZED     2 /* 'PNG' for opaque pixels, else 'STANDARD' */
 #define PNG_ALPHA_BROKEN        3 /* the alpha channel is gamma encoded */
 
-PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structrp png_ptr, int mode,
-    double output_gamma))
-PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structrp png_ptr,
-    int mode, png_fixed_point output_gamma))
+PNG_FP_EXPORT(227, void, png_set_alpha_mode,
+   (png_structrp png_ptr, int mode, double output_gamma))
+PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed,
+   (png_structrp png_ptr, int mode, png_fixed_point output_gamma))
 #endif
 
 #if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED)
@@ -1269,51 +1298,57 @@ PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structrp png_ptr,
  */
 
 #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
-PNG_EXPORT(36, void, png_set_strip_alpha, (png_structrp png_ptr));
+PNG_EXPORT(36, void, png_set_strip_alpha,
+   (png_structrp png_ptr));
 #endif
 
 #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
     defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
-PNG_EXPORT(37, void, png_set_swap_alpha, (png_structrp png_ptr));
+PNG_EXPORT(37, void, png_set_swap_alpha,
+   (png_structrp png_ptr));
 #endif
 
 #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \
     defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
-PNG_EXPORT(38, void, png_set_invert_alpha, (png_structrp png_ptr));
+PNG_EXPORT(38, void, png_set_invert_alpha,
+   (png_structrp png_ptr));
 #endif
 
 #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
 /* Add a filler byte to 8-bit or 16-bit Gray or 24-bit or 48-bit RGB images. */
-PNG_EXPORT(39, void, png_set_filler, (png_structrp png_ptr, png_uint_32 filler,
-    int flags));
+PNG_EXPORT(39, void, png_set_filler,
+   (png_structrp png_ptr, png_uint_32 filler, int flags));
 /* The values of the PNG_FILLER_ defines should NOT be changed */
 #  define PNG_FILLER_BEFORE 0
 #  define PNG_FILLER_AFTER 1
 /* Add an alpha byte to 8-bit or 16-bit Gray or 24-bit or 48-bit RGB images. */
-PNG_EXPORT(40, void, png_set_add_alpha, (png_structrp png_ptr,
-    png_uint_32 filler, int flags));
+PNG_EXPORT(40, void, png_set_add_alpha,
+   (png_structrp png_ptr, png_uint_32 filler, int flags));
 #endif /* READ_FILLER || WRITE_FILLER */
 
 #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
 /* Swap bytes in 16-bit depth files. */
-PNG_EXPORT(41, void, png_set_swap, (png_structrp png_ptr));
+PNG_EXPORT(41, void, png_set_swap,
+   (png_structrp png_ptr));
 #endif
 
 #if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
 /* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */
-PNG_EXPORT(42, void, png_set_packing, (png_structrp png_ptr));
+PNG_EXPORT(42, void, png_set_packing,
+   (png_structrp png_ptr));
 #endif
 
 #if defined(PNG_READ_PACKSWAP_SUPPORTED) || \
     defined(PNG_WRITE_PACKSWAP_SUPPORTED)
 /* Swap packing order of pixels in bytes. */
-PNG_EXPORT(43, void, png_set_packswap, (png_structrp png_ptr));
+PNG_EXPORT(43, void, png_set_packswap,
+   (png_structrp png_ptr));
 #endif
 
 #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
 /* Converts files to legal bit depths. */
-PNG_EXPORT(44, void, png_set_shift, (png_structrp png_ptr, png_const_color_8p
-    true_bits));
+PNG_EXPORT(44, void, png_set_shift,
+   (png_structrp png_ptr, png_const_color_8p true_bits));
 #endif
 
 #if defined(PNG_READ_INTERLACING_SUPPORTED) || \
@@ -1324,12 +1359,14 @@ PNG_EXPORT(44, void, png_set_shift, (png_structrp png_ptr, png_const_color_8p
  * necessary to call png_read_row or png_read_rows png_get_image_height
  * times for each pass.
 */
-PNG_EXPORT(45, int, png_set_interlace_handling, (png_structrp png_ptr));
+PNG_EXPORT(45, int, png_set_interlace_handling,
+   (png_structrp png_ptr));
 #endif
 
 #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
 /* Invert monochrome files */
-PNG_EXPORT(46, void, png_set_invert_mono, (png_structrp png_ptr));
+PNG_EXPORT(46, void, png_set_invert_mono,
+   (png_structrp png_ptr));
 #endif
 
 #ifdef PNG_READ_BACKGROUND_SUPPORTED
@@ -1338,10 +1375,12 @@ PNG_EXPORT(46, void, png_set_invert_mono, (png_structrp png_ptr));
  * read.  Doing so will result in unexpected behavior and possible warnings or
  * errors if the PNG file contains a bKGD chunk.
  */
-PNG_FP_EXPORT(47, void, png_set_background, (png_structrp png_ptr,
+PNG_FP_EXPORT(47, void, png_set_background,
+   (png_structrp png_ptr,
     png_const_color_16p background_color, int background_gamma_code,
     int need_expand, double background_gamma))
-PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structrp png_ptr,
+PNG_FIXED_EXPORT(215, void, png_set_background_fixed,
+   (png_structrp png_ptr,
     png_const_color_16p background_color, int background_gamma_code,
     int need_expand, png_fixed_point background_gamma))
 #endif
@@ -1354,20 +1393,23 @@ PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structrp png_ptr,
 
 #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
 /* Scale a 16-bit depth file down to 8-bit, accurately. */
-PNG_EXPORT(229, void, png_set_scale_16, (png_structrp png_ptr));
+PNG_EXPORT(229, void, png_set_scale_16,
+   (png_structrp png_ptr));
 #endif
 
 #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
 #define PNG_READ_16_TO_8_SUPPORTED /* Name prior to 1.5.4 */
 /* Strip the second byte of information from a 16-bit depth file. */
-PNG_EXPORT(48, void, png_set_strip_16, (png_structrp png_ptr));
+PNG_EXPORT(48, void, png_set_strip_16,
+   (png_structrp png_ptr));
 #endif
 
 #ifdef PNG_READ_QUANTIZE_SUPPORTED
 /* Turn on quantizing, and reduce the palette to the number of colors
  * available.
  */
-PNG_EXPORT(49, void, png_set_quantize, (png_structrp png_ptr,
+PNG_EXPORT(49, void, png_set_quantize,
+   (png_structrp png_ptr,
     png_colorp palette, int num_palette, int maximum_colors,
     png_const_uint_16p histogram, int full_quantize));
 #endif
@@ -1389,82 +1431,92 @@ PNG_EXPORT(49, void, png_set_quantize, (png_structrp png_ptr,
  * API (floating point or fixed.)  Notice, however, that the 'file_gamma' value
  * is the inverse of a 'screen gamma' value.
  */
-PNG_FP_EXPORT(50, void, png_set_gamma, (png_structrp png_ptr,
+PNG_FP_EXPORT(50, void, png_set_gamma,
+   (png_structrp png_ptr,
     double screen_gamma, double override_file_gamma))
-PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structrp png_ptr,
+PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed,
+   (png_structrp png_ptr,
     png_fixed_point screen_gamma, png_fixed_point override_file_gamma))
 #endif
 
 #ifdef PNG_WRITE_FLUSH_SUPPORTED
 /* Set how many lines between output flushes - 0 for no flushing */
-PNG_EXPORT(51, void, png_set_flush, (png_structrp png_ptr, int nrows));
+PNG_EXPORT(51, void, png_set_flush,
+   (png_structrp png_ptr, int nrows));
 /* Flush the current PNG output buffer */
-PNG_EXPORT(52, void, png_write_flush, (png_structrp png_ptr));
+PNG_EXPORT(52, void, png_write_flush,
+   (png_structrp png_ptr));
 #endif
 
 /* Optional update palette with requested transformations */
-PNG_EXPORT(53, void, png_start_read_image, (png_structrp png_ptr));
+PNG_EXPORT(53, void, png_start_read_image,
+   (png_structrp png_ptr));
 
 /* Optional call to update the users info structure */
-PNG_EXPORT(54, void, png_read_update_info, (png_structrp png_ptr,
-    png_inforp info_ptr));
+PNG_EXPORT(54, void, png_read_update_info,
+   (png_structrp png_ptr, png_inforp info_ptr));
 
 #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
 /* Read one or more rows of image data. */
-PNG_EXPORT(55, void, png_read_rows, (png_structrp png_ptr, png_bytepp row,
+PNG_EXPORT(55, void, png_read_rows,
+   (png_structrp png_ptr, png_bytepp row,
     png_bytepp display_row, png_uint_32 num_rows));
 #endif
 
 #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
 /* Read a row of data. */
-PNG_EXPORT(56, void, png_read_row, (png_structrp png_ptr, png_bytep row,
-    png_bytep display_row));
+PNG_EXPORT(56, void, png_read_row,
+   (png_structrp png_ptr, png_bytep row, png_bytep display_row));
 #endif
 
 #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
 /* Read the whole image into memory at once. */
-PNG_EXPORT(57, void, png_read_image, (png_structrp png_ptr, png_bytepp image));
+PNG_EXPORT(57, void, png_read_image,
+   (png_structrp png_ptr, png_bytepp image));
 #endif
 
 /* Write a row of image data */
-PNG_EXPORT(58, void, png_write_row, (png_structrp png_ptr,
-    png_const_bytep row));
+PNG_EXPORT(58, void, png_write_row,
+   (png_structrp png_ptr, png_const_bytep row));
 
 /* Write a few rows of image data: (*row) is not written; however, the type
  * is declared as writeable to maintain compatibility with previous versions
  * of libpng and to allow the 'display_row' array from read_rows to be passed
  * unchanged to write_rows.
  */
-PNG_EXPORT(59, void, png_write_rows, (png_structrp png_ptr, png_bytepp row,
-    png_uint_32 num_rows));
+PNG_EXPORT(59, void, png_write_rows,
+   (png_structrp png_ptr, png_bytepp row, png_uint_32 num_rows));
 
 /* Write the image data */
-PNG_EXPORT(60, void, png_write_image, (png_structrp png_ptr, png_bytepp image));
+PNG_EXPORT(60, void, png_write_image,
+   (png_structrp png_ptr, png_bytepp image));
 
 /* Write the end of the PNG file. */
-PNG_EXPORT(61, void, png_write_end, (png_structrp png_ptr,
-    png_inforp info_ptr));
+PNG_EXPORT(61, void, png_write_end,
+   (png_structrp png_ptr, png_inforp info_ptr));
 
 #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
 /* Read the end of the PNG file. */
-PNG_EXPORT(62, void, png_read_end, (png_structrp png_ptr, png_inforp info_ptr));
+PNG_EXPORT(62, void, png_read_end,
+   (png_structrp png_ptr, png_inforp info_ptr));
 #endif
 
 /* Free any memory associated with the png_info_struct */
-PNG_EXPORT(63, void, png_destroy_info_struct, (png_const_structrp png_ptr,
-    png_infopp info_ptr_ptr));
+PNG_EXPORT(63, void, png_destroy_info_struct,
+   (png_const_structrp png_ptr, png_infopp info_ptr_ptr));
 
 /* Free any memory associated with the png_struct and the png_info_structs */
-PNG_EXPORT(64, void, png_destroy_read_struct, (png_structpp png_ptr_ptr,
+PNG_EXPORT(64, void, png_destroy_read_struct,
+   (png_structpp png_ptr_ptr,
     png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr));
 
 /* Free any memory associated with the png_struct and the png_info_structs */
-PNG_EXPORT(65, void, png_destroy_write_struct, (png_structpp png_ptr_ptr,
-    png_infopp info_ptr_ptr));
+PNG_EXPORT(65, void, png_destroy_write_struct,
+   (png_structpp png_ptr_ptr, png_infopp info_ptr_ptr));
 
 /* Set the libpng method of handling chunk CRC errors */
-PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action,
-    int ancil_action));
+PNG_EXPORT(66, void, png_set_crc_action,
+   (png_structrp png_ptr, int crit_action, int ancil_action));
 
 /* Values for png_set_crc_action() say how to handle CRC errors in
  * ancillary and critical chunks, and whether to use the data contained
@@ -1494,8 +1546,8 @@ PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action,
 /* Set the filtering method(s) used by libpng.  Currently, the only valid
  * value for "method" is 0.
  */
-PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method,
-    int filters));
+PNG_EXPORT(67, void, png_set_filter,
+   (png_structrp png_ptr, int method, int filters));
 #endif /* WRITE */
 
 /* Flags for png_set_filter() to say which filters to use.  The flags
@@ -1524,11 +1576,14 @@ PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method,
 
 #ifdef PNG_WRITE_SUPPORTED
 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */
-PNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structrp png_ptr,
-    int heuristic_method, int num_weights, png_const_doublep filter_weights,
+PNG_FP_EXPORT(68, void, png_set_filter_heuristics,
+   (png_structrp png_ptr,
+    int heuristic_method, int num_weights,
+    png_const_doublep filter_weights,
     png_const_doublep filter_costs))
 PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed,
-    (png_structrp png_ptr, int heuristic_method, int num_weights,
+   (png_structrp png_ptr,
+    int heuristic_method, int num_weights,
     png_const_fixed_point_p filter_weights,
     png_const_fixed_point_p filter_costs))
 #endif /* WRITE_WEIGHTED_FILTER */
@@ -1547,44 +1602,44 @@ PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed,
  * these values may not correspond directly to the zlib compression levels.
  */
 #ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
-PNG_EXPORT(69, void, png_set_compression_level, (png_structrp png_ptr,
-    int level));
+PNG_EXPORT(69, void, png_set_compression_level,
+   (png_structrp png_ptr, int level));
 
-PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structrp png_ptr,
-    int mem_level));
+PNG_EXPORT(70, void, png_set_compression_mem_level,
+   (png_structrp png_ptr, int mem_level));
 
-PNG_EXPORT(71, void, png_set_compression_strategy, (png_structrp png_ptr,
-    int strategy));
+PNG_EXPORT(71, void, png_set_compression_strategy,
+   (png_structrp png_ptr, int strategy));
 
 /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
  * smaller value of window_bits if it can do so safely.
  */
-PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structrp png_ptr,
-    int window_bits));
+PNG_EXPORT(72, void, png_set_compression_window_bits,
+   (png_structrp png_ptr, int window_bits));
 
-PNG_EXPORT(73, void, png_set_compression_method, (png_structrp png_ptr,
-    int method));
+PNG_EXPORT(73, void, png_set_compression_method,
+   (png_structrp png_ptr, int method));
 #endif /* WRITE_CUSTOMIZE_COMPRESSION */
 
 #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
 /* Also set zlib parameters for compressing non-IDAT chunks */
-PNG_EXPORT(222, void, png_set_text_compression_level, (png_structrp png_ptr,
-    int level));
+PNG_EXPORT(222, void, png_set_text_compression_level,
+   (png_structrp png_ptr, int level));
 
-PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structrp png_ptr,
-    int mem_level));
+PNG_EXPORT(223, void, png_set_text_compression_mem_level,
+   (png_structrp png_ptr, int mem_level));
 
-PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structrp png_ptr,
-    int strategy));
+PNG_EXPORT(224, void, png_set_text_compression_strategy,
+   (png_structrp png_ptr, int strategy));
 
 /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
  * smaller value of window_bits if it can do so safely.
  */
 PNG_EXPORT(225, void, png_set_text_compression_window_bits,
-    (png_structrp png_ptr, int window_bits));
+   (png_structrp png_ptr, int window_bits));
 
-PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr,
-    int method));
+PNG_EXPORT(226, void, png_set_text_compression_method,
+   (png_structrp png_ptr, int method));
 #endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */
 #endif /* WRITE */
 
@@ -1599,7 +1654,8 @@ PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr,
 
 #ifdef PNG_STDIO_SUPPORTED
 /* Initialize the input/output for the PNG file to the default functions. */
-PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, FILE *fp));
+PNG_EXPORT(74, void, png_init_io,
+   (png_structrp png_ptr, FILE *fp));
 #endif
 
 /* Replace the (error and abort), and warning functions with user
@@ -1610,11 +1666,13 @@ PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, FILE *fp));
  * default function will be used.
  */
 
-PNG_EXPORT(75, void, png_set_error_fn, (png_structrp png_ptr,
+PNG_EXPORT(75, void, png_set_error_fn,
+   (png_structrp png_ptr,
     png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn));
 
 /* Return the user pointer associated with the error functions */
-PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structrp png_ptr));
+PNG_EXPORT(76, png_voidp, png_get_error_ptr,
+   (png_const_structrp png_ptr));
 
 /* Replace the default data output functions with a user supplied one(s).
  * If buffered output is not used, then output_flush_fn can be set to NULL.
@@ -1626,47 +1684,54 @@ PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structrp png_ptr));
  * default flush function, which uses the standard *FILE structure, will
  * be used.
  */
-PNG_EXPORT(77, void, png_set_write_fn, (png_structrp png_ptr, png_voidp io_ptr,
+PNG_EXPORT(77, void, png_set_write_fn,
+   (png_structrp png_ptr,
+    png_voidp io_ptr,
     png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn));
 
 /* Replace the default data input function with a user supplied one. */
-PNG_EXPORT(78, void, png_set_read_fn, (png_structrp png_ptr, png_voidp io_ptr,
-    png_rw_ptr read_data_fn));
+PNG_EXPORT(78, void, png_set_read_fn,
+   (png_structrp png_ptr,
+    png_voidp io_ptr, png_rw_ptr read_data_fn));
 
 /* Return the user pointer associated with the I/O functions */
-PNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_const_structrp png_ptr));
+PNG_EXPORT(79, png_voidp, png_get_io_ptr,
+   (png_const_structrp png_ptr));
 
-PNG_EXPORT(80, void, png_set_read_status_fn, (png_structrp png_ptr,
-    png_read_status_ptr read_row_fn));
+PNG_EXPORT(80, void, png_set_read_status_fn,
+   (png_structrp png_ptr, png_read_status_ptr read_row_fn));
 
-PNG_EXPORT(81, void, png_set_write_status_fn, (png_structrp png_ptr,
-    png_write_status_ptr write_row_fn));
+PNG_EXPORT(81, void, png_set_write_status_fn,
+   (png_structrp png_ptr, png_write_status_ptr write_row_fn));
 
 #ifdef PNG_USER_MEM_SUPPORTED
 /* Replace the default memory allocation functions with user supplied one(s). */
-PNG_EXPORT(82, void, png_set_mem_fn, (png_structrp png_ptr, png_voidp mem_ptr,
-    png_malloc_ptr malloc_fn, png_free_ptr free_fn));
+PNG_EXPORT(82, void, png_set_mem_fn,
+   (png_structrp png_ptr,
+    png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn));
 /* Return the user pointer associated with the memory functions */
-PNG_EXPORT(83, png_voidp, png_get_mem_ptr, (png_const_structrp png_ptr));
+PNG_EXPORT(83, png_voidp, png_get_mem_ptr,
+   (png_const_structrp png_ptr));
 #endif
 
 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
-PNG_EXPORT(84, void, png_set_read_user_transform_fn, (png_structrp png_ptr,
-    png_user_transform_ptr read_user_transform_fn));
+PNG_EXPORT(84, void, png_set_read_user_transform_fn,
+   (png_structrp png_ptr, png_user_transform_ptr read_user_transform_fn));
 #endif
 
 #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
-PNG_EXPORT(85, void, png_set_write_user_transform_fn, (png_structrp png_ptr,
-    png_user_transform_ptr write_user_transform_fn));
+PNG_EXPORT(85, void, png_set_write_user_transform_fn,
+   (png_structrp png_ptr, png_user_transform_ptr write_user_transform_fn));
 #endif
 
 #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
-PNG_EXPORT(86, void, png_set_user_transform_info, (png_structrp png_ptr,
-    png_voidp user_transform_ptr, int user_transform_depth,
-    int user_transform_channels));
+PNG_EXPORT(86, void, png_set_user_transform_info,
+   (png_structrp png_ptr,
+    png_voidp user_transform_ptr,
+    int user_transform_depth, int user_transform_channels));
 /* Return the user pointer associated with the user transform functions */
 PNG_EXPORT(87, png_voidp, png_get_user_transform_ptr,
-    (png_const_structrp png_ptr));
+   (png_const_structrp png_ptr));
 #endif
 
 #ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED
@@ -1681,8 +1746,10 @@ PNG_EXPORT(87, png_voidp, png_get_user_transform_ptr,
  * find the output pixel (x,y) given an interlaced sub-image pixel
  * (row,col,pass).  (See below for these macros.)
  */
-PNG_EXPORT(217, png_uint_32, png_get_current_row_number, (png_const_structrp));
-PNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structrp));
+PNG_EXPORT(217, png_uint_32, png_get_current_row_number,
+   (png_const_structrp));
+PNG_EXPORT(218, png_byte, png_get_current_pass_number,
+   (png_const_structrp));
 #endif
 
 #ifdef PNG_READ_USER_CHUNKS_SUPPORTED
@@ -1705,28 +1772,32 @@ PNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structrp));
  * See "INTERACTION WITH USER CHUNK CALLBACKS" below for important notes about
  * how this behavior will change in libpng 1.7
  */
-PNG_EXPORT(88, void, png_set_read_user_chunk_fn, (png_structrp png_ptr,
+PNG_EXPORT(88, void, png_set_read_user_chunk_fn,
+   (png_structrp png_ptr,
     png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn));
 #endif
 
 #ifdef PNG_USER_CHUNKS_SUPPORTED
-PNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr, (png_const_structrp png_ptr));
+PNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr,
+   (png_const_structrp png_ptr));
 #endif
 
 #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
 /* Sets the function callbacks for the push reader, and a pointer to a
  * user-defined structure available to the callback functions.
  */
-PNG_EXPORT(90, void, png_set_progressive_read_fn, (png_structrp png_ptr,
+PNG_EXPORT(90, void, png_set_progressive_read_fn,
+   (png_structrp png_ptr,
     png_voidp progressive_ptr, png_progressive_info_ptr info_fn,
     png_progressive_row_ptr row_fn, png_progressive_end_ptr end_fn));
 
 /* Returns the user pointer associated with the push read functions */
 PNG_EXPORT(91, png_voidp, png_get_progressive_ptr,
-    (png_const_structrp png_ptr));
+   (png_const_structrp png_ptr));
 
 /* Function to be called when data becomes available */
-PNG_EXPORT(92, void, png_process_data, (png_structrp png_ptr,
+PNG_EXPORT(92, void, png_process_data,
+   (png_structrp png_ptr,
     png_inforp info_ptr, png_bytep buffer, size_t buffer_size));
 
 /* A function which may be called *only* within png_process_data to stop the
@@ -1736,7 +1807,8 @@ PNG_EXPORT(92, void, png_process_data, (png_structrp png_ptr,
  * 'save' is set to true the routine will first save all the pending data and
  * will always return 0.
  */
-PNG_EXPORT(219, size_t, png_process_data_pause, (png_structrp, int save));
+PNG_EXPORT(219, size_t, png_process_data_pause,
+   (png_structrp, int save));
 
 /* A function which may be called *only* outside (after) a call to
  * png_process_data.  It returns the number of bytes of data to skip in the
@@ -1744,45 +1816,53 @@ PNG_EXPORT(219, size_t, png_process_data_pause, (png_structrp, int save));
  * application must skip than number of bytes of input data and pass the
  * following data to the next call to png_process_data.
  */
-PNG_EXPORT(220, png_uint_32, png_process_data_skip, (png_structrp));
+PNG_EXPORT(220, png_uint_32, png_process_data_skip,
+   (png_structrp));
 
 /* Function that combines rows.  'new_row' is a flag that should come from
  * the callback and be non-NULL if anything needs to be done; the library
  * stores its own version of the new data internally and ignores the passed
  * in value.
  */
-PNG_EXPORT(93, void, png_progressive_combine_row, (png_const_structrp png_ptr,
+PNG_EXPORT(93, void, png_progressive_combine_row,
+   (png_const_structrp png_ptr,
     png_bytep old_row, png_const_bytep new_row));
 #endif /* PROGRESSIVE_READ */
 
-PNG_EXPORTA(94, png_voidp, png_malloc, (png_const_structrp png_ptr,
-    png_alloc_size_t size), PNG_ALLOCATED);
+PNG_EXPORTA(94, png_voidp, png_malloc,
+   (png_const_structrp png_ptr, png_alloc_size_t size),
+   PNG_ALLOCATED);
 /* Added at libpng version 1.4.0 */
-PNG_EXPORTA(95, png_voidp, png_calloc, (png_const_structrp png_ptr,
-    png_alloc_size_t size), PNG_ALLOCATED);
+PNG_EXPORTA(95, png_voidp, png_calloc,
+   (png_const_structrp png_ptr, png_alloc_size_t size),
+   PNG_ALLOCATED);
 
 /* Added at libpng version 1.2.4 */
-PNG_EXPORTA(96, png_voidp, png_malloc_warn, (png_const_structrp png_ptr,
-    png_alloc_size_t size), PNG_ALLOCATED);
+PNG_EXPORTA(96, png_voidp, png_malloc_warn,
+   (png_const_structrp png_ptr, png_alloc_size_t size),
+   PNG_ALLOCATED);
 
 /* Frees a pointer allocated by png_malloc() */
-PNG_EXPORT(97, void, png_free, (png_const_structrp png_ptr, png_voidp ptr));
+PNG_EXPORT(97, void, png_free,
+   (png_const_structrp png_ptr, png_voidp ptr));
 
 /* Free data that was allocated internally */
-PNG_EXPORT(98, void, png_free_data, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 free_me, int num));
+PNG_EXPORT(98, void, png_free_data,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_uint_32 free_me, int num));
 
 /* Reassign the responsibility for freeing existing data, whether allocated
  * by libpng or by the application; this works on the png_info structure passed
  * in, without changing the state for other png_info structures.
  */
-PNG_EXPORT(99, void, png_data_freer, (png_const_structrp png_ptr,
-    png_inforp info_ptr, int freer, png_uint_32 mask));
+PNG_EXPORT(99, void, png_data_freer,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    int freer, png_uint_32 mask));
 
 /* Assignments for png_data_freer */
 #define PNG_DESTROY_WILL_FREE_DATA 1
-#define PNG_SET_WILL_FREE_DATA 1
-#define PNG_USER_WILL_FREE_DATA 2
+#define PNG_SET_WILL_FREE_DATA     1
+#define PNG_USER_WILL_FREE_DATA    2
 /* Flags for png_ptr->free_me and info_ptr->free_me */
 #define PNG_FREE_HIST 0x0008U
 #define PNG_FREE_ICCP 0x0010U
@@ -1802,36 +1882,42 @@ PNG_EXPORT(99, void, png_data_freer, (png_const_structrp png_ptr,
 #define PNG_FREE_MUL  0x4220U /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */
 
 #ifdef PNG_USER_MEM_SUPPORTED
-PNG_EXPORTA(100, png_voidp, png_malloc_default, (png_const_structrp png_ptr,
-    png_alloc_size_t size), PNG_ALLOCATED PNG_DEPRECATED);
-PNG_EXPORTA(101, void, png_free_default, (png_const_structrp png_ptr,
-    png_voidp ptr), PNG_DEPRECATED);
+PNG_EXPORTA(100, png_voidp, png_malloc_default,
+   (png_const_structrp png_ptr, png_alloc_size_t size),
+   PNG_ALLOCATED PNG_DEPRECATED);
+PNG_EXPORTA(101, void, png_free_default,
+   (png_const_structrp png_ptr, png_voidp ptr),
+   PNG_DEPRECATED);
 #endif
 
 #ifdef PNG_ERROR_TEXT_SUPPORTED
 /* Fatal error in PNG image of libpng - can't continue */
-PNG_EXPORTA(102, void, png_error, (png_const_structrp png_ptr,
-    png_const_charp error_message), PNG_NORETURN);
+PNG_EXPORTA(102, void, png_error,
+   (png_const_structrp png_ptr, png_const_charp error_message),
+   PNG_NORETURN);
 
 /* The same, but the chunk name is prepended to the error string. */
-PNG_EXPORTA(103, void, png_chunk_error, (png_const_structrp png_ptr,
-    png_const_charp error_message), PNG_NORETURN);
+PNG_EXPORTA(103, void, png_chunk_error,
+   (png_const_structrp png_ptr, png_const_charp error_message),
+   PNG_NORETURN);
 
 #else
 /* Fatal error in PNG image of libpng - can't continue */
-PNG_EXPORTA(104, void, png_err, (png_const_structrp png_ptr), PNG_NORETURN);
+PNG_EXPORTA(104, void, png_err,
+   (png_const_structrp png_ptr),
+   PNG_NORETURN);
 #  define png_error(s1,s2) png_err(s1)
 #  define png_chunk_error(s1,s2) png_err(s1)
 #endif
 
 #ifdef PNG_WARNINGS_SUPPORTED
 /* Non-fatal error in libpng.  Can continue, but may have a problem. */
-PNG_EXPORT(105, void, png_warning, (png_const_structrp png_ptr,
-    png_const_charp warning_message));
+PNG_EXPORT(105, void, png_warning,
+   (png_const_structrp png_ptr, png_const_charp warning_message));
 
 /* Non-fatal error in libpng, chunk name is prepended to message. */
-PNG_EXPORT(106, void, png_chunk_warning, (png_const_structrp png_ptr,
-    png_const_charp warning_message));
+PNG_EXPORT(106, void, png_chunk_warning,
+   (png_const_structrp png_ptr, png_const_charp warning_message));
 #else
 #  define png_warning(s1,s2) ((void)(s1))
 #  define png_chunk_warning(s1,s2) ((void)(s1))
@@ -1840,17 +1926,17 @@ PNG_EXPORT(106, void, png_chunk_warning, (png_const_structrp png_ptr,
 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
 /* Benign error in libpng.  Can continue, but may have a problem.
  * User can choose whether to handle as a fatal error or as a warning. */
-PNG_EXPORT(107, void, png_benign_error, (png_const_structrp png_ptr,
-    png_const_charp warning_message));
+PNG_EXPORT(107, void, png_benign_error,
+   (png_const_structrp png_ptr, png_const_charp warning_message));
 
 #ifdef PNG_READ_SUPPORTED
 /* Same, chunk name is prepended to message (only during read) */
-PNG_EXPORT(108, void, png_chunk_benign_error, (png_const_structrp png_ptr,
-    png_const_charp warning_message));
+PNG_EXPORT(108, void, png_chunk_benign_error,
+   (png_const_structrp png_ptr, png_const_charp warning_message));
 #endif
 
 PNG_EXPORT(109, void, png_set_benign_errors,
-    (png_structrp png_ptr, int allowed));
+   (png_structrp png_ptr, int allowed));
 #else
 #  ifdef PNG_ALLOW_BENIGN_ERRORS
 #    define png_benign_error png_warning
@@ -1874,169 +1960,181 @@ PNG_EXPORT(109, void, png_set_benign_errors,
  * png_info_struct.
  */
 /* Returns "flag" if chunk data is valid in info_ptr. */
-PNG_EXPORT(110, png_uint_32, png_get_valid, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr, png_uint_32 flag));
+PNG_EXPORT(110, png_uint_32, png_get_valid,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 flag));
 
 /* Returns number of bytes needed to hold a transformed row. */
-PNG_EXPORT(111, size_t, png_get_rowbytes, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr));
+PNG_EXPORT(111, size_t, png_get_rowbytes,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 
 #ifdef PNG_INFO_IMAGE_SUPPORTED
 /* Returns row_pointers, which is an array of pointers to scanlines that was
  * returned from png_read_png().
  */
-PNG_EXPORT(112, png_bytepp, png_get_rows, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr));
+PNG_EXPORT(112, png_bytepp, png_get_rows,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 
 /* Set row_pointers, which is an array of pointers to scanlines for use
  * by png_write_png().
  */
-PNG_EXPORT(113, void, png_set_rows, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_bytepp row_pointers));
+PNG_EXPORT(113, void, png_set_rows,
+   (png_const_structrp png_ptr, png_inforp info_ptr, png_bytepp row_pointers));
 #endif
 
 /* Returns number of color channels in image. */
-PNG_EXPORT(114, png_byte, png_get_channels, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr));
+PNG_EXPORT(114, png_byte, png_get_channels,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 
 #ifdef PNG_EASY_ACCESS_SUPPORTED
 /* Returns image width in pixels. */
-PNG_EXPORT(115, png_uint_32, png_get_image_width, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr));
+PNG_EXPORT(115, png_uint_32, png_get_image_width,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 
 /* Returns image height in pixels. */
-PNG_EXPORT(116, png_uint_32, png_get_image_height, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr));
+PNG_EXPORT(116, png_uint_32, png_get_image_height,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 
 /* Returns image bit_depth. */
-PNG_EXPORT(117, png_byte, png_get_bit_depth, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr));
+PNG_EXPORT(117, png_byte, png_get_bit_depth,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 
 /* Returns image color_type. */
-PNG_EXPORT(118, png_byte, png_get_color_type, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr));
+PNG_EXPORT(118, png_byte, png_get_color_type,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 
 /* Returns image filter_type. */
-PNG_EXPORT(119, png_byte, png_get_filter_type, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr));
+PNG_EXPORT(119, png_byte, png_get_filter_type,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 
 /* Returns image interlace_type. */
-PNG_EXPORT(120, png_byte, png_get_interlace_type, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr));
+PNG_EXPORT(120, png_byte, png_get_interlace_type,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 
 /* Returns image compression_type. */
-PNG_EXPORT(121, png_byte, png_get_compression_type, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr));
+PNG_EXPORT(121, png_byte, png_get_compression_type,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 
 /* Returns image resolution in pixels per meter, from pHYs chunk data. */
 PNG_EXPORT(122, png_uint_32, png_get_pixels_per_meter,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 PNG_EXPORT(123, png_uint_32, png_get_x_pixels_per_meter,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 PNG_EXPORT(124, png_uint_32, png_get_y_pixels_per_meter,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 
 /* Returns pixel aspect ratio, computed from pHYs chunk data.  */
 PNG_FP_EXPORT(125, float, png_get_pixel_aspect_ratio,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr))
+   (png_const_structrp png_ptr, png_const_inforp info_ptr))
 PNG_FIXED_EXPORT(210, png_fixed_point, png_get_pixel_aspect_ratio_fixed,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr))
+   (png_const_structrp png_ptr, png_const_inforp info_ptr))
 
 /* Returns image x, y offset in pixels or microns, from oFFs chunk data. */
 PNG_EXPORT(126, png_int_32, png_get_x_offset_pixels,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 PNG_EXPORT(127, png_int_32, png_get_y_offset_pixels,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 PNG_EXPORT(128, png_int_32, png_get_x_offset_microns,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 PNG_EXPORT(129, png_int_32, png_get_y_offset_microns,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 
 #endif /* EASY_ACCESS */
 
 #ifdef PNG_READ_SUPPORTED
 /* Returns pointer to signature string read from PNG header */
-PNG_EXPORT(130, png_const_bytep, png_get_signature, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr));
+PNG_EXPORT(130, png_const_bytep, png_get_signature,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 #endif
 
 #ifdef PNG_bKGD_SUPPORTED
-PNG_EXPORT(131, png_uint_32, png_get_bKGD, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_color_16p *background));
+PNG_EXPORT(131, png_uint_32, png_get_bKGD,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_color_16p *background));
 #endif
 
 #ifdef PNG_bKGD_SUPPORTED
-PNG_EXPORT(132, void, png_set_bKGD, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_const_color_16p background));
+PNG_EXPORT(132, void, png_set_bKGD,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_const_color_16p background));
 #endif
 
 #ifdef PNG_cHRM_SUPPORTED
-PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr, double *white_x, double *white_y, double *red_x,
-    double *red_y, double *green_x, double *green_y, double *blue_x,
-    double *blue_y))
-PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr, double *red_X, double *red_Y, double *red_Z,
-    double *green_X, double *green_Y, double *green_Z, double *blue_X,
-    double *blue_Y, double *blue_Z))
+PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    double *white_x, double *white_y,
+    double *red_x, double *red_y,
+    double *green_x, double *green_y,
+    double *blue_x, double *blue_y))
+PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    double *red_X, double *red_Y, double *red_Z,
+    double *green_X, double *green_Y, double *green_Z,
+    double *blue_X, double *blue_Y, double *blue_Z))
 PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
     png_fixed_point *int_white_x, png_fixed_point *int_white_y,
     png_fixed_point *int_red_x, png_fixed_point *int_red_y,
     png_fixed_point *int_green_x, png_fixed_point *int_green_y,
     png_fixed_point *int_blue_x, png_fixed_point *int_blue_y))
 PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
     png_fixed_point *int_red_X, png_fixed_point *int_red_Y,
-    png_fixed_point *int_red_Z, png_fixed_point *int_green_X,
-    png_fixed_point *int_green_Y, png_fixed_point *int_green_Z,
+    png_fixed_point *int_red_Z,
+    png_fixed_point *int_green_X, png_fixed_point *int_green_Y,
+    png_fixed_point *int_green_Z,
     png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,
     png_fixed_point *int_blue_Z))
 #endif
 
 #ifdef PNG_cHRM_SUPPORTED
-PNG_FP_EXPORT(135, void, png_set_cHRM, (png_const_structrp png_ptr,
-    png_inforp info_ptr,
-    double white_x, double white_y, double red_x, double red_y, double green_x,
-    double green_y, double blue_x, double blue_y))
-PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_const_structrp png_ptr,
-    png_inforp info_ptr, double red_X, double red_Y, double red_Z,
-    double green_X, double green_Y, double green_Z, double blue_X,
-    double blue_Y, double blue_Z))
-PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_fixed_point int_white_x,
-    png_fixed_point int_white_y, png_fixed_point int_red_x,
-    png_fixed_point int_red_y, png_fixed_point int_green_x,
-    png_fixed_point int_green_y, png_fixed_point int_blue_x,
-    png_fixed_point int_blue_y))
-PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y,
-    png_fixed_point int_red_Z, png_fixed_point int_green_X,
-    png_fixed_point int_green_Y, png_fixed_point int_green_Z,
+PNG_FP_EXPORT(135, void, png_set_cHRM,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    double white_x, double white_y,
+    double red_x, double red_y,
+    double green_x, double green_y,
+    double blue_x, double blue_y))
+PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    double red_X, double red_Y, double red_Z,
+    double green_X, double green_Y, double green_Z,
+    double blue_X, double blue_Y, double blue_Z))
+PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_fixed_point int_white_x, png_fixed_point int_white_y,
+    png_fixed_point int_red_x, png_fixed_point int_red_y,
+    png_fixed_point int_green_x, png_fixed_point int_green_y,
+    png_fixed_point int_blue_x, png_fixed_point int_blue_y))
+PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_fixed_point int_red_X, png_fixed_point int_red_Y,
+    png_fixed_point int_red_Z,
+    png_fixed_point int_green_X, png_fixed_point int_green_Y,
+    png_fixed_point int_green_Z,
     png_fixed_point int_blue_X, png_fixed_point int_blue_Y,
     png_fixed_point int_blue_Z))
 #endif
 
 #ifdef PNG_cICP_SUPPORTED
-PNG_EXPORT(250, png_uint_32, png_get_cICP, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr, png_bytep colour_primaries,
-    png_bytep transfer_function, png_bytep matrix_coefficients,
-    png_bytep video_full_range_flag));
+PNG_EXPORT(250, png_uint_32, png_get_cICP,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    png_bytep colour_primaries, png_bytep transfer_function,
+    png_bytep matrix_coefficients, png_bytep video_full_range_flag));
 #endif
 
 #ifdef PNG_cICP_SUPPORTED
-PNG_EXPORT(251, void, png_set_cICP, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_byte colour_primaries,
-    png_byte transfer_function, png_byte matrix_coefficients,
-    png_byte video_full_range_flag));
+PNG_EXPORT(251, void, png_set_cICP,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_byte colour_primaries, png_byte transfer_function,
+    png_byte matrix_coefficients, png_byte video_full_range_flag));
 #endif
 
 #ifdef PNG_cLLI_SUPPORTED
-PNG_FP_EXPORT(252, png_uint_32, png_get_cLLI, (png_const_structrp png_ptr,
-         png_const_inforp info_ptr, double *maximum_content_light_level,
-         double *maximum_frame_average_light_level))
+PNG_FP_EXPORT(252, png_uint_32, png_get_cLLI,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    double *maximum_content_light_level,
+    double *maximum_frame_average_light_level))
 PNG_FIXED_EXPORT(253, png_uint_32, png_get_cLLI_fixed,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
     /* The values below are in cd/m2 (nits) and are scaled by 10,000; not
      * 100,000 as in the case of png_fixed_point.
      */
@@ -2045,11 +2143,12 @@ PNG_FIXED_EXPORT(253, png_uint_32, png_get_cLLI_fixed,
 #endif
 
 #ifdef PNG_cLLI_SUPPORTED
-PNG_FP_EXPORT(254, void, png_set_cLLI, (png_const_structrp png_ptr,
-         png_inforp info_ptr, double maximum_content_light_level,
-         double maximum_frame_average_light_level))
-PNG_FIXED_EXPORT(255, void, png_set_cLLI_fixed, (png_const_structrp png_ptr,
-    png_inforp info_ptr,
+PNG_FP_EXPORT(254, void, png_set_cLLI,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    double maximum_content_light_level,
+    double maximum_frame_average_light_level))
+PNG_FIXED_EXPORT(255, void, png_set_cLLI_fixed,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
     /* The values below are in cd/m2 (nits) and are scaled by 10,000; not
      * 100,000 as in the case of png_fixed_point.
      */
@@ -2058,64 +2157,73 @@ PNG_FIXED_EXPORT(255, void, png_set_cLLI_fixed, (png_const_structrp png_ptr,
 #endif
 
 #ifdef PNG_eXIf_SUPPORTED
-PNG_EXPORT(246, png_uint_32, png_get_eXIf, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_bytep *exif));
-PNG_EXPORT(247, void, png_set_eXIf, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_bytep exif));
+PNG_EXPORT(246, png_uint_32, png_get_eXIf,
+   (png_const_structrp png_ptr, png_inforp info_ptr, png_bytep *exif));
+PNG_EXPORT(247, void, png_set_eXIf,
+   (png_const_structrp png_ptr, png_inforp info_ptr, png_bytep exif));
 
-PNG_EXPORT(248, png_uint_32, png_get_eXIf_1, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr, png_uint_32 *num_exif, png_bytep *exif));
-PNG_EXPORT(249, void, png_set_eXIf_1, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 num_exif, png_bytep exif));
+PNG_EXPORT(248, png_uint_32, png_get_eXIf_1,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    png_uint_32 *num_exif, png_bytep *exif));
+PNG_EXPORT(249, void, png_set_eXIf_1,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_uint_32 num_exif, png_bytep exif));
 #endif
 
 #ifdef PNG_gAMA_SUPPORTED
-PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr, double *file_gamma))
+PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    double *file_gamma))
 PNG_FIXED_EXPORT(138, png_uint_32, png_get_gAMA_fixed,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
     png_fixed_point *int_file_gamma))
 #endif
 
 #ifdef PNG_gAMA_SUPPORTED
-PNG_FP_EXPORT(139, void, png_set_gAMA, (png_const_structrp png_ptr,
-    png_inforp info_ptr, double file_gamma))
-PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_fixed_point int_file_gamma))
+PNG_FP_EXPORT(139, void, png_set_gAMA,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    double file_gamma))
+PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_fixed_point int_file_gamma))
 #endif
 
 #ifdef PNG_hIST_SUPPORTED
-PNG_EXPORT(141, png_uint_32, png_get_hIST, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_uint_16p *hist));
-PNG_EXPORT(142, void, png_set_hIST, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_const_uint_16p hist));
+PNG_EXPORT(141, png_uint_32, png_get_hIST,
+   (png_const_structrp png_ptr, png_inforp info_ptr, png_uint_16p *hist));
+PNG_EXPORT(142, void, png_set_hIST,
+   (png_const_structrp png_ptr, png_inforp info_ptr, png_const_uint_16p hist));
 #endif
 
-PNG_EXPORT(143, png_uint_32, png_get_IHDR, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height,
-    int *bit_depth, int *color_type, int *interlace_method,
-    int *compression_method, int *filter_method));
+PNG_EXPORT(143, png_uint_32, png_get_IHDR,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    png_uint_32 *width, png_uint_32 *height,
+    int *bit_depth, int *color_type,
+    int *interlace_method, int *compression_method, int *filter_method));
 
-PNG_EXPORT(144, void, png_set_IHDR, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth,
-    int color_type, int interlace_method, int compression_method,
-    int filter_method));
+PNG_EXPORT(144, void, png_set_IHDR,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_uint_32 width, png_uint_32 height,
+    int bit_depth, int color_type,
+    int interlace_method, int compression_method, int filter_method));
 
 #ifdef PNG_mDCV_SUPPORTED
-PNG_FP_EXPORT(256, png_uint_32, png_get_mDCV, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr,
+PNG_FP_EXPORT(256, png_uint_32, png_get_mDCV,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
     /* The chromaticities of the mastering display.  As cHRM, but independent of
      * the encoding endpoints in cHRM, or cICP, or iCCP.  These values will
      * always be in the range 0 to 1.3107.
      */
-    double *white_x, double *white_y, double *red_x, double *red_y,
-    double *green_x, double *green_y, double *blue_x, double *blue_y,
+    double *white_x, double *white_y,
+    double *red_x, double *red_y,
+    double *green_x, double *green_y,
+    double *blue_x, double *blue_y,
     /* Mastering display luminance in cd/m2 (nits). */
     double *mastering_display_maximum_luminance,
     double *mastering_display_minimum_luminance))
 
 PNG_FIXED_EXPORT(257, png_uint_32, png_get_mDCV_fixed,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
     png_fixed_point *int_white_x, png_fixed_point *int_white_y,
     png_fixed_point *int_red_x, png_fixed_point *int_red_y,
     png_fixed_point *int_green_x, png_fixed_point *int_green_y,
@@ -2128,19 +2236,21 @@ PNG_FIXED_EXPORT(257, png_uint_32, png_get_mDCV_fixed,
 #endif
 
 #ifdef PNG_mDCV_SUPPORTED
-PNG_FP_EXPORT(258, void, png_set_mDCV, (png_const_structrp png_ptr,
-    png_inforp info_ptr,
+PNG_FP_EXPORT(258, void, png_set_mDCV,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
     /* The chromaticities of the mastering display.  As cHRM, but independent of
      * the encoding endpoints in cHRM, or cICP, or iCCP.
      */
-    double white_x, double white_y, double red_x, double red_y, double green_x,
-    double green_y, double blue_x, double blue_y,
+    double white_x, double white_y,
+    double red_x, double red_y,
+    double green_x, double green_y,
+    double blue_x, double blue_y,
     /* Mastering display luminance in cd/m2 (nits). */
     double mastering_display_maximum_luminance,
     double mastering_display_minimum_luminance))
 
-PNG_FIXED_EXPORT(259, void, png_set_mDCV_fixed, (png_const_structrp png_ptr,
-    png_inforp info_ptr,
+PNG_FIXED_EXPORT(259, void, png_set_mDCV_fixed,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
     /* The admissible range of these values is not the full range of a PNG
      * fixed point value.  Negative values cannot be encoded and the maximum
      * value is about 1.3 */
@@ -2156,95 +2266,107 @@ PNG_FIXED_EXPORT(259, void, png_set_mDCV_fixed, (png_const_structrp png_ptr,
 #endif
 
 #ifdef PNG_oFFs_SUPPORTED
-PNG_EXPORT(145, png_uint_32, png_get_oFFs, (png_const_structrp png_ptr,
-   png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y,
-   int *unit_type));
+PNG_EXPORT(145, png_uint_32, png_get_oFFs,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type));
 #endif
 
 #ifdef PNG_oFFs_SUPPORTED
-PNG_EXPORT(146, void, png_set_oFFs, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_int_32 offset_x, png_int_32 offset_y,
-    int unit_type));
+PNG_EXPORT(146, void, png_set_oFFs,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_int_32 offset_x, png_int_32 offset_y, int unit_type));
 #endif
 
 #ifdef PNG_pCAL_SUPPORTED
-PNG_EXPORT(147, png_uint_32, png_get_pCAL, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_charp *purpose, png_int_32 *X0,
-    png_int_32 *X1, int *type, int *nparams, png_charp *units,
-    png_charpp *params));
+PNG_EXPORT(147, png_uint_32, png_get_pCAL,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_charp *purpose, png_int_32 *X0, png_int_32 *X1,
+    int *type, int *nparams, png_charp *units, png_charpp *params));
 #endif
 
 #ifdef PNG_pCAL_SUPPORTED
-PNG_EXPORT(148, void, png_set_pCAL, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1,
+PNG_EXPORT(148, void, png_set_pCAL,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_const_charp purpose, png_int_32 X0, png_int_32 X1,
     int type, int nparams, png_const_charp units, png_charpp params));
 #endif
 
 #ifdef PNG_pHYs_SUPPORTED
-PNG_EXPORT(149, png_uint_32, png_get_pHYs, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y,
-    int *unit_type));
+PNG_EXPORT(149, png_uint_32, png_get_pHYs,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type));
 #endif
 
 #ifdef PNG_pHYs_SUPPORTED
-PNG_EXPORT(150, void, png_set_pHYs, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type));
+PNG_EXPORT(150, void, png_set_pHYs,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_uint_32 res_x, png_uint_32 res_y, int unit_type));
 #endif
 
-PNG_EXPORT(151, png_uint_32, png_get_PLTE, (png_const_structrp png_ptr,
-   png_inforp info_ptr, png_colorp *palette, int *num_palette));
+PNG_EXPORT(151, png_uint_32, png_get_PLTE,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_colorp *palette, int *num_palette));
 
-PNG_EXPORT(152, void, png_set_PLTE, (png_structrp png_ptr,
-    png_inforp info_ptr, png_const_colorp palette, int num_palette));
+PNG_EXPORT(152, void, png_set_PLTE,
+   (png_structrp png_ptr, png_inforp info_ptr,
+    png_const_colorp palette, int num_palette));
 
 #ifdef PNG_sBIT_SUPPORTED
-PNG_EXPORT(153, png_uint_32, png_get_sBIT, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_color_8p *sig_bit));
+PNG_EXPORT(153, png_uint_32, png_get_sBIT,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_color_8p *sig_bit));
 #endif
 
 #ifdef PNG_sBIT_SUPPORTED
-PNG_EXPORT(154, void, png_set_sBIT, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_const_color_8p sig_bit));
+PNG_EXPORT(154, void, png_set_sBIT,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_const_color_8p sig_bit));
 #endif
 
 #ifdef PNG_sRGB_SUPPORTED
-PNG_EXPORT(155, png_uint_32, png_get_sRGB, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr, int *file_srgb_intent));
+PNG_EXPORT(155, png_uint_32, png_get_sRGB,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    int *file_srgb_intent));
 #endif
 
 #ifdef PNG_sRGB_SUPPORTED
-PNG_EXPORT(156, void, png_set_sRGB, (png_const_structrp png_ptr,
-    png_inforp info_ptr, int srgb_intent));
-PNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM, (png_const_structrp png_ptr,
-    png_inforp info_ptr, int srgb_intent));
+PNG_EXPORT(156, void, png_set_sRGB,
+   (png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent));
+PNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM,
+   (png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent));
 #endif
 
 #ifdef PNG_iCCP_SUPPORTED
-PNG_EXPORT(158, png_uint_32, png_get_iCCP, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_charpp name, int *compression_type,
+PNG_EXPORT(158, png_uint_32, png_get_iCCP,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_charpp name, int *compression_type,
     png_bytepp profile, png_uint_32 *proflen));
 #endif
 
 #ifdef PNG_iCCP_SUPPORTED
-PNG_EXPORT(159, void, png_set_iCCP, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_const_charp name, int compression_type,
+PNG_EXPORT(159, void, png_set_iCCP,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_const_charp name, int compression_type,
     png_const_bytep profile, png_uint_32 proflen));
 #endif
 
 #ifdef PNG_sPLT_SUPPORTED
-PNG_EXPORT(160, int, png_get_sPLT, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_sPLT_tpp entries));
+PNG_EXPORT(160, int, png_get_sPLT,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_sPLT_tpp entries));
 #endif
 
 #ifdef PNG_sPLT_SUPPORTED
-PNG_EXPORT(161, void, png_set_sPLT, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_const_sPLT_tp entries, int nentries));
+PNG_EXPORT(161, void, png_set_sPLT,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_const_sPLT_tp entries, int nentries));
 #endif
 
 #ifdef PNG_TEXT_SUPPORTED
 /* png_get_text also returns the number of text chunks in *num_text */
-PNG_EXPORT(162, int, png_get_text, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_textp *text_ptr, int *num_text));
+PNG_EXPORT(162, int, png_get_text,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_textp *text_ptr, int *num_text));
 #endif
 
 /* Note while png_set_text() will accept a structure whose text,
@@ -2255,35 +2377,41 @@ PNG_EXPORT(162, int, png_get_text, (png_const_structrp png_ptr,
  */
 
 #ifdef PNG_TEXT_SUPPORTED
-PNG_EXPORT(163, void, png_set_text, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_const_textp text_ptr, int num_text));
+PNG_EXPORT(163, void, png_set_text,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_const_textp text_ptr, int num_text));
 #endif
 
 #ifdef PNG_tIME_SUPPORTED
-PNG_EXPORT(164, png_uint_32, png_get_tIME, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_timep *mod_time));
+PNG_EXPORT(164, png_uint_32, png_get_tIME,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_timep *mod_time));
 #endif
 
 #ifdef PNG_tIME_SUPPORTED
-PNG_EXPORT(165, void, png_set_tIME, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_const_timep mod_time));
+PNG_EXPORT(165, void, png_set_tIME,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_const_timep mod_time));
 #endif
 
 #ifdef PNG_tRNS_SUPPORTED
-PNG_EXPORT(166, png_uint_32, png_get_tRNS, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_bytep *trans_alpha, int *num_trans,
+PNG_EXPORT(166, png_uint_32, png_get_tRNS,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_bytep *trans_alpha, int *num_trans,
     png_color_16p *trans_color));
 #endif
 
 #ifdef PNG_tRNS_SUPPORTED
-PNG_EXPORT(167, void, png_set_tRNS, (png_structrp png_ptr,
-    png_inforp info_ptr, png_const_bytep trans_alpha, int num_trans,
+PNG_EXPORT(167, void, png_set_tRNS,
+   (png_structrp png_ptr, png_inforp info_ptr,
+    png_const_bytep trans_alpha, int num_trans,
     png_const_color_16p trans_color));
 #endif
 
 #ifdef PNG_sCAL_SUPPORTED
-PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr, int *unit, double *width, double *height))
+PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    int *unit, double *width, double *height))
 #if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \
    defined(PNG_FLOATING_POINT_SUPPORTED)
 /* NOTE: this API is currently implemented using floating point arithmetic,
@@ -2292,21 +2420,22 @@ PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, (png_const_structrp png_ptr,
  * is highly recommended that png_get_sCAL_s be used instead.
  */
 PNG_FIXED_EXPORT(214, png_uint_32, png_get_sCAL_fixed,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit,
-    png_fixed_point *width, png_fixed_point *height))
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    int *unit, png_fixed_point *width, png_fixed_point *height))
 #endif
 PNG_EXPORT(169, png_uint_32, png_get_sCAL_s,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit,
-    png_charpp swidth, png_charpp sheight));
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    int *unit, png_charpp swidth, png_charpp sheight));
 
-PNG_FP_EXPORT(170, void, png_set_sCAL, (png_const_structrp png_ptr,
-    png_inforp info_ptr, int unit, double width, double height))
-PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_const_structrp png_ptr,
-   png_inforp info_ptr, int unit, png_fixed_point width,
-   png_fixed_point height))
-PNG_EXPORT(171, void, png_set_sCAL_s, (png_const_structrp png_ptr,
-    png_inforp info_ptr, int unit,
-    png_const_charp swidth, png_const_charp sheight));
+PNG_FP_EXPORT(170, void, png_set_sCAL,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    int unit, double width, double height))
+PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    int unit, png_fixed_point width, png_fixed_point height))
+PNG_EXPORT(171, void, png_set_sCAL_s,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    int unit, png_const_charp swidth, png_const_charp sheight));
 #endif /* sCAL */
 
 #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
@@ -2409,7 +2538,8 @@ PNG_EXPORT(171, void, png_set_sCAL_s, (png_const_structrp png_ptr,
  *    be processed by libpng.
  */
 #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
-PNG_EXPORT(172, void, png_set_keep_unknown_chunks, (png_structrp png_ptr,
+PNG_EXPORT(172, void, png_set_keep_unknown_chunks,
+   (png_structrp png_ptr,
     int keep, png_const_bytep chunk_list, int num_chunks));
 #endif /* HANDLE_AS_UNKNOWN */
 
@@ -2417,14 +2547,14 @@ PNG_EXPORT(172, void, png_set_keep_unknown_chunks, (png_structrp png_ptr,
  * the result is therefore true (non-zero) if special handling is required,
  * false for the default handling.
  */
-PNG_EXPORT(173, int, png_handle_as_unknown, (png_const_structrp png_ptr,
-    png_const_bytep chunk_name));
+PNG_EXPORT(173, int, png_handle_as_unknown,
+   (png_const_structrp png_ptr, png_const_bytep chunk_name));
 #endif /* SET_UNKNOWN_CHUNKS */
 
 #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
-PNG_EXPORT(174, void, png_set_unknown_chunks, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_const_unknown_chunkp unknowns,
-    int num_unknowns));
+PNG_EXPORT(174, void, png_set_unknown_chunks,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_const_unknown_chunkp unknowns, int num_unknowns));
    /* NOTE: prior to 1.6.0 this routine set the 'location' field of the added
     * unknowns to the location currently stored in the png_struct.  This is
     * invariably the wrong value on write.  To fix this call the following API
@@ -2435,43 +2565,47 @@ PNG_EXPORT(174, void, png_set_unknown_chunks, (png_const_structrp png_ptr,
     */
 
 PNG_EXPORT(175, void, png_set_unknown_chunk_location,
-    (png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location));
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    int chunk, int location));
 
-PNG_EXPORT(176, int, png_get_unknown_chunks, (png_const_structrp png_ptr,
-    png_inforp info_ptr, png_unknown_chunkpp entries));
+PNG_EXPORT(176, int, png_get_unknown_chunks,
+   (png_const_structrp png_ptr, png_inforp info_ptr,
+    png_unknown_chunkpp entries));
 #endif
 
 /* Png_free_data() will turn off the "valid" flag for anything it frees.
  * If you need to turn it off for a chunk that your application has freed,
  * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK);
  */
-PNG_EXPORT(177, void, png_set_invalid, (png_const_structrp png_ptr,
-    png_inforp info_ptr, int mask));
+PNG_EXPORT(177, void, png_set_invalid,
+   (png_const_structrp png_ptr, png_inforp info_ptr, int mask));
 
 #ifdef PNG_INFO_IMAGE_SUPPORTED
 /* The "params" pointer is currently not used and is for future expansion. */
 #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
-PNG_EXPORT(178, void, png_read_png, (png_structrp png_ptr, png_inforp info_ptr,
+PNG_EXPORT(178, void, png_read_png,
+   (png_structrp png_ptr, png_inforp info_ptr,
     int transforms, png_voidp params));
 #endif
 #ifdef PNG_WRITE_SUPPORTED
-PNG_EXPORT(179, void, png_write_png, (png_structrp png_ptr, png_inforp info_ptr,
+PNG_EXPORT(179, void, png_write_png,
+   (png_structrp png_ptr, png_inforp info_ptr,
     int transforms, png_voidp params));
 #endif
 #endif
 
 PNG_EXPORT(180, png_const_charp, png_get_copyright,
-    (png_const_structrp png_ptr));
+   (png_const_structrp png_ptr));
 PNG_EXPORT(181, png_const_charp, png_get_header_ver,
-    (png_const_structrp png_ptr));
+   (png_const_structrp png_ptr));
 PNG_EXPORT(182, png_const_charp, png_get_header_version,
-    (png_const_structrp png_ptr));
+   (png_const_structrp png_ptr));
 PNG_EXPORT(183, png_const_charp, png_get_libpng_ver,
-    (png_const_structrp png_ptr));
+   (png_const_structrp png_ptr));
 
 #ifdef PNG_MNG_FEATURES_SUPPORTED
-PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structrp png_ptr,
-    png_uint_32 mng_features_permitted));
+PNG_EXPORT(184, png_uint_32, png_permit_mng_features,
+   (png_structrp png_ptr, png_uint_32 mng_features_permitted));
 #endif
 
 /* For use in png_set_keep_unknown, added to version 1.2.6 */
@@ -2485,71 +2619,74 @@ PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structrp png_ptr,
  * messages before passing them to the error or warning handler.
  */
 #ifdef PNG_ERROR_NUMBERS_SUPPORTED
-PNG_EXPORT(185, void, png_set_strip_error_numbers, (png_structrp png_ptr,
-    png_uint_32 strip_mode));
+PNG_EXPORT(185, void, png_set_strip_error_numbers,
+   (png_structrp png_ptr, png_uint_32 strip_mode));
 #endif
 
 /* Added in libpng-1.2.6 */
 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
-PNG_EXPORT(186, void, png_set_user_limits, (png_structrp png_ptr,
+PNG_EXPORT(186, void, png_set_user_limits,
+   (png_structrp png_ptr,
     png_uint_32 user_width_max, png_uint_32 user_height_max));
 PNG_EXPORT(187, png_uint_32, png_get_user_width_max,
-    (png_const_structrp png_ptr));
+   (png_const_structrp png_ptr));
 PNG_EXPORT(188, png_uint_32, png_get_user_height_max,
-    (png_const_structrp png_ptr));
+   (png_const_structrp png_ptr));
 /* Added in libpng-1.4.0 */
-PNG_EXPORT(189, void, png_set_chunk_cache_max, (png_structrp png_ptr,
-    png_uint_32 user_chunk_cache_max));
+PNG_EXPORT(189, void, png_set_chunk_cache_max,
+   (png_structrp png_ptr, png_uint_32 user_chunk_cache_max));
 PNG_EXPORT(190, png_uint_32, png_get_chunk_cache_max,
-    (png_const_structrp png_ptr));
+   (png_const_structrp png_ptr));
 /* Added in libpng-1.4.1 */
-PNG_EXPORT(191, void, png_set_chunk_malloc_max, (png_structrp png_ptr,
-    png_alloc_size_t user_chunk_cache_max));
+PNG_EXPORT(191, void, png_set_chunk_malloc_max,
+   (png_structrp png_ptr, png_alloc_size_t user_chunk_cache_max));
 PNG_EXPORT(192, png_alloc_size_t, png_get_chunk_malloc_max,
-    (png_const_structrp png_ptr));
+   (png_const_structrp png_ptr));
 #endif
 
 #if defined(PNG_INCH_CONVERSIONS_SUPPORTED)
 PNG_EXPORT(193, png_uint_32, png_get_pixels_per_inch,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 
 PNG_EXPORT(194, png_uint_32, png_get_x_pixels_per_inch,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 
 PNG_EXPORT(195, png_uint_32, png_get_y_pixels_per_inch,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+   (png_const_structrp png_ptr, png_const_inforp info_ptr));
 
 PNG_FP_EXPORT(196, float, png_get_x_offset_inches,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr))
+   (png_const_structrp png_ptr, png_const_inforp info_ptr))
 #ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */
 PNG_FIXED_EXPORT(211, png_fixed_point, png_get_x_offset_inches_fixed,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr))
+   (png_const_structrp png_ptr, png_const_inforp info_ptr))
 #endif
 
-PNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr))
+PNG_FP_EXPORT(197, float, png_get_y_offset_inches,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr))
 #ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */
 PNG_FIXED_EXPORT(212, png_fixed_point, png_get_y_offset_inches_fixed,
-    (png_const_structrp png_ptr, png_const_inforp info_ptr))
+   (png_const_structrp png_ptr, png_const_inforp info_ptr))
 #endif
 
 #  ifdef PNG_pHYs_SUPPORTED
-PNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi, (png_const_structrp png_ptr,
-    png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y,
-    int *unit_type));
+PNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi,
+   (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type));
 #  endif /* pHYs */
 #endif  /* INCH_CONVERSIONS */
 
 /* Added in libpng-1.4.0 */
 #ifdef PNG_IO_STATE_SUPPORTED
-PNG_EXPORT(199, png_uint_32, png_get_io_state, (png_const_structrp png_ptr));
+PNG_EXPORT(199, png_uint_32, png_get_io_state,
+   (png_const_structrp png_ptr));
 
 /* Removed from libpng 1.6; use png_get_io_chunk_type. */
-PNG_REMOVED(200, png_const_bytep, png_get_io_chunk_name, (png_structrp png_ptr),
-    PNG_DEPRECATED)
+PNG_REMOVED(200, png_const_bytep, png_get_io_chunk_name,
+   (png_structrp png_ptr),
+   PNG_DEPRECATED)
 
 PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type,
-    (png_const_structrp png_ptr));
+   (png_const_structrp png_ptr));
 
 /* The flags returned by png_get_io_state() are the following: */
 #  define PNG_IO_NONE        0x0000   /* no I/O at this moment */
@@ -2674,21 +2811,26 @@ PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type,
 #endif /* READ_COMPOSITE_NODIV */
 
 #ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED
-PNG_EXPORT(201, png_uint_32, png_get_uint_32, (png_const_bytep buf));
-PNG_EXPORT(202, png_uint_16, png_get_uint_16, (png_const_bytep buf));
-PNG_EXPORT(203, png_int_32, png_get_int_32, (png_const_bytep buf));
+PNG_EXPORT(201, png_uint_32, png_get_uint_32,
+   (png_const_bytep buf));
+PNG_EXPORT(202, png_uint_16, png_get_uint_16,
+   (png_const_bytep buf));
+PNG_EXPORT(203, png_int_32, png_get_int_32,
+   (png_const_bytep buf));
 #endif
 
-PNG_EXPORT(204, png_uint_32, png_get_uint_31, (png_const_structrp png_ptr,
-    png_const_bytep buf));
+PNG_EXPORT(204, png_uint_32, png_get_uint_31,
+   (png_const_structrp png_ptr, png_const_bytep buf));
 /* No png_get_int_16 -- may be added if there's a real need for it. */
 
 /* Place a 32-bit number into a buffer in PNG byte order (big-endian). */
 #ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED
-PNG_EXPORT(205, void, png_save_uint_32, (png_bytep buf, png_uint_32 i));
+PNG_EXPORT(205, void, png_save_uint_32,
+   (png_bytep buf, png_uint_32 i));
 #endif
 #ifdef PNG_SAVE_INT_32_SUPPORTED
-PNG_EXPORT(206, void, png_save_int_32, (png_bytep buf, png_int_32 i));
+PNG_EXPORT(206, void, png_save_int_32,
+   (png_bytep buf, png_int_32 i));
 #endif
 
 /* Place a 16-bit number into a buffer in PNG byte order.
@@ -2696,7 +2838,8 @@ PNG_EXPORT(206, void, png_save_int_32, (png_bytep buf, png_int_32 i));
  * just to avoid potential problems on pre-ANSI C compilers.
  */
 #ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED
-PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i));
+PNG_EXPORT(207, void, png_save_uint_16,
+   (png_bytep buf, unsigned int i));
 /* No png_save_int_16 -- may be added if there's a real need for it. */
 #endif
 
@@ -2743,10 +2886,10 @@ PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i));
 
 #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
 PNG_EXPORT(242, void, png_set_check_for_invalid_index,
-    (png_structrp png_ptr, int allowed));
+   (png_structrp png_ptr, int allowed));
 #  ifdef PNG_GET_PALETTE_MAX_SUPPORTED
-PNG_EXPORT(243, int, png_get_palette_max, (png_const_structp png_ptr,
-    png_const_infop info_ptr));
+PNG_EXPORT(243, int, png_get_palette_max,
+   (png_const_structp png_ptr, png_const_infop info_ptr));
 #  endif
 #endif /* CHECK_FOR_INVALID_INDEX */
 
@@ -3110,24 +3253,25 @@ typedef struct
  * the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.)
  */
 #ifdef PNG_STDIO_SUPPORTED
-PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image,
-   const char *file_name));
+PNG_EXPORT(234, int, png_image_begin_read_from_file,
+   (png_imagep image, const char *file_name));
    /* The named file is opened for read and the image header is filled in
     * from the PNG header in the file.
     */
 
-PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image,
-   FILE *file));
+PNG_EXPORT(235, int, png_image_begin_read_from_stdio,
+   (png_imagep image, FILE *file));
    /* The PNG header is read from the stdio FILE object. */
 #endif /* STDIO */
 
-PNG_EXPORT(236, int, png_image_begin_read_from_memory, (png_imagep image,
-   png_const_voidp memory, size_t size));
+PNG_EXPORT(236, int, png_image_begin_read_from_memory,
+   (png_imagep image, png_const_voidp memory, size_t size));
    /* The PNG header is read from the given memory buffer. */
 
-PNG_EXPORT(237, int, png_image_finish_read, (png_imagep image,
-   png_const_colorp background, void *buffer, png_int_32 row_stride,
-   void *colormap));
+PNG_EXPORT(237, int, png_image_finish_read,
+   (png_imagep image,
+    png_const_colorp background, void *buffer, png_int_32 row_stride,
+    void *colormap));
    /* Finish reading the image into the supplied buffer and clean up the
     * png_image structure.
     *
@@ -3160,7 +3304,8 @@ PNG_EXPORT(237, int, png_image_finish_read, (png_imagep image,
     * written to the colormap; this may be less than the original value.
     */
 
-PNG_EXPORT(238, void, png_image_free, (png_imagep image));
+PNG_EXPORT(238, void, png_image_free,
+   (png_imagep image));
    /* Free any data allocated by libpng in image->opaque, setting the pointer to
     * NULL.  May be called at any time after the structure is initialized.
     */
@@ -3184,14 +3329,16 @@ PNG_EXPORT(238, void, png_image_free, (png_imagep image));
  * colormap_entries: set to the number of entries in the color-map (0 to 256)
  */
 #ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
-PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image,
-   const char *file, int convert_to_8bit, const void *buffer,
-   png_int_32 row_stride, const void *colormap));
+PNG_EXPORT(239, int, png_image_write_to_file,
+   (png_imagep image,
+    const char *file, int convert_to_8bit, const void *buffer,
+    png_int_32 row_stride, const void *colormap));
    /* Write the image to the named file. */
 
-PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file,
-   int convert_to_8_bit, const void *buffer, png_int_32 row_stride,
-   const void *colormap));
+PNG_EXPORT(240, int, png_image_write_to_stdio,
+   (png_imagep image,
+    FILE *file, int convert_to_8_bit, const void *buffer,
+    png_int_32 row_stride, const void *colormap));
    /* Write the image to the given FILE object. */
 #endif /* SIMPLIFIED_WRITE_STDIO */
 
@@ -3216,9 +3363,11 @@ PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file,
  * notices) you need to use one of the other APIs.
  */
 
-PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory,
-   png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8_bit,
-   const void *buffer, png_int_32 row_stride, const void *colormap));
+PNG_EXPORT(245, int, png_image_write_to_memory,
+   (png_imagep image,
+    void *memory, png_alloc_size_t * PNG_RESTRICT memory_bytes,
+    int convert_to_8_bit,
+    const void *buffer, png_int_32 row_stride, const void *colormap));
    /* Write the image to the given memory buffer.  The function both writes the
     * whole PNG data stream to *memory and updates *memory_bytes with the count
     * of bytes written.
@@ -3394,7 +3543,7 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option,
  * one to use is one more than this.)
  */
 #ifdef PNG_EXPORT_LAST_ORDINAL
-  PNG_EXPORT_LAST_ORDINAL(259);
+   PNG_EXPORT_LAST_ORDINAL(259);
 #endif
 
 #ifdef __cplusplus
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
index 4bc5f7bb468..959c604edbc 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
@@ -29,9 +29,9 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * libpng version 1.6.51
+ * libpng version 1.6.54
  *
- * Copyright (c) 2018-2025 Cosmin Truta
+ * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c
index 44c86ebfef9..324d1951a52 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c
@@ -78,7 +78,8 @@ png_error,(png_const_structrp png_ptr, png_const_charp error_message),
 }
 #else
 PNG_FUNCTION(void,PNGAPI
-png_err,(png_const_structrp png_ptr),PNG_NORETURN)
+png_err,(png_const_structrp png_ptr),
+    PNG_NORETURN)
 {
    /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed
     * erroneously as '\0', instead of the empty string "".  This was
@@ -405,8 +406,8 @@ static const char png_digit[16] = {
 };
 
 static void /* PRIVATE */
-png_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp
-    error_message)
+png_format_buffer(png_const_structrp png_ptr, png_charp buffer,
+    png_const_charp error_message)
 {
    png_uint_32 chunk_name = png_ptr->chunk_name;
    int iout = 0, ishift = 24;
@@ -485,8 +486,8 @@ png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message)
 #ifdef PNG_READ_SUPPORTED
 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
 void PNGAPI
-png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp
-    error_message)
+png_chunk_benign_error(png_const_structrp png_ptr,
+    png_const_charp error_message)
 {
    if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0)
       png_chunk_warning(png_ptr, error_message);
@@ -543,7 +544,8 @@ png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error)
 #ifdef PNG_ERROR_TEXT_SUPPORTED
 #ifdef PNG_FLOATING_POINT_SUPPORTED
 PNG_FUNCTION(void,
-png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN)
+png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),
+    PNG_NORETURN)
 {
 #  define fixed_message "fixed point overflow in "
 #  define fixed_message_ln ((sizeof fixed_message)-1)
@@ -696,7 +698,8 @@ png_default_error,(png_const_structrp png_ptr, png_const_charp error_message),
 }
 
 PNG_FUNCTION(void,PNGAPI
-png_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN)
+png_longjmp,(png_const_structrp png_ptr, int val),
+    PNG_NORETURN)
 {
 #ifdef PNG_SETJMP_SUPPORTED
    if (png_ptr != NULL && png_ptr->longjmp_fn != NULL &&
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
index ed2e7f886f5..a5bdcd1b524 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
@@ -151,8 +151,8 @@ png_get_compression_type(png_const_structrp png_ptr, png_const_inforp info_ptr)
 }
 
 png_uint_32 PNGAPI
-png_get_x_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp
-   info_ptr)
+png_get_x_pixels_per_meter(png_const_structrp png_ptr,
+    png_const_inforp info_ptr)
 {
 #ifdef PNG_pHYs_SUPPORTED
    png_debug(1, "in png_get_x_pixels_per_meter");
@@ -172,8 +172,8 @@ png_get_x_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp
 }
 
 png_uint_32 PNGAPI
-png_get_y_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp
-    info_ptr)
+png_get_y_pixels_per_meter(png_const_structrp png_ptr,
+    png_const_inforp info_ptr)
 {
 #ifdef PNG_pHYs_SUPPORTED
    png_debug(1, "in png_get_y_pixels_per_meter");
@@ -215,8 +215,8 @@ png_get_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp info_ptr)
 
 #ifdef PNG_FLOATING_POINT_SUPPORTED
 float PNGAPI
-png_get_pixel_aspect_ratio(png_const_structrp png_ptr, png_const_inforp
-   info_ptr)
+png_get_pixel_aspect_ratio(png_const_structrp png_ptr,
+    png_const_inforp info_ptr)
 {
 #ifdef PNG_READ_pHYs_SUPPORTED
    png_debug(1, "in png_get_pixel_aspect_ratio");
@@ -766,7 +766,6 @@ png_get_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,
    }
 
    return 0;
-
 }
 #endif
 
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
index 4cfae474751..b413b510acf 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
@@ -31,9 +31,9 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  */
-/* libpng version 1.6.51 */
+/* libpng version 1.6.54 */
 
-/* Copyright (c) 2018-2025 Cosmin Truta */
+/* Copyright (c) 2018-2026 Cosmin Truta */
 /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
 
 /* This code is released under the libpng license. */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngmem.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngmem.c
index 12b71bcbc02..8ec703616ec 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngmem.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngmem.c
@@ -75,7 +75,8 @@ png_destroy_png_struct(png_structrp png_ptr)
  * have the ability to do that.
  */
 PNG_FUNCTION(png_voidp,PNGAPI
-png_calloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED)
+png_calloc,(png_const_structrp png_ptr, png_alloc_size_t size),
+    PNG_ALLOCATED)
 {
    png_voidp ret;
 
@@ -147,7 +148,8 @@ png_malloc_array_checked(png_const_structrp png_ptr, int nelements,
 
 PNG_FUNCTION(png_voidp /* PRIVATE */,
 png_malloc_array,(png_const_structrp png_ptr, int nelements,
-    size_t element_size),PNG_ALLOCATED)
+    size_t element_size),
+    PNG_ALLOCATED)
 {
    if (nelements <= 0 || element_size == 0)
       png_error(png_ptr, "internal error: array alloc");
@@ -157,7 +159,8 @@ png_malloc_array,(png_const_structrp png_ptr, int nelements,
 
 PNG_FUNCTION(png_voidp /* PRIVATE */,
 png_realloc_array,(png_const_structrp png_ptr, png_const_voidp old_array,
-    int old_elements, int add_elements, size_t element_size),PNG_ALLOCATED)
+    int old_elements, int add_elements, size_t element_size),
+    PNG_ALLOCATED)
 {
    /* These are internal errors: */
    if (add_elements <= 0 || element_size == 0 || old_elements < 0 ||
@@ -196,7 +199,8 @@ png_realloc_array,(png_const_structrp png_ptr, png_const_voidp old_array,
  * function png_malloc_default is also provided.
  */
 PNG_FUNCTION(png_voidp,PNGAPI
-png_malloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED)
+png_malloc,(png_const_structrp png_ptr, png_alloc_size_t size),
+    PNG_ALLOCATED)
 {
    png_voidp ret;
 
@@ -270,7 +274,8 @@ png_free(png_const_structrp png_ptr, png_voidp ptr)
 }
 
 PNG_FUNCTION(void,PNGAPI
-png_free_default,(png_const_structrp png_ptr, png_voidp ptr),PNG_DEPRECATED)
+png_free_default,(png_const_structrp png_ptr, png_voidp ptr),
+    PNG_DEPRECATED)
 {
    if (png_ptr == NULL || ptr == NULL)
       return;
@@ -284,8 +289,8 @@ png_free_default,(png_const_structrp png_ptr, png_voidp ptr),PNG_DEPRECATED)
  * of allocating and freeing memory.
  */
 void PNGAPI
-png_set_mem_fn(png_structrp png_ptr, png_voidp mem_ptr, png_malloc_ptr
-  malloc_fn, png_free_ptr free_fn)
+png_set_mem_fn(png_structrp png_ptr, png_voidp mem_ptr,
+    png_malloc_ptr malloc_fn, png_free_ptr free_fn)
 {
    if (png_ptr != NULL)
    {
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
index dcd005efb34..ee91f58d4ba 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
@@ -1104,15 +1104,17 @@ extern "C" {
  */
 /* Zlib support */
 #define PNG_UNEXPECTED_ZLIB_RETURN (-7)
-PNG_INTERNAL_FUNCTION(void, png_zstream_error,(png_structrp png_ptr, int ret),
+PNG_INTERNAL_FUNCTION(void, png_zstream_error,
+   (png_structrp png_ptr, int ret),
    PNG_EMPTY);
    /* Used by the zlib handling functions to ensure that z_stream::msg is always
     * set before they return.
     */
 
 #ifdef PNG_WRITE_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr,
-   png_compression_bufferp *list),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_free_buffer_list,
+   (png_structrp png_ptr, png_compression_bufferp *list),
+   PNG_EMPTY);
    /* Free the buffer list used by the compressed write code. */
 #endif
 
@@ -1124,22 +1126,25 @@ PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr,
    defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \
    (defined(PNG_sCAL_SUPPORTED) && \
    defined(PNG_FLOATING_ARITHMETIC_SUPPORTED))
-PNG_INTERNAL_FUNCTION(png_fixed_point,png_fixed,(png_const_structrp png_ptr,
-   double fp, png_const_charp text),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(png_fixed_point, png_fixed,
+   (png_const_structrp png_ptr, double fp, png_const_charp text),
+   PNG_EMPTY);
 #endif
 
 #if defined(PNG_FLOATING_POINT_SUPPORTED) && \
    !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \
    (defined(PNG_cLLI_SUPPORTED) || defined(PNG_mDCV_SUPPORTED))
-PNG_INTERNAL_FUNCTION(png_uint_32,png_fixed_ITU,(png_const_structrp png_ptr,
-   double fp, png_const_charp text),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(png_uint_32, png_fixed_ITU,
+   (png_const_structrp png_ptr, double fp, png_const_charp text),
+   PNG_EMPTY);
 #endif
 
 /* Check the user version string for compatibility, returns false if the version
  * numbers aren't compatible.
  */
-PNG_INTERNAL_FUNCTION(int,png_user_version_check,(png_structrp png_ptr,
-   png_const_charp user_png_ver),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(int, png_user_version_check,
+   (png_structrp png_ptr, png_const_charp user_png_ver),
+   PNG_EMPTY);
 
 #ifdef PNG_READ_SUPPORTED /* should only be used on read */
 /* Security: read limits on the largest allocations while reading a PNG.  This
@@ -1164,24 +1169,28 @@ PNG_INTERNAL_FUNCTION(int,png_user_version_check,(png_structrp png_ptr,
  * does, however, call the application provided allocator and that could call
  * png_error (although that would be a bug in the application implementation.)
  */
-PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_base,(png_const_structrp png_ptr,
-   png_alloc_size_t size),PNG_ALLOCATED);
+PNG_INTERNAL_FUNCTION(png_voidp, png_malloc_base,
+   (png_const_structrp png_ptr, png_alloc_size_t size),
+   PNG_ALLOCATED);
 
 #if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\
    defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED)
 /* Internal array allocator, outputs no error or warning messages on failure,
  * just returns NULL.
  */
-PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_array,(png_const_structrp png_ptr,
-   int nelements, size_t element_size),PNG_ALLOCATED);
+PNG_INTERNAL_FUNCTION(png_voidp, png_malloc_array,
+   (png_const_structrp png_ptr, int nelements, size_t element_size),
+   PNG_ALLOCATED);
 
 /* The same but an existing array is extended by add_elements.  This function
  * also memsets the new elements to 0 and copies the old elements.  The old
  * array is not freed or altered.
  */
-PNG_INTERNAL_FUNCTION(png_voidp,png_realloc_array,(png_const_structrp png_ptr,
-   png_const_voidp array, int old_elements, int add_elements,
-   size_t element_size),PNG_ALLOCATED);
+PNG_INTERNAL_FUNCTION(png_voidp, png_realloc_array,
+   (png_const_structrp png_ptr,
+    png_const_voidp array, int old_elements, int add_elements,
+    size_t element_size),
+   PNG_ALLOCATED);
 #endif /* text, sPLT or unknown chunks */
 
 /* Magic to create a struct when there is no struct to call the user supplied
@@ -1190,84 +1199,106 @@ PNG_INTERNAL_FUNCTION(png_voidp,png_realloc_array,(png_const_structrp png_ptr,
  * restriction so libpng has to assume that the 'free' handler, at least, might
  * call png_error.
  */
-PNG_INTERNAL_FUNCTION(png_structp,png_create_png_struct,
-   (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,
-    png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn,
-    png_free_ptr free_fn),PNG_ALLOCATED);
+PNG_INTERNAL_FUNCTION(png_structp, png_create_png_struct,
+   (png_const_charp user_png_ver,
+    png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn,
+    png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),
+   PNG_ALLOCATED);
 
 /* Free memory from internal libpng struct */
-PNG_INTERNAL_FUNCTION(void,png_destroy_png_struct,(png_structrp png_ptr),
+PNG_INTERNAL_FUNCTION(void, png_destroy_png_struct,
+   (png_structrp png_ptr),
    PNG_EMPTY);
 
 /* Free an allocated jmp_buf (always succeeds) */
-PNG_INTERNAL_FUNCTION(void,png_free_jmpbuf,(png_structrp png_ptr),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_free_jmpbuf,
+   (png_structrp png_ptr),
+   PNG_EMPTY);
 
 /* Function to allocate memory for zlib.  PNGAPI is disallowed. */
-PNG_INTERNAL_FUNCTION(voidpf,png_zalloc,(voidpf png_ptr, uInt items, uInt size),
+PNG_INTERNAL_FUNCTION(voidpf, png_zalloc,
+   (voidpf png_ptr, uInt items, uInt size),
    PNG_ALLOCATED);
 
 /* Function to free memory for zlib.  PNGAPI is disallowed. */
-PNG_INTERNAL_FUNCTION(void,png_zfree,(voidpf png_ptr, voidpf ptr),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_zfree,
+   (voidpf png_ptr, voidpf ptr),
+   PNG_EMPTY);
 
 /* Next four functions are used internally as callbacks.  PNGCBAPI is required
  * but not PNG_EXPORT.  PNGAPI added at libpng version 1.2.3, changed to
  * PNGCBAPI at 1.5.0
  */
 
-PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_read_data,(png_structp png_ptr,
-    png_bytep data, size_t length),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void PNGCBAPI, png_default_read_data,
+   (png_structp png_ptr, png_bytep data, size_t length),
+   PNG_EMPTY);
 
 #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_push_fill_buffer,(png_structp png_ptr,
-    png_bytep buffer, size_t length),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void PNGCBAPI, png_push_fill_buffer,
+   (png_structp png_ptr, png_bytep buffer, size_t length),
+   PNG_EMPTY);
 #endif
 
-PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_write_data,(png_structp png_ptr,
-    png_bytep data, size_t length),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void PNGCBAPI, png_default_write_data,
+   (png_structp png_ptr, png_bytep data, size_t length),
+   PNG_EMPTY);
 
 #ifdef PNG_WRITE_FLUSH_SUPPORTED
 #  ifdef PNG_STDIO_SUPPORTED
-PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_flush,(png_structp png_ptr),
+PNG_INTERNAL_FUNCTION(void PNGCBAPI, png_default_flush,
+   (png_structp png_ptr),
    PNG_EMPTY);
 #  endif
 #endif
 
 /* Reset the CRC variable */
-PNG_INTERNAL_FUNCTION(void,png_reset_crc,(png_structrp png_ptr),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_reset_crc,
+   (png_structrp png_ptr),
+   PNG_EMPTY);
 
 /* Write the "data" buffer to whatever output you are using */
-PNG_INTERNAL_FUNCTION(void,png_write_data,(png_structrp png_ptr,
-    png_const_bytep data, size_t length),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_data,
+   (png_structrp png_ptr, png_const_bytep data, size_t length),
+   PNG_EMPTY);
 
 /* Read and check the PNG file signature */
-PNG_INTERNAL_FUNCTION(void,png_read_sig,(png_structrp png_ptr,
-   png_inforp info_ptr),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_sig,
+   (png_structrp png_ptr, png_inforp info_ptr),
+   PNG_EMPTY);
 
 /* Read the chunk header (length + type name) */
-PNG_INTERNAL_FUNCTION(png_uint_32,png_read_chunk_header,(png_structrp png_ptr),
+PNG_INTERNAL_FUNCTION(png_uint_32, png_read_chunk_header,
+   (png_structrp png_ptr),
    PNG_EMPTY);
 
 /* Read data from whatever input you are using into the "data" buffer */
-PNG_INTERNAL_FUNCTION(void,png_read_data,(png_structrp png_ptr, png_bytep data,
-    size_t length),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_data,
+   (png_structrp png_ptr, png_bytep data, size_t length),
+   PNG_EMPTY);
 
 /* Read bytes into buf, and update png_ptr->crc */
-PNG_INTERNAL_FUNCTION(void,png_crc_read,(png_structrp png_ptr, png_bytep buf,
-    png_uint_32 length),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_crc_read,
+   (png_structrp png_ptr, png_bytep buf, png_uint_32 length),
+   PNG_EMPTY);
 
 /* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */
-PNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr,
-   png_uint_32 skip),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(int, png_crc_finish,
+   (png_structrp png_ptr, png_uint_32 skip),
+   PNG_EMPTY);
 
 /* Calculate the CRC over a section of data.  Note that we are only
  * passing a maximum of 64K on systems that have this as a memory limit,
  * since this is the maximum buffer size we can specify.
  */
-PNG_INTERNAL_FUNCTION(void,png_calculate_crc,(png_structrp png_ptr,
-   png_const_bytep ptr, size_t length),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_calculate_crc,
+   (png_structrp png_ptr, png_const_bytep ptr, size_t length),
+   PNG_EMPTY);
 
 #ifdef PNG_WRITE_FLUSH_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_flush,(png_structrp png_ptr),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_flush,
+   (png_structrp png_ptr),
+   PNG_EMPTY);
 #endif
 
 /* Write various chunks */
@@ -1275,68 +1306,86 @@ PNG_INTERNAL_FUNCTION(void,png_flush,(png_structrp png_ptr),PNG_EMPTY);
 /* Write the IHDR chunk, and update the png_struct with the necessary
  * information.
  */
-PNG_INTERNAL_FUNCTION(void,png_write_IHDR,(png_structrp png_ptr,
-   png_uint_32 width, png_uint_32 height, int bit_depth, int color_type,
-   int compression_method, int filter_method, int interlace_method),PNG_EMPTY);
-
-PNG_INTERNAL_FUNCTION(void,png_write_PLTE,(png_structrp png_ptr,
-   png_const_colorp palette, png_uint_32 num_pal),PNG_EMPTY);
-
-PNG_INTERNAL_FUNCTION(void,png_compress_IDAT,(png_structrp png_ptr,
-   png_const_bytep row_data, png_alloc_size_t row_data_length, int flush),
+PNG_INTERNAL_FUNCTION(void, png_write_IHDR,
+   (png_structrp png_ptr,
+    png_uint_32 width, png_uint_32 height, int bit_depth, int color_type,
+    int compression_method, int filter_method, int interlace_method),
    PNG_EMPTY);
 
-PNG_INTERNAL_FUNCTION(void,png_write_IEND,(png_structrp png_ptr),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_PLTE,
+   (png_structrp png_ptr,
+    png_const_colorp palette, png_uint_32 num_pal),
+   PNG_EMPTY);
+
+PNG_INTERNAL_FUNCTION(void, png_compress_IDAT,
+   (png_structrp png_ptr,
+    png_const_bytep row_data, png_alloc_size_t row_data_length, int flush),
+   PNG_EMPTY);
+
+PNG_INTERNAL_FUNCTION(void, png_write_IEND,
+   (png_structrp png_ptr),
+   PNG_EMPTY);
 
 #ifdef PNG_WRITE_gAMA_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_gAMA_fixed,(png_structrp png_ptr,
-    png_fixed_point file_gamma),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_gAMA_fixed,
+   (png_structrp png_ptr, png_fixed_point file_gamma),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_sBIT_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_sBIT,(png_structrp png_ptr,
-    png_const_color_8p sbit, int color_type),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_sBIT,
+   (png_structrp png_ptr, png_const_color_8p sbit, int color_type),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_cHRM_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr,
-    const png_xy *xy), PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_cHRM_fixed,
+   (png_structrp png_ptr, const png_xy *xy),
+   PNG_EMPTY);
    /* The xy value must have been previously validated */
 #endif
 
 #ifdef PNG_WRITE_cICP_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_cICP,(png_structrp png_ptr,
+PNG_INTERNAL_FUNCTION(void, png_write_cICP,
+   (png_structrp png_ptr,
     png_byte colour_primaries, png_byte transfer_function,
-    png_byte matrix_coefficients, png_byte video_full_range_flag), PNG_EMPTY);
+    png_byte matrix_coefficients, png_byte video_full_range_flag),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_cLLI_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_cLLI_fixed,(png_structrp png_ptr,
-   png_uint_32 maxCLL, png_uint_32 maxFALL), PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_cLLI_fixed,
+   (png_structrp png_ptr, png_uint_32 maxCLL, png_uint_32 maxFALL),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_mDCV_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_mDCV_fixed,(png_structrp png_ptr,
-   png_uint_16 red_x, png_uint_16 red_y,
-   png_uint_16 green_x, png_uint_16 green_y,
-   png_uint_16 blue_x, png_uint_16 blue_y,
-   png_uint_16 white_x, png_uint_16 white_y,
-   png_uint_32 maxDL, png_uint_32 minDL), PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_mDCV_fixed,
+   (png_structrp png_ptr,
+    png_uint_16 red_x, png_uint_16 red_y,
+    png_uint_16 green_x, png_uint_16 green_y,
+    png_uint_16 blue_x, png_uint_16 blue_y,
+    png_uint_16 white_x, png_uint_16 white_y,
+    png_uint_32 maxDL, png_uint_32 minDL),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_sRGB_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr,
-    int intent),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_sRGB,
+   (png_structrp png_ptr, int intent),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_eXIf_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_eXIf,(png_structrp png_ptr,
-    png_bytep exif, int num_exif),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_eXIf,
+   (png_structrp png_ptr, png_bytep exif, int num_exif),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_iCCP_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_iCCP,(png_structrp png_ptr,
-   png_const_charp name, png_const_bytep profile, png_uint_32 proflen),
+PNG_INTERNAL_FUNCTION(void, png_write_iCCP,
+   (png_structrp png_ptr,
+    png_const_charp name, png_const_bytep profile, png_uint_32 proflen),
    PNG_EMPTY);
    /* Writes a previously 'set' profile.  The profile argument is **not**
     * compressed.
@@ -1344,82 +1393,106 @@ PNG_INTERNAL_FUNCTION(void,png_write_iCCP,(png_structrp png_ptr,
 #endif
 
 #ifdef PNG_WRITE_sPLT_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_sPLT,(png_structrp png_ptr,
-    png_const_sPLT_tp palette),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_sPLT,
+   (png_structrp png_ptr, png_const_sPLT_tp palette),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_tRNS_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_tRNS,(png_structrp png_ptr,
+PNG_INTERNAL_FUNCTION(void, png_write_tRNS,
+   (png_structrp png_ptr,
     png_const_bytep trans, png_const_color_16p values, int number,
-    int color_type),PNG_EMPTY);
+    int color_type),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_bKGD_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_bKGD,(png_structrp png_ptr,
-    png_const_color_16p values, int color_type),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_bKGD,
+   (png_structrp png_ptr, png_const_color_16p values, int color_type),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_hIST_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_hIST,(png_structrp png_ptr,
-    png_const_uint_16p hist, int num_hist),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_hIST,
+   (png_structrp png_ptr, png_const_uint_16p hist, int num_hist),
+   PNG_EMPTY);
 #endif
 
 /* Chunks that have keywords */
 #ifdef PNG_WRITE_tEXt_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_tEXt,(png_structrp png_ptr,
-   png_const_charp key, png_const_charp text, size_t text_len),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_tEXt,
+   (png_structrp png_ptr,
+    png_const_charp key, png_const_charp text, size_t text_len),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_zTXt_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_zTXt,(png_structrp png_ptr, png_const_charp
-    key, png_const_charp text, int compression),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_zTXt,
+   (png_structrp png_ptr,
+    png_const_charp key, png_const_charp text, int compression),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_iTXt_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_iTXt,(png_structrp png_ptr,
+PNG_INTERNAL_FUNCTION(void, png_write_iTXt,
+   (png_structrp png_ptr,
     int compression, png_const_charp key, png_const_charp lang,
-    png_const_charp lang_key, png_const_charp text),PNG_EMPTY);
+    png_const_charp lang_key, png_const_charp text),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_TEXT_SUPPORTED  /* Added at version 1.0.14 and 1.2.4 */
-PNG_INTERNAL_FUNCTION(int,png_set_text_2,(png_const_structrp png_ptr,
-    png_inforp info_ptr, png_const_textp text_ptr, int num_text),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(int, png_set_text_2,
+   (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_const_textp text_ptr, int num_text),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_oFFs_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_oFFs,(png_structrp png_ptr,
-    png_int_32 x_offset, png_int_32 y_offset, int unit_type),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_oFFs,
+   (png_structrp png_ptr,
+    png_int_32 x_offset, png_int_32 y_offset, int unit_type),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_pCAL_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_pCAL,(png_structrp png_ptr,
-    png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams,
-    png_const_charp units, png_charpp params),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_pCAL,
+   (png_structrp png_ptr,
+    png_charp purpose, png_int_32 X0, png_int_32 X1,
+    int type, int nparams, png_const_charp units, png_charpp params),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_pHYs_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_pHYs,(png_structrp png_ptr,
+PNG_INTERNAL_FUNCTION(void, png_write_pHYs,
+   (png_structrp png_ptr,
     png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit,
-    int unit_type),PNG_EMPTY);
+    int unit_type),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_tIME_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_tIME,(png_structrp png_ptr,
-    png_const_timep mod_time),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_tIME,
+   (png_structrp png_ptr, png_const_timep mod_time),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_WRITE_sCAL_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr,
-    int unit, png_const_charp width, png_const_charp height),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_sCAL_s,
+   (png_structrp png_ptr,
+    int unit, png_const_charp width, png_const_charp height),
+   PNG_EMPTY);
 #endif
 
 /* Called when finished processing a row of data */
-PNG_INTERNAL_FUNCTION(void,png_write_finish_row,(png_structrp png_ptr),
-    PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_finish_row,
+   (png_structrp png_ptr),
+   PNG_EMPTY);
 
 /* Internal use only.   Called before first row of data */
-PNG_INTERNAL_FUNCTION(void,png_write_start_row,(png_structrp png_ptr),
-    PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_start_row,
+   (png_structrp png_ptr),
+   PNG_EMPTY);
 
 /* Combine a row of data, dealing with alpha, etc. if requested.  'row' is an
  * array of png_ptr->width pixels.  If the image is not interlaced or this
@@ -1447,8 +1520,9 @@ PNG_INTERNAL_FUNCTION(void,png_write_start_row,(png_structrp png_ptr),
 #ifndef PNG_USE_COMPILE_TIME_MASKS
 #  define PNG_USE_COMPILE_TIME_MASKS 1
 #endif
-PNG_INTERNAL_FUNCTION(void,png_combine_row,(png_const_structrp png_ptr,
-    png_bytep row, int display),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_combine_row,
+   (png_const_structrp png_ptr, png_bytep row, int display),
+   PNG_EMPTY);
 
 #ifdef PNG_READ_INTERLACING_SUPPORTED
 /* Expand an interlaced row: the 'row_info' describes the pass data that has
@@ -1457,170 +1531,230 @@ PNG_INTERNAL_FUNCTION(void,png_combine_row,(png_const_structrp png_ptr,
  * the pixels are *replicated* to the intervening space.  This is essential for
  * the correct operation of png_combine_row, above.
  */
-PNG_INTERNAL_FUNCTION(void,png_do_read_interlace,(png_row_infop row_info,
-    png_bytep row, int pass, png_uint_32 transformations),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_do_read_interlace,
+   (png_row_infop row_info,
+    png_bytep row, int pass, png_uint_32 transformations),
+   PNG_EMPTY);
 #endif
 
 /* GRR TO DO (2.0 or whenever):  simplify other internal calling interfaces */
 
 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
 /* Grab pixels out of a row for an interlaced pass */
-PNG_INTERNAL_FUNCTION(void,png_do_write_interlace,(png_row_infop row_info,
-    png_bytep row, int pass),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_do_write_interlace,
+   (png_row_infop row_info, png_bytep row, int pass),
+   PNG_EMPTY);
 #endif
 
 /* Unfilter a row: check the filter value before calling this, there is no point
  * calling it for PNG_FILTER_VALUE_NONE.
  */
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row,(png_structrp pp, png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row, int filter),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row,
+   (png_structrp pp, png_row_infop row_info,
+    png_bytep row, png_const_bytep prev_row, int filter),
+   PNG_EMPTY);
 
 #if PNG_ARM_NEON_OPT > 0
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_neon,(png_row_infop row_info,
-    png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_neon,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_neon,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_neon,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_neon,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_neon,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_neon,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_up_neon,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub3_neon,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub4_neon,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg3_neon,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg4_neon,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth3_neon,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth4_neon,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
 #endif
 
 #if PNG_MIPS_MSA_IMPLEMENTATION == 1
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_msa,(png_row_infop row_info,
-    png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_msa,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_msa,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_msa,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_msa,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_msa,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_msa,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_up_msa,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub3_msa,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub4_msa,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg3_msa,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg4_msa,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth3_msa,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth4_msa,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
 #endif
 
 #if PNG_MIPS_MMI_IMPLEMENTATION > 0
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_mmi,(png_row_infop row_info,
-    png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_mmi,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_mmi,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_mmi,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_mmi,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_mmi,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_mmi,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_up_mmi,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub3_mmi,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub4_mmi,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg3_mmi,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg4_mmi,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth3_mmi,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth4_mmi,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
 #endif
 
 #if PNG_POWERPC_VSX_OPT > 0
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_vsx,(png_row_infop row_info,
-    png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_vsx,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_vsx,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_vsx,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_vsx,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_vsx,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_vsx,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_up_vsx,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub3_vsx,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub4_vsx,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg3_vsx,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg4_vsx,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth3_vsx,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth4_vsx,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
 #endif
 
 #if PNG_INTEL_SSE_IMPLEMENTATION > 0
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_sse2,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_sse2,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_sse2,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_sse2,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_sse2,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_sse2,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub3_sse2,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub4_sse2,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg3_sse2,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg4_sse2,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth3_sse2,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth4_sse2,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
 #endif
 
 #if PNG_LOONGARCH_LSX_IMPLEMENTATION == 1
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_lsx,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_lsx,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_lsx,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_lsx,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_lsx,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_lsx,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_lsx,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_up_lsx,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub3_lsx,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub4_lsx,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg3_lsx,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg4_lsx,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth3_lsx,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth4_lsx,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
 #endif
 
 #if PNG_RISCV_RVV_IMPLEMENTATION == 1
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_rvv,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_rvv,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_rvv,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_rvv,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_rvv,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_rvv,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_rvv,(png_row_infop
-    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_up_rvv,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub3_rvv,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub4_rvv,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg3_rvv,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg4_rvv,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth3_rvv,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth4_rvv,
+   (png_row_infop row_info, png_bytep row, png_const_bytep prev_row),
+   PNG_EMPTY);
 #endif
 
 /* Choose the best filter to use and filter the row data */
-PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr,
-    png_row_infop row_info),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_write_find_filter,
+   (png_structrp png_ptr, png_row_infop row_info),
+   PNG_EMPTY);
 
 #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_read_IDAT_data,(png_structrp png_ptr,
-   png_bytep output, png_alloc_size_t avail_out),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_IDAT_data,
+   (png_structrp png_ptr, png_bytep output, png_alloc_size_t avail_out),
+   PNG_EMPTY);
    /* Read 'avail_out' bytes of data from the IDAT stream.  If the output buffer
     * is NULL the function checks, instead, for the end of the stream.  In this
     * case a benign error will be issued if the stream end is not found or if
     * extra data has to be consumed.
     */
-PNG_INTERNAL_FUNCTION(void,png_read_finish_IDAT,(png_structrp png_ptr),
+PNG_INTERNAL_FUNCTION(void, png_read_finish_IDAT,
+   (png_structrp png_ptr),
    PNG_EMPTY);
    /* This cleans up when the IDAT LZ stream does not end when the last image
     * byte is read; there is still some pending input.
     */
 
-PNG_INTERNAL_FUNCTION(void,png_read_finish_row,(png_structrp png_ptr),
+PNG_INTERNAL_FUNCTION(void, png_read_finish_row,
+   (png_structrp png_ptr),
    PNG_EMPTY);
    /* Finish a row while reading, dealing with interlacing passes, etc. */
 #endif /* SEQUENTIAL_READ */
 
 /* Initialize the row buffers, etc. */
-PNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_start_row,
+   (png_structrp png_ptr),
+   PNG_EMPTY);
 
 #if ZLIB_VERNUM >= 0x1240
-PNG_INTERNAL_FUNCTION(int,png_zlib_inflate,(png_structrp png_ptr, int flush),
-      PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(int, png_zlib_inflate,
+   (png_structrp png_ptr, int flush),
+   PNG_EMPTY);
 #  define PNG_INFLATE(pp, flush) png_zlib_inflate(pp, flush)
 #else /* Zlib < 1.2.4 */
 #  define PNG_INFLATE(pp, flush) inflate(&(pp)->zstream, flush)
@@ -1628,38 +1762,44 @@ PNG_INTERNAL_FUNCTION(int,png_zlib_inflate,(png_structrp png_ptr, int flush),
 
 #ifdef PNG_READ_TRANSFORMS_SUPPORTED
 /* Optional call to update the users info structure */
-PNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr,
-    png_inforp info_ptr),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_transform_info,
+   (png_structrp png_ptr, png_inforp info_ptr),
+   PNG_EMPTY);
 #endif
 
 /* Shared transform functions, defined in pngtran.c */
 #if defined(PNG_WRITE_FILLER_SUPPORTED) || \
     defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
-PNG_INTERNAL_FUNCTION(void,png_do_strip_channel,(png_row_infop row_info,
-    png_bytep row, int at_start),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_do_strip_channel,
+   (png_row_infop row_info, png_bytep row, int at_start),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_16BIT_SUPPORTED
 #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
-PNG_INTERNAL_FUNCTION(void,png_do_swap,(png_row_infop row_info,
-    png_bytep row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_do_swap,
+   (png_row_infop row_info, png_bytep row),
+   PNG_EMPTY);
 #endif
 #endif
 
 #if defined(PNG_READ_PACKSWAP_SUPPORTED) || \
     defined(PNG_WRITE_PACKSWAP_SUPPORTED)
-PNG_INTERNAL_FUNCTION(void,png_do_packswap,(png_row_infop row_info,
-    png_bytep row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_do_packswap,
+   (png_row_infop row_info, png_bytep row),
+   PNG_EMPTY);
 #endif
 
 #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
-PNG_INTERNAL_FUNCTION(void,png_do_invert,(png_row_infop row_info,
-    png_bytep row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_do_invert,
+   (png_row_infop row_info, png_bytep row),
+   PNG_EMPTY);
 #endif
 
 #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
-PNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_row_infop row_info,
-    png_bytep row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_do_bgr,
+   (png_row_infop row_info, png_bytep row),
+   PNG_EMPTY);
 #endif
 
 /* The following decodes the appropriate chunks, and does error correction,
@@ -1680,25 +1820,27 @@ typedef enum
    handled_ok          /* known, supported and handled without error */
 } png_handle_result_code;
 
-PNG_INTERNAL_FUNCTION(png_handle_result_code,png_handle_unknown,
-    (png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length, int keep),
-    PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(png_handle_result_code, png_handle_unknown,
+   (png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length, int keep),
+   PNG_EMPTY);
    /* This is the function that gets called for unknown chunks.  The 'keep'
     * argument is either non-zero for a known chunk that has been set to be
     * handled as unknown or zero for an unknown chunk.  By default the function
     * just skips the chunk or errors out if it is critical.
     */
 
-PNG_INTERNAL_FUNCTION(png_handle_result_code,png_handle_chunk,
-    (png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(png_handle_result_code, png_handle_chunk,
+   (png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),
+   PNG_EMPTY);
    /* This handles the current chunk png_ptr->chunk_name with unread
     * data[length] and returns one of the above result codes.
     */
 
 #if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\
     defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED)
-PNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling,
-    (png_const_structrp png_ptr, png_uint_32 chunk_name),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(int, png_chunk_unknown_handling,
+   (png_const_structrp png_ptr, png_uint_32 chunk_name),
+   PNG_EMPTY);
    /* Exactly as the API png_handle_as_unknown() except that the argument is a
     * 32-bit chunk name, not a string.
     */
@@ -1706,93 +1848,122 @@ PNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling,
 
 /* Handle the transformations for reading and writing */
 #ifdef PNG_READ_TRANSFORMS_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_do_read_transformations,(png_structrp png_ptr,
-   png_row_infop row_info),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_do_read_transformations,
+   (png_structrp png_ptr, png_row_infop row_info),
+   PNG_EMPTY);
 #endif
 #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_do_write_transformations,(png_structrp png_ptr,
-   png_row_infop row_info),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_do_write_transformations,
+   (png_structrp png_ptr, png_row_infop row_info),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_READ_TRANSFORMS_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_init_read_transformations,(png_structrp png_ptr),
-    PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_init_read_transformations,
+   (png_structrp png_ptr),
+   PNG_EMPTY);
 #endif
 
 #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_push_read_chunk,(png_structrp png_ptr,
-    png_inforp info_ptr),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_push_read_sig,(png_structrp png_ptr,
-    png_inforp info_ptr),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_push_check_crc,(png_structrp png_ptr),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_push_save_buffer,(png_structrp png_ptr),
-    PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_push_restore_buffer,(png_structrp png_ptr,
-    png_bytep buffer, size_t buffer_length),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_push_read_IDAT,(png_structrp png_ptr),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_process_IDAT_data,(png_structrp png_ptr,
-    png_bytep buffer, size_t buffer_length),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_push_process_row,(png_structrp png_ptr),
-    PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_push_have_info,(png_structrp png_ptr,
-   png_inforp info_ptr),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_push_have_end,(png_structrp png_ptr,
-   png_inforp info_ptr),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_push_have_row,(png_structrp png_ptr,
-    png_bytep row),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_push_read_end,(png_structrp png_ptr,
-    png_inforp info_ptr),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_process_some_data,(png_structrp png_ptr,
-    png_inforp info_ptr),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_read_push_finish_row,(png_structrp png_ptr),
-    PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_push_read_chunk,
+   (png_structrp png_ptr, png_inforp info_ptr),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_push_read_sig,
+   (png_structrp png_ptr, png_inforp info_ptr),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_push_check_crc,
+   (png_structrp png_ptr),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_push_save_buffer,
+   (png_structrp png_ptr),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_push_restore_buffer,
+   (png_structrp png_ptr, png_bytep buffer, size_t buffer_length),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_push_read_IDAT,
+   (png_structrp png_ptr),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_process_IDAT_data,
+   (png_structrp png_ptr, png_bytep buffer, size_t buffer_length),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_push_process_row,
+   (png_structrp png_ptr),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_push_have_info,
+   (png_structrp png_ptr, png_inforp info_ptr),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_push_have_end,
+   (png_structrp png_ptr, png_inforp info_ptr),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_push_have_row,
+   (png_structrp png_ptr, png_bytep row),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_push_read_end,
+   (png_structrp png_ptr, png_inforp info_ptr),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_process_some_data,
+   (png_structrp png_ptr, png_inforp info_ptr),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_read_push_finish_row,
+   (png_structrp png_ptr),
+   PNG_EMPTY);
 #endif /* PROGRESSIVE_READ */
 
 #ifdef PNG_iCCP_SUPPORTED
 /* Routines for checking parts of an ICC profile. */
 #ifdef PNG_READ_iCCP_SUPPORTED
-PNG_INTERNAL_FUNCTION(int,png_icc_check_length,(png_const_structrp png_ptr,
-   png_const_charp name, png_uint_32 profile_length), PNG_EMPTY);
-#endif /* READ_iCCP */
-PNG_INTERNAL_FUNCTION(int,png_icc_check_header,(png_const_structrp png_ptr,
-   png_const_charp name, png_uint_32 profile_length,
-   png_const_bytep profile /* first 132 bytes only */, int color_type),
+PNG_INTERNAL_FUNCTION(int, png_icc_check_length,
+   (png_const_structrp png_ptr,
+    png_const_charp name, png_uint_32 profile_length),
+   PNG_EMPTY);
+#endif /* READ_iCCP */
+PNG_INTERNAL_FUNCTION(int, png_icc_check_header,
+   (png_const_structrp png_ptr,
+    png_const_charp name, png_uint_32 profile_length,
+    png_const_bytep profile /* first 132 bytes only */, int color_type),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(int, png_icc_check_tag_table,
+   (png_const_structrp png_ptr,
+    png_const_charp name, png_uint_32 profile_length,
+    png_const_bytep profile /* header plus whole tag table */),
    PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(int,png_icc_check_tag_table,(png_const_structrp png_ptr,
-   png_const_charp name, png_uint_32 profile_length,
-   png_const_bytep profile /* header plus whole tag table */), PNG_EMPTY);
 #endif /* iCCP */
 
 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_set_rgb_coefficients, (png_structrp png_ptr),
+PNG_INTERNAL_FUNCTION(void, png_set_rgb_coefficients,
+   (png_structrp png_ptr),
    PNG_EMPTY);
    /* Set the rgb_to_gray coefficients from the cHRM Y values (if unset) */
 #endif /* READ_RGB_TO_GRAY */
 
 /* Added at libpng version 1.4.0 */
-PNG_INTERNAL_FUNCTION(void,png_check_IHDR,(png_const_structrp png_ptr,
-    png_uint_32 width, png_uint_32 height, int bit_depth,
-    int color_type, int interlace_type, int compression_type,
-    int filter_type),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_check_IHDR,
+   (png_const_structrp png_ptr,
+    png_uint_32 width, png_uint_32 height, int bit_depth, int color_type,
+    int interlace_type, int compression_type, int filter_type),
+   PNG_EMPTY);
 
 /* Added at libpng version 1.5.10 */
 #if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \
     defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED)
-PNG_INTERNAL_FUNCTION(void,png_do_check_palette_indexes,
-   (png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_do_check_palette_indexes,
+   (png_structrp png_ptr, png_row_infop row_info),
+   PNG_EMPTY);
 #endif
 
 #if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)
-PNG_INTERNAL_FUNCTION(void,png_fixed_error,(png_const_structrp png_ptr,
-   png_const_charp name),PNG_NORETURN);
+PNG_INTERNAL_FUNCTION(void, png_fixed_error,
+   (png_const_structrp png_ptr, png_const_charp name),
+   PNG_NORETURN);
 #endif
 
 /* Puts 'string' into 'buffer' at buffer[pos], taking care never to overwrite
  * the end.  Always leaves the buffer nul terminated.  Never errors out (and
  * there is no error code.)
  */
-PNG_INTERNAL_FUNCTION(size_t,png_safecat,(png_charp buffer, size_t bufsize,
-   size_t pos, png_const_charp string),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(size_t, png_safecat,
+   (png_charp buffer, size_t bufsize, size_t pos, png_const_charp string),
+   PNG_EMPTY);
 
 /* Various internal functions to handle formatted warning messages, currently
  * only implemented for warnings.
@@ -1803,8 +1974,9 @@ PNG_INTERNAL_FUNCTION(size_t,png_safecat,(png_charp buffer, size_t bufsize,
  * Returns the pointer to the start of the formatted string.  This utility only
  * does unsigned values.
  */
-PNG_INTERNAL_FUNCTION(png_charp,png_format_number,(png_const_charp start,
-   png_charp end, int format, png_alloc_size_t number),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(png_charp, png_format_number,
+   (png_const_charp start, png_charp end, int format, png_alloc_size_t number),
+   PNG_EMPTY);
 
 /* Convenience macro that takes an array: */
 #define PNG_FORMAT_NUMBER(buffer,format,number) \
@@ -1836,23 +2008,26 @@ PNG_INTERNAL_FUNCTION(png_charp,png_format_number,(png_const_charp start,
 typedef char png_warning_parameters[PNG_WARNING_PARAMETER_COUNT][
    PNG_WARNING_PARAMETER_SIZE];
 
-PNG_INTERNAL_FUNCTION(void,png_warning_parameter,(png_warning_parameters p,
-   int number, png_const_charp string),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_warning_parameter,
+   (png_warning_parameters p, int number, png_const_charp string),
+   PNG_EMPTY);
    /* Parameters are limited in size to PNG_WARNING_PARAMETER_SIZE characters,
     * including the trailing '\0'.
     */
-PNG_INTERNAL_FUNCTION(void,png_warning_parameter_unsigned,
+PNG_INTERNAL_FUNCTION(void, png_warning_parameter_unsigned,
    (png_warning_parameters p, int number, int format, png_alloc_size_t value),
    PNG_EMPTY);
    /* Use png_alloc_size_t because it is an unsigned type as big as any we
     * need to output.  Use the following for a signed value.
     */
-PNG_INTERNAL_FUNCTION(void,png_warning_parameter_signed,
+PNG_INTERNAL_FUNCTION(void, png_warning_parameter_signed,
    (png_warning_parameters p, int number, int format, png_int_32 value),
    PNG_EMPTY);
 
-PNG_INTERNAL_FUNCTION(void,png_formatted_warning,(png_const_structrp png_ptr,
-   png_warning_parameters p, png_const_charp message),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_formatted_warning,
+   (png_const_structrp png_ptr,
+    png_warning_parameters p, png_const_charp message),
+   PNG_EMPTY);
    /* 'message' follows the X/Open approach of using @1, @2 to insert
     * parameters previously supplied using the above functions.  Errors in
     * specifying the parameters will simply result in garbage substitutions.
@@ -1874,14 +2049,16 @@ PNG_INTERNAL_FUNCTION(void,png_formatted_warning,(png_const_structrp png_ptr,
  * If benign errors aren't supported they end up as the corresponding base call
  * (png_warning or png_error.)
  */
-PNG_INTERNAL_FUNCTION(void,png_app_warning,(png_const_structrp png_ptr,
-   png_const_charp message),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_app_warning,
+   (png_const_structrp png_ptr, png_const_charp message),
+   PNG_EMPTY);
    /* The application provided invalid parameters to an API function or called
     * an API function at the wrong time, libpng can completely recover.
     */
 
-PNG_INTERNAL_FUNCTION(void,png_app_error,(png_const_structrp png_ptr,
-   png_const_charp message),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_app_error,
+   (png_const_structrp png_ptr, png_const_charp message),
+   PNG_EMPTY);
    /* As above but libpng will ignore the call, or attempt some other partial
     * recovery from the error.
     */
@@ -1890,8 +2067,9 @@ PNG_INTERNAL_FUNCTION(void,png_app_error,(png_const_structrp png_ptr,
 #  define png_app_error(pp,s) png_error(pp,s)
 #endif
 
-PNG_INTERNAL_FUNCTION(void,png_chunk_report,(png_const_structrp png_ptr,
-   png_const_charp message, int error),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_chunk_report,
+   (png_const_structrp png_ptr, png_const_charp message, int error),
+   PNG_EMPTY);
    /* Report a recoverable issue in chunk data.  On read this is used to report
     * a problem found while reading a particular chunk and the
     * png_chunk_benign_error or png_chunk_warning function is used as
@@ -1917,14 +2095,17 @@ PNG_INTERNAL_FUNCTION(void,png_chunk_report,(png_const_structrp png_ptr,
 #define PNG_sCAL_MAX_DIGITS (PNG_sCAL_PRECISION+1/*.*/+1/*E*/+10/*exponent*/)
 
 #ifdef PNG_FLOATING_POINT_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_ascii_from_fp,(png_const_structrp png_ptr,
-   png_charp ascii, size_t size, double fp, unsigned int precision),
+PNG_INTERNAL_FUNCTION(void, png_ascii_from_fp,
+   (png_const_structrp png_ptr,
+    png_charp ascii, size_t size, double fp, unsigned int precision),
    PNG_EMPTY);
 #endif /* FLOATING_POINT */
 
 #ifdef PNG_FIXED_POINT_SUPPORTED
-PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr,
-   png_charp ascii, size_t size, png_fixed_point fp),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_ascii_from_fixed,
+   (png_const_structrp png_ptr,
+    png_charp ascii, size_t size, png_fixed_point fp),
+   PNG_EMPTY);
 #endif /* FIXED_POINT */
 #endif /* sCAL */
 
@@ -2016,8 +2197,9 @@ PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr,
  * that omits the last character (i.e. set the size to the index of
  * the problem character.)  This has not been tested within libpng.
  */
-PNG_INTERNAL_FUNCTION(int,png_check_fp_number,(png_const_charp string,
-   size_t size, int *statep, size_t *whereami),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(int, png_check_fp_number,
+   (png_const_charp string, size_t size, int *statep, size_t *whereami),
+   PNG_EMPTY);
 
 /* This is the same but it checks a complete string and returns true
  * only if it just contains a floating point number.  As of 1.5.4 this
@@ -2025,8 +2207,9 @@ PNG_INTERNAL_FUNCTION(int,png_check_fp_number,(png_const_charp string,
  * it was valid (otherwise it returns 0.)  This can be used for testing
  * for negative or zero values using the sticky flag.
  */
-PNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string,
-   size_t size),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(int, png_check_fp_string,
+   (png_const_charp string, size_t size),
+   PNG_EMPTY);
 #endif /* pCAL || sCAL */
 
 #if defined(PNG_READ_GAMMA_SUPPORTED) ||\
@@ -2039,14 +2222,17 @@ PNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string,
  * for overflow, true (1) if no overflow, in which case *res
  * holds the result.
  */
-PNG_INTERNAL_FUNCTION(int,png_muldiv,(png_fixed_point_p res, png_fixed_point a,
-   png_int_32 multiplied_by, png_int_32 divided_by),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(int, png_muldiv,
+   (png_fixed_point_p res, png_fixed_point a,
+    png_int_32 multiplied_by, png_int_32 divided_by),
+   PNG_EMPTY);
 
 /* Calculate a reciprocal - used for gamma values.  This returns
  * 0 if the argument is 0 in order to maintain an undefined value;
  * there are no warnings.
  */
-PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a),
+PNG_INTERNAL_FUNCTION(png_fixed_point, png_reciprocal,
+   (png_fixed_point a),
    PNG_EMPTY);
 #endif
 
@@ -2055,11 +2241,13 @@ PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a),
  * values.  Accuracy is suitable for gamma calculations but this is
  * not exact - use png_muldiv for that.  Only required at present on read.
  */
-PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal2,(png_fixed_point a,
-   png_fixed_point b),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(png_fixed_point, png_reciprocal2,
+   (png_fixed_point a, png_fixed_point b),
+   PNG_EMPTY);
 
 /* Return true if the gamma value is significantly different from 1.0 */
-PNG_INTERNAL_FUNCTION(int,png_gamma_significant,(png_fixed_point gamma_value),
+PNG_INTERNAL_FUNCTION(int, png_gamma_significant,
+   (png_fixed_point gamma_value),
    PNG_EMPTY);
 
 /* PNGv3: 'resolve' the file gamma according to the new PNGv3 rules for colour
@@ -2070,8 +2258,9 @@ PNG_INTERNAL_FUNCTION(int,png_gamma_significant,(png_fixed_point gamma_value),
  * transforms.  For this reason a gamma specified by png_set_gamma always takes
  * precedence.
  */
-PNG_INTERNAL_FUNCTION(png_fixed_point,png_resolve_file_gamma,
-   (png_const_structrp png_ptr),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(png_fixed_point, png_resolve_file_gamma,
+   (png_const_structrp png_ptr),
+   PNG_EMPTY);
 
 /* Internal fixed point gamma correction.  These APIs are called as
  * required to convert single values - they don't need to be fast,
@@ -2080,37 +2269,45 @@ PNG_INTERNAL_FUNCTION(png_fixed_point,png_resolve_file_gamma,
  * While the input is an 'unsigned' value it must actually be the
  * correct bit value - 0..255 or 0..65535 as required.
  */
-PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_correct,(png_structrp png_ptr,
-   unsigned int value, png_fixed_point gamma_value),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_16bit_correct,(unsigned int value,
-   png_fixed_point gamma_value),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(png_byte,png_gamma_8bit_correct,(unsigned int value,
-   png_fixed_point gamma_value),PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_destroy_gamma_table,(png_structrp png_ptr),
+PNG_INTERNAL_FUNCTION(png_uint_16, png_gamma_correct,
+   (png_structrp png_ptr, unsigned int value, png_fixed_point gamma_value),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(png_uint_16, png_gamma_16bit_correct,
+   (unsigned int value, png_fixed_point gamma_value),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(png_byte, png_gamma_8bit_correct,
+   (unsigned int value, png_fixed_point gamma_value),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_destroy_gamma_table,
+   (png_structrp png_ptr),
+   PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_build_gamma_table,
+   (png_structrp png_ptr, int bit_depth),
    PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_build_gamma_table,(png_structrp png_ptr,
-   int bit_depth),PNG_EMPTY);
 #endif /* READ_GAMMA */
 
 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
 /* Set the RGB coefficients if not already set by png_set_rgb_to_gray */
-PNG_INTERNAL_FUNCTION(void,png_set_rgb_coefficients,(png_structrp png_ptr),
+PNG_INTERNAL_FUNCTION(void, png_set_rgb_coefficients,
+   (png_structrp png_ptr),
    PNG_EMPTY);
 #endif
 
 #if defined(PNG_cHRM_SUPPORTED) || defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
-PNG_INTERNAL_FUNCTION(int,png_XYZ_from_xy,(png_XYZ *XYZ, const png_xy *xy),
+PNG_INTERNAL_FUNCTION(int, png_XYZ_from_xy,
+   (png_XYZ *XYZ, const png_xy *xy),
    PNG_EMPTY);
 #endif /* cHRM || READ_RGB_TO_GRAY */
 
 #ifdef PNG_COLORSPACE_SUPPORTED
-PNG_INTERNAL_FUNCTION(int,png_xy_from_XYZ,(png_xy *xy, const png_XYZ *XYZ),
+PNG_INTERNAL_FUNCTION(int, png_xy_from_XYZ,
+   (png_xy *xy, const png_XYZ *XYZ),
    PNG_EMPTY);
 #endif
 
 /* SIMPLIFIED READ/WRITE SUPPORT */
 #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\
-   defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
+    defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
 /* The internal structure that png_image::opaque points to. */
 typedef struct png_control
 {
@@ -2138,28 +2335,34 @@ typedef struct png_control
  * errors that might occur.  Returns true on success, false on failure (either
  * of the function or as a result of a png_error.)
  */
-PNG_INTERNAL_CALLBACK(void,png_safe_error,(png_structp png_ptr,
-   png_const_charp error_message),PNG_NORETURN);
+PNG_INTERNAL_CALLBACK(void, png_safe_error,
+   (png_structp png_ptr, png_const_charp error_message),
+   PNG_NORETURN);
 
 #ifdef PNG_WARNINGS_SUPPORTED
-PNG_INTERNAL_CALLBACK(void,png_safe_warning,(png_structp png_ptr,
-   png_const_charp warning_message),PNG_EMPTY);
+PNG_INTERNAL_CALLBACK(void, png_safe_warning,
+   (png_structp png_ptr, png_const_charp warning_message),
+   PNG_EMPTY);
 #else
 #  define png_safe_warning 0/*dummy argument*/
 #endif
 
-PNG_INTERNAL_FUNCTION(int,png_safe_execute,(png_imagep image,
-   int (*function)(png_voidp), png_voidp arg),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(int, png_safe_execute,
+   (png_imagep image, int (*function)(png_voidp), png_voidp arg),
+   PNG_EMPTY);
 
 /* Utility to log an error; this also cleans up the png_image; the function
  * always returns 0 (false).
  */
-PNG_INTERNAL_FUNCTION(int,png_image_error,(png_imagep image,
-   png_const_charp error_message),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(int, png_image_error,
+   (png_imagep image, png_const_charp error_message),
+   PNG_EMPTY);
 
 #ifndef PNG_SIMPLIFIED_READ_SUPPORTED
 /* png_image_free is used by the write code but not exported */
-PNG_INTERNAL_FUNCTION(void, png_image_free, (png_imagep image), PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_image_free,
+   (png_imagep image),
+   PNG_EMPTY);
 #endif /* !SIMPLIFIED_READ */
 
 #endif /* SIMPLIFIED READ/WRITE */
@@ -2170,8 +2373,9 @@ PNG_INTERNAL_FUNCTION(void, png_image_free, (png_imagep image), PNG_EMPTY);
  * the generic code is used.
  */
 #ifdef PNG_FILTER_OPTIMIZATIONS
-PNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS, (png_structp png_ptr,
-   unsigned int bpp), PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS,
+   (png_structp png_ptr, unsigned int bpp),
+   PNG_EMPTY);
    /* Just declare the optimization that will be used */
 #else
    /* List *all* the possible optimizations here - this branch is required if
@@ -2180,37 +2384,44 @@ PNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS, (png_structp png_ptr,
     */
 #  if PNG_ARM_NEON_OPT > 0
 PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon,
-   (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+   (png_structp png_ptr, unsigned int bpp),
+   PNG_EMPTY);
 #endif
 
 #if PNG_MIPS_MSA_IMPLEMENTATION == 1
 PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_mips,
-   (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+   (png_structp png_ptr, unsigned int bpp),
+   PNG_EMPTY);
 #endif
 
 #  if PNG_MIPS_MMI_IMPLEMENTATION > 0
 PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_mips,
-   (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+   (png_structp png_ptr, unsigned int bpp),
+   PNG_EMPTY);
 #  endif
 
 #  if PNG_INTEL_SSE_IMPLEMENTATION > 0
 PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_sse2,
-   (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+   (png_structp png_ptr, unsigned int bpp),
+   PNG_EMPTY);
 #  endif
 #endif
 
 #if PNG_LOONGARCH_LSX_OPT > 0
 PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_lsx,
-    (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+   (png_structp png_ptr, unsigned int bpp),
+   PNG_EMPTY);
 #endif
 
 #  if PNG_RISCV_RVV_IMPLEMENTATION == 1
 PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_rvv,
-   (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+   (png_structp png_ptr, unsigned int bpp),
+   PNG_EMPTY);
 #endif
 
-PNG_INTERNAL_FUNCTION(png_uint_32, png_check_keyword, (png_structrp png_ptr,
-   png_const_charp key, png_bytep new_key), PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(png_uint_32, png_check_keyword,
+   (png_structrp png_ptr, png_const_charp key, png_bytep new_key),
+   PNG_EMPTY);
 
 #if PNG_ARM_NEON_IMPLEMENTATION == 1
 PNG_INTERNAL_FUNCTION(void,
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
index b53668a09ce..79fd9ad6a82 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2025 Cosmin Truta
+ * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -52,7 +52,8 @@
 /* Create a PNG structure for reading, and allocate any memory needed. */
 PNG_FUNCTION(png_structp,PNGAPI
 png_create_read_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
-    png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED)
+    png_error_ptr error_fn, png_error_ptr warn_fn),
+    PNG_ALLOCATED)
 {
 #ifndef PNG_USER_MEM_SUPPORTED
    png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr,
@@ -68,7 +69,8 @@ png_create_read_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
 PNG_FUNCTION(png_structp,PNGAPI
 png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
     png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
-    png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)
+    png_malloc_ptr malloc_fn, png_free_ptr free_fn),
+    PNG_ALLOCATED)
 {
    png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr,
        error_fn, warn_fn, mem_ptr, malloc_fn, free_fn);
@@ -548,7 +550,6 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row)
 
    if (png_ptr->read_row_fn != NULL)
       (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
-
 }
 #endif /* SEQUENTIAL_READ */
 
@@ -896,7 +897,7 @@ png_set_read_status_fn(png_structrp png_ptr, png_read_status_ptr read_row_fn)
 #ifdef PNG_INFO_IMAGE_SUPPORTED
 void PNGAPI
 png_read_png(png_structrp png_ptr, png_inforp info_ptr,
-    int transforms, voidp params)
+    int transforms, png_voidp params)
 {
    png_debug(1, "in png_read_png");
 
@@ -1133,19 +1134,20 @@ png_read_png(png_structrp png_ptr, png_inforp info_ptr,
 
 typedef struct
 {
-   /* Arguments: */
+   /* Arguments */
    png_imagep image;
-   png_voidp  buffer;
+   png_voidp buffer;
    png_int_32 row_stride;
-   png_voidp  colormap;
+   png_voidp colormap;
    png_const_colorp background;
-   /* Local variables: */
-   png_voidp       local_row;
-   png_voidp       first_row;
-   ptrdiff_t       row_bytes;           /* step between rows */
-   int             file_encoding;       /* E_ values above */
-   png_fixed_point gamma_to_linear;     /* For P_FILE, reciprocal of gamma */
-   int             colormap_processing; /* PNG_CMAP_ values above */
+
+   /* Instance variables */
+   png_voidp local_row;
+   png_voidp first_row;
+   ptrdiff_t row_step;              /* step between rows */
+   int file_encoding;               /* E_ values above */
+   png_fixed_point gamma_to_linear; /* For P_FILE, reciprocal of gamma */
+   int colormap_processing;         /* PNG_CMAP_ values above */
 } png_image_read_control;
 
 /* Do all the *safe* initialization - 'safe' means that png_error won't be
@@ -2866,17 +2868,17 @@ png_image_read_and_map(png_voidp argument)
    }
 
    {
-      png_uint_32  height = image->height;
-      png_uint_32  width = image->width;
-      int          proc = display->colormap_processing;
-      png_bytep    first_row = png_voidcast(png_bytep, display->first_row);
-      ptrdiff_t    step_row = display->row_bytes;
+      png_uint_32 height = image->height;
+      png_uint_32 width = image->width;
+      int proc = display->colormap_processing;
+      png_bytep first_row = png_voidcast(png_bytep, display->first_row);
+      ptrdiff_t row_step = display->row_step;
       int pass;
 
       for (pass = 0; pass < passes; ++pass)
       {
-         unsigned int     startx, stepx, stepy;
-         png_uint_32      y;
+         unsigned int startx, stepx, stepy;
+         png_uint_32 y;
 
          if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)
          {
@@ -2900,7 +2902,7 @@ png_image_read_and_map(png_voidp argument)
          for (; ylocal_row);
-            png_bytep outrow = first_row + y * step_row;
+            png_bytep outrow = first_row + y * row_step;
             png_const_bytep end_row = outrow + width;
 
             /* Read read the libpng data into the temporary buffer. */
@@ -3109,20 +3111,20 @@ png_image_read_colormapped(png_voidp argument)
     */
    {
       png_voidp first_row = display->buffer;
-      ptrdiff_t row_bytes = display->row_stride;
+      ptrdiff_t row_step = display->row_stride;
 
-      /* The following expression is designed to work correctly whether it gives
-       * a signed or an unsigned result.
+      /* The following adjustment is to ensure that calculations are correct,
+       * regardless whether row_step is positive or negative.
        */
-      if (row_bytes < 0)
+      if (row_step < 0)
       {
          char *ptr = png_voidcast(char*, first_row);
-         ptr += (image->height-1) * (-row_bytes);
+         ptr += (image->height-1) * (-row_step);
          first_row = png_voidcast(png_voidp, ptr);
       }
 
       display->first_row = first_row;
-      display->row_bytes = row_bytes;
+      display->row_step = row_step;
    }
 
    if (passes == 0)
@@ -3140,17 +3142,17 @@ png_image_read_colormapped(png_voidp argument)
 
    else
    {
-      png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes;
+      ptrdiff_t row_step = display->row_step;
 
       while (--passes >= 0)
       {
-         png_uint_32      y = image->height;
-         png_bytep        row = png_voidcast(png_bytep, display->first_row);
+         png_uint_32 y = image->height;
+         png_bytep row = png_voidcast(png_bytep, display->first_row);
 
          for (; y > 0; --y)
          {
             png_read_row(png_ptr, row, NULL);
-            row += row_bytes;
+            row += row_step;
          }
       }
 
@@ -3166,9 +3168,11 @@ png_image_read_direct_scaled(png_voidp argument)
        argument);
    png_imagep image = display->image;
    png_structrp png_ptr = image->opaque->png_ptr;
+   png_inforp info_ptr = image->opaque->info_ptr;
    png_bytep local_row = png_voidcast(png_bytep, display->local_row);
    png_bytep first_row = png_voidcast(png_bytep, display->first_row);
-   ptrdiff_t row_bytes = display->row_bytes;
+   ptrdiff_t row_step = display->row_step;
+   size_t row_bytes = png_get_rowbytes(png_ptr, info_ptr);
    int passes;
 
    /* Handle interlacing. */
@@ -3197,9 +3201,14 @@ png_image_read_direct_scaled(png_voidp argument)
          /* Read into local_row (gets transformed 8-bit data). */
          png_read_row(png_ptr, local_row, NULL);
 
-         /* Copy from local_row to user buffer. */
-         memcpy(output_row, local_row, (size_t)row_bytes);
-         output_row += row_bytes;
+         /* Copy from local_row to user buffer.
+          * Use row_bytes (i.e. the actual size in bytes of the row data) for
+          * copying into output_row. Use row_step for advancing output_row,
+          * to respect the caller's stride for padding or negative (bottom-up)
+          * layouts.
+          */
+         memcpy(output_row, local_row, row_bytes);
+         output_row += row_step;
       }
    }
 
@@ -3231,17 +3240,18 @@ png_image_read_composite(png_voidp argument)
    }
 
    {
-      png_uint_32  height = image->height;
-      png_uint_32  width = image->width;
-      ptrdiff_t    step_row = display->row_bytes;
+      png_uint_32 height = image->height;
+      png_uint_32 width = image->width;
+      ptrdiff_t row_step = display->row_step;
       unsigned int channels =
           (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1;
+      int optimize_alpha = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0;
       int pass;
 
       for (pass = 0; pass < passes; ++pass)
       {
-         unsigned int     startx, stepx, stepy;
-         png_uint_32      y;
+         unsigned int startx, stepx, stepy;
+         png_uint_32 y;
 
          if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)
          {
@@ -3273,7 +3283,7 @@ png_image_read_composite(png_voidp argument)
             png_read_row(png_ptr, inrow, NULL);
 
             outrow = png_voidcast(png_bytep, display->first_row);
-            outrow += y * step_row;
+            outrow += y * row_step;
             end_row = outrow + width * channels;
 
             /* Now do the composition on each pixel in this row. */
@@ -3292,20 +3302,44 @@ png_image_read_composite(png_voidp argument)
 
                      if (alpha < 255) /* else just use component */
                      {
-                        /* This is PNG_OPTIMIZED_ALPHA, the component value
-                         * is a linear 8-bit value.  Combine this with the
-                         * current outrow[c] value which is sRGB encoded.
-                         * Arithmetic here is 16-bits to preserve the output
-                         * values correctly.
-                         */
-                        component *= 257*255; /* =65535 */
-                        component += (255-alpha)*png_sRGB_table[outrow[c]];
+                        if (optimize_alpha != 0)
+                        {
+                           /* This is PNG_OPTIMIZED_ALPHA, the component value
+                            * is a linear 8-bit value.  Combine this with the
+                            * current outrow[c] value which is sRGB encoded.
+                            * Arithmetic here is 16-bits to preserve the output
+                            * values correctly.
+                            */
+                           component *= 257*255; /* =65535 */
+                           component += (255-alpha)*png_sRGB_table[outrow[c]];
 
-                        /* So 'component' is scaled by 255*65535 and is
-                         * therefore appropriate for the sRGB to linear
-                         * conversion table.
-                         */
-                        component = PNG_sRGB_FROM_LINEAR(component);
+                           /* Clamp to the valid range to defend against
+                            * unforeseen cases where the data might be sRGB
+                            * instead of linear premultiplied.
+                            * (Belt-and-suspenders for CVE-2025-66293.)
+                            */
+                           if (component > 255*65535)
+                              component = 255*65535;
+
+                           /* So 'component' is scaled by 255*65535 and is
+                            * therefore appropriate for the sRGB-to-linear
+                            * conversion table.
+                            */
+                           component = PNG_sRGB_FROM_LINEAR(component);
+                        }
+                        else
+                        {
+                           /* Compositing was already done on the palette
+                            * entries.  The data is sRGB premultiplied on black.
+                            * Composite with the background in sRGB space.
+                            * This is not gamma-correct, but matches what was
+                            * done to the palette.
+                            */
+                           png_uint_32 background = outrow[c];
+                           component += ((255-alpha) * background + 127) / 255;
+                           if (component > 255)
+                              component = 255;
+                        }
                      }
 
                      outrow[c] = (png_byte)component;
@@ -3394,12 +3428,12 @@ png_image_read_background(png_voidp argument)
           */
          {
             png_bytep first_row = png_voidcast(png_bytep, display->first_row);
-            ptrdiff_t step_row = display->row_bytes;
+            ptrdiff_t row_step = display->row_step;
 
             for (pass = 0; pass < passes; ++pass)
             {
-               unsigned int     startx, stepx, stepy;
-               png_uint_32      y;
+               unsigned int startx, stepx, stepy;
+               png_uint_32 y;
 
                if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)
                {
@@ -3426,7 +3460,7 @@ png_image_read_background(png_voidp argument)
                   {
                      png_bytep inrow = png_voidcast(png_bytep,
                          display->local_row);
-                     png_bytep outrow = first_row + y * step_row;
+                     png_bytep outrow = first_row + y * row_step;
                      png_const_bytep end_row = outrow + width;
 
                      /* Read the row, which is packed: */
@@ -3471,7 +3505,7 @@ png_image_read_background(png_voidp argument)
                   {
                      png_bytep inrow = png_voidcast(png_bytep,
                          display->local_row);
-                     png_bytep outrow = first_row + y * step_row;
+                     png_bytep outrow = first_row + y * row_step;
                      png_const_bytep end_row = outrow + width;
 
                      /* Read the row, which is packed: */
@@ -3517,9 +3551,9 @@ png_image_read_background(png_voidp argument)
             png_uint_16p first_row = png_voidcast(png_uint_16p,
                 display->first_row);
             /* The division by two is safe because the caller passed in a
-             * stride which was multiplied by 2 (below) to get row_bytes.
+             * stride which was multiplied by 2 (below) to get row_step.
              */
-            ptrdiff_t    step_row = display->row_bytes / 2;
+            ptrdiff_t row_step = display->row_step / 2;
             unsigned int preserve_alpha = (image->format &
                 PNG_FORMAT_FLAG_ALPHA) != 0;
             unsigned int outchannels = 1U+preserve_alpha;
@@ -3533,8 +3567,8 @@ png_image_read_background(png_voidp argument)
 
             for (pass = 0; pass < passes; ++pass)
             {
-               unsigned int     startx, stepx, stepy;
-               png_uint_32      y;
+               unsigned int startx, stepx, stepy;
+               png_uint_32 y;
 
                /* The 'x' start and step are adjusted to output components here.
                 */
@@ -3561,7 +3595,7 @@ png_image_read_background(png_voidp argument)
                for (; ybuffer;
-      ptrdiff_t row_bytes = display->row_stride;
+      ptrdiff_t row_step = display->row_stride;
 
       if (linear != 0)
-         row_bytes *= 2;
+         row_step *= 2;
 
-      /* The following expression is designed to work correctly whether it gives
-       * a signed or an unsigned result.
+      /* The following adjustment is to ensure that calculations are correct,
+       * regardless whether row_step is positive or negative.
        */
-      if (row_bytes < 0)
+      if (row_step < 0)
       {
          char *ptr = png_voidcast(char*, first_row);
-         ptr += (image->height-1) * (-row_bytes);
+         ptr += (image->height - 1) * (-row_step);
          first_row = png_voidcast(png_voidp, ptr);
       }
 
       display->first_row = first_row;
-      display->row_bytes = row_bytes;
+      display->row_step = row_step;
    }
 
    if (do_local_compose != 0)
@@ -4063,17 +4097,17 @@ png_image_read_direct(png_voidp argument)
 
    else
    {
-      png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes;
+      ptrdiff_t row_step = display->row_step;
 
       while (--passes >= 0)
       {
-         png_uint_32      y = image->height;
-         png_bytep        row = png_voidcast(png_bytep, display->first_row);
+         png_uint_32 y = image->height;
+         png_bytep row = png_voidcast(png_bytep, display->first_row);
 
          for (; y > 0; --y)
          {
             png_read_row(png_ptr, row, NULL);
-            row += row_bytes;
+            row += row_step;
          }
       }
 
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
index a19615f49fe..7680fe64828 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
@@ -1149,8 +1149,8 @@ png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red,
 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
     defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
 void PNGAPI
-png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr
-    read_user_transform_fn)
+png_set_read_user_transform_fn(png_structrp png_ptr,
+    png_user_transform_ptr read_user_transform_fn)
 {
    png_debug(1, "in png_set_read_user_transform_fn");
 
@@ -1872,6 +1872,7 @@ png_init_read_transformations(png_structrp png_ptr)
              * transformations elsewhere.
              */
             png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA);
+            png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
          } /* color_type == PNG_COLOR_TYPE_PALETTE */
 
          /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
index 07d53cb2c76..01bb0c8bedc 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
@@ -2415,7 +2415,7 @@ png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 static png_handle_result_code /* PRIVATE */
 png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
-   png_text  text_info;
+   png_text text_info;
    png_bytep buffer;
    png_charp key;
    png_charp text;
@@ -2488,8 +2488,8 @@ static png_handle_result_code /* PRIVATE */
 png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
    png_const_charp errmsg = NULL;
-   png_bytep       buffer;
-   png_uint_32     keyword_length;
+   png_bytep buffer;
+   png_uint_32 keyword_length;
 
    png_debug(1, "in png_handle_zTXt");
 
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c
index 2350057e70e..b9f6cb5d437 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c
@@ -831,8 +831,8 @@ png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info)
     defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
 #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
 void PNGAPI
-png_set_user_transform_info(png_structrp png_ptr, png_voidp
-   user_transform_ptr, int user_transform_depth, int user_transform_channels)
+png_set_user_transform_info(png_structrp png_ptr, png_voidp user_transform_ptr,
+    int user_transform_depth, int user_transform_channels)
 {
    png_debug(1, "in png_set_user_transform_info");
 

From 599ed0bb5fd62e26c71651bc02f198cd27636cfb Mon Sep 17 00:00:00 2001
From: SendaoYan 
Date: Wed, 21 Jan 2026 03:39:02 +0000
Subject: [PATCH 115/328] 8375485: Tests in vmTestbase/nsk are failing due to
 missing class unloading after 8373945

Reviewed-by: lmesnik, cjplummer
---
 .../jvmti/scenarios/events/EM02/em02t003.java   | 17 ++++++++++++++++-
 .../vmTestbase/nsk/share/ClassUnloader.java     | 17 ++++++++++++++++-
 2 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003.java
index d4cb4a8569a..a23732dc554 100644
--- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003.java
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2026, 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
@@ -105,6 +105,21 @@ public class em02t003 extends DebugeeClass {
                 return Consts.TEST_FAILED;
             }
 
+            while (thrd.isAlive()) {
+                logger.display("Thread state: " + thrd.getState()
+                    + " - waiting for completion.");
+                try {
+                    // small delay to avoid produce huge amount of output
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                }
+            }
+            try {
+                // give some time wait thread to exit completely
+                Thread.sleep(2000);
+            } catch (InterruptedException e) {
+            }
+
             logger.display("MethodCompiling:: Provoke unloading compiled method - "
                                 + "\n\ttrying to unload class...");
             thrd = null;
diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java b/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java
index 94b086f5757..5c7d2b8d640 100644
--- a/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java
@@ -239,6 +239,9 @@ public class ClassUnloader {
      *
      * @see WhiteBox.getWhiteBox().fullGC()
      */
+
+    public static final int MAX_UNLOAD_ATTEMPS = 10;
+
     public boolean unloadClass() {
 
         // free references to class and class loader to be able for collecting by GC
@@ -247,14 +250,26 @@ public class ClassUnloader {
 
         // force class unloading by triggering full GC
         WhiteBox.getWhiteBox().fullGC();
+        int count = 0;
+        while (count++ < MAX_UNLOAD_ATTEMPS && !isClassLoaderReclaimed()) {
+            System.out.println("ClassUnloader: waiting for class loader reclaiming... " + count);
+            WhiteBox.getWhiteBox().fullGC();
+            try {
+                // small delay to give more changes to process objects
+                // inside VM like jvmti deferred queue
+                Thread.sleep(100);
+            } catch (InterruptedException e) {
+            }
+        }
 
         // force GC to unload marked class loader and its classes
         if (isClassLoaderReclaimed()) {
-            Runtime.getRuntime().gc();
+            System.out.println("ClassUnloader: class loader has been reclaimed.");
             return true;
         }
 
         // class loader has not been reclaimed
+        System.out.println("ClassUnloader: class loader is still reachable.");
         return false;
     }
 }

From a448f0b9f46de35ef26994e8540b9ae242372e8d Mon Sep 17 00:00:00 2001
From: SendaoYan 
Date: Wed, 21 Jan 2026 03:39:26 +0000
Subject: [PATCH 116/328] 8375668: Compiler warning
 implicit-const-int-float-conversion by clang23

Reviewed-by: dholmes, cnorrbin
---
 src/hotspot/os/linux/cgroupSubsystem_linux.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
index 8aafbf49c63..d083a9985c2 100644
--- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
+++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
@@ -188,7 +188,7 @@ class CachedMetric : public CHeapObj{
     volatile jlong _next_check_counter;
   public:
     CachedMetric() {
-      _metric = value_unlimited;
+      _metric = static_cast(value_unlimited);
       _next_check_counter = min_jlong;
     }
     bool should_check_metric() {

From 34d6e5e07b8ee43ee7f913dd47fa7c897f52e6c0 Mon Sep 17 00:00:00 2001
From: Kim Barrett 
Date: Wed, 21 Jan 2026 05:56:19 +0000
Subject: [PATCH 117/328] 8375737: Fix -Wzero-as-null-pointer-constant warnings
 in arm32 code

Reviewed-by: dholmes
---
 src/hotspot/cpu/arm/frame_arm.cpp         | 6 +++---
 src/hotspot/cpu/arm/nativeInst_arm_32.cpp | 6 +++---
 src/hotspot/cpu/arm/nativeInst_arm_32.hpp | 4 ++--
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/hotspot/cpu/arm/frame_arm.cpp b/src/hotspot/cpu/arm/frame_arm.cpp
index 7a23296a3d4..f791fae7bd7 100644
--- a/src/hotspot/cpu/arm/frame_arm.cpp
+++ b/src/hotspot/cpu/arm/frame_arm.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2026, 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
@@ -356,10 +356,10 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
 bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
   assert(is_interpreted_frame(), "Not an interpreted frame");
   // These are reasonable sanity checks
-  if (fp() == 0 || (intptr_t(fp()) & (wordSize-1)) != 0) {
+  if (fp() == nullptr || (intptr_t(fp()) & (wordSize-1)) != 0) {
     return false;
   }
-  if (sp() == 0 || (intptr_t(sp()) & (wordSize-1)) != 0) {
+  if (sp() == nullptr || (intptr_t(sp()) & (wordSize-1)) != 0) {
     return false;
   }
   if (fp() + interpreter_frame_initial_sp_offset < sp()) {
diff --git a/src/hotspot/cpu/arm/nativeInst_arm_32.cpp b/src/hotspot/cpu/arm/nativeInst_arm_32.cpp
index 232294b246a..df780ac31a6 100644
--- a/src/hotspot/cpu/arm/nativeInst_arm_32.cpp
+++ b/src/hotspot/cpu/arm/nativeInst_arm_32.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2026, 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
@@ -172,7 +172,7 @@ void NativeMovConstReg::set_data(intptr_t x, address pc) {
 
     address addr = oop_addr != nullptr ? (address)oop_addr : (address)metadata_addr;
 
-    if(pc == 0) {
+    if (pc == nullptr) {
       offset = addr - instruction_address() - 8;
     } else {
       offset = addr - pc - 8;
@@ -228,7 +228,7 @@ void NativeMovConstReg::set_data(intptr_t x, address pc) {
 
 void NativeMovConstReg::set_pc_relative_offset(address addr, address pc) {
   int offset;
-  if (pc == 0) {
+  if (pc == nullptr) {
     offset = addr - instruction_address() - 8;
   } else {
     offset = addr - pc - 8;
diff --git a/src/hotspot/cpu/arm/nativeInst_arm_32.hpp b/src/hotspot/cpu/arm/nativeInst_arm_32.hpp
index 82385bf0244..2b52db89285 100644
--- a/src/hotspot/cpu/arm/nativeInst_arm_32.hpp
+++ b/src/hotspot/cpu/arm/nativeInst_arm_32.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -371,7 +371,7 @@ class NativeMovConstReg: public NativeInstruction {
  public:
 
   intptr_t data() const;
-  void set_data(intptr_t x, address pc = 0);
+  void set_data(intptr_t x, address pc = nullptr);
   bool is_pc_relative() {
     return !is_movw();
   }

From b5727d27622e1e321733f8d0e606b366984104be Mon Sep 17 00:00:00 2001
From: Kim Barrett 
Date: Wed, 21 Jan 2026 06:04:09 +0000
Subject: [PATCH 118/328] 8375738: Fix -Wzero-as-null-pointer-constant warnings
 in MacOSX/bsd code

Reviewed-by: erikj, dholmes
---
 make/hotspot/lib/CompileGtest.gmk           | 5 +++--
 src/hotspot/os/bsd/memMapPrinter_macosx.cpp | 2 +-
 src/hotspot/os/bsd/os_bsd.cpp               | 4 ++--
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk
index 60912992134..327014b1e9d 100644
--- a/make/hotspot/lib/CompileGtest.gmk
+++ b/make/hotspot/lib/CompileGtest.gmk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2026, 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,8 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBGTEST, \
     INCLUDE_FILES := gtest-all.cc gmock-all.cc, \
     DISABLED_WARNINGS_gcc := format-nonliteral maybe-uninitialized undef \
         unused-result zero-as-null-pointer-constant, \
-    DISABLED_WARNINGS_clang := format-nonliteral undef unused-result, \
+    DISABLED_WARNINGS_clang := format-nonliteral undef unused-result \
+        zero-as-null-pointer-constant, \
     DISABLED_WARNINGS_microsoft := 4530, \
     DEFAULT_CFLAGS := false, \
     CFLAGS := $(JVM_CFLAGS) \
diff --git a/src/hotspot/os/bsd/memMapPrinter_macosx.cpp b/src/hotspot/os/bsd/memMapPrinter_macosx.cpp
index 6fd08d63e85..30e258c9d2c 100644
--- a/src/hotspot/os/bsd/memMapPrinter_macosx.cpp
+++ b/src/hotspot/os/bsd/memMapPrinter_macosx.cpp
@@ -132,7 +132,7 @@ public:
   static const char* tagToStr(uint32_t user_tag) {
     switch (user_tag) {
       case 0:
-        return 0;
+        return nullptr;
       X1(MALLOC, malloc);
       X1(MALLOC_SMALL, malloc_small);
       X1(MALLOC_LARGE, malloc_large);
diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp
index 667810bd6ca..0e21c2d1785 100644
--- a/src/hotspot/os/bsd/os_bsd.cpp
+++ b/src/hotspot/os/bsd/os_bsd.cpp
@@ -628,7 +628,7 @@ static void *thread_native_entry(Thread *thread) {
   log_info(os, thread)("Thread finished (tid: %zu, pthread id: %zu).",
     os::current_thread_id(), (uintx) pthread_self());
 
-  return 0;
+  return nullptr;
 }
 
 bool os::create_thread(Thread* thread, ThreadType thr_type,
@@ -1420,7 +1420,7 @@ int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *pa
 #elif defined(__APPLE__)
   for (uint32_t i = 1; i < _dyld_image_count(); i++) {
     // Value for top_address is returned as 0 since we don't have any information about module size
-    if (callback(_dyld_get_image_name(i), (address)_dyld_get_image_header(i), (address)0, param)) {
+    if (callback(_dyld_get_image_name(i), (address)_dyld_get_image_header(i), nullptr, param)) {
       return 1;
     }
   }

From 560a92a6327221c90596bcd17a87722e4910472a Mon Sep 17 00:00:00 2001
From: Jie Fu 
Date: Wed, 21 Jan 2026 06:33:54 +0000
Subject: [PATCH 119/328] 8375787: compiler/vectorapi/TestCastShapeBadOpc.java
 fails with release VMs

Reviewed-by: syan, lmesnik, fyang, epeter
---
 test/hotspot/jtreg/compiler/vectorapi/TestCastShapeBadOpc.java | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestCastShapeBadOpc.java b/test/hotspot/jtreg/compiler/vectorapi/TestCastShapeBadOpc.java
index 4c20c84bc50..743c243cb58 100644
--- a/test/hotspot/jtreg/compiler/vectorapi/TestCastShapeBadOpc.java
+++ b/test/hotspot/jtreg/compiler/vectorapi/TestCastShapeBadOpc.java
@@ -30,6 +30,7 @@
  * @run main/othervm
  *      -XX:+IgnoreUnrecognizedVMOptions
  *      -XX:-TieredCompilation -Xbatch
+ *      -XX:+UnlockDiagnosticVMOptions
  *      -XX:StressSeed=1462975402
  *      -XX:+StressIncrementalInlining
  *      -XX:CompileCommand=compileonly,${test.main.class}::test2
@@ -44,6 +45,7 @@
  * @run main/othervm
  *      -XX:+IgnoreUnrecognizedVMOptions
  *      -XX:-TieredCompilation -Xbatch
+ *      -XX:+UnlockDiagnosticVMOptions
  *      -XX:+StressIncrementalInlining
  *      -XX:CompileCommand=compileonly,${test.main.class}::test2
  *      ${test.main.class}

From 4f87fb53ee5c6071fa57dfe9452eca9fe7b460ee Mon Sep 17 00:00:00 2001
From: Thomas Schatzl 
Date: Wed, 21 Jan 2026 09:01:00 +0000
Subject: [PATCH 120/328] 8375622: G1: Convert G1CodeRootSet to use Atomic

Reviewed-by: shade, sjohanss
---
 src/hotspot/share/gc/g1/g1CodeRootSet.cpp | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/hotspot/share/gc/g1/g1CodeRootSet.cpp b/src/hotspot/share/gc/g1/g1CodeRootSet.cpp
index 60ad3a2af32..ca4487876b9 100644
--- a/src/hotspot/share/gc/g1/g1CodeRootSet.cpp
+++ b/src/hotspot/share/gc/g1/g1CodeRootSet.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,7 @@
 #include "gc/g1/g1HeapRegion.hpp"
 #include "memory/allocation.hpp"
 #include "oops/oop.inline.hpp"
-#include "runtime/atomicAccess.hpp"
+#include "runtime/atomic.hpp"
 #include "utilities/concurrentHashTable.inline.hpp"
 #include "utilities/concurrentHashTableTasks.inline.hpp"
 
@@ -60,7 +60,7 @@ class G1CodeRootSetHashTable : public CHeapObj {
   HashTable _table;
   HashTableScanTask _table_scanner;
 
-  size_t volatile _num_entries;
+  Atomic _num_entries;
 
   bool is_empty() const { return number_of_entries() == 0; }
 
@@ -120,7 +120,7 @@ public:
     bool grow_hint = false;
     bool inserted = _table.insert(Thread::current(), lookup, method, &grow_hint);
     if (inserted) {
-      AtomicAccess::inc(&_num_entries);
+      _num_entries.add_then_fetch(1u);
     }
     if (grow_hint) {
       _table.grow(Thread::current());
@@ -131,7 +131,7 @@ public:
     HashTableLookUp lookup(method);
     bool removed = _table.remove(Thread::current(), lookup);
     if (removed) {
-      AtomicAccess::dec(&_num_entries);
+      _num_entries.sub_then_fetch(1u);
     }
     return removed;
   }
@@ -182,7 +182,7 @@ public:
     guarantee(succeeded, "unable to clean table");
 
     if (num_deleted != 0) {
-      size_t current_size = AtomicAccess::sub(&_num_entries, num_deleted);
+      size_t current_size = _num_entries.sub_then_fetch(num_deleted);
       shrink_to_match(current_size);
     }
   }
@@ -226,7 +226,7 @@ public:
 
   size_t mem_size() { return sizeof(*this) + _table.get_mem_size(Thread::current()); }
 
-  size_t number_of_entries() const { return AtomicAccess::load(&_num_entries); }
+  size_t number_of_entries() const { return _num_entries.load_relaxed(); }
 };
 
 uintx G1CodeRootSetHashTable::HashTableLookUp::get_hash() const {

From b1340305c8f5ea53b45b8bd3bd2ebe8f74864d40 Mon Sep 17 00:00:00 2001
From: Ivan Walulya 
Date: Wed, 21 Jan 2026 09:51:01 +0000
Subject: [PATCH 121/328] 8238686: G1 may waste lots of space or fail to
 uncommit when observing MinHeapFreeRatio during sizing after full gc

Reviewed-by: tschatzl, sjohanss
---
 src/hotspot/share/gc/g1/g1Arguments.cpp | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/src/hotspot/share/gc/g1/g1Arguments.cpp b/src/hotspot/share/gc/g1/g1Arguments.cpp
index 58e76cdd43a..ffb06a7d822 100644
--- a/src/hotspot/share/gc/g1/g1Arguments.cpp
+++ b/src/hotspot/share/gc/g1/g1Arguments.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -209,6 +209,17 @@ void G1Arguments::initialize() {
     FLAG_SET_DEFAULT(GCTimeRatio, 24);
   }
 
+  // Do not interfere with GC-Pressure driven heap resizing unless the user
+  // explicitly sets otherwise. G1 heap sizing should be free to grow or shrink
+  // the heap based on GC pressure, rather than being forced to satisfy
+  // MinHeapFreeRatio or MaxHeapFreeRatio defaults that the user did not set.
+  if (FLAG_IS_DEFAULT(MinHeapFreeRatio)) {
+    FLAG_SET_DEFAULT(MinHeapFreeRatio, 0);
+  }
+  if (FLAG_IS_DEFAULT(MaxHeapFreeRatio)) {
+    FLAG_SET_DEFAULT(MaxHeapFreeRatio, 100);
+  }
+
   // Below, we might need to calculate the pause time interval based on
   // the pause target. When we do so we are going to give G1 maximum
   // flexibility and allow it to do pauses when it needs to. So, we'll

From 5c7c2f093b83a017970d9d05c258b4c0910bfc2c Mon Sep 17 00:00:00 2001
From: Francesco Andreuzzi 
Date: Wed, 21 Jan 2026 10:42:05 +0000
Subject: [PATCH 122/328] 8375717: Outdated link in jdk.jfr.internal.JVM
 javadoc

Reviewed-by: egahlin
---
 src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java
index 841221c57d9..24c92e81a4c 100644
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java
@@ -71,7 +71,7 @@ public final class JVM {
     /**
      * Begin recording events
      *
-     * Requires that JFR has been started with {@link #createNativeJFR()}
+     * Requires that JFR has been started with {@link JVMSupport#createJFR()}
      */
     public static native void beginRecording();
 
@@ -83,7 +83,7 @@ public final class JVM {
     /**
      * End recording events, which includes flushing data in thread buffers
      *
-     * Requires that JFR has been started with {@link #createNativeJFR()}
+     * Requires that JFR has been started with {@link JVMSupport#createJFR()}
      *
      */
     public static native void endRecording();
@@ -144,7 +144,7 @@ public final class JVM {
     /**
      * Return unique identifier for stack trace.
      *
-     * Requires that JFR has been started with {@link #createNativeJFR()}
+     * Requires that JFR has been started with {@link JVMSupport#createJFR()}
      *
      * @param skipCount number of frames to skip, or 0 if no frames should be
      *                  skipped
@@ -295,7 +295,7 @@ public final class JVM {
     /**
      * Sets the file where data should be written.
      *
-     * Requires that JFR has been started with {@link #createNativeJFR()}
+     * Requires that JFR has been started with {@link JVMSupport#createJFR()}
      *
      * 
      * Recording  Previous  Current  Action
@@ -380,7 +380,7 @@ public final class JVM {
      * chunk, data should be written after GMT offset and size of metadata event
      * should be adjusted
      *
-     * Requires that JFR has been started with {@link #createNativeJFR()}
+     * Requires that JFR has been started with {@link JVMSupport#createJFR()}
      *
      * @param bytes binary representation of metadata descriptor
      */
@@ -409,7 +409,7 @@ public final class JVM {
     /**
      * Destroys native part of JFR. If already destroy, call is ignored.
      *
-     * Requires that JFR has been started with {@link #createNativeJFR()}
+     * Requires that JFR has been started with {@link JVMSupport#createJFR()}
      *
      * @return if an instance was actually destroyed.
      *

From 983ae96f60c935aa52f482d21ae6a0d947679541 Mon Sep 17 00:00:00 2001
From: Jatin Bhateja 
Date: Wed, 21 Jan 2026 11:20:18 +0000
Subject: [PATCH 123/328] 8375498: [VectorAPI] Dump primary vector IR details
 with -XX:+TraceNewVectors

Reviewed-by: epeter
---
 src/hotspot/share/opto/vectorIntrinsics.cpp | 81 ++++++++++++---------
 1 file changed, 45 insertions(+), 36 deletions(-)

diff --git a/src/hotspot/share/opto/vectorIntrinsics.cpp b/src/hotspot/share/opto/vectorIntrinsics.cpp
index 6dcf4615b10..65d54e076b6 100644
--- a/src/hotspot/share/opto/vectorIntrinsics.cpp
+++ b/src/hotspot/share/opto/vectorIntrinsics.cpp
@@ -74,6 +74,11 @@ static bool is_vector_mask(ciKlass* klass) {
   return klass->is_subclass_of(ciEnv::current()->vector_VectorMask_klass());
 }
 
+static Node* trace_vector(Node* operation) {
+  VectorNode::trace_new_vector(operation, "VectorAPI");
+  return operation;
+}
+
 bool LibraryCallKit::arch_supports_vector_rotate(int opc, int num_elem, BasicType elem_bt,
                                                  VectorMaskUseType mask_use_type, bool has_scalar_args) {
   bool is_supported = true;
@@ -458,7 +463,7 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) {
     }
     default: fatal("unsupported arity: %d", n);
   }
-
+  trace_vector(operation);
   if (is_masked_op && mask != nullptr) {
     if (use_predicate) {
       operation->add_req(mask);
@@ -466,7 +471,7 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) {
     } else {
       operation->add_flag(Node::Flag_is_predicated_using_blend);
       operation = gvn().transform(operation);
-      operation = new VectorBlendNode(opd1, operation, mask);
+      operation = trace_vector(new VectorBlendNode(opd1, operation, mask));
     }
   }
   operation = gvn().transform(operation);
@@ -627,7 +632,7 @@ bool LibraryCallKit::inline_vector_mask_operation() {
     mask_vec = gvn().transform(VectorStoreMaskNode::make(gvn(), mask_vec, elem_bt, num_elem));
   }
   const Type* maskoper_ty = mopc == Op_VectorMaskToLong ? (const Type*)TypeLong::LONG : (const Type*)TypeInt::INT;
-  Node* maskoper = gvn().transform(VectorMaskOpNode::make(mask_vec, maskoper_ty, mopc));
+  Node* maskoper = gvn().transform(trace_vector(VectorMaskOpNode::make(mask_vec, maskoper_ty, mopc)));
   if (mopc != Op_VectorMaskToLong) {
     maskoper = ConvI2L(maskoper);
   }
@@ -710,10 +715,10 @@ bool LibraryCallKit::inline_vector_frombits_coerced() {
   if (opc == Op_VectorLongToMask) {
     const TypeVect* vt = TypeVect::makemask(elem_bt, num_elem);
     if (Matcher::mask_op_prefers_predicate(opc, vt)) {
-      broadcast = gvn().transform(new VectorLongToMaskNode(elem, vt));
+      broadcast = gvn().transform(trace_vector(new VectorLongToMaskNode(elem, vt)));
     } else {
       const TypeVect* mvt = TypeVect::make(T_BOOLEAN, num_elem);
-      broadcast = gvn().transform(new VectorLongToMaskNode(elem, mvt));
+      broadcast = gvn().transform(trace_vector(new VectorLongToMaskNode(elem, mvt)));
       broadcast = gvn().transform(new VectorLoadMaskNode(broadcast, vt));
     }
   } else {
@@ -741,7 +746,7 @@ bool LibraryCallKit::inline_vector_frombits_coerced() {
       }
       default: fatal("%s", type2name(elem_bt));
     }
-    broadcast = VectorNode::scalar2vector(elem, num_elem, elem_bt, is_mask);
+    broadcast = trace_vector(VectorNode::scalar2vector(elem, num_elem, elem_bt, is_mask));
     broadcast = gvn().transform(broadcast);
   }
 
@@ -927,22 +932,22 @@ bool LibraryCallKit::inline_vector_mem_operation(bool is_store) {
     if (is_mask) {
       val = gvn().transform(VectorStoreMaskNode::make(gvn(), val, elem_bt, num_elem));
     }
-    Node* vstore = gvn().transform(StoreVectorNode::make(0, control(), memory(addr), addr, addr_type, val, store_num_elem));
+    Node* vstore = gvn().transform(trace_vector(StoreVectorNode::make(0, control(), memory(addr), addr, addr_type, val, store_num_elem)));
     set_memory(vstore, addr_type);
   } else {
     // When using byte array, we need to load as byte then reinterpret the value. Otherwise, do a simple vector load.
     Node* vload = nullptr;
     if (mismatched_ms) {
-      vload = gvn().transform(LoadVectorNode::make(0, control(), memory(addr), addr, addr_type, mem_num_elem, mem_elem_bt));
+      vload = gvn().transform(trace_vector(LoadVectorNode::make(0, control(), memory(addr), addr, addr_type, mem_num_elem, mem_elem_bt)));
       const TypeVect* to_vect_type = TypeVect::make(elem_bt, num_elem);
       vload = gvn().transform(new VectorReinterpretNode(vload, vload->bottom_type()->is_vect(), to_vect_type));
     } else {
       // Special handle for masks
       if (is_mask) {
-        vload = gvn().transform(LoadVectorNode::make(0, control(), memory(addr), addr, addr_type, num_elem, T_BOOLEAN));
+        vload = gvn().transform(trace_vector(LoadVectorNode::make(0, control(), memory(addr), addr, addr_type, num_elem, T_BOOLEAN)));
         vload = gvn().transform(new VectorLoadMaskNode(vload, TypeVect::makemask(elem_bt, num_elem)));
       } else {
-        vload = gvn().transform(LoadVectorNode::make(0, control(), memory(addr), addr, addr_type, num_elem, elem_bt));
+        vload = gvn().transform(trace_vector(LoadVectorNode::make(0, control(), memory(addr), addr, addr_type, num_elem, elem_bt)));
       }
     }
     Node* box = box_vector(vload, vbox_type, elem_bt, num_elem);
@@ -1140,7 +1145,7 @@ bool LibraryCallKit::inline_vector_mem_masked_operation(bool is_store) {
       const TypeVect* to_mask_type = TypeVect::makemask(mem_elem_bt, mem_num_elem);
       mask = gvn().transform(new VectorReinterpretNode(mask, from_mask_type, to_mask_type));
     }
-    Node* vstore = gvn().transform(new StoreVectorMaskedNode(control(), memory(addr), addr, val, addr_type, mask));
+    Node* vstore = gvn().transform(trace_vector(new StoreVectorMaskedNode(control(), memory(addr), addr, val, addr_type, mask)));
     set_memory(vstore, addr_type);
   } else {
     Node* vload = nullptr;
@@ -1155,13 +1160,13 @@ bool LibraryCallKit::inline_vector_mem_masked_operation(bool is_store) {
     if (supports_predicate) {
       // Generate masked load vector node if predicate feature is supported.
       const TypeVect* vt = TypeVect::make(mem_elem_bt, mem_num_elem);
-      vload = gvn().transform(new LoadVectorMaskedNode(control(), memory(addr), addr, addr_type, vt, mask));
+      vload = gvn().transform(trace_vector(new LoadVectorMaskedNode(control(), memory(addr), addr, addr_type, vt, mask)));
     } else {
       // Use the vector blend to implement the masked load vector. The biased elements are zeros.
       Node* zero = gvn().transform(gvn().zerocon(mem_elem_bt));
       zero = gvn().transform(VectorNode::scalar2vector(zero, mem_num_elem, mem_elem_bt));
-      vload = gvn().transform(LoadVectorNode::make(0, control(), memory(addr), addr, addr_type, mem_num_elem, mem_elem_bt));
-      vload = gvn().transform(new VectorBlendNode(zero, vload, mask));
+      vload = gvn().transform(trace_vector(LoadVectorNode::make(0, control(), memory(addr), addr, addr_type, mem_num_elem, mem_elem_bt)));
+      vload = gvn().transform(trace_vector(new VectorBlendNode(zero, vload, mask)));
     }
 
     if (mismatched_ms) {
@@ -1365,17 +1370,17 @@ bool LibraryCallKit::inline_vector_gather_scatter(bool is_scatter) {
 
     Node* vstore = nullptr;
     if (mask != nullptr) {
-      vstore = gvn().transform(new StoreVectorScatterMaskedNode(control(), memory(addr), addr, addr_type, val, indexes, mask));
+      vstore = gvn().transform(trace_vector(new StoreVectorScatterMaskedNode(control(), memory(addr), addr, addr_type, val, indexes, mask)));
     } else {
-      vstore = gvn().transform(new StoreVectorScatterNode(control(), memory(addr), addr, addr_type, val, indexes));
+      vstore = gvn().transform(trace_vector(new StoreVectorScatterNode(control(), memory(addr), addr, addr_type, val, indexes)));
     }
     set_memory(vstore, addr_type);
   } else {
     Node* vload = nullptr;
     if (mask != nullptr) {
-      vload = gvn().transform(new LoadVectorGatherMaskedNode(control(), memory(addr), addr, addr_type, vector_type, indexes, mask));
+      vload = gvn().transform(trace_vector(new LoadVectorGatherMaskedNode(control(), memory(addr), addr, addr_type, vector_type, indexes, mask)));
     } else {
-      vload = gvn().transform(new LoadVectorGatherNode(control(), memory(addr), addr, addr_type, vector_type, indexes));
+      vload = gvn().transform(trace_vector(new LoadVectorGatherNode(control(), memory(addr), addr, addr_type, vector_type, indexes)));
     }
     Node* box = box_vector(vload, vbox_type, elem_bt, num_elem);
     set_result(box);
@@ -1493,7 +1498,7 @@ bool LibraryCallKit::inline_vector_reduction() {
 
   // Make an unordered Reduction node. This affects only AddReductionVF/VD and MulReductionVF/VD,
   // as these operations are allowed to be associative (not requiring strict order) in VectorAPI.
-  value = ReductionNode::make(opc, nullptr, init, value, elem_bt, /* requires_strict_order */ false);
+  value = trace_vector(ReductionNode::make(opc, nullptr, init, value, elem_bt, /* requires_strict_order */ false));
 
   if (mask != nullptr && use_predicate) {
     value->add_req(mask);
@@ -1585,7 +1590,7 @@ bool LibraryCallKit::inline_vector_test() {
     return false; // operand unboxing failed
   }
 
-  Node* cmp = gvn().transform(new VectorTestNode(opd1, opd2, booltest));
+  Node* cmp = gvn().transform(trace_vector(new VectorTestNode(opd1, opd2, booltest)));
   BoolTest::mask test = Matcher::vectortest_mask(booltest == BoolTest::overflow,
                                                  opd1->bottom_type()->isa_vectmask(), num_elem);
   Node* bol = gvn().transform(new BoolNode(cmp, test));
@@ -1653,7 +1658,7 @@ bool LibraryCallKit::inline_vector_blend() {
     return false; // operand unboxing failed
   }
 
-  Node* blend = gvn().transform(new VectorBlendNode(v1, v2, mask));
+  Node* blend = gvn().transform(trace_vector(new VectorBlendNode(v1, v2, mask)));
 
   Node* box = box_vector(blend, vbox_type, elem_bt, num_elem);
   set_result(box);
@@ -1748,6 +1753,7 @@ bool LibraryCallKit::inline_vector_compare() {
 
   const TypeVect* vmask_type = TypeVect::makemask(mask_bt, num_elem);
   Node* operation = new VectorMaskCmpNode(pred, v1, v2, pred_node, vmask_type);
+  trace_vector(operation);
 
   if (is_masked_op) {
     if (use_predicate) {
@@ -1887,6 +1893,7 @@ bool LibraryCallKit::inline_vector_rearrange() {
   }
 
   Node* rearrange = new VectorRearrangeNode(v1, shuffle);
+  trace_vector(rearrange);
   if (is_masked_op) {
     if (use_predicate) {
       rearrange->add_req(mask);
@@ -2034,6 +2041,7 @@ bool LibraryCallKit::inline_vector_select_from() {
 
   // and finally rearrange
   Node* rearrange = new VectorRearrangeNode(v2, shuffle);
+  trace_vector(rearrange);
   if (is_masked_op) {
     if (use_predicate) {
       // masked rearrange is supported so use that directly
@@ -2193,6 +2201,7 @@ bool LibraryCallKit::inline_vector_broadcast_int() {
   }
 
   Node* operation = VectorNode::make(opc, opd1, opd2, num_elem, elem_bt);
+  trace_vector(operation);
   if (is_masked_op && mask != nullptr) {
     if (use_predicate) {
       operation->add_req(mask);
@@ -2370,7 +2379,7 @@ bool LibraryCallKit::inline_vector_convert() {
         return false;
       }
 
-      op = gvn().transform(VectorCastNode::make(cast_vopc, op, elem_bt_to, num_elem_for_cast));
+      op = gvn().transform(trace_vector(VectorCastNode::make(cast_vopc, op, elem_bt_to, num_elem_for_cast)));
       // Now ensure that the destination gets properly resized to needed size.
       op = gvn().transform(new VectorReinterpretNode(op, op->bottom_type()->is_vect(), dst_type));
     } else if (num_elem_from > num_elem_to) {
@@ -2391,7 +2400,7 @@ bool LibraryCallKit::inline_vector_convert() {
 
       const TypeVect* resize_type = TypeVect::make(elem_bt_from, num_elem_for_resize);
       op = gvn().transform(new VectorReinterpretNode(op, src_type, resize_type));
-      op = gvn().transform(VectorCastNode::make(cast_vopc, op, elem_bt_to, num_elem_to));
+      op = gvn().transform(trace_vector(VectorCastNode::make(cast_vopc, op, elem_bt_to, num_elem_to)));
     } else { // num_elem_from == num_elem_to
       if (is_mask) {
         // Make sure that cast for vector mask is implemented to particular type/size combination.
@@ -2400,16 +2409,16 @@ bool LibraryCallKit::inline_vector_convert() {
                           num_elem_to, type2name(elem_bt_to), is_mask);
           return false;
         }
-        op = gvn().transform(new VectorMaskCastNode(op, dst_type));
+        op = gvn().transform(trace_vector(new VectorMaskCastNode(op, dst_type)));
       } else {
         // Since input and output number of elements match, and since we know this vector size is
         // supported, simply do a cast with no resize needed.
-        op = gvn().transform(VectorCastNode::make(cast_vopc, op, elem_bt_to, num_elem_to));
+        op = gvn().transform(trace_vector(VectorCastNode::make(cast_vopc, op, elem_bt_to, num_elem_to)));
       }
     }
   } else if (!Type::equals(src_type, dst_type)) {
     assert(!is_cast, "must be reinterpret");
-    op = gvn().transform(new VectorReinterpretNode(op, src_type, dst_type));
+    op = gvn().transform(trace_vector(new VectorReinterpretNode(op, src_type, dst_type)));
   }
 
   const TypeInstPtr* vbox_type_to = TypeInstPtr::make_exact(TypePtr::NotNull, vbox_klass_to);
@@ -2494,7 +2503,7 @@ bool LibraryCallKit::inline_vector_insert() {
     default: fatal("%s", type2name(elem_bt)); break;
   }
 
-  Node* operation = gvn().transform(VectorInsertNode::make(opd, insert_val, idx->get_con(), gvn()));
+  Node* operation = gvn().transform(trace_vector(VectorInsertNode::make(opd, insert_val, idx->get_con(), gvn())));
 
   Node* vbox = box_vector(operation, vbox_type, elem_bt, num_elem);
   set_result(vbox);
@@ -2552,7 +2561,7 @@ bool LibraryCallKit::inline_vector_extract() {
       if (opd == nullptr) {
         return false;
       }
-      opd = gvn().transform(VectorStoreMaskNode::make(gvn(), opd, elem_bt, num_elem));
+      opd = gvn().transform(trace_vector(VectorStoreMaskNode::make(gvn(), opd, elem_bt, num_elem)));
       opd = gvn().transform(new ExtractUBNode(opd, pos));
       opd = gvn().transform(new ConvI2LNode(opd));
     } else if (arch_supports_vector(Op_VectorMaskToLong, num_elem, elem_bt, VecMaskUseLoad)) {
@@ -2562,7 +2571,7 @@ bool LibraryCallKit::inline_vector_extract() {
       }
       // VectorMaskToLongNode requires the input is either a mask or a vector with BOOLEAN type.
       if (!Matcher::mask_op_prefers_predicate(Op_VectorMaskToLong, opd->bottom_type()->is_vect())) {
-        opd = gvn().transform(VectorStoreMaskNode::make(gvn(), opd, elem_bt, num_elem));
+        opd = gvn().transform(trace_vector(VectorStoreMaskNode::make(gvn(), opd, elem_bt, num_elem)));
       }
       // ((toLong() >>> pos) & 1L
       opd = gvn().transform(new VectorMaskToLongNode(opd, TypeLong::LONG));
@@ -2680,8 +2689,8 @@ static Node* LowerSelectFromTwoVectorOperation(PhaseGVN& phase, Node* index_vec,
   vmask_type = TypeVect::makemask(elem_bt, num_elem);
   mask = phase.transform(new VectorMaskCastNode(mask, vmask_type));
 
-  Node* p1 = phase.transform(new VectorRearrangeNode(src1, wrapped_index_vec));
-  Node* p2 = phase.transform(new VectorRearrangeNode(src2, wrapped_index_vec));
+  Node* p1 = phase.transform(trace_vector(new VectorRearrangeNode(src1, wrapped_index_vec)));
+  Node* p2 = phase.transform(trace_vector(new VectorRearrangeNode(src2, wrapped_index_vec)));
 
   return new VectorBlendNode(p2, p1, mask);
 }
@@ -2799,7 +2808,7 @@ bool LibraryCallKit::inline_vector_select_from_two_vectors() {
     Node* wrap_mask = gvn().makecon(TypeInteger::make(indexRangeMask, indexRangeMask, Type::WidenMin, index_elem_bt != T_LONG ? T_INT : index_elem_bt));
     Node* wrap_mask_vec = gvn().transform(VectorNode::scalar2vector(wrap_mask, num_elem, index_elem_bt, false));
     opd1 = gvn().transform(VectorNode::make(Op_AndV, opd1, wrap_mask_vec, opd1->bottom_type()->is_vect()));
-    operation = gvn().transform(VectorNode::make(Op_SelectFromTwoVector, opd1, opd2, opd3, vt));
+    operation = gvn().transform(trace_vector(VectorNode::make(Op_SelectFromTwoVector, opd1, opd2, opd3, vt)));
   }
 
   // Wrap it up in VectorBox to keep object type information.
@@ -2884,7 +2893,7 @@ bool LibraryCallKit::inline_vector_compress_expand() {
   }
 
   const TypeVect* vt = TypeVect::make(elem_bt, num_elem, opc == Op_CompressM);
-  Node* operation = gvn().transform(VectorNode::make(opc, opd1, mask, vt));
+  Node* operation = gvn().transform(trace_vector(VectorNode::make(opc, opd1, mask, vt)));
 
   // Wrap it up in VectorBox to keep object type information.
   const TypeInstPtr* box_type = opc == Op_CompressM ? mbox_type : vbox_type;
@@ -3017,12 +3026,12 @@ bool LibraryCallKit::inline_index_vector() {
       default: fatal("%s", type2name(elem_bt));
     }
     scale = gvn().transform(VectorNode::scalar2vector(scale, num_elem, elem_bt));
-    index = gvn().transform(VectorNode::make(vmul_op, index, scale, vt));
+    index = gvn().transform(trace_vector(VectorNode::make(vmul_op, index, scale, vt)));
   }
 
   // Add "opd" if addition is needed.
   if (needs_add) {
-    index = gvn().transform(VectorNode::make(vadd_op, opd, index, vt));
+    index = gvn().transform(trace_vector(VectorNode::make(vadd_op, opd, index, vt)));
   }
   Node* vbox = box_vector(index, vbox_type, elem_bt, num_elem);
   set_result(vbox);
@@ -3139,7 +3148,7 @@ bool LibraryCallKit::inline_index_partially_in_upper_range() {
     // Compute the vector mask with "mask = iota < indexLimit".
     ConINode* pred_node = (ConINode*)gvn().makecon(TypeInt::make(BoolTest::lt));
     const TypeVect* vmask_type = TypeVect::makemask(elem_bt, num_elem);
-    mask = gvn().transform(new VectorMaskCmpNode(BoolTest::lt, iota, indexLimit, pred_node, vmask_type));
+    mask = gvn().transform(trace_vector(new VectorMaskCmpNode(BoolTest::lt, iota, indexLimit, pred_node, vmask_type)));
   }
   Node* vbox = box_vector(mask, box_type, elem_bt, num_elem);
   set_result(vbox);

From 4c9103f7b6c91b0f237859516ef72bb9ee27157e Mon Sep 17 00:00:00 2001
From: Matthias Baesken 
Date: Wed, 21 Jan 2026 14:14:33 +0000
Subject: [PATCH 124/328] 8374998: Failing os::write - remove bad file

Reviewed-by: mdoerr, lucy
---
 src/hotspot/os/posix/perfMemory_posix.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp
index 08a19270943..ce9c2a4f031 100644
--- a/src/hotspot/os/posix/perfMemory_posix.cpp
+++ b/src/hotspot/os/posix/perfMemory_posix.cpp
@@ -112,6 +112,10 @@ static void save_memory_to_file(char* addr, size_t size) {
     result = ::close(fd);
     if (result == OS_ERR) {
       warning("Could not close %s: %s\n", destfile, os::strerror(errno));
+    } else {
+      if (!successful_write) {
+        remove(destfile);
+      }
     }
   }
   FREE_C_HEAP_ARRAY(char, destfile);
@@ -949,6 +953,7 @@ static int create_sharedmem_file(const char* dirname, const char* filename, size
         warning("Insufficient space for shared memory file: %s/%s\n", dirname, filename);
       }
       result = OS_ERR;
+      remove(filename);
       break;
     }
   }

From 3033e6f421d0f6e0aea1d976a806d7abca7c6360 Mon Sep 17 00:00:00 2001
From: Kim Barrett 
Date: Wed, 21 Jan 2026 14:55:26 +0000
Subject: [PATCH 125/328] 8375544: JfrSet::clear should not use memset

Reviewed-by: mgronlun
---
 src/hotspot/share/jfr/utilities/jfrSet.hpp | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/src/hotspot/share/jfr/utilities/jfrSet.hpp b/src/hotspot/share/jfr/utilities/jfrSet.hpp
index 3d394d10d8b..c443434800a 100644
--- a/src/hotspot/share/jfr/utilities/jfrSet.hpp
+++ b/src/hotspot/share/jfr/utilities/jfrSet.hpp
@@ -26,6 +26,7 @@
 #define SHARE_JFR_UTILITIES_JFRSET_HPP
 
 #include "cppstdlib/new.hpp"
+#include "cppstdlib/type_traits.hpp"
 #include "jfr/utilities/jfrTypes.hpp"
 #include "memory/allocation.hpp"
 
@@ -110,7 +111,14 @@ class JfrSetStorage : public AnyObj {
   }
 
   void clear() {
-    memset(_table, 0, _table_size * sizeof(K));
+    for (unsigned i = 0; i < _table_size; ++i) {
+      if constexpr (std::is_copy_assignable_v) {
+        _table[i] = K{};
+      } else {
+        _table[i].~K();
+        ::new (&_table[i]) K{};
+      }
+    }
   }
 };
 

From 17086d31196827432477391fd2921a82868eaa05 Mon Sep 17 00:00:00 2001
From: Maurizio Cimadamore 
Date: Wed, 21 Jan 2026 16:14:35 +0000
Subject: [PATCH 126/328] 8375646: Some parser flags seem unused

Reviewed-by: jlahoda, vromero
---
 .../sun/tools/javac/parser/JavacParser.java   | 114 ++++++++----------
 1 file changed, 51 insertions(+), 63 deletions(-)

diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
index d3539b53541..d658275d4dc 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
@@ -271,16 +271,11 @@ public class JavacParser implements Parser {
     /** When terms are parsed, the mode determines which is expected:
      *     mode = EXPR        : an expression
      *     mode = TYPE        : a type
-     *     mode = NOPARAMS    : no parameters allowed for type
-     *     mode = TYPEARG     : type argument
-     *     mode |= NOLAMBDA   : lambdas are not allowed
+     *     mode = NOLAMBDA    : lambdas are not allowed
      */
     protected static final int EXPR          = 1 << 0;
     protected static final int TYPE          = 1 << 1;
-    protected static final int NOPARAMS      = 1 << 2;
-    protected static final int TYPEARG       = 1 << 3;
-    protected static final int DIAMOND       = 1 << 4;
-    protected static final int NOLAMBDA      = 1 << 5;
+    protected static final int NOLAMBDA      = 1 << 2;
 
     protected void setMode(int mode) {
         this.mode = mode;
@@ -1439,12 +1434,6 @@ public class JavacParser implements Parser {
         int startMode = mode;
         List typeArgs = typeArgumentsOpt(EXPR);
         switch (token.kind) {
-        case QUES:
-            if (isMode(TYPE) && isMode(TYPEARG) && !isMode(NOPARAMS)) {
-                selectTypeMode();
-                return typeArgument();
-            } else
-                return illegal();
         case PLUSPLUS: case SUBSUB: case BANG: case TILDE: case PLUS: case SUB:
             if (typeArgs == null && isMode(EXPR)) {
                 TokenKind tk = token.kind;
@@ -1522,7 +1511,7 @@ public class JavacParser implements Parser {
             if (isMode(EXPR)) {
                 selectExprMode();
                 nextToken();
-                if (token.kind == LT) typeArgs = typeArguments(false);
+                if (token.kind == LT) typeArgs = typeArguments();
                 t = creator(pos, typeArgs);
                 typeArgs = null;
             } else return illegal();
@@ -1625,7 +1614,6 @@ public class JavacParser implements Parser {
                             return illegal();
                         }
                         int prevmode = mode;
-                        setMode(mode & ~NOPARAMS);
                         typeArgs = typeArgumentsOpt(EXPR);
                         setMode(prevmode);
                         if (isMode(EXPR)) {
@@ -1653,7 +1641,7 @@ public class JavacParser implements Parser {
                                 selectExprMode();
                                 int pos1 = token.pos;
                                 nextToken();
-                                if (token.kind == LT) typeArgs = typeArguments(false);
+                                if (token.kind == LT) typeArgs = typeArguments();
                                 t = innerCreator(pos1, typeArgs, t);
                                 typeArgs = null;
                                 break loop;
@@ -1704,7 +1692,7 @@ public class JavacParser implements Parser {
                                 nextToken();
                                 selectTypeMode();
                                 t = toP(F.at(token.pos).Select(t, ident()));
-                                t = typeArgumentsOpt(t);
+                                t = typeApplyOpt(t);
                             }
                             t = bracketsOpt(t);
                             if (token.kind != COLCOL) {
@@ -1721,7 +1709,7 @@ public class JavacParser implements Parser {
                 }
             }
             if (typeArgs != null) illegal();
-            t = typeArgumentsOpt(t);
+            t = typeApplyOpt(t);
             break;
         case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
         case DOUBLE: case BOOLEAN:
@@ -1880,7 +1868,7 @@ public class JavacParser implements Parser {
                     selectExprMode();
                     int pos2 = token.pos;
                     nextToken();
-                    if (token.kind == LT) typeArgs = typeArguments(false);
+                    if (token.kind == LT) typeArgs = typeArguments();
                     t = innerCreator(pos2, typeArgs, t);
                     typeArgs = null;
                 } else {
@@ -1900,7 +1888,7 @@ public class JavacParser implements Parser {
                     if (tyannos != null && tyannos.nonEmpty()) {
                         t = toP(F.at(tyannos.head.pos).AnnotatedType(tyannos, t));
                     }
-                    t = argumentsOpt(typeArgs, typeArgumentsOpt(t));
+                    t = argumentsOpt(typeArgs, typeApplyOpt(t));
                     typeArgs = null;
                 }
             } else if (isMode(EXPR) && token.kind == COLCOL) {
@@ -2302,7 +2290,7 @@ public class JavacParser implements Parser {
         } else {
             int pos = token.pos;
             accept(DOT);
-            typeArgs = (token.kind == LT) ? typeArguments(false) : null;
+            typeArgs = (token.kind == LT) ? typeArguments() : null;
             t = toP(F.at(pos).Select(t, ident()));
             t = argumentsOpt(typeArgs, t);
         }
@@ -2373,12 +2361,11 @@ public class JavacParser implements Parser {
 
     /**  TypeArgumentsOpt = [ TypeArguments ]
      */
-    JCExpression typeArgumentsOpt(JCExpression t) {
+    JCExpression typeApplyOpt(JCExpression t) {
         if (token.kind == LT &&
-            isMode(TYPE) &&
-            !isMode(NOPARAMS)) {
+            isMode(TYPE)) {
             selectTypeMode();
-            return typeArguments(t, false);
+            return typeApply(t);
         } else {
             return t;
         }
@@ -2389,12 +2376,11 @@ public class JavacParser implements Parser {
 
     List typeArgumentsOpt(int useMode) {
         if (token.kind == LT) {
-            if (!isMode(useMode) ||
-                isMode(NOPARAMS)) {
+            if (!isMode(useMode)) {
                 illegal();
             }
             setMode(useMode);
-            return typeArguments(false);
+            return typeArguments();
         }
         return null;
     }
@@ -2404,35 +2390,29 @@ public class JavacParser implements Parser {
      *  TypeArguments  = "<" TypeArgument {"," TypeArgument} ">"
      *  }
      */
-    List typeArguments(boolean diamondAllowed) {
+    List typeArguments() {
         if (token.kind == LT) {
             nextToken();
-            if (token.kind == GT && diamondAllowed) {
-                setMode(mode | DIAMOND);
+            ListBuffer args = new ListBuffer<>();
+            args.append(!isMode(EXPR) ? typeArgument() : parseType());
+            while (token.kind == COMMA) {
                 nextToken();
-                return List.nil();
-            } else {
-                ListBuffer args = new ListBuffer<>();
                 args.append(!isMode(EXPR) ? typeArgument() : parseType());
-                while (token.kind == COMMA) {
-                    nextToken();
-                    args.append(!isMode(EXPR) ? typeArgument() : parseType());
-                }
-                switch (token.kind) {
-
-                case GTGTGTEQ: case GTGTEQ: case GTEQ:
-                case GTGTGT: case GTGT:
-                    token = S.split();
-                    break;
-                case GT:
-                    nextToken();
-                    break;
-                default:
-                    args.append(syntaxError(token.pos, Errors.Expected2(GT, COMMA)));
-                    break;
-                }
-                return args.toList();
             }
+            switch (token.kind) {
+
+            case GTGTGTEQ: case GTGTEQ: case GTEQ:
+            case GTGTGT: case GTGT:
+                token = S.split();
+                break;
+            case GT:
+                nextToken();
+                break;
+            default:
+                args.append(syntaxError(token.pos, Errors.Expected2(GT, COMMA)));
+                break;
+            }
+            return args.toList();
         } else {
             return List.of(syntaxError(token.pos, Errors.Expected(LT)));
         }
@@ -2480,12 +2460,23 @@ public class JavacParser implements Parser {
         return result;
     }
 
-    JCTypeApply typeArguments(JCExpression t, boolean diamondAllowed) {
+    JCTypeApply typeApply(JCExpression t) {
         int pos = token.pos;
-        List args = typeArguments(diamondAllowed);
+        List args = typeArguments();
         return toP(F.at(pos).TypeApply(t, args));
     }
 
+    JCTypeApply typeApplyOrDiamond(JCExpression t) {
+        if (peekToken(GT)) {
+            int pos = token.pos;
+            accept(LT);
+            accept(GT);
+            return toP(F.at(pos).TypeApply(t, List.nil()));
+        } else {
+            return typeApply(t);
+        }
+    }
+
     /**
      * BracketsOpt = { [Annotations] "[" "]" }*
      *
@@ -2585,7 +2576,7 @@ public class JavacParser implements Parser {
         selectExprMode();
         List typeArgs = null;
         if (token.kind == LT) {
-            typeArgs = typeArguments(false);
+            typeArgs = typeArguments();
         }
         Name refName;
         ReferenceMode refMode;
@@ -2622,15 +2613,13 @@ public class JavacParser implements Parser {
 
         int prevmode = mode;
         selectTypeMode();
-        boolean diamondFound = false;
         int lastTypeargsPos = -1;
         if (token.kind == LT) {
             lastTypeargsPos = token.pos;
-            t = typeArguments(t, true);
-            diamondFound = isMode(DIAMOND);
+            t = typeApplyOrDiamond(t);
         }
         while (token.kind == DOT) {
-            if (diamondFound) {
+            if (TreeInfo.isDiamond(t)) {
                 //cannot select after a diamond
                 illegal();
             }
@@ -2645,8 +2634,7 @@ public class JavacParser implements Parser {
 
             if (token.kind == LT) {
                 lastTypeargsPos = token.pos;
-                t = typeArguments(t, true);
-                diamondFound = isMode(DIAMOND);
+                t = typeApplyOrDiamond(t);
             }
         }
         setMode(prevmode);
@@ -2657,7 +2645,7 @@ public class JavacParser implements Parser {
             }
 
             JCExpression e = arrayCreatorRest(newpos, t);
-            if (diamondFound) {
+            if (TreeInfo.isDiamond(t)) {
                 reportSyntaxError(lastTypeargsPos, Errors.CannotCreateArrayWithDiamond);
                 return toP(F.at(newpos).Erroneous(List.of(e)));
             }
@@ -2702,7 +2690,7 @@ public class JavacParser implements Parser {
 
         if (token.kind == LT) {
             int prevmode = mode;
-            t = typeArguments(t, true);
+            t = typeApplyOrDiamond(t);
             setMode(prevmode);
         }
         return classCreatorRest(newpos, encl, typeArgs, t);

From a0ac5b34a742cf18d86f3ac77110bcaa00192169 Mon Sep 17 00:00:00 2001
From: Damon Nguyen 
Date: Wed, 21 Jan 2026 18:47:39 +0000
Subject: [PATCH 127/328] 8375775: JDK 26 RDP2 L10n resource files update

Reviewed-by: naoto, jlu, liach
---
 .../com/sun/tools/javac/resources/compiler_zh_CN.properties     | 2 +-
 .../classes/com/sun/tools/javac/resources/javac_ja.properties   | 2 +-
 .../com/sun/tools/javac/resources/javac_zh_CN.properties        | 2 +-
 .../classes/jdk/tools/jlink/resources/plugins_de.properties     | 2 +-
 .../classes/jdk/tools/jlink/resources/plugins_ja.properties     | 2 +-
 .../classes/jdk/tools/jlink/resources/plugins_zh_CN.properties  | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties
index 861f371632d..900557a29da 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties
@@ -292,7 +292,7 @@ compiler.err.annotation.decl.not.allowed.here=此处不允许批注接口声明
 compiler.err.cant.inherit.from.final=无法从最终{0}进行继承
 
 # 0: symbol or name
-compiler.err.cant.ref.before.ctor.called=对 {0} 的引用只能在显式调用构造器后显示
+compiler.err.cant.ref.before.ctor.called=对 {0} 的引用只能在显式调用构造器后出现
 
 # 0: symbol or name
 compiler.err.cant.assign.initialized.before.ctor.called=对初始化字段 ''{0}'' 的分配只能在显式调用构造器后显示
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_ja.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_ja.properties
index 0ea1796a8e6..3ae7ab1690e 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_ja.properties
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_ja.properties
@@ -60,7 +60,7 @@ javac.opt.target=指定されたJava SEリリースに適したクラス・フ
 javac.opt.release=指定されたJava SEリリースに対してコンパイルします。サポートされているリリース: \n    {0}
 javac.opt.source=指定されたJava SEリリースとソースの互換性を保持します。サポートされているリリース: \n    {0}
 javac.opt.Werror=警告が発生した場合にコンパイルを終了します
-javac.opt.arg.Werror=(,)*
+javac.opt.arg.Werror=<キー>(,<キー>)*
 javac.opt.Werror.custom=コンパイルを終了する警告のlintカテゴリを\nコンマで区切って指定します。\n指定したカテゴリを除外するには、キーの前に''-''を指定します。\nサポートされているキーを表示するには--help-lintを使用します。
 javac.opt.A=注釈プロセッサに渡されるオプション
 javac.opt.implicit=暗黙的に参照されるファイルについてクラス・ファイルを生成するかどうかを指定する
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_zh_CN.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_zh_CN.properties
index 0cbfac7e778..447d0d26239 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_zh_CN.properties
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_zh_CN.properties
@@ -60,7 +60,7 @@ javac.opt.target=生成适合指定的 Java SE 发行版的类文件。支持的
 javac.opt.release=为指定的 Java SE 发行版编译。支持的发行版:{0}
 javac.opt.source=提供与指定的 Java SE 发行版的源兼容性。支持的发行版:{0}
 javac.opt.Werror=出现任何警告时终止编译
-javac.opt.arg.Werror=(,)*
+javac.opt.arg.Werror=<键>(,<键>)*
 javac.opt.Werror.custom=指定出现警告时应终止编译的 lint 类别,\n以逗号分隔。\n在关键字前面加上 ''-'' 可排除指定的类别。\n使用 --help-lint 可查看支持的关键字。
 javac.opt.A=传递给批注处理程序的选项
 javac.opt.implicit=指定是否为隐式引用文件生成类文件
diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_de.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_de.properties
index 80d1ba6e05f..c313d6a348d 100644
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_de.properties
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_de.properties
@@ -170,7 +170,7 @@ plugin.opt.resources-last-sorter=\      --resources-last-sorter     Das le
 
 plugin.opt.disable-plugin=\      --disable-plugin      Deaktiviert das angegebene Plug-in
 
-plugin.opt.compress=\      --compress              Komprimiert alle Ressourcen im Ausgabeimage:\n                                        Zulässige Werte:\n                                        zip-'{0-9}', wobei "zip-0" für keine Komprimierung\n                                        und "zip-9" für die beste Komprimierung steht.\n                                        Standardwert ist "zip-6."\n                                        Veraltete Werte, die in einem zukünftigen Release entfernt werden:\n                                        0:  Keine Komprimierung. Verwenden Sie stattdessen "zip-0".\n                                        1:  Gemeinsame Verwendung konstanter Zeichenfolgen\n                                        2:  ZIP. Verwenden Sie stattdessen "zip-6".
+plugin.opt.compress=\      --compress              Komprimiert alle Ressourcen im Ausgabeimage:\n                                        Zulässige Werte:\n                                        zip-'{0-9}', wobei "zip-0" für keine Komprimierung\n                                        und "zip-9" für die beste Komprimierung steht.\n                                        Standardwert ist "zip-6".\n                                        Veraltete Werte, die in einem zukünftigen Release entfernt werden:\n                                        0:  Keine Komprimierung. Verwenden Sie stattdessen "zip-0".\n                                        1:  Gemeinsame Verwendung konstanter Zeichenfolgen\n                                        2:  ZIP. Verwenden Sie stattdessen "zip-6".
 
 plugin.opt.strip-debug=\  -G, --strip-debug                     Entfernt Debuginformationen
 
diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_ja.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_ja.properties
index 6ed0a486132..a5dc70061f6 100644
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_ja.properties
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_ja.properties
@@ -170,7 +170,7 @@ plugin.opt.resources-last-sorter=\      --resources-last-sorter     最後
 
 plugin.opt.disable-plugin=\      --disable-plugin      指定したプラグインを無効にします
 
-plugin.opt.compress=\      --compress              出力イメージ内のすべてのリソースを圧縮します:\n                                        使用可能な値は\n                                        zip-'{0-9}'です。zip-0では圧縮は行われず、\n                                        zip-9では最適な圧縮が行われます。\n                                        デフォルトはzip-6です。\n                                        今後のリリースで削除される非推奨の値:\n                                        0:  圧縮なし。かわりにzip-0を使用。\n                                        1:  定数文字列の共有\n                                        2:  ZIP。かわりにzip-6を使用。
+plugin.opt.compress=\      --compress <圧縮>             出力イメージ内のすべてのリソースを圧縮します:\n                                        使用可能な値は\n                                        zip-'{0-9}'です。zip-0では圧縮は行われず、\n                                        zip-9では最適な圧縮が行われます。\n                                        デフォルトはzip-6です。\n                                        今後のリリースで削除される非推奨の値:\n                                        0:  圧縮なし。かわりにzip-0を使用。\n                                        1:  定数文字列の共有\n                                        2:  ZIP。かわりにzip-6を使用。
 
 plugin.opt.strip-debug=\  -G, --strip-debug                     デバッグ情報を削除します
 
diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_zh_CN.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_zh_CN.properties
index a0480a31fc3..1de1ef372b6 100644
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_zh_CN.properties
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_zh_CN.properties
@@ -170,7 +170,7 @@ plugin.opt.resources-last-sorter=\      --resources-last-sorter     允许
 
 plugin.opt.disable-plugin=\      --disable-plugin      禁用所提及的插件
 
-plugin.opt.compress=\      --compress              在输出映像中压缩所有资源:\n                                        接受的值包括:\n                                        zip-'{0-9}',其中 zip-0 表示无压缩,\n                                        zip-9 表示最佳压缩。\n                                        默认值为 zip-6。\n                                        要在未来发行版中删除的已过时值:\n                                        0:无压缩。改为使用 zip-0。\n                                        1:常量字符串共享\n                                        2:ZIP。改为使用 zip-6。
+plugin.opt.compress=\      --compress <压缩>             在输出映像中压缩所有资源:\n                                        接受的值包括:\n                                        zip-'{0-9}',其中 zip-0 表示无压缩,\n                                        zip-9 表示最佳压缩。\n                                        默认值为 zip-6。\n                                        要在未来发行版中删除的已过时值:\n                                        0:无压缩。改为使用 zip-0。\n                                        1:常量字符串共享\n                                        2:ZIP。改为使用 zip-6。
 
 plugin.opt.strip-debug=\  -G, --strip-debug                     去除调试信息
 

From 3d919ad43a041eb60ce51e78831c77fd3b109aee Mon Sep 17 00:00:00 2001
From: Serguei Spitsyn 
Date: Thu, 22 Jan 2026 01:53:42 +0000
Subject: [PATCH 128/328] 8373366: HandshakeState should disallow suspend ops
 for disabler threads 8375362: Deadlock with unmount of suspended virtual
 thread interrupting another virtual thread

Reviewed-by: lmesnik, pchilanomate
---
 src/hotspot/share/runtime/handshake.cpp       |   6 +-
 src/hotspot/share/runtime/javaThread.cpp      |  12 +-
 src/hotspot/share/runtime/javaThread.hpp      |   8 +-
 .../share/runtime/mountUnmountDisabler.cpp    |  15 +-
 .../share/runtime/suspendResumeManager.cpp    |   3 +-
 .../ThreadStateTest2/ThreadStateTest2.java    | 144 ++++++++++++++++++
 .../ThreadStateTest2/libThreadStateTest2.cpp  | 118 ++++++++++++++
 7 files changed, 286 insertions(+), 20 deletions(-)
 create mode 100644 test/hotspot/jtreg/serviceability/jvmti/vthread/ThreadStateTest2/ThreadStateTest2.java
 create mode 100644 test/hotspot/jtreg/serviceability/jvmti/vthread/ThreadStateTest2/libThreadStateTest2.cpp

diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp
index 89b02717a7a..b54068d65d6 100644
--- a/src/hotspot/share/runtime/handshake.cpp
+++ b/src/hotspot/share/runtime/handshake.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2026, 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
@@ -521,8 +521,8 @@ HandshakeOperation* HandshakeState::get_op_for_self(bool allow_suspend, bool che
   assert(_lock.owned_by_self(), "Lock must be held");
   assert(allow_suspend || !check_async_exception, "invalid case");
 #if INCLUDE_JVMTI
-  if (allow_suspend && _handshakee->is_disable_suspend()) {
-    // filter out suspend operations while JavaThread is in disable_suspend mode
+  if (allow_suspend && (_handshakee->is_disable_suspend() || _handshakee->is_vthread_transition_disabler())) {
+    // filter out suspend operations while JavaThread can not be suspended
     allow_suspend = false;
   }
 #endif
diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp
index 4ee9a9dfd79..e73347f35d8 100644
--- a/src/hotspot/share/runtime/javaThread.cpp
+++ b/src/hotspot/share/runtime/javaThread.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2021, Azul Systems, Inc. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -499,7 +499,7 @@ JavaThread::JavaThread(MemTag mem_tag) :
   _suspend_resume_manager(this, &_handshake._lock),
 
   _is_in_vthread_transition(false),
-  DEBUG_ONLY(_is_vthread_transition_disabler(false) COMMA)
+  JVMTI_ONLY(_is_vthread_transition_disabler(false) COMMA)
   DEBUG_ONLY(_is_disabler_at_start(false) COMMA)
 
   _popframe_preserved_args(nullptr),
@@ -1165,11 +1165,13 @@ void JavaThread::set_is_in_vthread_transition(bool val) {
   AtomicAccess::store(&_is_in_vthread_transition, val);
 }
 
-#ifdef ASSERT
+#if INCLUDE_JVMTI
 void JavaThread::set_is_vthread_transition_disabler(bool val) {
   _is_vthread_transition_disabler = val;
 }
+#endif
 
+#ifdef ASSERT
 void JavaThread::set_is_disabler_at_start(bool val) {
   _is_disabler_at_start = val;
 }
@@ -1183,7 +1185,9 @@ void JavaThread::set_is_disabler_at_start(bool val) {
 //
 bool JavaThread::java_suspend(bool register_vthread_SR) {
   // Suspending a vthread transition disabler can cause deadlocks.
-  assert(!is_vthread_transition_disabler(), "no suspend allowed for vthread transition disablers");
+  // The HandshakeState::has_operation does not allow such suspends.
+  // But the suspender thread is an exclusive transition disablers, so there can't be other disabers here.
+  JVMTI_ONLY(assert(!is_vthread_transition_disabler(), "suspender thread is an exclusive transition disabler");)
 
   guarantee(Thread::is_JavaThread_protected(/* target */ this),
             "target JavaThread is not protected in calling context.");
diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp
index d4c12887e10..1aae37c0697 100644
--- a/src/hotspot/share/runtime/javaThread.hpp
+++ b/src/hotspot/share/runtime/javaThread.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2021, Azul Systems, Inc. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -734,14 +734,14 @@ public:
 
 private:
   bool _is_in_vthread_transition;                    // thread is in virtual thread mount state transition
-  DEBUG_ONLY(bool _is_vthread_transition_disabler;)  // thread currently disabled vthread transitions
+  JVMTI_ONLY(bool _is_vthread_transition_disabler;)  // thread currently disabled vthread transitions
   DEBUG_ONLY(bool _is_disabler_at_start;)            // thread at process of disabling vthread transitions
 public:
   bool is_in_vthread_transition() const;
   void set_is_in_vthread_transition(bool val);
+  JVMTI_ONLY(bool is_vthread_transition_disabler() const { return _is_vthread_transition_disabler; })
+  JVMTI_ONLY(void set_is_vthread_transition_disabler(bool val);)
 #ifdef ASSERT
-  bool is_vthread_transition_disabler() const       { return _is_vthread_transition_disabler; }
-  void set_is_vthread_transition_disabler(bool val);
   bool is_disabler_at_start() const                 { return _is_disabler_at_start; }
   void set_is_disabler_at_start(bool val);
 #endif
diff --git a/src/hotspot/share/runtime/mountUnmountDisabler.cpp b/src/hotspot/share/runtime/mountUnmountDisabler.cpp
index 8635eeb2dcc..65a82d6c563 100644
--- a/src/hotspot/share/runtime/mountUnmountDisabler.cpp
+++ b/src/hotspot/share/runtime/mountUnmountDisabler.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, 2026, 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
@@ -129,7 +129,8 @@ bool MountUnmountDisabler::is_start_transition_disabled(JavaThread* thread, oop
   int base_disable_count = notify_jvmti_events() ? 1 : 0;
   return java_lang_Thread::vthread_transition_disable_count(vthread) > 0
          || global_vthread_transition_disable_count() > base_disable_count
-         JVMTI_ONLY(|| (JvmtiVTSuspender::is_vthread_suspended(java_lang_Thread::thread_id(vthread)) || thread->is_suspended()));
+         JVMTI_ONLY(|| (!thread->is_vthread_transition_disabler() &&
+                        (JvmtiVTSuspender::is_vthread_suspended(java_lang_Thread::thread_id(vthread)) || thread->is_suspended())));
 }
 
 void MountUnmountDisabler::start_transition(JavaThread* current, oop vthread, bool is_mount, bool is_thread_end) {
@@ -294,7 +295,7 @@ MountUnmountDisabler::disable_transition_for_one() {
   // carrierThread to float up.
   // This pairs with the release barrier in end_transition().
   OrderAccess::acquire();
-  DEBUG_ONLY(JavaThread::current()->set_is_vthread_transition_disabler(true);)
+  JVMTI_ONLY(JavaThread::current()->set_is_vthread_transition_disabler(true);)
 }
 
 // disable transitions for all virtual threads
@@ -335,7 +336,7 @@ MountUnmountDisabler::disable_transition_for_all() {
   // carrierThread to float up.
   // This pairs with the release barrier in end_transition().
   OrderAccess::acquire();
-  DEBUG_ONLY(thread->set_is_vthread_transition_disabler(true);)
+  JVMTI_ONLY(JavaThread::current()->set_is_vthread_transition_disabler(true);)
   DEBUG_ONLY(thread->set_is_disabler_at_start(false);)
 }
 
@@ -358,14 +359,12 @@ MountUnmountDisabler::enable_transition_for_one() {
   if (java_lang_Thread::vthread_transition_disable_count(_vthread()) == 0) {
     ml.notify_all();
   }
-  DEBUG_ONLY(JavaThread::current()->set_is_vthread_transition_disabler(false);)
+  JVMTI_ONLY(JavaThread::current()->set_is_vthread_transition_disabler(false);)
 }
 
 // enable transitions for all virtual threads
 void
 MountUnmountDisabler::enable_transition_for_all() {
-  JavaThread* thread = JavaThread::current();
-
   // End of the critical section. If some target was unmounted, we need a
   // release barrier before decrementing _global_vthread_transition_disable_count
   // to make sure any memory operations executed by the disabler are visible to
@@ -384,7 +383,7 @@ MountUnmountDisabler::enable_transition_for_all() {
   if (global_vthread_transition_disable_count() == base_disable_count || _is_exclusive) {
     ml.notify_all();
   }
-  DEBUG_ONLY(thread->set_is_vthread_transition_disabler(false);)
+  JVMTI_ONLY(JavaThread::current()->set_is_vthread_transition_disabler(false);)
 }
 
 int MountUnmountDisabler::global_vthread_transition_disable_count() {
diff --git a/src/hotspot/share/runtime/suspendResumeManager.cpp b/src/hotspot/share/runtime/suspendResumeManager.cpp
index 067579b6386..3408d763e57 100644
--- a/src/hotspot/share/runtime/suspendResumeManager.cpp
+++ b/src/hotspot/share/runtime/suspendResumeManager.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, 2026, 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
@@ -130,6 +130,7 @@ void SuspendResumeManager::do_owner_suspend() {
   assert(_state_lock->owned_by_self(), "Lock must be held");
   assert(!_target->has_last_Java_frame() || _target->frame_anchor()->walkable(), "should have walkable stack");
   assert(_target->thread_state() == _thread_blocked, "Caller should have transitioned to _thread_blocked");
+  JVMTI_ONLY(assert(!_target->is_vthread_transition_disabler(), "attempt to suspend a vthread transition disabler");)
 
   while (is_suspended()) {
     log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " suspended", p2i(_target));
diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/ThreadStateTest2/ThreadStateTest2.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/ThreadStateTest2/ThreadStateTest2.java
new file mode 100644
index 00000000000..ce3f2a5fe40
--- /dev/null
+++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/ThreadStateTest2/ThreadStateTest2.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2026, 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 8373366
+ * @summary HandshakeState should disallow suspend ops for disabler threads
+ * @requires vm.continuations
+ * @requires vm.jvmti
+ * @requires vm.compMode != "Xcomp"
+ * @modules java.base/java.lang:+open
+ * @library /test/lib
+ * @run main/othervm/native -agentlib:ThreadStateTest2 ThreadStateTest2
+ */
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
+import jdk.test.lib.thread.VThreadScheduler;
+
+/* Testing scenario:
+ * Several threads are involved:
+ *  - VT-0: a virtual thread which is interrupt-friendly and constantly interrupted with JVMTI InterruptThread
+ *  - VT-1: a virtual thread which state is constantly checked with JVMTI GetThreadState
+ *  - VT-2: a virtual thread: in a loop calls JVMTI InterruptThread(VT-0) and GetThreadState(VT-1)
+ *  - main: a platform thread: in a loop invokes native method testSuspendResume which suspends and resumes VT-2
+ * The JVMTI functions above install a MountUnmountDisabler for target virtual thread (VT-0 or VT-1).
+ * The goal is to catch VT-2 in an attempt to self-suspend while in a context of MountUnmountDisabler.
+ * This would mean there is a suspend point while VT-2 is in a context of MountUnmountDisabler.
+ * The InterruptThread implementation does a Java upcall to j.l.Thread::interrupt().
+ * The JavaCallWrapper constructor has such a suspend point.
+ */
+public class ThreadStateTest2 {
+    private static native void setMonitorContendedMode(boolean enable);
+    private static native void testSuspendResume(Thread vthread);
+    private static native void testInterruptThread(Thread vthread);
+    private static native int testGetThreadState(Thread vthread);
+
+    static Thread vthread0;
+    static Thread vthread1;
+    static Thread vthread2;
+    static AtomicBoolean vt2Started = new AtomicBoolean();
+    static AtomicBoolean vt2Finished = new AtomicBoolean();
+
+    static void log(String msg) { System.out.println(msg); }
+
+    // Should handle interruptions from vthread2.
+    final Runnable FOO_0 = () -> {
+        log("VT-0 started");
+        while (!vt2Finished.get()) {
+            try {
+                Thread.sleep(10);
+            } catch (InterruptedException ie) {
+                // ignore
+            }
+        }
+        log("VT-0 finished");
+    };
+
+    // A target for vthread2 to check state with JVMTI GetThreadState.
+    final Runnable FOO_1 = () -> {
+        log("VT-1 started");
+        while (!vt2Finished.get()) {
+            Thread.yield();
+        }
+        log("VT-1 finished");
+    };
+
+    // In a loop execute JVMTI functions on threads vthread0 and vthread1:
+    // InterruptThread(vthread0) and GetThreadState(vthread1).
+    final Runnable FOO_2 = () -> {
+        log("VT-2 started");
+        vt2Started.set(true);
+        for (int i = 0; i < 40; i++) {
+            testInterruptThread(vthread0);
+            int state = testGetThreadState(vthread1);
+            if (state == 2) {
+                break;
+            }
+            Thread.yield();
+        }
+        vt2Finished.set(true);
+        log("VT-2 finished");
+    };
+
+    private void runTest() throws Exception {
+        // Force creation of JvmtiThreadState on vthread start.
+        setMonitorContendedMode(true);
+
+        ExecutorService scheduler = Executors.newFixedThreadPool(2);
+        ThreadFactory factory = VThreadScheduler.virtualThreadBuilder(scheduler).factory();
+
+        vthread0 = factory.newThread(FOO_0);
+        vthread1 = factory.newThread(FOO_1);
+        vthread2 = factory.newThread(FOO_2);
+        vthread0.setName("VT-0");
+        vthread1.setName("VT-1");
+        vthread2.setName("VT-2");
+        vthread0.start();
+        vthread1.start();
+        vthread2.start();
+
+        // Give some time for vthreads to start.
+        while (!vt2Started.get()) {
+            Thread.sleep(1);
+        }
+        while (!vt2Finished.get() /* && tryCount-- > 0 */) {
+            testSuspendResume(vthread2);
+        }
+        vthread0.join();
+        vthread1.join();
+        vthread2.join();
+
+        // Let all carriers go away.
+        scheduler.shutdown();
+        Thread.sleep(20);
+    }
+
+    public static void main(String[] args) throws Exception {
+        ThreadStateTest2 obj = new ThreadStateTest2();
+        obj.runTest();
+    }
+}
diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/ThreadStateTest2/libThreadStateTest2.cpp b/test/hotspot/jtreg/serviceability/jvmti/vthread/ThreadStateTest2/libThreadStateTest2.cpp
new file mode 100644
index 00000000000..8464e8ebc57
--- /dev/null
+++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/ThreadStateTest2/libThreadStateTest2.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2026, 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 
+#include 
+#include 
+#include 
+#include "jvmti_common.hpp"
+
+// set by Agent_OnLoad
+static jvmtiEnv* jvmti = nullptr;
+static jrawMonitorID agent_event_lock = nullptr;
+
+extern "C" {
+
+static void JNICALL
+MonitorContended(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread,
+                 jobject object) {
+}
+
+JNIEXPORT void JNICALL
+Java_ThreadStateTest2_testSuspendResume(JNIEnv* jni, jclass klass, jthread thread) {
+  jvmtiError err;
+  RawMonitorLocker event_locker(jvmti, jni, agent_event_lock);
+
+  LOG("\nMAIN: testSuspendResume: before suspend\n");
+  err = jvmti->SuspendThread(thread);
+  if (err == JVMTI_ERROR_THREAD_NOT_ALIVE) {
+    return;
+  }
+  check_jvmti_status(jni, err, "testSuspendResume error in JVMTI SuspendThread");
+  LOG("\nMAIN: testSuspendResume:  after suspend\n");
+
+  event_locker.wait(1);
+
+  LOG("MAIN: testSuspendResume: before resume\n");
+  err = jvmti->ResumeThread(thread);
+  check_jvmti_status(jni, err, "testSuspendResume error in JVMTI ResumeThread");
+}
+
+JNIEXPORT void JNICALL
+Java_ThreadStateTest2_setMonitorContendedMode(JNIEnv* jni, jclass klass, jboolean enable) {
+  set_event_notification_mode(jvmti, jni, enable ? JVMTI_ENABLE : JVMTI_DISABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, nullptr);
+}
+
+JNIEXPORT void JNICALL
+Java_ThreadStateTest2_testInterruptThread(JNIEnv* jni, jclass klass, jthread vthread) {
+  char* tname = get_thread_name(jvmti, jni, vthread);
+  LOG("VT-2: testInterruptThread: %s\n", tname);
+
+  jvmtiError err = jvmti->InterruptThread(vthread);
+  check_jvmti_status(jni, err, "testInterruptThread error in JVMTI InterruptThread");
+}
+
+JNIEXPORT jint JNICALL
+Java_ThreadStateTest2_testGetThreadState(JNIEnv* jni, jclass klass, jthread vthread) {
+  jint  state = get_thread_state(jvmti, jni, vthread);
+  char* tname = get_thread_name(jvmti, jni, vthread);
+
+  LOG("VT-2: testGetThreadState: %s state: %x\n", tname, state);
+  return state;
+}
+
+JNIEXPORT jint JNICALL
+Agent_OnLoad(JavaVM* jvm, char* options, void* reserved) {
+  jvmtiEventCallbacks callbacks;
+  jvmtiCapabilities caps;
+  jvmtiError err;
+
+  printf("Agent_OnLoad: started\n");
+  if (jvm->GetEnv((void **) (&jvmti), JVMTI_VERSION) != JNI_OK) {
+    LOG("Agent_OnLoad: error in GetEnv");
+    return JNI_ERR;
+  }
+
+  memset(&caps, 0, sizeof(caps));
+  caps.can_suspend = 1;
+  caps.can_signal_thread = 1;
+  caps.can_support_virtual_threads = 1;
+  caps.can_generate_monitor_events = 1;
+
+  err = jvmti->AddCapabilities(&caps);
+  if (err != JVMTI_ERROR_NONE) {
+    LOG("Agent_OnLoad: error in JVMTI AddCapabilities: %d\n", err);
+  }
+  memset(&callbacks, 0, sizeof(callbacks));
+  callbacks.MonitorContendedEnter = &MonitorContended;
+  err = jvmti->SetEventCallbacks(&callbacks, sizeof(jvmtiEventCallbacks));
+  if (err != JVMTI_ERROR_NONE) {
+    LOG("Agent_OnLoad: Error in JVMTI SetEventCallbacks: %d\n", err);
+  }
+  agent_event_lock = create_raw_monitor(jvmti, "agent_event_lock");
+  printf("Agent_OnLoad: finished\n");
+
+  return 0;
+}
+
+} // extern "C"

From 38a8309b3f2544fa13448f5217e4227f0e2fe171 Mon Sep 17 00:00:00 2001
From: Ivan Walulya 
Date: Thu, 22 Jan 2026 05:38:32 +0000
Subject: [PATCH 129/328] 8341630: G1: Adopt PartialArrayState to consolidate
 marking stack in concurrent marking

Co-authored-by: Stefan Johansson 
Reviewed-by: tschatzl, sjohanss
---
 src/hotspot/share/gc/g1/g1ConcurrentMark.cpp  | 107 ++++++++++++++++--
 src/hotspot/share/gc/g1/g1ConcurrentMark.hpp  |  81 +++++++------
 .../share/gc/g1/g1ConcurrentMark.inline.hpp   |  49 ++++----
 .../g1/g1ConcurrentMarkObjArrayProcessor.cpp  |  80 -------------
 .../g1/g1ConcurrentMarkObjArrayProcessor.hpp  |  59 ----------
 ...ConcurrentMarkObjArrayProcessor.inline.hpp |  38 -------
 src/hotspot/share/gc/shared/taskqueue.hpp     |   6 +-
 7 files changed, 167 insertions(+), 253 deletions(-)
 delete mode 100644 src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.cpp
 delete mode 100644 src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.hpp
 delete mode 100644 src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp

diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
index 1077939f953..52591f7ce5f 100644
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
@@ -51,6 +51,9 @@
 #include "gc/shared/gcTimer.hpp"
 #include "gc/shared/gcTraceTime.inline.hpp"
 #include "gc/shared/gcVMOperations.hpp"
+#include "gc/shared/partialArraySplitter.inline.hpp"
+#include "gc/shared/partialArrayState.hpp"
+#include "gc/shared/partialArrayTaskStats.hpp"
 #include "gc/shared/referencePolicy.hpp"
 #include "gc/shared/suspendibleThreadSet.hpp"
 #include "gc/shared/taskqueue.inline.hpp"
@@ -75,6 +78,7 @@
 #include "runtime/prefetch.inline.hpp"
 #include "runtime/threads.hpp"
 #include "utilities/align.hpp"
+#include "utilities/checkedCast.hpp"
 #include "utilities/formatBuffer.hpp"
 #include "utilities/growableArray.hpp"
 #include "utilities/powerOfTwo.hpp"
@@ -98,7 +102,7 @@ bool G1CMBitMapClosure::do_addr(HeapWord* const addr) {
   // We move that task's local finger along.
   _task->move_finger_to(addr);
 
-  _task->scan_task_entry(G1TaskQueueEntry::from_oop(cast_to_oop(addr)));
+  _task->process_entry(G1TaskQueueEntry(cast_to_oop(addr)), false /* stolen */);
   // we only partially drain the local queue and global stack
   _task->drain_local_queue(true);
   _task->drain_global_stack(true);
@@ -489,6 +493,7 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h,
 
   _task_queues(new G1CMTaskQueueSet(_max_num_tasks)),
   _terminator(_max_num_tasks, _task_queues),
+  _partial_array_state_manager(new PartialArrayStateManager(_max_num_tasks)),
 
   _first_overflow_barrier_sync(),
   _second_overflow_barrier_sync(),
@@ -555,6 +560,10 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h,
   reset_at_marking_complete();
 }
 
+PartialArrayStateManager* G1ConcurrentMark::partial_array_state_manager() const {
+  return _partial_array_state_manager;
+}
+
 void G1ConcurrentMark::reset() {
   _has_aborted = false;
 
@@ -649,7 +658,26 @@ void G1ConcurrentMark::set_concurrency_and_phase(uint active_tasks, bool concurr
   }
 }
 
+#if TASKQUEUE_STATS
+void G1ConcurrentMark::print_and_reset_taskqueue_stats() {
+
+  _task_queues->print_and_reset_taskqueue_stats("G1ConcurrentMark Oop Queue");
+
+  auto get_pa_stats = [&](uint i) {
+    return _tasks[i]->partial_array_task_stats();
+  };
+
+  PartialArrayTaskStats::log_set(_max_num_tasks, get_pa_stats,
+                                 "G1ConcurrentMark Partial Array Task Stats");
+
+  for (uint i = 0; i < _max_num_tasks; ++i) {
+    get_pa_stats(i)->reset();
+  }
+}
+#endif
+
 void G1ConcurrentMark::reset_at_marking_complete() {
+  TASKQUEUE_STATS_ONLY(print_and_reset_taskqueue_stats());
   // We set the global marking state to some default values when we're
   // not doing marking.
   reset_marking_for_restart();
@@ -803,11 +831,25 @@ void G1ConcurrentMark::cleanup_for_next_mark() {
 
   clear_bitmap(_concurrent_workers, true);
 
+  reset_partial_array_state_manager();
+
   // Repeat the asserts from above.
   guarantee(cm_thread()->in_progress(), "invariant");
   guarantee(!_g1h->collector_state()->mark_or_rebuild_in_progress(), "invariant");
 }
 
+void G1ConcurrentMark::reset_partial_array_state_manager() {
+  for (uint i = 0; i < _max_num_tasks; ++i) {
+    _tasks[i]->unregister_partial_array_splitter();
+  }
+
+  partial_array_state_manager()->reset();
+
+  for (uint i = 0; i < _max_num_tasks; ++i) {
+    _tasks[i]->register_partial_array_splitter();
+  }
+}
+
 void G1ConcurrentMark::clear_bitmap(WorkerThreads* workers) {
   assert_at_safepoint_on_vm_thread();
   // To avoid fragmentation the full collection requesting to clear the bitmap
@@ -1788,17 +1830,18 @@ public:
   { }
 
   void operator()(G1TaskQueueEntry task_entry) const {
-    if (task_entry.is_array_slice()) {
-      guarantee(_g1h->is_in_reserved(task_entry.slice()), "Slice " PTR_FORMAT " must be in heap.", p2i(task_entry.slice()));
+    if (task_entry.is_partial_array_state()) {
+      oop obj = task_entry.to_partial_array_state()->source();
+      guarantee(_g1h->is_in_reserved(obj), "Partial Array " PTR_FORMAT " must be in heap.", p2i(obj));
       return;
     }
-    guarantee(oopDesc::is_oop(task_entry.obj()),
+    guarantee(oopDesc::is_oop(task_entry.to_oop()),
               "Non-oop " PTR_FORMAT ", phase: %s, info: %d",
-              p2i(task_entry.obj()), _phase, _info);
-    G1HeapRegion* r = _g1h->heap_region_containing(task_entry.obj());
+              p2i(task_entry.to_oop()), _phase, _info);
+    G1HeapRegion* r = _g1h->heap_region_containing(task_entry.to_oop());
     guarantee(!(r->in_collection_set() || r->has_index_in_opt_cset()),
               "obj " PTR_FORMAT " from %s (%d) in region %u in (optional) collection set",
-              p2i(task_entry.obj()), _phase, _info, r->hrm_index());
+              p2i(task_entry.to_oop()), _phase, _info, r->hrm_index());
   }
 };
 
@@ -2054,6 +2097,17 @@ void G1CMTask::reset(G1CMBitMap* mark_bitmap) {
   _mark_stats_cache.reset();
 }
 
+void G1CMTask::register_partial_array_splitter() {
+
+  ::new (&_partial_array_splitter) PartialArraySplitter(_cm->partial_array_state_manager(),
+                                                        _cm->max_num_tasks(),
+                                                        ObjArrayMarkingStride);
+}
+
+void G1CMTask::unregister_partial_array_splitter() {
+  _partial_array_splitter.~PartialArraySplitter();
+}
+
 bool G1CMTask::should_exit_termination() {
   if (!regular_clock_call()) {
     return true;
@@ -2184,7 +2238,7 @@ bool G1CMTask::get_entries_from_global_stack() {
     if (task_entry.is_null()) {
       break;
     }
-    assert(task_entry.is_array_slice() || oopDesc::is_oop(task_entry.obj()), "Element " PTR_FORMAT " must be an array slice or oop", p2i(task_entry.obj()));
+    assert(task_entry.is_partial_array_state() || oopDesc::is_oop(task_entry.to_oop()), "Element " PTR_FORMAT " must be an array slice or oop", p2i(task_entry.to_oop()));
     bool success = _task_queue->push(task_entry);
     // We only call this when the local queue is empty or under a
     // given target limit. So, we do not expect this push to fail.
@@ -2215,7 +2269,7 @@ void G1CMTask::drain_local_queue(bool partially) {
     G1TaskQueueEntry entry;
     bool ret = _task_queue->pop_local(entry);
     while (ret) {
-      scan_task_entry(entry);
+      process_entry(entry, false /* stolen */);
       if (_task_queue->size() <= target_size || has_aborted()) {
         ret = false;
       } else {
@@ -2225,6 +2279,37 @@ void G1CMTask::drain_local_queue(bool partially) {
   }
 }
 
+size_t G1CMTask::start_partial_array_processing(oop obj) {
+  assert(should_be_sliced(obj), "Must be an array object %d and large %zu", obj->is_objArray(), obj->size());
+
+  objArrayOop obj_array = objArrayOop(obj);
+  size_t array_length = obj_array->length();
+
+  size_t initial_chunk_size = _partial_array_splitter.start(_task_queue, obj_array, nullptr, array_length);
+
+  // Mark objArray klass metadata
+  if (_cm_oop_closure->do_metadata()) {
+    _cm_oop_closure->do_klass(obj_array->klass());
+  }
+
+  process_array_chunk(obj_array, 0, initial_chunk_size);
+
+  // Include object header size
+  return objArrayOopDesc::object_size(checked_cast(initial_chunk_size));
+}
+
+size_t G1CMTask::process_partial_array(const G1TaskQueueEntry& task, bool stolen) {
+  PartialArrayState* state = task.to_partial_array_state();
+  // Access state before release by claim().
+  objArrayOop obj = objArrayOop(state->source());
+
+  PartialArraySplitter::Claim claim =
+    _partial_array_splitter.claim(state, _task_queue, stolen);
+
+  process_array_chunk(obj, claim._start, claim._end);
+  return heap_word_size((claim._end - claim._start) * heapOopSize);
+}
+
 void G1CMTask::drain_global_stack(bool partially) {
   if (has_aborted()) {
     return;
@@ -2429,7 +2514,7 @@ void G1CMTask::attempt_stealing() {
   while (!has_aborted()) {
     G1TaskQueueEntry entry;
     if (_cm->try_stealing(_worker_id, entry)) {
-      scan_task_entry(entry);
+      process_entry(entry, true /* stolen */);
 
       // And since we're towards the end, let's totally drain the
       // local queue and global stack.
@@ -2758,12 +2843,12 @@ G1CMTask::G1CMTask(uint worker_id,
                    G1ConcurrentMark* cm,
                    G1CMTaskQueue* task_queue,
                    G1RegionMarkStats* mark_stats) :
-  _objArray_processor(this),
   _worker_id(worker_id),
   _g1h(G1CollectedHeap::heap()),
   _cm(cm),
   _mark_bitmap(nullptr),
   _task_queue(task_queue),
+  _partial_array_splitter(_cm->partial_array_state_manager(), _cm->max_num_tasks(), ObjArrayMarkingStride),
   _mark_stats_cache(mark_stats, G1RegionMarkStatsCache::RegionMarkStatsCacheSize),
   _calls(0),
   _time_target_ms(0.0),
diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
index 7ea9151c6f1..52a1b133439 100644
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
@@ -26,11 +26,13 @@
 #define SHARE_GC_G1_G1CONCURRENTMARK_HPP
 
 #include "gc/g1/g1ConcurrentMarkBitMap.hpp"
-#include "gc/g1/g1ConcurrentMarkObjArrayProcessor.hpp"
 #include "gc/g1/g1HeapRegionSet.hpp"
 #include "gc/g1/g1HeapVerifier.hpp"
 #include "gc/g1/g1RegionMarkStatsCache.hpp"
 #include "gc/shared/gcCause.hpp"
+#include "gc/shared/partialArraySplitter.hpp"
+#include "gc/shared/partialArrayState.hpp"
+#include "gc/shared/partialArrayTaskStats.hpp"
 #include "gc/shared/taskqueue.hpp"
 #include "gc/shared/taskTerminator.hpp"
 #include "gc/shared/verifyOption.hpp"
@@ -54,41 +56,7 @@ class G1RegionToSpaceMapper;
 class G1SurvivorRegions;
 class ThreadClosure;
 
-// This is a container class for either an oop or a continuation address for
-// mark stack entries. Both are pushed onto the mark stack.
-class G1TaskQueueEntry {
-private:
-  void* _holder;
-
-  static const uintptr_t ArraySliceBit = 1;
-
-  G1TaskQueueEntry(oop obj) : _holder(obj) {
-    assert(_holder != nullptr, "Not allowed to set null task queue element");
-  }
-  G1TaskQueueEntry(HeapWord* addr) : _holder((void*)((uintptr_t)addr | ArraySliceBit)) { }
-public:
-
-  G1TaskQueueEntry() : _holder(nullptr) { }
-  // Trivially copyable, for use in GenericTaskQueue.
-
-  static G1TaskQueueEntry from_slice(HeapWord* what) { return G1TaskQueueEntry(what); }
-  static G1TaskQueueEntry from_oop(oop obj) { return G1TaskQueueEntry(obj); }
-
-  oop obj() const {
-    assert(!is_array_slice(), "Trying to read array slice " PTR_FORMAT " as oop", p2i(_holder));
-    return cast_to_oop(_holder);
-  }
-
-  HeapWord* slice() const {
-    assert(is_array_slice(), "Trying to read oop " PTR_FORMAT " as array slice", p2i(_holder));
-    return (HeapWord*)((uintptr_t)_holder & ~ArraySliceBit);
-  }
-
-  bool is_oop() const { return !is_array_slice(); }
-  bool is_array_slice() const { return ((uintptr_t)_holder & ArraySliceBit) != 0; }
-  bool is_null() const { return _holder == nullptr; }
-};
-
+typedef ScannerTask G1TaskQueueEntry;
 typedef GenericTaskQueue G1CMTaskQueue;
 typedef GenericTaskQueueSet G1CMTaskQueueSet;
 
@@ -412,6 +380,8 @@ class G1ConcurrentMark : public CHeapObj {
   G1CMTaskQueueSet*       _task_queues; // Task queue set
   TaskTerminator          _terminator;  // For termination
 
+  PartialArrayStateManager* _partial_array_state_manager;
+
   // Two sync barriers that are used to synchronize tasks when an
   // overflow occurs. The algorithm is the following. All tasks enter
   // the first one to ensure that they have all stopped manipulating
@@ -489,6 +459,8 @@ class G1ConcurrentMark : public CHeapObj {
   // Prints all gathered CM-related statistics
   void print_stats();
 
+  void print_and_reset_taskqueue_stats();
+
   HeapWord*           finger()       { return _finger;   }
   bool                concurrent()   { return _concurrent; }
   uint                active_tasks() { return _num_active_tasks; }
@@ -583,6 +555,8 @@ public:
 
   uint worker_id_offset() const { return _worker_id_offset; }
 
+  uint max_num_tasks() const {return _max_num_tasks; }
+
   // Clear statistics gathered during the concurrent cycle for the given region after
   // it has been reclaimed.
   void clear_statistics(G1HeapRegion* r);
@@ -632,6 +606,8 @@ public:
   // Calculates the number of concurrent GC threads to be used in the marking phase.
   uint calc_active_marking_workers();
 
+  PartialArrayStateManager* partial_array_state_manager() const;
+
   // Resets the global marking data structures, as well as the
   // task local ones; should be called during concurrent start.
   void reset();
@@ -643,6 +619,10 @@ public:
   // to be called concurrently to the mutator. It will yield to safepoint requests.
   void cleanup_for_next_mark();
 
+  // Recycle the memory that has been requested by allocators associated with
+  // this manager.
+  void reset_partial_array_state_manager();
+
   // Clear the next marking bitmap during safepoint.
   void clear_bitmap(WorkerThreads* workers);
 
@@ -733,14 +713,13 @@ private:
     refs_reached_period           = 1024,
   };
 
-  G1CMObjArrayProcessor       _objArray_processor;
-
   uint                        _worker_id;
   G1CollectedHeap*            _g1h;
   G1ConcurrentMark*           _cm;
   G1CMBitMap*                 _mark_bitmap;
   // the task queue of this task
   G1CMTaskQueue*              _task_queue;
+  PartialArraySplitter        _partial_array_splitter;
 
   G1RegionMarkStatsCache      _mark_stats_cache;
   // Number of calls to this task
@@ -851,13 +830,24 @@ private:
   // mark bitmap scan, and so needs to be pushed onto the mark stack.
   bool is_below_finger(oop obj, HeapWord* global_finger) const;
 
-  template void process_grey_task_entry(G1TaskQueueEntry task_entry);
+  template void process_grey_task_entry(G1TaskQueueEntry task_entry, bool stolen);
+
+  static bool should_be_sliced(oop obj);
+  // Start processing the given objArrayOop by first pushing its continuations and
+  // then scanning the first chunk including the header.
+  size_t start_partial_array_processing(oop obj);
+  // Process the given continuation. Returns the number of words scanned.
+  size_t process_partial_array(const G1TaskQueueEntry& task, bool stolen);
+  // Apply the closure to the given range of elements in the objArray.
+  inline void process_array_chunk(objArrayOop obj, size_t start, size_t end);
 public:
-  // Apply the closure on the given area of the objArray. Return the number of words
-  // scanned.
-  inline size_t scan_objArray(objArrayOop obj, MemRegion mr);
   // Resets the task; should be called right at the beginning of a marking phase.
   void reset(G1CMBitMap* mark_bitmap);
+  // Register/unregister Partial Array Splitter Allocator with the PartialArrayStateManager.
+  // This allows us to discard memory arenas used for partial object array states at the end
+  // of a concurrent mark cycle.
+  void register_partial_array_splitter();
+  void unregister_partial_array_splitter();
   // Clears all the fields that correspond to a claimed region.
   void clear_region_fields();
 
@@ -913,7 +903,7 @@ public:
   inline bool deal_with_reference(T* p);
 
   // Scans an object and visits its children.
-  inline void scan_task_entry(G1TaskQueueEntry task_entry);
+  inline void process_entry(G1TaskQueueEntry task_entry, bool stolen);
 
   // Pushes an object on the local queue.
   inline void push(G1TaskQueueEntry task_entry);
@@ -958,6 +948,11 @@ public:
   Pair flush_mark_stats_cache();
   // Prints statistics associated with this task
   void print_stats();
+#if TASKQUEUE_STATS
+  PartialArrayTaskStats* partial_array_task_stats() {
+    return _partial_array_splitter.stats();
+  }
+#endif
 };
 
 // Class that's used to to print out per-region liveness
diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp
index 6f71012ff7c..fe72c68d4eb 100644
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2026, 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
@@ -29,7 +29,6 @@
 
 #include "gc/g1/g1CollectedHeap.inline.hpp"
 #include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp"
-#include "gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp"
 #include "gc/g1/g1HeapRegion.hpp"
 #include "gc/g1/g1HeapRegionRemSet.inline.hpp"
 #include "gc/g1/g1OopClosures.inline.hpp"
@@ -39,6 +38,7 @@
 #include "gc/shared/suspendibleThreadSet.hpp"
 #include "gc/shared/taskqueue.inline.hpp"
 #include "utilities/bitMap.inline.hpp"
+#include "utilities/checkedCast.hpp"
 
 inline bool G1CMIsAliveClosure::do_object_b(oop obj) {
   // Check whether the passed in object is null. During discovery the referent
@@ -107,13 +107,15 @@ inline void G1CMMarkStack::iterate(Fn fn) const {
 #endif
 
 // It scans an object and visits its children.
-inline void G1CMTask::scan_task_entry(G1TaskQueueEntry task_entry) { process_grey_task_entry(task_entry); }
+inline void G1CMTask::process_entry(G1TaskQueueEntry task_entry, bool stolen) {
+  process_grey_task_entry(task_entry, stolen);
+}
 
 inline void G1CMTask::push(G1TaskQueueEntry task_entry) {
-  assert(task_entry.is_array_slice() || _g1h->is_in_reserved(task_entry.obj()), "invariant");
-  assert(task_entry.is_array_slice() || !_g1h->is_on_master_free_list(
-              _g1h->heap_region_containing(task_entry.obj())), "invariant");
-  assert(task_entry.is_array_slice() || _mark_bitmap->is_marked(cast_from_oop(task_entry.obj())), "invariant");
+  assert(task_entry.is_partial_array_state() || _g1h->is_in_reserved(task_entry.to_oop()), "invariant");
+  assert(task_entry.is_partial_array_state() || !_g1h->is_on_master_free_list(
+              _g1h->heap_region_containing(task_entry.to_oop())), "invariant");
+  assert(task_entry.is_partial_array_state() || _mark_bitmap->is_marked(cast_from_oop(task_entry.to_oop())), "invariant");
 
   if (!_task_queue->push(task_entry)) {
     // The local task queue looks full. We need to push some entries
@@ -159,29 +161,34 @@ inline bool G1CMTask::is_below_finger(oop obj, HeapWord* global_finger) const {
 }
 
 template
-inline void G1CMTask::process_grey_task_entry(G1TaskQueueEntry task_entry) {
-  assert(scan || (task_entry.is_oop() && task_entry.obj()->is_typeArray()), "Skipping scan of grey non-typeArray");
-  assert(task_entry.is_array_slice() || _mark_bitmap->is_marked(cast_from_oop(task_entry.obj())),
+inline void G1CMTask::process_grey_task_entry(G1TaskQueueEntry task_entry, bool stolen) {
+  assert(scan || (!task_entry.is_partial_array_state() && task_entry.to_oop()->is_typeArray()), "Skipping scan of grey non-typeArray");
+  assert(task_entry.is_partial_array_state() || _mark_bitmap->is_marked(cast_from_oop(task_entry.to_oop())),
          "Any stolen object should be a slice or marked");
 
   if (scan) {
-    if (task_entry.is_array_slice()) {
-      _words_scanned += _objArray_processor.process_slice(task_entry.slice());
+    if (task_entry.is_partial_array_state()) {
+      _words_scanned += process_partial_array(task_entry, stolen);
     } else {
-      oop obj = task_entry.obj();
-      if (G1CMObjArrayProcessor::should_be_sliced(obj)) {
-        _words_scanned += _objArray_processor.process_obj(obj);
+      oop obj = task_entry.to_oop();
+      if (should_be_sliced(obj)) {
+        _words_scanned += start_partial_array_processing(obj);
       } else {
-        _words_scanned += obj->oop_iterate_size(_cm_oop_closure);;
+        _words_scanned += obj->oop_iterate_size(_cm_oop_closure);
       }
     }
   }
   check_limits();
 }
 
-inline size_t G1CMTask::scan_objArray(objArrayOop obj, MemRegion mr) {
-  obj->oop_iterate(_cm_oop_closure, mr);
-  return mr.word_size();
+inline bool G1CMTask::should_be_sliced(oop obj) {
+  return obj->is_objArray() && ((objArrayOop)obj)->length() >= (int)ObjArrayMarkingStride;
+}
+
+inline void G1CMTask::process_array_chunk(objArrayOop obj, size_t start, size_t end) {
+  obj->oop_iterate_elements_range(_cm_oop_closure,
+                                  checked_cast(start),
+                                  checked_cast(end));
 }
 
 inline void G1ConcurrentMark::update_top_at_mark_start(G1HeapRegion* r) {
@@ -265,7 +272,7 @@ inline bool G1CMTask::make_reference_grey(oop obj) {
   // be pushed on the stack. So, some duplicate work, but no
   // correctness problems.
   if (is_below_finger(obj, global_finger)) {
-    G1TaskQueueEntry entry = G1TaskQueueEntry::from_oop(obj);
+    G1TaskQueueEntry entry(obj);
     if (obj->is_typeArray()) {
       // Immediately process arrays of primitive types, rather
       // than pushing on the mark stack.  This keeps us from
@@ -277,7 +284,7 @@ inline bool G1CMTask::make_reference_grey(oop obj) {
       // by only doing a bookkeeping update and avoiding the
       // actual scan of the object - a typeArray contains no
       // references, and the metadata is built-in.
-      process_grey_task_entry(entry);
+      process_grey_task_entry(entry, false /* stolen */);
     } else {
       push(entry);
     }
diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.cpp
deleted file mode 100644
index 7f62e5527d5..00000000000
--- a/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "gc/g1/g1CollectedHeap.inline.hpp"
-#include "gc/g1/g1ConcurrentMark.inline.hpp"
-#include "gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp"
-#include "gc/g1/g1HeapRegion.inline.hpp"
-#include "gc/shared/gc_globals.hpp"
-#include "memory/memRegion.hpp"
-#include "utilities/globalDefinitions.hpp"
-
-void G1CMObjArrayProcessor::push_array_slice(HeapWord* what) {
-  _task->push(G1TaskQueueEntry::from_slice(what));
-}
-
-size_t G1CMObjArrayProcessor::process_array_slice(objArrayOop obj, HeapWord* start_from, size_t remaining) {
-  size_t words_to_scan = MIN2(remaining, (size_t)ObjArrayMarkingStride);
-
-  if (remaining > ObjArrayMarkingStride) {
-    push_array_slice(start_from + ObjArrayMarkingStride);
-  }
-
-  // Then process current area.
-  MemRegion mr(start_from, words_to_scan);
-  return _task->scan_objArray(obj, mr);
-}
-
-size_t G1CMObjArrayProcessor::process_obj(oop obj) {
-  assert(should_be_sliced(obj), "Must be an array object %d and large %zu", obj->is_objArray(), obj->size());
-
-  return process_array_slice(objArrayOop(obj), cast_from_oop(obj), objArrayOop(obj)->size());
-}
-
-size_t G1CMObjArrayProcessor::process_slice(HeapWord* slice) {
-
-  // Find the start address of the objArrayOop.
-  // Shortcut the BOT access if the given address is from a humongous object. The BOT
-  // slide is fast enough for "smaller" objects in non-humongous regions, but is slower
-  // than directly using heap region table.
-  G1CollectedHeap* g1h = G1CollectedHeap::heap();
-  G1HeapRegion* r = g1h->heap_region_containing(slice);
-
-  HeapWord* const start_address = r->is_humongous() ?
-                                  r->humongous_start_region()->bottom() :
-                                  r->block_start(slice);
-
-  assert(cast_to_oop(start_address)->is_objArray(), "Address " PTR_FORMAT " does not refer to an object array ", p2i(start_address));
-  assert(start_address < slice,
-         "Object start address " PTR_FORMAT " must be smaller than decoded address " PTR_FORMAT,
-         p2i(start_address),
-         p2i(slice));
-
-  objArrayOop objArray = objArrayOop(cast_to_oop(start_address));
-
-  size_t already_scanned = pointer_delta(slice, start_address);
-  size_t remaining = objArray->size() - already_scanned;
-
-  return process_array_slice(objArray, slice, remaining);
-}
diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.hpp
deleted file mode 100644
index c2737dbbda6..00000000000
--- a/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.hpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2016, 2019, 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_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_HPP
-#define SHARE_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_HPP
-
-#include "oops/oopsHierarchy.hpp"
-
-class G1CMTask;
-
-// Helper class to mark through large objArrays during marking in an efficient way.
-// Instead of pushing large object arrays, we push continuations onto the
-// mark stack. These continuations are identified by having their LSB set.
-// This allows incremental processing of large objects.
-class G1CMObjArrayProcessor {
-private:
-  // Reference to the task for doing the actual work.
-  G1CMTask* _task;
-
-  // Push the continuation at the given address onto the mark stack.
-  void push_array_slice(HeapWord* addr);
-
-  // Process (apply the closure) on the given continuation of the given objArray.
-  size_t process_array_slice(objArrayOop const obj, HeapWord* start_from, size_t remaining);
-public:
-  static bool should_be_sliced(oop obj);
-
-  G1CMObjArrayProcessor(G1CMTask* task) : _task(task) {
-  }
-
-  // Process the given continuation. Returns the number of words scanned.
-  size_t process_slice(HeapWord* slice);
-  // Start processing the given objArrayOop by scanning the header and pushing its
-  // continuation.
-  size_t process_obj(oop obj);
-};
-
-#endif // SHARE_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_HPP
diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp
deleted file mode 100644
index f6d47acdc01..00000000000
--- a/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_INLINE_HPP
-#define SHARE_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_INLINE_HPP
-
-#include "gc/g1/g1ConcurrentMarkObjArrayProcessor.hpp"
-
-#include "gc/shared/gc_globals.hpp"
-#include "oops/oop.inline.hpp"
-#include "oops/oopsHierarchy.hpp"
-
-inline bool G1CMObjArrayProcessor::should_be_sliced(oop obj) {
-  return obj->is_objArray() && ((objArrayOop)obj)->size() >= 2 * ObjArrayMarkingStride;
-}
-
-#endif // SHARE_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_INLINE_HPP
diff --git a/src/hotspot/share/gc/shared/taskqueue.hpp b/src/hotspot/share/gc/shared/taskqueue.hpp
index 4334773a4e9..5c2fe4e5178 100644
--- a/src/hotspot/share/gc/shared/taskqueue.hpp
+++ b/src/hotspot/share/gc/shared/taskqueue.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2026, 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
@@ -641,6 +641,10 @@ public:
     return (raw_value() & PartialArrayTag) != 0;
   }
 
+  bool is_null() const {
+    return _p == nullptr;
+  }
+
   oop* to_oop_ptr() const {
     return static_cast(decode(OopTag));
   }

From 0f4d775085109981fbf00623d38da22655d04675 Mon Sep 17 00:00:00 2001
From: Tobias Hartmann 
Date: Thu, 22 Jan 2026 06:56:51 +0000
Subject: [PATCH 130/328] 8375534: Debug method 'pp' should support compressed
 oops

Reviewed-by: vlivanov, phubner
---
 src/hotspot/share/utilities/debug.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp
index 0e1ca1efb98..504b923237e 100644
--- a/src/hotspot/share/utilities/debug.cpp
+++ b/src/hotspot/share/utilities/debug.cpp
@@ -429,10 +429,8 @@ extern "C" DEBUGEXPORT void pp(void* p) {
     tty->print_cr("null");
     return;
   }
-  if (Universe::heap()->is_in(p)) {
-    oop obj = cast_to_oop(p);
-    obj->print();
-  } else {
+
+  if (!Universe::heap()->print_location(tty, p)) {
     // Ask NMT about this pointer.
     // GDB note: We will be using SafeFetch to access the supposed malloc header. If the address is
     // not readable, this will generate a signal. That signal will trip up the debugger: gdb will

From f3381f0ffe2207e1765558f6f49e5a0280a3f920 Mon Sep 17 00:00:00 2001
From: Thomas Schatzl 
Date: Thu, 22 Jan 2026 08:29:05 +0000
Subject: [PATCH 131/328] 8375314: Parallel: Crash iterating over unloaded
 classes for ObjectCountAfterGC event

Reviewed-by: rkennke, sjohanss, iwalulya
---
 src/hotspot/share/gc/g1/g1CollectedHeap.hpp   |   1 -
 .../share/gc/g1/g1CollectedHeap.inline.hpp    |   8 +-
 .../share/gc/parallel/psParallelCompact.cpp   |  23 ++--
 .../share/gc/parallel/psParallelCompact.hpp   |   1 +
 src/hotspot/share/gc/shared/collectedHeap.hpp |   4 +-
 .../share/gc/shared/collectedHeap.inline.hpp  |   9 +-
 .../gc/parallel/TestObjectCountAfterGC.java   | 104 ++++++++++++++++++
 7 files changed, 134 insertions(+), 16 deletions(-)
 create mode 100644 test/hotspot/jtreg/gc/parallel/TestObjectCountAfterGC.java

diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
index a0104d04f4f..8009df1fa6a 100644
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
@@ -1268,7 +1268,6 @@ public:
 
   bool is_marked(oop obj) const;
 
-  inline static bool is_obj_filler(const oop obj);
   // Determine if an object is dead, given the object and also
   // the region to which the object belongs.
   inline bool is_obj_dead(const oop obj, const G1HeapRegion* hr) const;
diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp
index 577450b3be9..958b171444e 100644
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp
@@ -38,6 +38,7 @@
 #include "gc/g1/g1Policy.hpp"
 #include "gc/g1/g1RegionPinCache.inline.hpp"
 #include "gc/g1/g1RemSet.hpp"
+#include "gc/shared/collectedHeap.inline.hpp"
 #include "gc/shared/markBitMap.inline.hpp"
 #include "gc/shared/taskqueue.inline.hpp"
 #include "oops/stackChunkOop.hpp"
@@ -229,16 +230,11 @@ inline bool G1CollectedHeap::requires_barriers(stackChunkOop obj) const {
   return !heap_region_containing(obj)->is_young(); // is_in_young does an unnecessary null check
 }
 
-inline bool G1CollectedHeap::is_obj_filler(const oop obj) {
-  Klass* k = obj->klass_without_asserts();
-  return k == Universe::fillerArrayKlass() || k == vmClasses::FillerObject_klass();
-}
-
 inline bool G1CollectedHeap::is_obj_dead(const oop obj, const G1HeapRegion* hr) const {
   assert(!hr->is_free(), "looking up obj " PTR_FORMAT " in Free region %u", p2i(obj), hr->hrm_index());
   if (hr->is_in_parsable_area(obj)) {
     // This object is in the parsable part of the heap, live unless scrubbed.
-    return is_obj_filler(obj);
+    return is_filler_object(obj);
   } else {
     // From Remark until a region has been concurrently scrubbed, parts of the
     // region is not guaranteed to be parsable. Use the bitmap for liveness.
diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp
index b1b07b4bc5c..bab72296d4c 100644
--- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp
+++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2026, 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
@@ -44,6 +44,7 @@
 #include "gc/parallel/psStringDedup.hpp"
 #include "gc/parallel/psYoungGen.hpp"
 #include "gc/shared/classUnloadingContext.hpp"
+#include "gc/shared/collectedHeap.inline.hpp"
 #include "gc/shared/fullGCForwarding.inline.hpp"
 #include "gc/shared/gcCause.hpp"
 #include "gc/shared/gcHeapSummary.hpp"
@@ -932,6 +933,17 @@ void PSParallelCompact::summary_phase(bool should_do_max_compaction)
   }
 }
 
+void PSParallelCompact::report_object_count_after_gc() {
+  GCTraceTime(Debug, gc, phases) tm("Report Object Count", &_gc_timer);
+  // The heap is compacted, all objects are iterable. However there may be
+  // filler objects in the heap which we should ignore.
+  class SkipFillerObjectClosure : public BoolObjectClosure {
+  public:
+    bool do_object_b(oop obj) override { return !CollectedHeap::is_filler_object(obj); }
+  } cl;
+  _gc_tracer.report_object_count_after_gc(&cl, &ParallelScavengeHeap::heap()->workers());
+}
+
 bool PSParallelCompact::invoke(bool clear_all_soft_refs, bool should_do_max_compaction) {
   assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
   assert(Thread::current() == (Thread*)VMThread::vm_thread(),
@@ -1027,6 +1039,8 @@ bool PSParallelCompact::invoke(bool clear_all_soft_refs, bool should_do_max_comp
 
     heap->print_heap_change(pre_gc_values);
 
+    report_object_count_after_gc();
+
     // Track memory usage and detect low memory
     MemoryService::track_memory_usage();
     heap->update_counters();
@@ -1274,10 +1288,6 @@ void PSParallelCompact::marking_phase(ParallelOldTracer *gc_tracer) {
     }
   }
 
-  {
-    GCTraceTime(Debug, gc, phases) tm("Report Object Count", &_gc_timer);
-    _gc_tracer.report_object_count_after_gc(is_alive_closure(), &ParallelScavengeHeap::heap()->workers());
-  }
 #if TASKQUEUE_STATS
   ParCompactionManager::print_and_reset_taskqueue_stats();
 #endif
@@ -1835,8 +1845,7 @@ void PSParallelCompact::verify_filler_in_dense_prefix() {
       oop obj = cast_to_oop(cur_addr);
       oopDesc::verify(obj);
       if (!mark_bitmap()->is_marked(cur_addr)) {
-        Klass* k = cast_to_oop(cur_addr)->klass();
-        assert(k == Universe::fillerArrayKlass() || k == vmClasses::FillerObject_klass(), "inv");
+        assert(CollectedHeap::is_filler_object(cast_to_oop(cur_addr)), "inv");
       }
       cur_addr += obj->size();
     }
diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp
index 2297d720b35..4ac9395d727 100644
--- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp
+++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp
@@ -749,6 +749,7 @@ private:
   // Move objects to new locations.
   static void compact();
 
+  static void report_object_count_after_gc();
   // Add available regions to the stack and draining tasks to the task queue.
   static void prepare_region_draining_tasks(uint parallel_gc_threads);
 
diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp
index 6f335b1cdf4..363ccf321b2 100644
--- a/src/hotspot/share/gc/shared/collectedHeap.hpp
+++ b/src/hotspot/share/gc/shared/collectedHeap.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2026, 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
@@ -309,6 +309,8 @@ protected:
     fill_with_object(start, pointer_delta(end, start), zap);
   }
 
+  inline static bool is_filler_object(oop obj);
+
   virtual void fill_with_dummy_object(HeapWord* start, HeapWord* end, bool zap);
   static size_t min_dummy_object_size() {
     return oopDesc::header_size();
diff --git a/src/hotspot/share/gc/shared/collectedHeap.inline.hpp b/src/hotspot/share/gc/shared/collectedHeap.inline.hpp
index c9d84f54449..194c1fe0bf2 100644
--- a/src/hotspot/share/gc/shared/collectedHeap.inline.hpp
+++ b/src/hotspot/share/gc/shared/collectedHeap.inline.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,9 @@
 
 #include "gc/shared/collectedHeap.hpp"
 
+#include "classfile/vmClasses.hpp"
 #include "gc/shared/memAllocator.hpp"
+#include "memory/universe.hpp"
 #include "oops/oop.inline.hpp"
 #include "utilities/align.hpp"
 
@@ -50,4 +52,9 @@ inline void CollectedHeap::add_vmthread_cpu_time(jlong time) {
   _vmthread_cpu_time += time;
 }
 
+inline bool CollectedHeap::is_filler_object(oop obj) {
+  Klass* k = obj->klass_without_asserts();
+  return k == Universe::fillerArrayKlass() || k == vmClasses::FillerObject_klass();
+}
+
 #endif // SHARE_GC_SHARED_COLLECTEDHEAP_INLINE_HPP
diff --git a/test/hotspot/jtreg/gc/parallel/TestObjectCountAfterGC.java b/test/hotspot/jtreg/gc/parallel/TestObjectCountAfterGC.java
new file mode 100644
index 00000000000..e61e7518938
--- /dev/null
+++ b/test/hotspot/jtreg/gc/parallel/TestObjectCountAfterGC.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2026, 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 gc.parallel;
+
+/*
+ * @test TestObjectCountAfterGC
+ * @bug 8375314
+ * @summary Verifies that the HeapInspection VM operation for the ObjectCountAfterGC JFR event does not crash the VM.
+ *          Creates a set of custom classes that are about to be unloaded to cause metaspace to uncommit pages. When
+ *          the execution of the heap inspection iterates over the heap, it will come across these unloaded classes
+ *          referencing uncommitted memory, crashing.
+ * @requires vm.gc.Parallel
+ * @requires vm.opt.final.ClassUnloading
+ * @library /test/lib
+ * @library /testlibrary/asm
+ * @modules java.base/jdk.internal.misc
+ * @run main/othervm -XX:+UseParallelGC -Xlog:gc=debug,metaspace=info -XX:StartFlightRecording:gc=all,duration=1s,filename=myrecording.jfr
+ *                   gc.parallel.TestObjectCountAfterGC
+ */
+
+import java.lang.ref.Reference;
+
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+public class TestObjectCountAfterGC {
+
+    static final String className = "ClassToLoadUnload";
+
+    public static void main(String args[]) throws Exception {
+        final int KEEPALIVE_LENGTH = 100;
+
+        Object[] keepalive = new Object[KEEPALIVE_LENGTH];
+
+        for (int i = 1; i < 1000; i++) {
+            ClassLoader cl = new MyClassLoader();
+            Object o = null;
+            // Create some random kept alive objects so that the
+            // compaction regions are not totally empty and the
+            // heap inspection VM operation needs to iterate them.
+            keepalive[(i / KEEPALIVE_LENGTH) % KEEPALIVE_LENGTH] = new int[100];
+            o = cl.loadClass(className + i).newInstance();
+
+            cl = null;
+            o = null;
+        }
+
+        // There is heap inspection VM operation for the ObjectCountAfterGC event
+        // when JFR stops recording.
+
+        Reference.reachabilityFence(keepalive);
+    }
+}
+
+class MyClassLoader extends ClassLoader {
+
+    // Create a class of the given name with a default constructor.
+    public byte[] createClass(String name) {
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
+        cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, name, null, "java/lang/Object", null);
+        // Add default constructor that just calls the super class constructor.
+        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null);
+        mv.visitCode();
+        mv.visitVarInsn(Opcodes.ALOAD, 0);
+        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false);
+        mv.visitInsn(Opcodes.RETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+        return cw.toByteArray();
+    }
+
+    // If the given name starts with "TestObjectCountAfterGC" create a new class on the fly,
+    // delegate otherwise.
+    public Class loadClass(String name) throws ClassNotFoundException {
+        if (!name.startsWith(TestObjectCountAfterGC.className)) {
+            return super.loadClass(name);
+        }
+        byte[] cls = createClass(name);
+        return defineClass(name, cls, 0, cls.length, null);
+    }
+  }
+

From e50bf1f2a4702ef48cf16cc4f45d034a652bf358 Mon Sep 17 00:00:00 2001
From: Thomas Schatzl 
Date: Thu, 22 Jan 2026 08:29:27 +0000
Subject: [PATCH 132/328] 8375616: G1: Convert G1BatchedTask to use Atomic

Reviewed-by: sjohanss, kbarrett
---
 src/hotspot/share/gc/g1/g1BatchedTask.cpp | 9 ++++-----
 src/hotspot/share/gc/g1/g1BatchedTask.hpp | 5 +++--
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/hotspot/share/gc/g1/g1BatchedTask.cpp b/src/hotspot/share/gc/g1/g1BatchedTask.cpp
index 57558301541..1f082153476 100644
--- a/src/hotspot/share/gc/g1/g1BatchedTask.cpp
+++ b/src/hotspot/share/gc/g1/g1BatchedTask.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,6 @@
 #include "gc/g1/g1BatchedTask.hpp"
 #include "gc/g1/g1CollectedHeap.inline.hpp"
 #include "gc/g1/g1GCParPhaseTimesTracker.hpp"
-#include "runtime/atomicAccess.hpp"
 #include "utilities/growableArray.hpp"
 
 void G1AbstractSubTask::record_work_item(uint worker_id, uint index, size_t count) {
@@ -40,7 +39,7 @@ const char* G1AbstractSubTask::name() const {
 }
 
 bool G1BatchedTask::try_claim_serial_task(int& task) {
-  task = AtomicAccess::fetch_then_add(&_num_serial_tasks_done, 1);
+  task = _num_serial_tasks_done.fetch_then_add(1);
   return task < _serial_tasks.length();
 }
 
@@ -96,8 +95,8 @@ void G1BatchedTask::work(uint worker_id) {
 }
 
 G1BatchedTask::~G1BatchedTask() {
-  assert(AtomicAccess::load(&_num_serial_tasks_done) >= _serial_tasks.length(),
-         "Only %d tasks of %d claimed", AtomicAccess::load(&_num_serial_tasks_done), _serial_tasks.length());
+  assert(_num_serial_tasks_done.load_relaxed() >= _serial_tasks.length(),
+         "Only %d tasks of %d claimed", _num_serial_tasks_done.load_relaxed(), _serial_tasks.length());
 
   for (G1AbstractSubTask* task : _parallel_tasks) {
     delete task;
diff --git a/src/hotspot/share/gc/g1/g1BatchedTask.hpp b/src/hotspot/share/gc/g1/g1BatchedTask.hpp
index 020fda634e4..a6d2ef923c0 100644
--- a/src/hotspot/share/gc/g1/g1BatchedTask.hpp
+++ b/src/hotspot/share/gc/g1/g1BatchedTask.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
 #include "gc/g1/g1GCPhaseTimes.hpp"
 #include "gc/shared/workerThread.hpp"
 #include "memory/allocation.hpp"
+#include "runtime/atomic.hpp"
 
 template 
 class GrowableArrayCHeap;
@@ -120,7 +121,7 @@ public:
 // 5) ~T()
 //
 class G1BatchedTask : public WorkerTask {
-  volatile int _num_serial_tasks_done;
+  Atomic _num_serial_tasks_done;
   G1GCPhaseTimes* _phase_times;
 
   bool try_claim_serial_task(int& task);

From 92236ead1dea813cf456855f0aa6b73c16e9dc70 Mon Sep 17 00:00:00 2001
From: Quan Anh Mai 
Date: Thu, 22 Jan 2026 08:32:01 +0000
Subject: [PATCH 133/328] 8375618: Incorrect assert in CastLLNode::Ideal

Reviewed-by: chagedorn, dlong
---
 src/hotspot/share/opto/castnode.cpp           |  6 +-
 src/hotspot/share/opto/type.cpp               | 14 +++++
 src/hotspot/share/opto/type.hpp               | 10 +++
 .../jtreg/compiler/igvn/CastLLBits.java       | 63 +++++++++++++++++++
 4 files changed, 90 insertions(+), 3 deletions(-)
 create mode 100644 test/hotspot/jtreg/compiler/igvn/CastLLBits.java

diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp
index 998b6a79903..2ebbdd7cdb3 100644
--- a/src/hotspot/share/opto/castnode.cpp
+++ b/src/hotspot/share/opto/castnode.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2026, 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
@@ -392,8 +392,8 @@ Node* CastLLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
     if (t != Type::TOP && t_in != Type::TOP) {
       const TypeLong* tl = t->is_long();
       const TypeLong* t_in_l = t_in->is_long();
-      assert(tl->_lo >= t_in_l->_lo && tl->_hi <= t_in_l->_hi, "CastLL type should be narrower than or equal to the type of its input");
-      assert((tl != t_in_l) == (tl->_lo > t_in_l->_lo || tl->_hi < t_in_l->_hi), "if type differs then this nodes's type must be narrower");
+      assert(t_in_l->contains(tl), "CastLL type should be narrower than or equal to the type of its input");
+      assert((tl != t_in_l) == t_in_l->strictly_contains(tl), "if type differs then this nodes's type must be narrower");
       if (tl != t_in_l) {
         const TypeInt* ti = TypeInt::make(checked_cast(tl->_lo), checked_cast(tl->_hi), tl->_widen);
         Node* castii = phase->transform(new CastIINode(in(0), in1->in(1), ti));
diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp
index d3271e79f2f..c637737eef9 100644
--- a/src/hotspot/share/opto/type.cpp
+++ b/src/hotspot/share/opto/type.cpp
@@ -1816,6 +1816,13 @@ bool TypeInt::contains(const TypeInt* t) const {
   return TypeIntHelper::int_type_is_subset(this, t);
 }
 
+#ifdef ASSERT
+bool TypeInt::strictly_contains(const TypeInt* t) const {
+  assert(!_is_dual && !t->_is_dual, "dual types should only be used for join calculation");
+  return TypeIntHelper::int_type_is_subset(this, t) && !TypeIntHelper::int_type_is_equal(this, t);
+}
+#endif // ASSERT
+
 const Type* TypeInt::xmeet(const Type* t) const {
   return TypeIntHelper::int_type_xmeet(this, t);
 }
@@ -1944,6 +1951,13 @@ bool TypeLong::contains(const TypeLong* t) const {
   return TypeIntHelper::int_type_is_subset(this, t);
 }
 
+#ifdef ASSERT
+bool TypeLong::strictly_contains(const TypeLong* t) const {
+  assert(!_is_dual && !t->_is_dual, "dual types should only be used for join calculation");
+  return TypeIntHelper::int_type_is_subset(this, t) && !TypeIntHelper::int_type_is_equal(this, t);
+}
+#endif // ASSERT
+
 const Type* TypeLong::xmeet(const Type* t) const {
   return TypeIntHelper::int_type_xmeet(this, t);
 }
diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp
index 7c7ff035a54..135f37f7267 100644
--- a/src/hotspot/share/opto/type.hpp
+++ b/src/hotspot/share/opto/type.hpp
@@ -812,6 +812,11 @@ public:
   bool contains(jint i) const;
   bool contains(const TypeInt* t) const;
 
+#ifdef ASSERT
+  // Check whether t is a proper subset (i.e. a subset that is not equal to the superset) of this
+  bool strictly_contains(const TypeInt* t) const;
+#endif // ASSERT
+
   virtual bool is_finite() const;  // Has a finite value
 
   virtual const Type* xmeet(const Type* t) const;
@@ -897,6 +902,11 @@ public:
   bool contains(jlong i) const;
   bool contains(const TypeLong* t) const;
 
+#ifdef ASSERT
+  // Check whether t is a proper subset (i.e. a subset that is not equal to the superset) of this
+  bool strictly_contains(const TypeLong* t) const;
+#endif // ASSERT
+
   // Check for positive 32-bit value.
   int is_positive_int() const { return _lo >= 0 && _hi <= (jlong)max_jint; }
 
diff --git a/test/hotspot/jtreg/compiler/igvn/CastLLBits.java b/test/hotspot/jtreg/compiler/igvn/CastLLBits.java
new file mode 100644
index 00000000000..a212fd1d3b6
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/igvn/CastLLBits.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2026, 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.igvn;
+
+/**
+ * @test
+ * @bug 8375618
+ * @summary A CastLLNode may change only a bit of its input, which triggers the incorrect assertion
+ *          that the signed range must changes
+ * @run main/othervm -XX:-TieredCompilation -Xbatch ${test.main.class}
+ * @run main ${test.main.class}
+ */
+public class CastLLBits {
+    static long instanceCount;
+
+    public static void main(String[] args) {
+        for (int i = 0; i < 2000; i++) {
+            test();
+        }
+    }
+
+    static void test() {
+        int i, i1 = 6, i9, i10, i11, i12;
+        boolean b = false;
+        for (i = 25; i > 5; i--) {
+            i9 = 1;
+            do {
+                i1 += 0;
+                for (i10 = 1; i10 < 3; ++i10) {
+                    instanceCount = i9;
+                }
+                i12 = 3;
+                while (--i12 > 0) {
+                    i11 = (int) instanceCount;
+                    i1 = i11;
+                    if (b) {};
+                    instanceCount &= 21;
+                }
+                i9++;
+            } while (i9 < 9);
+        }
+    }
+}

From 63be87d7f38a83c5fcdf59b54c6d63e0f0ca34d6 Mon Sep 17 00:00:00 2001
From: Thomas Schatzl 
Date: Thu, 22 Jan 2026 08:35:03 +0000
Subject: [PATCH 134/328] 8375977: G1: Convert JVMCICleaningTask to use
 Atomic

Reviewed-by: kbarrett
---
 src/hotspot/share/gc/g1/g1ParallelCleaning.cpp | 7 +++----
 src/hotspot/share/gc/g1/g1ParallelCleaning.hpp | 7 +++++--
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/src/hotspot/share/gc/g1/g1ParallelCleaning.cpp b/src/hotspot/share/gc/g1/g1ParallelCleaning.cpp
index 8d5e2a3239c..e3eabff5a50 100644
--- a/src/hotspot/share/gc/g1/g1ParallelCleaning.cpp
+++ b/src/hotspot/share/gc/g1/g1ParallelCleaning.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,7 +24,6 @@
 
 
 #include "gc/g1/g1ParallelCleaning.hpp"
-#include "runtime/atomicAccess.hpp"
 #if INCLUDE_JVMCI
 #include "jvmci/jvmci.hpp"
 #endif
@@ -35,11 +34,11 @@ JVMCICleaningTask::JVMCICleaningTask() :
 }
 
 bool JVMCICleaningTask::claim_cleaning_task() {
-  if (AtomicAccess::load(&_cleaning_claimed)) {
+  if (_cleaning_claimed.load_relaxed()) {
     return false;
   }
 
-  return !AtomicAccess::cmpxchg(&_cleaning_claimed, false, true);
+  return _cleaning_claimed.compare_set(false, true);
 }
 
 void JVMCICleaningTask::work(bool unloading_occurred) {
diff --git a/src/hotspot/share/gc/g1/g1ParallelCleaning.hpp b/src/hotspot/share/gc/g1/g1ParallelCleaning.hpp
index d8725cb110d..815b0883e16 100644
--- a/src/hotspot/share/gc/g1/g1ParallelCleaning.hpp
+++ b/src/hotspot/share/gc/g1/g1ParallelCleaning.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,10 +26,13 @@
 #define SHARE_GC_G1_G1PARALLELCLEANING_HPP
 
 #include "gc/shared/parallelCleaning.hpp"
+#if INCLUDE_JVMCI
+#include "runtime/atomic.hpp"
+#endif
 
 #if INCLUDE_JVMCI
 class JVMCICleaningTask : public StackObj {
-  volatile bool _cleaning_claimed;
+  Atomic _cleaning_claimed;
 
 public:
   JVMCICleaningTask();

From 03038d802cc43b7694f554978ac9de8edca8a954 Mon Sep 17 00:00:00 2001
From: Thomas Schatzl 
Date: Thu, 22 Jan 2026 08:35:32 +0000
Subject: [PATCH 135/328] 8375978: G1: Convert G1Policy to use Atomic

Reviewed-by: kbarrett
---
 src/hotspot/share/gc/g1/g1Policy.cpp |  4 ++--
 src/hotspot/share/gc/g1/g1Policy.hpp | 13 +++++--------
 2 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp
index 2847a25c5b4..8818b477aae 100644
--- a/src/hotspot/share/gc/g1/g1Policy.cpp
+++ b/src/hotspot/share/gc/g1/g1Policy.cpp
@@ -203,8 +203,8 @@ void G1Policy::update_young_length_bounds(size_t pending_cards, size_t card_rs_l
   // allocation.
   // That is "fine" - at most this will schedule a GC (hopefully only a little) too
   // early or too late.
-  AtomicAccess::store(&_young_list_desired_length, new_young_list_desired_length);
-  AtomicAccess::store(&_young_list_target_length, new_young_list_target_length);
+  _young_list_desired_length.store_relaxed(new_young_list_desired_length);
+  _young_list_target_length.store_relaxed(new_young_list_target_length);
 }
 
 // Calculates desired young gen length. It is calculated from:
diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp
index cf12a7a8027..9513c79869e 100644
--- a/src/hotspot/share/gc/g1/g1Policy.hpp
+++ b/src/hotspot/share/gc/g1/g1Policy.hpp
@@ -35,7 +35,7 @@
 #include "gc/g1/g1RemSetTrackingPolicy.hpp"
 #include "gc/g1/g1YoungGenSizer.hpp"
 #include "gc/shared/gcCause.hpp"
-#include "runtime/atomicAccess.hpp"
+#include "runtime/atomic.hpp"
 #include "utilities/pair.hpp"
 #include "utilities/ticks.hpp"
 
@@ -81,12 +81,9 @@ class G1Policy: public CHeapObj {
 
   // Desired young gen length without taking actually available free regions into
   // account.
-  volatile uint _young_list_desired_length;
+  Atomic _young_list_desired_length;
   // Actual target length given available free memory.
-  volatile uint _young_list_target_length;
-  // The max number of regions we can extend the eden by while the GC
-  // locker is active. This should be >= _young_list_target_length;
-  volatile uint _young_list_max_length;
+  Atomic _young_list_target_length;
 
   // The survivor rate groups below must be initialized after the predictor because they
   // indirectly use it through the "this" object passed to their constructor.
@@ -362,8 +359,8 @@ public:
   // This must be called at the very beginning of an evacuation pause.
   void decide_on_concurrent_start_pause();
 
-  uint young_list_desired_length() const { return AtomicAccess::load(&_young_list_desired_length); }
-  uint young_list_target_length() const { return AtomicAccess::load(&_young_list_target_length); }
+  uint young_list_desired_length() const { return _young_list_desired_length.load_relaxed(); }
+  uint young_list_target_length() const { return _young_list_target_length.load_relaxed(); }
 
   bool should_allocate_mutator_region() const;
   bool should_expand_on_mutator_allocation() const;

From 6165daf03c8582cca8e5b075560aa978b90f677c Mon Sep 17 00:00:00 2001
From: Matthias Baesken 
Date: Thu, 22 Jan 2026 08:50:11 +0000
Subject: [PATCH 136/328] 8375458: Check legal folder of JDK image for unwanted
 files

Reviewed-by: erikj
---
 test/jdk/build/CheckFiles.java | 59 +++++++++++++++++++++++++++++++++-
 1 file changed, 58 insertions(+), 1 deletion(-)

diff --git a/test/jdk/build/CheckFiles.java b/test/jdk/build/CheckFiles.java
index eb903c0a224..5a915e881f0 100644
--- a/test/jdk/build/CheckFiles.java
+++ b/test/jdk/build/CheckFiles.java
@@ -23,6 +23,7 @@
  */
 
 import java.io.IOException;
+import java.nio.file.DirectoryStream;
 import java.nio.file.FileVisitResult;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -36,7 +37,7 @@ import jdk.test.lib.Platform;
 
 /*
  * @test
- * @summary Check for unwanted file (types/extensions) in the jdk image
+ * @summary Check for unwanted files (types/extensions) in the jdk image
  * @library /test/lib
  * @requires !vm.debug
  * @run main CheckFiles
@@ -47,6 +48,20 @@ public class CheckFiles {
     // JTREG=JAVA_OPTIONS=-Djdk.test.build.CheckFiles.dir=/path/to/dir
     public static final String DIR_PROPERTY = "jdk.test.build.CheckFiles.dir";
 
+    private static boolean isGpl(Path myFile) {
+        if (myFile == null || !Files.exists(myFile)) {
+            return false;
+        }
+
+        try {
+            String firstLine = Files.readAllLines(myFile).stream()
+                                    .findFirst().orElse("");
+            return firstLine.contains("The GNU General Public License (GPL)");
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
     public static void main(String[] args) throws Exception {
         String jdkPathString = System.getProperty("test.jdk");
         Path jdkHome = Paths.get(jdkPathString);
@@ -148,6 +163,48 @@ public class CheckFiles {
                 throw new Error("jmods dir scan failed");
             }
         }
+
+        Path legalDir = mainDirToScan.resolve("legal");
+        Path javabaseLicenseFile = mainDirToScan.resolve("legal/java.base/LICENSE");
+        if (isGpl(javabaseLicenseFile)) { // for now check only legal dir of GPL based images; other ones might have other content
+            System.out.println("GPL info found in java.base LICENSE file");
+            ArrayList allowedEndingsLegalDir = new ArrayList<>();
+            allowedEndingsLegalDir.add(".md");
+            allowedEndingsLegalDir.add("ADDITIONAL_LICENSE_INFO");
+            allowedEndingsLegalDir.add("ASSEMBLY_EXCEPTION");
+            allowedEndingsLegalDir.add("LICENSE");
+
+            ArrayList requiredFilesInLegalSubdirs = new ArrayList<>();
+            requiredFilesInLegalSubdirs.add("LICENSE");
+            requiredFilesInLegalSubdirs.add("ADDITIONAL_LICENSE_INFO");
+            requiredFilesInLegalSubdirs.add("ASSEMBLY_EXCEPTION");
+
+            System.out.println("Legal directory to scan:" + legalDir);
+            try (DirectoryStream stream = Files.newDirectoryStream(legalDir)) {
+                for (Path subfolder : stream) {
+                    if (Files.isDirectory(subfolder)) {
+                        System.out.println("Checking legal dir subfolder for required files: " + subfolder.getFileName());
+
+                        for (String fileName : requiredFilesInLegalSubdirs) {
+                            Path filePath = subfolder.resolve(fileName);
+                            if (Files.exists(filePath)) {
+                                System.out.println("  Found " + fileName);
+                            } else {
+                                System.out.println("  Missing " + fileName);
+                                throw new Error("legal dir scan for required files failed");
+                            }
+                        }
+                    }
+                }
+            }
+
+            boolean legalDirRes = scanFiles(legalDir, allowedEndingsLegalDir);
+            if (legalDirRes) {
+                System.out.println("Legal directory scan successful.");
+            } else {
+                throw new Error("Legal dir scan failed");
+            }
+        }
     }
 
     private static boolean scanFiles(Path root, ArrayList allowedEndings) throws IOException {

From ddbd4617a6172e3054b2afade4f304f66c79816e Mon Sep 17 00:00:00 2001
From: Casper Norrbin 
Date: Thu, 22 Jan 2026 09:45:40 +0000
Subject: [PATCH 137/328] 8303470: containers/docker/TestMemoryAwareness.java
 failed with "'memory_limit_in_bytes:.*512000 k' missing from stdout/stderr"

Reviewed-by: sgehwolf, dholmes
---
 src/hotspot/os/linux/osContainer_linux.cpp | 13 +++++++------
 test/hotspot/jtreg/ProblemList.txt         |  1 -
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/hotspot/os/linux/osContainer_linux.cpp b/src/hotspot/os/linux/osContainer_linux.cpp
index fe1dbc17239..b46263efd99 100644
--- a/src/hotspot/os/linux/osContainer_linux.cpp
+++ b/src/hotspot/os/linux/osContainer_linux.cpp
@@ -304,12 +304,13 @@ void OSContainer::print_container_metric(outputStream* st, const char* metrics,
   constexpr int longest_value = max_length - 11; // Max length - shortest "metric: " string ("cpu_quota: ")
   char value_str[longest_value + 1] = {};
   os::snprintf_checked(value_str, longest_value, metric_fmt::fmt, value);
-  st->print("%s: %*s", metrics, max_length - static_cast(strlen(metrics)) - 2, value_str); // -2 for the ": "
-  if (unit[0] != '\0') {
-    st->print_cr(" %s", unit);
-  } else {
-    st->print_cr("");
-  }
+
+  const int pad_width = max_length - static_cast(strlen(metrics)) - 2; // -2 for the ": "
+  const char* unit_prefix = unit[0] != '\0' ? " " : "";
+
+  char line[128] = {};
+  os::snprintf_checked(line, sizeof(line), "%s: %*s%s%s", metrics, pad_width, value_str, unit_prefix, unit);
+  st->print_cr("%s", line);
 }
 
 void OSContainer::print_container_helper(outputStream* st, MetricResult& res, const char* metrics) {
diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt
index 13e1ea30a34..84520b00056 100644
--- a/test/hotspot/jtreg/ProblemList.txt
+++ b/test/hotspot/jtreg/ProblemList.txt
@@ -113,7 +113,6 @@ runtime/NMT/VirtualAllocCommitMerge.java 8309698 linux-s390x
 applications/jcstress/copy.java 8229852 linux-all
 
 containers/docker/TestJcmd.java 8278102 linux-all
-containers/docker/TestMemoryAwareness.java 8303470 linux-all
 containers/docker/TestJFREvents.java 8327723 linux-x64
 containers/docker/TestJcmdWithSideCar.java 8341518 linux-x64
 

From e8eb218ca2d05736adc4b0aefa4b17e3062959b8 Mon Sep 17 00:00:00 2001
From: Liam Miller-Cushon 
Date: Thu, 22 Jan 2026 10:05:05 +0000
Subject: [PATCH 138/328] 8374643: Fix reference to implMethodKind in
 LambdaToMethod debug printf statement

Reviewed-by: vromero, liach
---
 .../sun/tools/javac/comp/LambdaToMethod.java  | 27 +++++++++-------
 .../tools/javac/resources/compiler.properties | 11 +++++++
 .../examples/LambdaDeserializationStat.java   | 31 +++++++++++++++++++
 .../lambda/SerializableObjectMethods.java     |  2 +-
 .../lambda/SerializableObjectMethods.out      |  4 +++
 5 files changed, 63 insertions(+), 12 deletions(-)
 create mode 100644 test/langtools/tools/javac/diags/examples/LambdaDeserializationStat.java
 create mode 100644 test/langtools/tools/javac/lambda/SerializableObjectMethods.out

diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
index 22cb796870b..7d0c5192039 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
@@ -142,6 +142,9 @@ public class LambdaToMethod extends TreeTranslator {
     /** dump statistics about lambda code generation */
     private final boolean dumpLambdaToMethodStats;
 
+    /** dump statistics about lambda deserialization code generation */
+    private final boolean dumpLambdaDeserializationStats;
+
     /** force serializable representation, for stress testing **/
     private final boolean forceSerializable;
 
@@ -187,6 +190,7 @@ public class LambdaToMethod extends TreeTranslator {
         transTypes = TransTypes.instance(context);
         Options options = Options.instance(context);
         dumpLambdaToMethodStats = options.isSet("debug.dumpLambdaToMethodStats");
+        dumpLambdaDeserializationStats = options.isSet("debug.dumpLambdaDeserializationStats");
         attr = Attr.instance(context);
         forceSerializable = options.isSet("forceSerializable");
         boolean lineDebugInfo =
@@ -714,8 +718,9 @@ public class LambdaToMethod extends TreeTranslator {
         String implMethodName = refSym.getQualifiedName().toString();
         String implMethodSignature = typeSig(types.erasure(refSym.type));
 
+        int implMethodKind = refSym.referenceKind();
         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType),
-                make.Literal(refSym.referenceKind()));
+                make.Literal(implMethodKind));
         ListBuffer serArgs = new ListBuffer<>();
         int i = 0;
         for (Type t : indyType.getParameterTypes()) {
@@ -743,16 +748,16 @@ public class LambdaToMethod extends TreeTranslator {
             stmts = new ListBuffer<>();
             kInfo.deserializeCases.put(implMethodName, stmts);
         }
-        /* **
-        System.err.printf("+++++++++++++++++\n");
-        System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
-        System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
-        System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
-        System.err.printf("*implMethodKind: %d\n", implMethodKind);
-        System.err.printf("*implClass: '%s'\n", implClass);
-        System.err.printf("*implMethodName: '%s'\n", implMethodName);
-        System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
-        ****/
+        if (dumpLambdaDeserializationStats) {
+            log.note(pos, Notes.LambdaDeserializationStat(
+                    functionalInterfaceClass,
+                    functionalInterfaceMethodName,
+                    functionalInterfaceMethodSignature,
+                    implMethodKind,
+                    implClass,
+                    implMethodName,
+                    implMethodSignature));
+        }
         stmts.append(stmt);
     }
 
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
index 95a7546e2b3..2ba9122c04a 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
@@ -1701,6 +1701,17 @@ compiler.note.mref.stat.1=\
     alternate metafactory = {0}\n\
     bridge method = {1}
 
+# 0: string, 1: string, 2: string, 3: number, 4: string, 5: string, 6: string
+compiler.note.lambda.deserialization.stat=\
+    Generating lambda deserialization\n\
+    functionalInterfaceClass: {0}\n\
+    functionalInterfaceMethodName: {1}\n\
+    functionalInterfaceMethodSignature:{2}\n\
+    implMethodKind: {3}\n\
+    implClass: {4}\n\
+    implMethodName: {5}\n\
+    implMethodSignature: {6}
+
 compiler.note.note=\
     Note:\u0020
 
diff --git a/test/langtools/tools/javac/diags/examples/LambdaDeserializationStat.java b/test/langtools/tools/javac/diags/examples/LambdaDeserializationStat.java
new file mode 100644
index 00000000000..4ab23ed0b3d
--- /dev/null
+++ b/test/langtools/tools/javac/diags/examples/LambdaDeserializationStat.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2026, Google LLC 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.
+ */
+
+// key: compiler.note.lambda.deserialization.stat
+// options: --debug=dumpLambdaDeserializationStats
+
+import java.io.Serializable;
+
+class LambdaDeserializationStat {
+    Runnable r = (Runnable & Serializable) () -> {};
+}
diff --git a/test/langtools/tools/javac/lambda/SerializableObjectMethods.java b/test/langtools/tools/javac/lambda/SerializableObjectMethods.java
index 52d4cfc7bf6..b489a22c7b4 100644
--- a/test/langtools/tools/javac/lambda/SerializableObjectMethods.java
+++ b/test/langtools/tools/javac/lambda/SerializableObjectMethods.java
@@ -25,7 +25,7 @@
  * @test
  * @bug 8282080
  * @summary Check that serializable lambdas referring to j.l.Object methods work.
- * @compile SerializableObjectMethods.java
+ * @compile/ref=SerializableObjectMethods.out -XDrawDiagnostics --debug=dumpLambdaDeserializationStats SerializableObjectMethods.java
  * @run main SerializableObjectMethods
  */
 import java.io.ByteArrayInputStream;
diff --git a/test/langtools/tools/javac/lambda/SerializableObjectMethods.out b/test/langtools/tools/javac/lambda/SerializableObjectMethods.out
new file mode 100644
index 00000000000..d03cc145794
--- /dev/null
+++ b/test/langtools/tools/javac/lambda/SerializableObjectMethods.out
@@ -0,0 +1,4 @@
+SerializableObjectMethods.java:59:35: compiler.note.lambda.deserialization.stat: SerializableObjectMethods$F, apply, (Ljava/lang/Object;)Ljava/lang/Object;, 5, java/lang/Object, hashCode, ()I
+SerializableObjectMethods.java:60:35: compiler.note.lambda.deserialization.stat: SerializableObjectMethods$F, apply, (Ljava/lang/Object;)Ljava/lang/Object;, 9, SerializableObjectMethods$I2, hashCode, ()I
+- compiler.note.unchecked.filename: SerializableObjectMethods.java
+- compiler.note.unchecked.recompile

From 6e9256cb613c9a3594546a45975a81def2efcf46 Mon Sep 17 00:00:00 2001
From: Roland Westrelin 
Date: Thu, 22 Jan 2026 10:37:26 +0000
Subject: [PATCH 139/328] 8373343: C2: verify AddP base input only set for heap
 addresses

Reviewed-by: dlong, chagedorn, qamai
---
 .../share/gc/shared/c2/barrierSetC2.cpp       |  2 +-
 src/hotspot/share/opto/addnode.hpp            |  5 ++-
 src/hotspot/share/opto/callnode.cpp           |  4 +--
 src/hotspot/share/opto/callnode.hpp           |  2 +-
 src/hotspot/share/opto/escape.cpp             |  7 ++--
 src/hotspot/share/opto/graphKit.cpp           |  6 ++--
 src/hotspot/share/opto/library_call.cpp       | 26 +++++++-------
 src/hotspot/share/opto/macro.cpp              | 19 +++++-----
 src/hotspot/share/opto/macro.hpp              | 13 ++++---
 src/hotspot/share/opto/macroArrayCopy.cpp     | 26 ++++++--------
 src/hotspot/share/opto/memnode.cpp            | 35 ++++++++++++++-----
 src/hotspot/share/opto/memnode.hpp            |  4 +++
 src/hotspot/share/opto/parse.hpp              |  2 +-
 src/hotspot/share/opto/parse1.cpp             | 19 +++++-----
 src/hotspot/share/opto/parseHelper.cpp        |  2 +-
 src/hotspot/share/opto/subtypenode.cpp        |  4 +--
 16 files changed, 98 insertions(+), 78 deletions(-)

diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp
index c4eefee5f65..53577bad1d8 100644
--- a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp
+++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp
@@ -771,7 +771,7 @@ Node* BarrierSetC2::obj_allocate(PhaseMacroExpand* macro, Node* mem, Node* toobi
   //       this will require extensive changes to the loop optimization in order to
   //       prevent a degradation of the optimization.
   //       See comment in memnode.hpp, around line 227 in class LoadPNode.
-  Node* tlab_end = macro->make_load(toobig_false, mem, tlab_end_adr, 0, TypeRawPtr::BOTTOM, T_ADDRESS);
+  Node* tlab_end = macro->make_load_raw(toobig_false, mem, tlab_end_adr, 0, TypeRawPtr::BOTTOM, T_ADDRESS);
 
   // Load the TLAB top.
   Node* old_tlab_top = new LoadPNode(toobig_false, mem, tlab_top_adr, TypeRawPtr::BOTTOM, TypeRawPtr::BOTTOM, MemNode::unordered);
diff --git a/src/hotspot/share/opto/addnode.hpp b/src/hotspot/share/opto/addnode.hpp
index 4151ab5d065..6128de00efb 100644
--- a/src/hotspot/share/opto/addnode.hpp
+++ b/src/hotspot/share/opto/addnode.hpp
@@ -226,8 +226,11 @@ public:
          Base,                  // Base oop, for GC purposes
          Address,               // Actually address, derived from base
          Offset } ;             // Offset added to address
-  AddPNode( Node *base, Node *ptr, Node *off ) : Node(nullptr,base,ptr,off) {
+  AddPNode(Node *base, Node *ptr, Node *off) : Node(nullptr,base,ptr,off) {
     init_class_id(Class_AddP);
+    assert((ptr->bottom_type() == Type::TOP) ||
+      ((base == Compile::current()->top()) == (ptr->bottom_type()->make_ptr()->isa_oopptr() == nullptr)),
+      "base input only needed for heap addresses");
   }
   virtual int Opcode() const;
   virtual Node* Identity(PhaseGVN* phase);
diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp
index fac8596173f..9b3d7b38d15 100644
--- a/src/hotspot/share/opto/callnode.cpp
+++ b/src/hotspot/share/opto/callnode.cpp
@@ -1737,11 +1737,11 @@ void AllocateNode::compute_MemBar_redundancy(ciMethod* initializer)
     _is_allocation_MemBar_redundant = true;
   }
 }
-Node *AllocateNode::make_ideal_mark(PhaseGVN *phase, Node* obj, Node* control, Node* mem) {
+Node *AllocateNode::make_ideal_mark(PhaseGVN* phase, Node* control, Node* mem) {
   Node* mark_node = nullptr;
   if (UseCompactObjectHeaders) {
     Node* klass_node = in(AllocateNode::KlassNode);
-    Node* proto_adr = phase->transform(new AddPNode(klass_node, klass_node, phase->MakeConX(in_bytes(Klass::prototype_header_offset()))));
+    Node* proto_adr = phase->transform(new AddPNode(phase->C->top(), klass_node, phase->MakeConX(in_bytes(Klass::prototype_header_offset()))));
     mark_node = LoadNode::make(*phase, control, mem, proto_adr, TypeRawPtr::BOTTOM, TypeX_X, TypeX_X->basic_type(), MemNode::unordered);
   } else {
     // For now only enable fast locking for non-array types
diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp
index 0bb064efc43..41d0c9f5aac 100644
--- a/src/hotspot/share/opto/callnode.hpp
+++ b/src/hotspot/share/opto/callnode.hpp
@@ -1101,7 +1101,7 @@ public:
   void compute_MemBar_redundancy(ciMethod* initializer);
   bool is_allocation_MemBar_redundant() { return _is_allocation_MemBar_redundant; }
 
-  Node* make_ideal_mark(PhaseGVN *phase, Node* obj, Node* control, Node* mem);
+  Node* make_ideal_mark(PhaseGVN* phase, Node* control, Node* mem);
 
   NOT_PRODUCT(virtual void dump_spec(outputStream* st) const;)
 };
diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp
index 792384b1ec1..357c91e8eb5 100644
--- a/src/hotspot/share/opto/escape.cpp
+++ b/src/hotspot/share/opto/escape.cpp
@@ -3772,9 +3772,9 @@ Node* ConnectionGraph::get_addp_base(Node *addp) {
   //       | |
   //       AddP  ( base == address )
   //
-  // case #6. Constant Pool, ThreadLocal, CastX2P or
+  // case #6. Constant Pool, ThreadLocal, CastX2P, Klass, OSR buffer buf or
   //          Raw object's field reference:
-  //      {ConP, ThreadLocal, CastX2P, raw Load}
+  //      {ConP, ThreadLocal, CastX2P, raw Load, Parm0}
   //  top   |
   //     \  |
   //     AddP  ( base == top )
@@ -3816,7 +3816,9 @@ Node* ConnectionGraph::get_addp_base(Node *addp) {
       int opcode = uncast_base->Opcode();
       assert(opcode == Op_ConP || opcode == Op_ThreadLocal ||
              opcode == Op_CastX2P || uncast_base->is_DecodeNarrowPtr() ||
+             (_igvn->C->is_osr_compilation() && uncast_base->is_Parm() && uncast_base->as_Parm()->_con == TypeFunc::Parms)||
              (uncast_base->is_Mem() && (uncast_base->bottom_type()->isa_rawptr() != nullptr)) ||
+             (uncast_base->is_Mem() && (uncast_base->bottom_type()->isa_klassptr() != nullptr)) ||
              is_captured_store_address(addp), "sanity");
     }
   }
@@ -4411,7 +4413,6 @@ void ConnectionGraph::split_unique_types(GrowableArray  &alloc_worklist,
   uint new_index_start = (uint) _compile->num_alias_types();
   VectorSet visited;
   ideal_nodes.clear(); // Reset for use with set_map/get_map.
-  uint unique_old = _compile->unique();
 
   //  Phase 1:  Process possible allocations from alloc_worklist.
   //  Create instance types for the CheckCastPP for allocations where possible.
diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp
index bc8ebaf1869..3d127322439 100644
--- a/src/hotspot/share/opto/graphKit.cpp
+++ b/src/hotspot/share/opto/graphKit.cpp
@@ -2743,7 +2743,7 @@ Node* Phase::gen_subtype_check(Node* subklass, Node* superklass, Node** ctrl, No
   // will always succeed.  We could leave a dependency behind to ensure this.
 
   // First load the super-klass's check-offset
-  Node *p1 = gvn.transform(new AddPNode(superklass, superklass, gvn.MakeConX(in_bytes(Klass::super_check_offset_offset()))));
+  Node *p1 = gvn.transform(new AddPNode(C->top(), superklass, gvn.MakeConX(in_bytes(Klass::super_check_offset_offset()))));
   Node* m = C->immutable_memory();
   Node *chk_off = gvn.transform(new LoadINode(nullptr, m, p1, gvn.type(p1)->is_ptr(), TypeInt::INT, MemNode::unordered));
   int cacheoff_con = in_bytes(Klass::secondary_super_cache_offset());
@@ -2761,7 +2761,7 @@ Node* Phase::gen_subtype_check(Node* subklass, Node* superklass, Node** ctrl, No
 #ifdef _LP64
   chk_off_X = gvn.transform(new ConvI2LNode(chk_off_X));
 #endif
-  Node *p2 = gvn.transform(new AddPNode(subklass,subklass,chk_off_X));
+  Node* p2 = gvn.transform(new AddPNode(C->top(), subklass, chk_off_X));
   // For some types like interfaces the following loadKlass is from a 1-word
   // cache which is mutable so can't use immutable memory.  Other
   // types load from the super-class display table which is immutable.
@@ -3598,7 +3598,7 @@ Node* GraphKit::get_layout_helper(Node* klass_node, jint& constant_value) {
     }
   }
   constant_value = Klass::_lh_neutral_value;  // put in a known value
-  Node* lhp = basic_plus_adr(klass_node, klass_node, in_bytes(Klass::layout_helper_offset()));
+  Node* lhp = basic_plus_adr(top(), klass_node, in_bytes(Klass::layout_helper_offset()));
   return make_load(nullptr, lhp, TypeInt::INT, T_INT, MemNode::unordered);
 }
 
diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp
index 2c2a7c020b8..e481833c816 100644
--- a/src/hotspot/share/opto/library_call.cpp
+++ b/src/hotspot/share/opto/library_call.cpp
@@ -3000,7 +3000,7 @@ bool LibraryCallKit::inline_unsafe_allocate() {
     // Note:  The argument might still be an illegal value like
     // Serializable.class or Object[].class.   The runtime will handle it.
     // But we must make an explicit check for initialization.
-    Node* insp = basic_plus_adr(kls, in_bytes(InstanceKlass::init_state_offset()));
+    Node* insp = basic_plus_adr(top(), kls, in_bytes(InstanceKlass::init_state_offset()));
     // Use T_BOOLEAN for InstanceKlass::_init_state so the compiler
     // can generate code to load it as unsigned byte.
     Node* inst = make_load(nullptr, insp, TypeInt::UBYTE, T_BOOLEAN, MemNode::acquire);
@@ -3048,7 +3048,7 @@ bool LibraryCallKit::inline_native_vthread_start_transition(address funcAddr, co
   IdealKit ideal(this);
 
   Node* thread = ideal.thread();
-  Node* jt_addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_vthread_transition_offset()));
+  Node* jt_addr = basic_plus_adr(top(), thread, in_bytes(JavaThread::is_in_vthread_transition_offset()));
   Node* vt_addr = basic_plus_adr(vt_oop, java_lang_Thread::is_in_vthread_transition_offset());
   access_store_at(nullptr, jt_addr, _gvn.type(jt_addr)->is_ptr(), ideal.ConI(1), TypeInt::BOOL, T_BOOLEAN, IN_NATIVE | MO_UNORDERED);
   access_store_at(nullptr, vt_addr, _gvn.type(vt_addr)->is_ptr(), ideal.ConI(1), TypeInt::BOOL, T_BOOLEAN, IN_NATIVE | MO_UNORDERED);
@@ -3089,7 +3089,7 @@ bool LibraryCallKit::inline_native_vthread_end_transition(address funcAddr, cons
     ideal.sync_kit(this);
   } ideal.else_(); {
     Node* thread = ideal.thread();
-    Node* jt_addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_vthread_transition_offset()));
+    Node* jt_addr = basic_plus_adr(top(), thread, in_bytes(JavaThread::is_in_vthread_transition_offset()));
     Node* vt_addr = basic_plus_adr(vt_oop, java_lang_Thread::is_in_vthread_transition_offset());
 
     sync_kit(ideal);
@@ -3115,7 +3115,7 @@ bool LibraryCallKit::inline_native_notify_jvmti_sync() {
     // unconditionally update the is_disable_suspend bit in current JavaThread
     Node* thread = ideal.thread();
     Node* arg = _gvn.transform(argument(0)); // argument for notification
-    Node* addr = basic_plus_adr(thread, in_bytes(JavaThread::is_disable_suspend_offset()));
+    Node* addr = basic_plus_adr(top(), thread, in_bytes(JavaThread::is_disable_suspend_offset()));
     const TypePtr *addr_type = _gvn.type(addr)->isa_ptr();
 
     sync_kit(ideal);
@@ -3689,7 +3689,7 @@ void LibraryCallKit::extend_setCurrentThread(Node* jt, Node* thread) {
   IfNode* iff_thread_not_equal_carrierThread =
     create_and_map_if(control(), test_thread_not_equal_carrierThread, PROB_FAIR, COUNT_UNKNOWN);
 
-  Node* vthread_offset = basic_plus_adr(jt, in_bytes(THREAD_LOCAL_OFFSET_JFR + VTHREAD_OFFSET_JFR));
+  Node* vthread_offset = basic_plus_adr(top(), jt, in_bytes(THREAD_LOCAL_OFFSET_JFR + VTHREAD_OFFSET_JFR));
 
   // False branch, is carrierThread.
   Node* thread_equal_carrierThread = _gvn.transform(new IfFalseNode(iff_thread_not_equal_carrierThread));
@@ -3714,7 +3714,7 @@ void LibraryCallKit::extend_setCurrentThread(Node* jt, Node* thread) {
   Node* tid = load_field_from_object(thread, "tid", "J");
 
   // Store the vthread tid to the jfr thread local.
-  Node* thread_id_offset = basic_plus_adr(jt, in_bytes(THREAD_LOCAL_OFFSET_JFR + VTHREAD_ID_OFFSET_JFR));
+  Node* thread_id_offset = basic_plus_adr(top(), jt, in_bytes(THREAD_LOCAL_OFFSET_JFR + VTHREAD_ID_OFFSET_JFR));
   Node* tid_memory = store_to_memory(control(), thread_id_offset, tid, T_LONG, MemNode::unordered, true);
 
   // Branch is_excluded to conditionalize updating the epoch .
@@ -3736,7 +3736,7 @@ void LibraryCallKit::extend_setCurrentThread(Node* jt, Node* thread) {
   Node* epoch = _gvn.transform(new AndINode(epoch_raw, _gvn.transform(epoch_mask)));
 
   // Store the vthread epoch to the jfr thread local.
-  Node* vthread_epoch_offset = basic_plus_adr(jt, in_bytes(THREAD_LOCAL_OFFSET_JFR + VTHREAD_EPOCH_OFFSET_JFR));
+  Node* vthread_epoch_offset = basic_plus_adr(top(), jt, in_bytes(THREAD_LOCAL_OFFSET_JFR + VTHREAD_EPOCH_OFFSET_JFR));
   Node* included_memory = store_to_memory(control(), vthread_epoch_offset, epoch, T_CHAR, MemNode::unordered, true);
 
   RegionNode* excluded_rgn = new RegionNode(PATH_LIMIT);
@@ -3759,7 +3759,7 @@ void LibraryCallKit::extend_setCurrentThread(Node* jt, Node* thread) {
   set_all_memory(excluded_mem);
 
   // Store the vthread exclusion state to the jfr thread local.
-  Node* thread_local_excluded_offset = basic_plus_adr(jt, in_bytes(THREAD_LOCAL_OFFSET_JFR + VTHREAD_EXCLUDED_OFFSET_JFR));
+  Node* thread_local_excluded_offset = basic_plus_adr(top(), jt, in_bytes(THREAD_LOCAL_OFFSET_JFR + VTHREAD_EXCLUDED_OFFSET_JFR));
   store_to_memory(control(), thread_local_excluded_offset, _gvn.transform(exclusion), T_BOOLEAN, MemNode::unordered, true);
 
   // Store release
@@ -3814,7 +3814,7 @@ bool LibraryCallKit::inline_native_setCurrentThread() {
 
   // Change the _monitor_owner_id of the JavaThread
   Node* tid = load_field_from_object(arr, "tid", "J");
-  Node* monitor_owner_id_offset = basic_plus_adr(thread, in_bytes(JavaThread::monitor_owner_id_offset()));
+  Node* monitor_owner_id_offset = basic_plus_adr(top(), thread, in_bytes(JavaThread::monitor_owner_id_offset()));
   store_to_memory(control(), monitor_owner_id_offset, tid, T_LONG, MemNode::unordered, true);
 
   JFR_ONLY(extend_setCurrentThread(thread, arr);)
@@ -3956,7 +3956,7 @@ bool LibraryCallKit::inline_native_Continuation_pinning(bool unpin) {
 //---------------------------load_mirror_from_klass----------------------------
 // Given a klass oop, load its java mirror (a java.lang.Class oop).
 Node* LibraryCallKit::load_mirror_from_klass(Node* klass) {
-  Node* p = basic_plus_adr(klass, in_bytes(Klass::java_mirror_offset()));
+  Node* p = basic_plus_adr(top(), klass, in_bytes(Klass::java_mirror_offset()));
   Node* load = make_load(nullptr, p, TypeRawPtr::NOTNULL, T_ADDRESS, MemNode::unordered);
   // mirror = ((OopHandle)mirror)->resolve();
   return access_load(load, TypeInstPtr::MIRROR, T_OBJECT, IN_NATIVE);
@@ -3996,7 +3996,7 @@ Node* LibraryCallKit::generate_klass_flags_guard(Node* kls, int modifier_mask, i
                                                  ByteSize offset, const Type* type, BasicType bt) {
   // Branch around if the given klass has the given modifier bit set.
   // Like generate_guard, adds a new path onto the region.
-  Node* modp = basic_plus_adr(kls, in_bytes(offset));
+  Node* modp = basic_plus_adr(top(), kls, in_bytes(offset));
   Node* mods = make_load(nullptr, modp, type, bt, MemNode::unordered);
   Node* mask = intcon(modifier_mask);
   Node* bits = intcon(modifier_bits);
@@ -4130,7 +4130,7 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) {
       phi->add_req(null());
     }
     // If we fall through, it's a plain class.  Get its _super.
-    p = basic_plus_adr(kls, in_bytes(Klass::super_offset()));
+    p = basic_plus_adr(top(), kls, in_bytes(Klass::super_offset()));
     kls = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeInstKlassPtr::OBJECT_OR_NULL));
     null_ctl = top();
     kls = null_check_oop(kls, &null_ctl);
@@ -4668,7 +4668,7 @@ Node* LibraryCallKit::generate_virtual_guard(Node* obj_klass,
   int entry_offset  = in_bytes(Klass::vtable_start_offset()) +
                      vtable_index*vtableEntry::size_in_bytes() +
                      in_bytes(vtableEntry::method_offset());
-  Node* entry_addr  = basic_plus_adr(obj_klass, entry_offset);
+  Node* entry_addr  = basic_plus_adr(top(), obj_klass, entry_offset);
   Node* target_call = make_load(nullptr, entry_addr, TypePtr::NOTNULL, T_ADDRESS, MemNode::unordered);
 
   // Compare the target method with the expected method (e.g., Object.hashCode).
diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp
index 4df03714376..56262d226fc 100644
--- a/src/hotspot/share/opto/macro.cpp
+++ b/src/hotspot/share/opto/macro.cpp
@@ -1198,8 +1198,8 @@ bool PhaseMacroExpand::eliminate_boxing_node(CallStaticJavaNode *boxing) {
 }
 
 
-Node* PhaseMacroExpand::make_load(Node* ctl, Node* mem, Node* base, int offset, const Type* value_type, BasicType bt) {
-  Node* adr = basic_plus_adr(base, offset);
+Node* PhaseMacroExpand::make_load_raw(Node* ctl, Node* mem, Node* base, int offset, const Type* value_type, BasicType bt) {
+  Node* adr = basic_plus_adr(top(), base, offset);
   const TypePtr* adr_type = adr->bottom_type()->is_ptr();
   Node* value = LoadNode::make(_igvn, ctl, mem, adr, adr_type, value_type, bt, MemNode::unordered);
   transform_later(value);
@@ -1207,8 +1207,8 @@ Node* PhaseMacroExpand::make_load(Node* ctl, Node* mem, Node* base, int offset,
 }
 
 
-Node* PhaseMacroExpand::make_store(Node* ctl, Node* mem, Node* base, int offset, Node* value, BasicType bt) {
-  Node* adr = basic_plus_adr(base, offset);
+Node* PhaseMacroExpand::make_store_raw(Node* ctl, Node* mem, Node* base, int offset, Node* value, BasicType bt) {
+  Node* adr = basic_plus_adr(top(), base, offset);
   mem = StoreNode::make(_igvn, ctl, mem, adr, nullptr, value, bt, MemNode::unordered);
   transform_later(mem);
   return mem;
@@ -1753,20 +1753,20 @@ PhaseMacroExpand::initialize_object(AllocateNode* alloc,
                                     Node* size_in_bytes) {
   InitializeNode* init = alloc->initialization();
   // Store the klass & mark bits
-  Node* mark_node = alloc->make_ideal_mark(&_igvn, object, control, rawmem);
+  Node* mark_node = alloc->make_ideal_mark(&_igvn, control, rawmem);
   if (!mark_node->is_Con()) {
     transform_later(mark_node);
   }
-  rawmem = make_store(control, rawmem, object, oopDesc::mark_offset_in_bytes(), mark_node, TypeX_X->basic_type());
+  rawmem = make_store_raw(control, rawmem, object, oopDesc::mark_offset_in_bytes(), mark_node, TypeX_X->basic_type());
 
   if (!UseCompactObjectHeaders) {
-    rawmem = make_store(control, rawmem, object, oopDesc::klass_offset_in_bytes(), klass_node, T_METADATA);
+    rawmem = make_store_raw(control, rawmem, object, oopDesc::klass_offset_in_bytes(), klass_node, T_METADATA);
   }
   int header_size = alloc->minimum_header_size();  // conservatively small
 
   // Array length
   if (length != nullptr) {         // Arrays need length field
-    rawmem = make_store(control, rawmem, object, arrayOopDesc::length_offset_in_bytes(), length, T_INT);
+    rawmem = make_store_raw(control, rawmem, object, arrayOopDesc::length_offset_in_bytes(), length, T_INT);
     // conservatively small header size:
     header_size = arrayOopDesc::base_offset_in_bytes(T_BYTE);
     if (_igvn.type(klass_node)->isa_aryklassptr()) {   // we know the exact header size in most cases:
@@ -1792,6 +1792,7 @@ PhaseMacroExpand::initialize_object(AllocateNode* alloc,
     if (!(UseTLAB && ZeroTLAB)) {
       rawmem = ClearArrayNode::clear_memory(control, rawmem, object,
                                             header_size, size_in_bytes,
+                                            true,
                                             &_igvn);
     }
   } else {
@@ -1946,7 +1947,7 @@ Node* PhaseMacroExpand::prefetch_allocation(Node* i_o, Node*& needgc_false,
       uint step_size = AllocatePrefetchStepSize;
       uint distance = AllocatePrefetchDistance;
       for ( intx i = 0; i < lines; i++ ) {
-        prefetch_adr = new AddPNode( old_eden_top, new_eden_top,
+        prefetch_adr = new AddPNode( top(), new_eden_top,
                                             _igvn.MakeConX(distance) );
         transform_later(prefetch_adr);
         prefetch = new PrefetchAllocationNode( i_o, prefetch_adr );
diff --git a/src/hotspot/share/opto/macro.hpp b/src/hotspot/share/opto/macro.hpp
index c899bed567c..0f8d8fb5172 100644
--- a/src/hotspot/share/opto/macro.hpp
+++ b/src/hotspot/share/opto/macro.hpp
@@ -58,10 +58,10 @@ public:
     _igvn.register_new_node_with_optimizer(n);
     return n;
   }
-  Node* make_load( Node* ctl, Node* mem, Node* base, int offset,
-                   const Type* value_type, BasicType bt);
-  Node* make_store(Node* ctl, Node* mem, Node* base, int offset,
-                   Node* value, BasicType bt);
+  Node* make_load_raw(Node* ctl, Node* mem, Node* base, int offset,
+                      const Type* value_type, BasicType bt);
+  Node* make_store_raw(Node* ctl, Node* mem, Node* base, int offset,
+                       Node* value, BasicType bt);
 
   Node* make_leaf_call(Node* ctrl, Node* mem,
                        const TypeFunc* call_type, address call_addr,
@@ -144,11 +144,10 @@ private:
                             Node* slice_idx,
                             Node* slice_len,
                             Node* dest_size);
-  bool generate_block_arraycopy(Node** ctrl, MergeMemNode** mem, Node* io,
+  bool generate_block_arraycopy(Node** ctrl, MergeMemNode** mem,
                                 const TypePtr* adr_type,
                                 BasicType basic_elem_type,
-                                AllocateNode* alloc,
-                                Node* src,  Node* src_offset,
+                                Node* src, Node* src_offset,
                                 Node* dest, Node* dest_offset,
                                 Node* dest_size, bool dest_uninitialized);
   MergeMemNode* generate_slow_arraycopy(ArrayCopyNode *ac,
diff --git a/src/hotspot/share/opto/macroArrayCopy.cpp b/src/hotspot/share/opto/macroArrayCopy.cpp
index fb4a1842a36..0719ffc45a5 100644
--- a/src/hotspot/share/opto/macroArrayCopy.cpp
+++ b/src/hotspot/share/opto/macroArrayCopy.cpp
@@ -384,7 +384,6 @@ Node* PhaseMacroExpand::generate_arraycopy(ArrayCopyNode *ac, AllocateArrayNode*
     transform_later(slow_region);
   }
 
-  Node* original_dest = dest;
   bool  dest_needs_zeroing   = false;
   bool  acopy_to_uninitialized = false;
 
@@ -424,7 +423,6 @@ Node* PhaseMacroExpand::generate_arraycopy(ArrayCopyNode *ac, AllocateArrayNode*
     // No zeroing elimination needed here.
     alloc                  = nullptr;
     acopy_to_uninitialized = false;
-    //original_dest        = dest;
     //dest_needs_zeroing   = false;
   }
 
@@ -557,10 +555,9 @@ Node* PhaseMacroExpand::generate_arraycopy(ArrayCopyNode *ac, AllocateArrayNode*
         MergeMemNode* local_mem = MergeMemNode::make(mem);
         transform_later(local_mem);
 
-        didit = generate_block_arraycopy(&local_ctrl, &local_mem, local_io,
-                                         adr_type, basic_elem_type, alloc,
-                                         src, src_offset, dest, dest_offset,
-                                         dest_size, acopy_to_uninitialized);
+        didit = generate_block_arraycopy(&local_ctrl, &local_mem, adr_type,
+                                         basic_elem_type, src, src_offset,
+                                         dest, dest_offset, dest_size, acopy_to_uninitialized);
         if (didit) {
           // Present the results of the block-copying fast call.
           result_region->init_req(bcopy_path, local_ctrl);
@@ -641,7 +638,7 @@ Node* PhaseMacroExpand::generate_arraycopy(ArrayCopyNode *ac, AllocateArrayNode*
 
         // (At this point we can assume disjoint_bases, since types differ.)
         int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset());
-        Node* p1 = basic_plus_adr(dest_klass, ek_offset);
+        Node* p1 = basic_plus_adr(top(), dest_klass, ek_offset);
         Node* n1 = LoadKlassNode::make(_igvn, C->immutable_memory(), p1, TypeRawPtr::BOTTOM);
         Node* dest_elem_klass = transform_later(n1);
         Node* cv = generate_checkcast_arraycopy(&local_ctrl, &local_mem,
@@ -918,12 +915,12 @@ void PhaseMacroExpand::generate_clear_array(Node* ctrl, MergeMemNode* merge_mem,
   if (start_con >= 0 && end_con >= 0) {
     // Constant start and end.  Simple.
     mem = ClearArrayNode::clear_memory(ctrl, mem, dest,
-                                       start_con, end_con, &_igvn);
+                                       start_con, end_con, false, &_igvn);
   } else if (start_con >= 0 && dest_size != top()) {
     // Constant start, pre-rounded end after the tail of the array.
     Node* end = dest_size;
     mem = ClearArrayNode::clear_memory(ctrl, mem, dest,
-                                       start_con, end, &_igvn);
+                                       start_con, end, false, &_igvn);
   } else if (start_con >= 0 && slice_len != top()) {
     // Constant start, non-constant end.  End needs rounding up.
     // End offset = round_up(abase + ((slice_idx_con + slice_len) << scale), 8)
@@ -936,7 +933,7 @@ void PhaseMacroExpand::generate_clear_array(Node* ctrl, MergeMemNode* merge_mem,
     end = transform_later(new AddXNode(end, MakeConX(end_base)) );
     end = transform_later(new AndXNode(end, MakeConX(~end_round)) );
     mem = ClearArrayNode::clear_memory(ctrl, mem, dest,
-                                       start_con, end, &_igvn);
+                                       start_con, end, false, &_igvn);
   } else if (start_con < 0 && dest_size != top()) {
     // Non-constant start, pre-rounded end after the tail of the array.
     // This is almost certainly a "round-to-end" operation.
@@ -970,7 +967,7 @@ void PhaseMacroExpand::generate_clear_array(Node* ctrl, MergeMemNode* merge_mem,
     }
     Node* end = dest_size; // pre-rounded
     mem = ClearArrayNode::clear_memory(ctrl, mem, dest,
-                                       start, end, &_igvn);
+                                       start, end, false, &_igvn);
   } else {
     // Non-constant start, unrounded non-constant end.
     // (Nobody zeroes a random midsection of an array using this routine.)
@@ -981,11 +978,10 @@ void PhaseMacroExpand::generate_clear_array(Node* ctrl, MergeMemNode* merge_mem,
   merge_mem->set_memory_at(alias_idx, mem);
 }
 
-bool PhaseMacroExpand::generate_block_arraycopy(Node** ctrl, MergeMemNode** mem, Node* io,
+bool PhaseMacroExpand::generate_block_arraycopy(Node** ctrl, MergeMemNode** mem,
                                                 const TypePtr* adr_type,
                                                 BasicType basic_elem_type,
-                                                AllocateNode* alloc,
-                                                Node* src,  Node* src_offset,
+                                                Node* src, Node* src_offset,
                                                 Node* dest, Node* dest_offset,
                                                 Node* dest_size, bool dest_uninitialized) {
   // See if there is an advantage from block transfer.
@@ -1133,7 +1129,7 @@ Node* PhaseMacroExpand::generate_checkcast_arraycopy(Node** ctrl, MergeMemNode**
   // look in each non-null element's class, at the desired klass's
   // super_check_offset, for the desired klass.
   int sco_offset = in_bytes(Klass::super_check_offset_offset());
-  Node* p3 = basic_plus_adr(dest_elem_klass, sco_offset);
+  Node* p3 = basic_plus_adr(top(), dest_elem_klass, sco_offset);
   Node* n3 = new LoadINode(nullptr, *mem /*memory(p3)*/, p3, _igvn.type(p3)->is_ptr(), TypeInt::INT, MemNode::unordered);
   Node* check_offset = ConvI2X(transform_later(n3));
   Node* check_value  = dest_elem_klass;
diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp
index 0d4fb6791a4..7f152eddd65 100644
--- a/src/hotspot/share/opto/memnode.cpp
+++ b/src/hotspot/share/opto/memnode.cpp
@@ -2563,7 +2563,13 @@ Node* LoadNode::klass_identity_common(PhaseGVN* phase) {
            ) {
           int mirror_field = in_bytes(Klass::java_mirror_offset());
           if (tkls->offset() == mirror_field) {
-            return adr2->in(AddPNode::Base);
+#ifdef ASSERT
+            const TypeKlassPtr* tkls2 = phase->type(adr2->in(AddPNode::Address))->is_klassptr();
+            assert(tkls2->offset() == 0, "not a load of java_mirror");
+#endif
+            assert(adr2->in(AddPNode::Base)->is_top(), "not an off heap load");
+            assert(adr2->in(AddPNode::Offset)->find_intptr_t_con(-1) == in_bytes(Klass::java_mirror_offset()), "incorrect offset");
+            return adr2->in(AddPNode::Address);
           }
         }
       }
@@ -4112,18 +4118,27 @@ bool ClearArrayNode::step_through(Node** np, uint instance_id, PhaseValues* phas
   return true;
 }
 
+Node* ClearArrayNode::make_address(Node* dest, Node* offset, bool raw_base, PhaseGVN* phase) {
+  Node* base = dest;
+  if (raw_base) {
+    // May be called as part of the initialization of a just allocated object
+    base = phase->C->top();
+  }
+  return phase->transform(new AddPNode(base, dest, offset));
+}
+
 //----------------------------clear_memory-------------------------------------
 // Generate code to initialize object storage to zero.
 Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest,
                                    intptr_t start_offset,
                                    Node* end_offset,
+                                   bool raw_base,
                                    PhaseGVN* phase) {
   intptr_t offset = start_offset;
 
   int unit = BytesPerLong;
   if ((offset % unit) != 0) {
-    Node* adr = new AddPNode(dest, dest, phase->MakeConX(offset));
-    adr = phase->transform(adr);
+    Node* adr = make_address(dest, phase->MakeConX(offset), raw_base, phase);
     const TypePtr* atp = TypeRawPtr::BOTTOM;
     mem = StoreNode::make(*phase, ctl, mem, adr, atp, phase->zerocon(T_INT), T_INT, MemNode::unordered);
     mem = phase->transform(mem);
@@ -4132,12 +4147,13 @@ Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest,
   assert((offset % unit) == 0, "");
 
   // Initialize the remaining stuff, if any, with a ClearArray.
-  return clear_memory(ctl, mem, dest, phase->MakeConX(offset), end_offset, phase);
+  return clear_memory(ctl, mem, dest, phase->MakeConX(offset), end_offset, raw_base, phase);
 }
 
 Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest,
                                    Node* start_offset,
                                    Node* end_offset,
+                                   bool raw_base,
                                    PhaseGVN* phase) {
   if (start_offset == end_offset) {
     // nothing to do
@@ -4157,7 +4173,7 @@ Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest,
 
   // Bulk clear double-words
   Node* zsize = phase->transform(new SubXNode(zend, zbase) );
-  Node* adr = phase->transform(new AddPNode(dest, dest, start_offset) );
+  Node* adr = make_address(dest, start_offset, raw_base, phase);
   mem = new ClearArrayNode(ctl, mem, zsize, adr, false);
   return phase->transform(mem);
 }
@@ -4165,6 +4181,7 @@ Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest,
 Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest,
                                    intptr_t start_offset,
                                    intptr_t end_offset,
+                                   bool raw_base,
                                    PhaseGVN* phase) {
   if (start_offset == end_offset) {
     // nothing to do
@@ -4178,11 +4195,10 @@ Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest,
   }
   if (done_offset > start_offset) {
     mem = clear_memory(ctl, mem, dest,
-                       start_offset, phase->MakeConX(done_offset), phase);
+                       start_offset, phase->MakeConX(done_offset), raw_base, phase);
   }
   if (done_offset < end_offset) { // emit the final 32-bit store
-    Node* adr = new AddPNode(dest, dest, phase->MakeConX(done_offset));
-    adr = phase->transform(adr);
+    Node* adr = make_address(dest, phase->MakeConX(done_offset), raw_base, phase);
     const TypePtr* atp = TypeRawPtr::BOTTOM;
     mem = StoreNode::make(*phase, ctl, mem, adr, atp, phase->zerocon(T_INT), T_INT, MemNode::unordered);
     mem = phase->transform(mem);
@@ -5389,6 +5405,7 @@ Node* InitializeNode::complete_stores(Node* rawctl, Node* rawmem, Node* rawptr,
         zeroes_done = align_down(zeroes_done, BytesPerInt);
         rawmem = ClearArrayNode::clear_memory(rawctl, rawmem, rawptr,
                                               zeroes_done, zeroes_needed,
+                                              true,
                                               phase);
         zeroes_done = zeroes_needed;
         if (zsize > InitArrayShortSize && ++big_init_gaps > 2)
@@ -5447,7 +5464,7 @@ Node* InitializeNode::complete_stores(Node* rawctl, Node* rawmem, Node* rawptr,
     }
     if (zeroes_done < size_limit) {
       rawmem = ClearArrayNode::clear_memory(rawctl, rawmem, rawptr,
-                                            zeroes_done, size_in_bytes, phase);
+                                            zeroes_done, size_in_bytes, true, phase);
     }
   }
 
diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp
index e84556528e6..249df51beb9 100644
--- a/src/hotspot/share/opto/memnode.hpp
+++ b/src/hotspot/share/opto/memnode.hpp
@@ -1072,6 +1072,7 @@ public:
 class ClearArrayNode: public Node {
 private:
   bool _is_large;
+  static Node* make_address(Node* dest, Node* offset, bool raw_base, PhaseGVN* phase);
 public:
   ClearArrayNode( Node *ctrl, Node *arymem, Node *word_cnt, Node *base, bool is_large)
     : Node(ctrl,arymem,word_cnt,base), _is_large(is_large) {
@@ -1099,14 +1100,17 @@ public:
   static Node* clear_memory(Node* control, Node* mem, Node* dest,
                             intptr_t start_offset,
                             intptr_t end_offset,
+                            bool raw_base,
                             PhaseGVN* phase);
   static Node* clear_memory(Node* control, Node* mem, Node* dest,
                             intptr_t start_offset,
                             Node* end_offset,
+                            bool raw_base,
                             PhaseGVN* phase);
   static Node* clear_memory(Node* control, Node* mem, Node* dest,
                             Node* start_offset,
                             Node* end_offset,
+                            bool raw_base,
                             PhaseGVN* phase);
   // Return allocation input memory edge if it is different instance
   // or itself if it is the one we are looking for.
diff --git a/src/hotspot/share/opto/parse.hpp b/src/hotspot/share/opto/parse.hpp
index 19b302a8924..397a7796f88 100644
--- a/src/hotspot/share/opto/parse.hpp
+++ b/src/hotspot/share/opto/parse.hpp
@@ -442,7 +442,7 @@ class Parse : public GraphKit {
   SafePointNode* create_entry_map();
 
   // OSR helpers
-  Node *fetch_interpreter_state(int index, BasicType bt, Node *local_addrs, Node *local_addrs_base);
+  Node *fetch_interpreter_state(int index, BasicType bt, Node* local_addrs);
   Node* check_interpreter_type(Node* l, const Type* type, SafePointNode* &bad_type_exit);
   void  load_interpreter_state(Node* osr_buf);
 
diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp
index 6122f7e7bfc..2f699650037 100644
--- a/src/hotspot/share/opto/parse1.cpp
+++ b/src/hotspot/share/opto/parse1.cpp
@@ -103,10 +103,9 @@ void Parse::print_statistics() {
 // on stack replacement.
 Node *Parse::fetch_interpreter_state(int index,
                                      BasicType bt,
-                                     Node *local_addrs,
-                                     Node *local_addrs_base) {
+                                     Node* local_addrs) {
   Node *mem = memory(Compile::AliasIdxRaw);
-  Node *adr = basic_plus_adr( local_addrs_base, local_addrs, -index*wordSize );
+  Node *adr = basic_plus_adr(top(), local_addrs, -index*wordSize);
   Node *ctl = control();
 
   // Very similar to LoadNode::make, except we handle un-aligned longs and
@@ -121,7 +120,7 @@ Node *Parse::fetch_interpreter_state(int index,
   case T_DOUBLE: {
     // Since arguments are in reverse order, the argument address 'adr'
     // refers to the back half of the long/double.  Recompute adr.
-    adr = basic_plus_adr(local_addrs_base, local_addrs, -(index+1)*wordSize);
+    adr = basic_plus_adr(top(), local_addrs, -(index+1)*wordSize);
     if (Matcher::misaligned_doubles_ok) {
       l = (bt == T_DOUBLE)
         ? (Node*)new LoadDNode(ctl, mem, adr, TypeRawPtr::BOTTOM, Type::DOUBLE, MemNode::unordered)
@@ -220,7 +219,7 @@ void Parse::load_interpreter_state(Node* osr_buf) {
   // Commute monitors from interpreter frame to compiler frame.
   assert(jvms()->monitor_depth() == 0, "should be no active locks at beginning of osr");
   int mcnt = osr_block->flow()->monitor_count();
-  Node *monitors_addr = basic_plus_adr(osr_buf, osr_buf, (max_locals+mcnt*2-1)*wordSize);
+  Node *monitors_addr = basic_plus_adr(top(), osr_buf, (max_locals+mcnt*2-1)*wordSize);
   for (index = 0; index < mcnt; index++) {
     // Make a BoxLockNode for the monitor.
     BoxLockNode* osr_box = new BoxLockNode(next_monitor());
@@ -241,9 +240,9 @@ void Parse::load_interpreter_state(Node* osr_buf) {
     // Displaced headers and locked objects are interleaved in the
     // temp OSR buffer.  We only copy the locked objects out here.
     // Fetch the locked object from the OSR temp buffer and copy to our fastlock node.
-    Node *lock_object = fetch_interpreter_state(index*2, T_OBJECT, monitors_addr, osr_buf);
+    Node *lock_object = fetch_interpreter_state(index*2, T_OBJECT, monitors_addr);
     // Try and copy the displaced header to the BoxNode
-    Node *displaced_hdr = fetch_interpreter_state((index*2) + 1, T_ADDRESS, monitors_addr, osr_buf);
+    Node *displaced_hdr = fetch_interpreter_state((index*2) + 1, T_ADDRESS, monitors_addr);
 
 
     store_to_memory(control(), box, displaced_hdr, T_ADDRESS, MemNode::unordered);
@@ -271,7 +270,7 @@ void Parse::load_interpreter_state(Node* osr_buf) {
   }
 
   // Extract the needed locals from the interpreter frame.
-  Node *locals_addr = basic_plus_adr(osr_buf, osr_buf, (max_locals-1)*wordSize);
+  Node *locals_addr = basic_plus_adr(top(), osr_buf, (max_locals-1)*wordSize);
 
   // find all the locals that the interpreter thinks contain live oops
   const ResourceBitMap live_oops = method()->live_local_oops_at_bci(osr_bci());
@@ -318,7 +317,7 @@ void Parse::load_interpreter_state(Node* osr_buf) {
       // really for T_OBJECT types so correct it.
       bt = T_OBJECT;
     }
-    Node *value = fetch_interpreter_state(index, bt, locals_addr, osr_buf);
+    Node *value = fetch_interpreter_state(index, bt, locals_addr);
     set_local(index, value);
   }
 
@@ -2128,7 +2127,7 @@ void Parse::call_register_finalizer() {
   Node* klass_addr = basic_plus_adr( receiver, receiver, oopDesc::klass_offset_in_bytes() );
   Node* klass = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), klass_addr, TypeInstPtr::KLASS));
 
-  Node* access_flags_addr = basic_plus_adr(klass, klass, in_bytes(Klass::misc_flags_offset()));
+  Node* access_flags_addr = basic_plus_adr(top(), klass, in_bytes(Klass::misc_flags_offset()));
   Node* access_flags = make_load(nullptr, access_flags_addr, TypeInt::UBYTE, T_BOOLEAN, MemNode::unordered);
 
   Node* mask  = _gvn.transform(new AndINode(access_flags, intcon(KlassFlags::_misc_has_finalizer)));
diff --git a/src/hotspot/share/opto/parseHelper.cpp b/src/hotspot/share/opto/parseHelper.cpp
index 1a1cea05454..2e8fca68a8d 100644
--- a/src/hotspot/share/opto/parseHelper.cpp
+++ b/src/hotspot/share/opto/parseHelper.cpp
@@ -220,7 +220,7 @@ void Parse::array_store_check() {
 
   // Extract the array element class
   int element_klass_offset = in_bytes(ObjArrayKlass::element_klass_offset());
-  Node* p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset);
+  Node* p2 = basic_plus_adr(top(), array_klass, element_klass_offset);
   Node* a_e_klass = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), p2, tak));
   assert(array_klass->is_Con() == a_e_klass->is_Con() || StressReflectiveCode, "a constant array type must come with a constant element type");
 
diff --git a/src/hotspot/share/opto/subtypenode.cpp b/src/hotspot/share/opto/subtypenode.cpp
index b58194b87d2..8e4c7d829a7 100644
--- a/src/hotspot/share/opto/subtypenode.cpp
+++ b/src/hotspot/share/opto/subtypenode.cpp
@@ -182,7 +182,7 @@ bool SubTypeCheckNode::verify(PhaseGVN* phase) {
         return verify_helper(phase, load_klass(phase), cached_t);
       }
       case Compile::SSC_full_test: {
-        Node* p1 = phase->transform(new AddPNode(superklass, superklass, phase->MakeConX(in_bytes(Klass::super_check_offset_offset()))));
+        Node* p1 = phase->transform(new AddPNode(C->top(), superklass, phase->MakeConX(in_bytes(Klass::super_check_offset_offset()))));
         Node* chk_off = phase->transform(new LoadINode(nullptr, C->immutable_memory(), p1, phase->type(p1)->is_ptr(), TypeInt::INT, MemNode::unordered));
         record_for_cleanup(chk_off, phase);
 
@@ -194,7 +194,7 @@ bool SubTypeCheckNode::verify(PhaseGVN* phase) {
 #ifdef _LP64
           chk_off_X = phase->transform(new ConvI2LNode(chk_off_X));
 #endif
-          Node* p2 = phase->transform(new AddPNode(subklass, subklass, chk_off_X));
+          Node* p2 = phase->transform(new AddPNode(C->top(), subklass, chk_off_X));
           Node* nkls = phase->transform(LoadKlassNode::make(*phase, C->immutable_memory(), p2, phase->type(p2)->is_ptr(), TypeInstKlassPtr::OBJECT_OR_NULL));
 
           return verify_helper(phase, nkls, cached_t);

From 0ad81fbd161edbc8479e5af5c0f8d6098f6c72d1 Mon Sep 17 00:00:00 2001
From: Thomas Schatzl 
Date: Thu, 22 Jan 2026 11:04:09 +0000
Subject: [PATCH 140/328] 8375541: G1: Race in
 G1BarrierSet::write_ref_field_post()

Reviewed-by: iwalulya, sjohanss, shade
---
 src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp b/src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp
index ee2c1450d9b..794e5db0634 100644
--- a/src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp
+++ b/src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp
@@ -70,7 +70,11 @@ inline void G1BarrierSet::write_ref_field_pre(T* field) {
 
 template 
 inline void G1BarrierSet::write_ref_field_post(T* field) {
-  volatile CardValue* byte = _card_table->byte_for(field);
+  // Make sure that the card table reference is read only once. Otherwise the compiler
+  // might reload that value in the two accesses below, that could cause writes to
+  // the wrong card table.
+  CardTable* card_table = AtomicAccess::load(&_card_table);
+  CardValue* byte = card_table->byte_for(field);
   if (*byte == G1CardTable::clean_card_val()) {
     *byte = G1CardTable::dirty_card_val();
   }

From 66e950e9b6414617952d22200831be5b0cafee85 Mon Sep 17 00:00:00 2001
From: Ivan Walulya 
Date: Thu, 22 Jan 2026 11:07:42 +0000
Subject: [PATCH 141/328] 8340470: G1: Adopt PartialArrayState to consolidate
 marking stack in Full GC

Co-authored-by: Stefan Johansson 
Reviewed-by: sjohanss, tschatzl
---
 src/hotspot/share/gc/g1/g1FullCollector.cpp   | 27 +++--
 src/hotspot/share/gc/g1/g1FullCollector.hpp   |  9 +-
 src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp  |  9 +-
 src/hotspot/share/gc/g1/g1FullGCMarker.cpp    | 46 ++++++---
 src/hotspot/share/gc/g1/g1FullGCMarker.hpp    | 47 ++++-----
 .../share/gc/g1/g1FullGCMarker.inline.hpp     | 98 ++++++-------------
 .../share/gc/g1/g1FullGCOopClosures.cpp       |  2 +-
 .../share/gc/g1/g1FullGCOopClosures.hpp       |  4 +-
 8 files changed, 110 insertions(+), 132 deletions(-)

diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp
index 5ca5dcef001..7395df01760 100644
--- a/src/hotspot/share/gc/g1/g1FullCollector.cpp
+++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -116,8 +116,8 @@ G1FullCollector::G1FullCollector(G1CollectedHeap* heap,
     _num_workers(calc_active_workers()),
     _has_compaction_targets(false),
     _has_humongous(false),
-    _oop_queue_set(_num_workers),
-    _array_queue_set(_num_workers),
+    _marking_task_queues(_num_workers),
+    _partial_array_state_manager(nullptr),
     _preserved_marks_set(true),
     _serial_compaction_point(this, nullptr),
     _humongous_compaction_point(this, nullptr),
@@ -140,23 +140,31 @@ G1FullCollector::G1FullCollector(G1CollectedHeap* heap,
     _compaction_tops[j] = nullptr;
   }
 
+  _partial_array_state_manager = new PartialArrayStateManager(_num_workers);
+
   for (uint i = 0; i < _num_workers; i++) {
     _markers[i] = new G1FullGCMarker(this, i, _live_stats);
     _compaction_points[i] = new G1FullGCCompactionPoint(this, _preserved_marks_set.get(i));
-    _oop_queue_set.register_queue(i, marker(i)->oop_stack());
-    _array_queue_set.register_queue(i, marker(i)->objarray_stack());
+    _marking_task_queues.register_queue(i, marker(i)->task_queue());
   }
+
   _serial_compaction_point.set_preserved_stack(_preserved_marks_set.get(0));
   _humongous_compaction_point.set_preserved_stack(_preserved_marks_set.get(0));
   _region_attr_table.initialize(heap->reserved(), G1HeapRegion::GrainBytes);
 }
 
+PartialArrayStateManager* G1FullCollector::partial_array_state_manager() const {
+  return _partial_array_state_manager;
+}
+
 G1FullCollector::~G1FullCollector() {
   for (uint i = 0; i < _num_workers; i++) {
     delete _markers[i];
     delete _compaction_points[i];
   }
 
+  delete _partial_array_state_manager;
+
   FREE_C_HEAP_ARRAY(G1FullGCMarker*, _markers);
   FREE_C_HEAP_ARRAY(G1FullGCCompactionPoint*, _compaction_points);
   FREE_C_HEAP_ARRAY(HeapWord*, _compaction_tops);
@@ -279,8 +287,8 @@ public:
     uint index = (_tm == RefProcThreadModel::Single) ? 0 : worker_id;
     G1FullKeepAliveClosure keep_alive(_collector.marker(index));
     BarrierEnqueueDiscoveredFieldClosure enqueue;
-    G1FollowStackClosure* complete_gc = _collector.marker(index)->stack_closure();
-    _rp_task->rp_work(worker_id, &is_alive, &keep_alive, &enqueue, complete_gc);
+    G1MarkStackClosure* complete_marking = _collector.marker(index)->stack_closure();
+    _rp_task->rp_work(worker_id, &is_alive, &keep_alive, &enqueue, complete_marking);
   }
 };
 
@@ -302,7 +310,7 @@ void G1FullCollector::phase1_mark_live_objects() {
     const ReferenceProcessorStats& stats = reference_processor()->process_discovered_references(task, _heap->workers(), pt);
     scope()->tracer()->report_gc_reference_stats(stats);
     pt.print_all_references();
-    assert(marker(0)->oop_stack()->is_empty(), "Should be no oops on the stack");
+    assert(marker(0)->task_queue()->is_empty(), "Should be no oops on the stack");
   }
 
   {
@@ -328,8 +336,7 @@ void G1FullCollector::phase1_mark_live_objects() {
     scope()->tracer()->report_object_count_after_gc(&_is_alive, _heap->workers());
   }
 #if TASKQUEUE_STATS
-  oop_queue_set()->print_and_reset_taskqueue_stats("Oop Queue");
-  array_queue_set()->print_and_reset_taskqueue_stats("ObjArrayOop Queue");
+  marking_task_queues()->print_and_reset_taskqueue_stats("Marking Task Queue");
 #endif
 }
 
diff --git a/src/hotspot/share/gc/g1/g1FullCollector.hpp b/src/hotspot/share/gc/g1/g1FullCollector.hpp
index 1fb3af17032..28ecffad944 100644
--- a/src/hotspot/share/gc/g1/g1FullCollector.hpp
+++ b/src/hotspot/share/gc/g1/g1FullCollector.hpp
@@ -79,8 +79,8 @@ class G1FullCollector : StackObj {
   bool                      _has_humongous;
   G1FullGCMarker**          _markers;
   G1FullGCCompactionPoint** _compaction_points;
-  OopQueueSet               _oop_queue_set;
-  ObjArrayTaskQueueSet      _array_queue_set;
+  G1MarkTasksQueueSet       _marking_task_queues;
+  PartialArrayStateManager* _partial_array_state_manager;
   PreservedMarksSet         _preserved_marks_set;
   G1FullGCCompactionPoint   _serial_compaction_point;
   G1FullGCCompactionPoint   _humongous_compaction_point;
@@ -113,8 +113,7 @@ public:
   uint                     workers() { return _num_workers; }
   G1FullGCMarker*          marker(uint id) { return _markers[id]; }
   G1FullGCCompactionPoint* compaction_point(uint id) { return _compaction_points[id]; }
-  OopQueueSet*             oop_queue_set() { return &_oop_queue_set; }
-  ObjArrayTaskQueueSet*    array_queue_set() { return &_array_queue_set; }
+  G1MarkTasksQueueSet*     marking_task_queues() { return &_marking_task_queues; }
   PreservedMarksSet*       preserved_mark_set() { return &_preserved_marks_set; }
   G1FullGCCompactionPoint* serial_compaction_point() { return &_serial_compaction_point; }
   G1FullGCCompactionPoint* humongous_compaction_point() { return &_humongous_compaction_point; }
@@ -125,6 +124,8 @@ public:
     return _live_stats[region_index].live_words();
   }
 
+  PartialArrayStateManager* partial_array_state_manager() const;
+
   void before_marking_update_attribute_table(G1HeapRegion* hr);
 
   inline bool is_compacting(oop obj) const;
diff --git a/src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp b/src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp
index 52b0d04a500..f14e1108db8 100644
--- a/src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp
+++ b/src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,7 @@
 G1FullGCMarkTask::G1FullGCMarkTask(G1FullCollector* collector) :
     G1FullGCTask("G1 Parallel Marking Task", collector),
     _root_processor(G1CollectedHeap::heap(), collector->workers()),
-    _terminator(collector->workers(), collector->array_queue_set()) {
+    _terminator(collector->workers(), collector->marking_task_queues()) {
 }
 
 void G1FullGCMarkTask::work(uint worker_id) {
@@ -54,10 +54,9 @@ void G1FullGCMarkTask::work(uint worker_id) {
   }
 
   // Mark stack is populated, now process and drain it.
-  marker->complete_marking(collector()->oop_queue_set(), collector()->array_queue_set(), &_terminator);
+  marker->complete_marking(collector()->marking_task_queues(), &_terminator);
 
   // This is the point where the entire marking should have completed.
-  assert(marker->oop_stack()->is_empty(), "Marking should have completed");
-  assert(marker->objarray_stack()->is_empty(), "Array marking should have completed");
+  assert(marker->task_queue()->is_empty(), "Marking should have completed");
   log_task("Marking task", worker_id, start);
 }
diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.cpp b/src/hotspot/share/gc/g1/g1FullGCMarker.cpp
index aa8f12a2d1b..2b0b78ac1ce 100644
--- a/src/hotspot/share/gc/g1/g1FullGCMarker.cpp
+++ b/src/hotspot/share/gc/g1/g1FullGCMarker.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
 #include "classfile/classLoaderData.hpp"
 #include "classfile/classLoaderDataGraph.hpp"
 #include "gc/g1/g1FullGCMarker.inline.hpp"
+#include "gc/shared/partialArraySplitter.inline.hpp"
+#include "gc/shared/partialArrayState.hpp"
 #include "gc/shared/referenceProcessor.hpp"
 #include "gc/shared/taskTerminator.hpp"
 #include "gc/shared/verifyOption.hpp"
@@ -36,8 +38,8 @@ G1FullGCMarker::G1FullGCMarker(G1FullCollector* collector,
     _collector(collector),
     _worker_id(worker_id),
     _bitmap(collector->mark_bitmap()),
-    _oop_stack(),
-    _objarray_stack(),
+    _task_queue(),
+    _partial_array_splitter(collector->partial_array_state_manager(), collector->workers(), ObjArrayMarkingStride),
     _mark_closure(worker_id, this, ClassLoaderData::_claim_stw_fullgc_mark, G1CollectedHeap::heap()->ref_processor_stw()),
     _stack_closure(this),
     _cld_closure(mark_closure(), ClassLoaderData::_claim_stw_fullgc_mark),
@@ -47,24 +49,36 @@ G1FullGCMarker::G1FullGCMarker(G1FullCollector* collector,
 }
 
 G1FullGCMarker::~G1FullGCMarker() {
-  assert(is_empty(), "Must be empty at this point");
+  assert(is_task_queue_empty(), "Must be empty at this point");
 }
 
-void G1FullGCMarker::complete_marking(OopQueueSet* oop_stacks,
-                                      ObjArrayTaskQueueSet* array_stacks,
+void G1FullGCMarker::process_partial_array(PartialArrayState* state, bool stolen) {
+  // Access state before release by claim().
+  objArrayOop obj_array = objArrayOop(state->source());
+  PartialArraySplitter::Claim claim =
+    _partial_array_splitter.claim(state, task_queue(), stolen);
+  process_array_chunk(obj_array, claim._start, claim._end);
+}
+
+void G1FullGCMarker::start_partial_array_processing(objArrayOop obj) {
+  mark_closure()->do_klass(obj->klass());
+  // Don't push empty arrays to avoid unnecessary work.
+  size_t array_length = obj->length();
+  if (array_length > 0) {
+    size_t initial_chunk_size = _partial_array_splitter.start(task_queue(), obj, nullptr, array_length);
+    process_array_chunk(obj, 0, initial_chunk_size);
+  }
+}
+
+void G1FullGCMarker::complete_marking(G1ScannerTasksQueueSet* task_queues,
                                       TaskTerminator* terminator) {
   do {
-    follow_marking_stacks();
-    ObjArrayTask steal_array;
-    if (array_stacks->steal(_worker_id, steal_array)) {
-      follow_array_chunk(objArrayOop(steal_array.obj()), steal_array.index());
-    } else {
-      oop steal_oop;
-      if (oop_stacks->steal(_worker_id, steal_oop)) {
-        follow_object(steal_oop);
-      }
+    process_marking_stacks();
+    ScannerTask stolen_task;
+    if (task_queues->steal(_worker_id, stolen_task)) {
+      dispatch_task(stolen_task, true);
     }
-  } while (!is_empty() || !terminator->offer_termination());
+  } while (!is_task_queue_empty() || !terminator->offer_termination());
 }
 
 void G1FullGCMarker::flush_mark_stats_cache() {
diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.hpp b/src/hotspot/share/gc/g1/g1FullGCMarker.hpp
index b1b750eae90..5973cc841c5 100644
--- a/src/hotspot/share/gc/g1/g1FullGCMarker.hpp
+++ b/src/hotspot/share/gc/g1/g1FullGCMarker.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,8 @@
 #include "gc/g1/g1FullGCOopClosures.hpp"
 #include "gc/g1/g1OopClosures.hpp"
 #include "gc/g1/g1RegionMarkStatsCache.hpp"
+#include "gc/shared/partialArraySplitter.hpp"
+#include "gc/shared/partialArrayState.hpp"
 #include "gc/shared/stringdedup/stringDedup.hpp"
 #include "gc/shared/taskqueue.hpp"
 #include "memory/iterator.hpp"
@@ -38,16 +40,15 @@
 #include "utilities/growableArray.hpp"
 #include "utilities/stack.hpp"
 
-typedef OverflowTaskQueue                 OopQueue;
-typedef OverflowTaskQueue        ObjArrayTaskQueue;
 
-typedef GenericTaskQueueSet          OopQueueSet;
-typedef GenericTaskQueueSet ObjArrayTaskQueueSet;
 
 class G1CMBitMap;
 class G1FullCollector;
 class TaskTerminator;
 
+typedef OverflowTaskQueue        G1MarkTasksQueue;
+typedef GenericTaskQueueSet G1MarkTasksQueueSet;
+
 class G1FullGCMarker : public CHeapObj {
   G1FullCollector*   _collector;
 
@@ -56,56 +57,50 @@ class G1FullGCMarker : public CHeapObj {
   G1CMBitMap*        _bitmap;
 
   // Mark stack
-  OopQueue           _oop_stack;
-  ObjArrayTaskQueue  _objarray_stack;
+  G1MarkTasksQueue     _task_queue;
+  PartialArraySplitter _partial_array_splitter;
 
   // Marking closures
   G1MarkAndPushClosure  _mark_closure;
-  G1FollowStackClosure  _stack_closure;
+  G1MarkStackClosure    _stack_closure;
   CLDToOopClosure       _cld_closure;
   StringDedup::Requests _string_dedup_requests;
 
 
   G1RegionMarkStatsCache _mark_stats_cache;
 
-  inline bool is_empty();
-  inline void push_objarray(oop obj, size_t index);
+  inline bool is_task_queue_empty();
   inline bool mark_object(oop obj);
 
   // Marking helpers
-  inline void follow_object(oop obj);
-  inline void follow_array(objArrayOop array);
-  inline void follow_array_chunk(objArrayOop array, int index);
+  inline void process_array_chunk(objArrayOop obj, size_t start, size_t end);
+  inline void dispatch_task(const ScannerTask& task, bool stolen);
+  // Start processing the given objArrayOop by first pushing its continuations and
+  // then scanning the first chunk.
+  void start_partial_array_processing(objArrayOop obj);
+  // Process the given continuation.
+  void process_partial_array(PartialArrayState* state, bool stolen);
 
   inline void publish_and_drain_oop_tasks();
-  // Try to publish all contents from the objArray task queue overflow stack to
-  // the shared objArray stack.
-  // Returns true and a valid task if there has not been enough space in the shared
-  // objArray stack, otherwise returns false and the task is invalid.
-  inline bool publish_or_pop_objarray_tasks(ObjArrayTask& task);
-
 public:
   G1FullGCMarker(G1FullCollector* collector,
                  uint worker_id,
                  G1RegionMarkStats* mark_stats);
   ~G1FullGCMarker();
 
-  // Stack getters
-  OopQueue*          oop_stack()       { return &_oop_stack; }
-  ObjArrayTaskQueue* objarray_stack()  { return &_objarray_stack; }
+  G1MarkTasksQueue* task_queue() { return &_task_queue; }
 
   // Marking entry points
   template  inline void mark_and_push(T* p);
 
-  inline void follow_marking_stacks();
-  void complete_marking(OopQueueSet* oop_stacks,
-                        ObjArrayTaskQueueSet* array_stacks,
+  inline void process_marking_stacks();
+  void complete_marking(G1MarkTasksQueueSet* task_queues,
                         TaskTerminator* terminator);
 
   // Closure getters
   CLDToOopClosure*      cld_closure()   { return &_cld_closure; }
   G1MarkAndPushClosure* mark_closure()  { return &_mark_closure; }
-  G1FollowStackClosure* stack_closure() { return &_stack_closure; }
+  G1MarkStackClosure*   stack_closure() { return &_stack_closure; }
 
   // Flush live bytes to regions
   void flush_mark_stats_cache();
diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp
index 398ef046bf5..a6f45abe005 100644
--- a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp
+++ b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2026, 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
@@ -42,6 +42,7 @@
 #include "oops/access.inline.hpp"
 #include "oops/compressedOops.inline.hpp"
 #include "oops/oop.inline.hpp"
+#include "utilities/checkedCast.hpp"
 #include "utilities/debug.hpp"
 
 inline bool G1FullGCMarker::mark_object(oop obj) {
@@ -71,94 +72,55 @@ template  inline void G1FullGCMarker::mark_and_push(T* p) {
   if (!CompressedOops::is_null(heap_oop)) {
     oop obj = CompressedOops::decode_not_null(heap_oop);
     if (mark_object(obj)) {
-      _oop_stack.push(obj);
+      _task_queue.push(ScannerTask(obj));
     }
     assert(_bitmap->is_marked(obj), "Must be marked");
   }
 }
 
-inline bool G1FullGCMarker::is_empty() {
-  return _oop_stack.is_empty() && _objarray_stack.is_empty();
+inline bool G1FullGCMarker::is_task_queue_empty() {
+  return _task_queue.is_empty();
 }
 
-inline void G1FullGCMarker::push_objarray(oop obj, size_t index) {
-  ObjArrayTask task(obj, index);
-  assert(task.is_valid(), "bad ObjArrayTask");
-  _objarray_stack.push(task);
+inline void G1FullGCMarker::process_array_chunk(objArrayOop obj, size_t start, size_t end) {
+  obj->oop_iterate_elements_range(mark_closure(),
+                                  checked_cast(start),
+                                  checked_cast(end));
 }
 
-inline void G1FullGCMarker::follow_array(objArrayOop array) {
-  mark_closure()->do_klass(array->klass());
-  // Don't push empty arrays to avoid unnecessary work.
-  if (array->length() > 0) {
-    push_objarray(array, 0);
-  }
-}
-
-void G1FullGCMarker::follow_array_chunk(objArrayOop array, int index) {
-  const int len = array->length();
-  const int beg_index = index;
-  assert(beg_index < len || len == 0, "index too large");
-
-  const int stride = MIN2(len - beg_index, (int) ObjArrayMarkingStride);
-  const int end_index = beg_index + stride;
-
-  // Push the continuation first to allow more efficient work stealing.
-  if (end_index < len) {
-    push_objarray(array, end_index);
-  }
-
-  array->oop_iterate_elements_range(mark_closure(), beg_index, end_index);
-}
-
-inline void G1FullGCMarker::follow_object(oop obj) {
-  assert(_bitmap->is_marked(obj), "should be marked");
-  if (obj->is_objArray()) {
-    // Handle object arrays explicitly to allow them to
-    // be split into chunks if needed.
-    follow_array((objArrayOop)obj);
+inline void G1FullGCMarker::dispatch_task(const ScannerTask& task, bool stolen) {
+  if (task.is_partial_array_state()) {
+    assert(_bitmap->is_marked(task.to_partial_array_state()->source()), "should be marked");
+    process_partial_array(task.to_partial_array_state(), stolen);
   } else {
-    obj->oop_iterate(mark_closure());
+    oop obj = task.to_oop();
+    assert(_bitmap->is_marked(obj), "should be marked");
+    if (obj->is_objArray()) {
+      // Handle object arrays explicitly to allow them to
+      // be split into chunks if needed.
+      start_partial_array_processing((objArrayOop)obj);
+    } else {
+      obj->oop_iterate(mark_closure());
+    }
   }
 }
 
 inline void G1FullGCMarker::publish_and_drain_oop_tasks() {
-  oop obj;
-  while (_oop_stack.pop_overflow(obj)) {
-    if (!_oop_stack.try_push_to_taskqueue(obj)) {
-      assert(_bitmap->is_marked(obj), "must be marked");
-      follow_object(obj);
+  ScannerTask task;
+  while (_task_queue.pop_overflow(task)) {
+    if (!_task_queue.try_push_to_taskqueue(task)) {
+      dispatch_task(task, false);
     }
   }
-  while (_oop_stack.pop_local(obj)) {
-    assert(_bitmap->is_marked(obj), "must be marked");
-    follow_object(obj);
+  while (_task_queue.pop_local(task)) {
+    dispatch_task(task, false);
   }
 }
 
-inline bool G1FullGCMarker::publish_or_pop_objarray_tasks(ObjArrayTask& task) {
-  // It is desirable to move as much as possible work from the overflow queue to
-  // the shared queue as quickly as possible.
-  while (_objarray_stack.pop_overflow(task)) {
-    if (!_objarray_stack.try_push_to_taskqueue(task)) {
-      return true;
-    }
-  }
-  return false;
-}
-
-void G1FullGCMarker::follow_marking_stacks() {
+void G1FullGCMarker::process_marking_stacks() {
   do {
-    // First, drain regular oop stack.
     publish_and_drain_oop_tasks();
-
-    // Then process ObjArrays one at a time to avoid marking stack bloat.
-    ObjArrayTask task;
-    if (publish_or_pop_objarray_tasks(task) ||
-        _objarray_stack.pop_local(task)) {
-      follow_array_chunk(objArrayOop(task.obj()), task.index());
-    }
-  } while (!is_empty());
+  } while (!is_task_queue_empty());
 }
 
 #endif // SHARE_GC_G1_G1FULLGCMARKER_INLINE_HPP
diff --git a/src/hotspot/share/gc/g1/g1FullGCOopClosures.cpp b/src/hotspot/share/gc/g1/g1FullGCOopClosures.cpp
index d9cf64a3655..273508ea9e3 100644
--- a/src/hotspot/share/gc/g1/g1FullGCOopClosures.cpp
+++ b/src/hotspot/share/gc/g1/g1FullGCOopClosures.cpp
@@ -35,7 +35,7 @@
 G1IsAliveClosure::G1IsAliveClosure(G1FullCollector* collector) :
   G1IsAliveClosure(collector, collector->mark_bitmap()) { }
 
-void G1FollowStackClosure::do_void() { _marker->follow_marking_stacks(); }
+void G1MarkStackClosure::do_void() { _marker->process_marking_stacks(); }
 
 void G1FullKeepAliveClosure::do_oop(oop* p) { do_oop_work(p); }
 void G1FullKeepAliveClosure::do_oop(narrowOop* p) { do_oop_work(p); }
diff --git a/src/hotspot/share/gc/g1/g1FullGCOopClosures.hpp b/src/hotspot/share/gc/g1/g1FullGCOopClosures.hpp
index 388f8032de4..08ed5f982e1 100644
--- a/src/hotspot/share/gc/g1/g1FullGCOopClosures.hpp
+++ b/src/hotspot/share/gc/g1/g1FullGCOopClosures.hpp
@@ -86,11 +86,11 @@ public:
   virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS; }
 };
 
-class G1FollowStackClosure: public VoidClosure {
+class G1MarkStackClosure: public VoidClosure {
   G1FullGCMarker* _marker;
 
 public:
-  G1FollowStackClosure(G1FullGCMarker* marker) : _marker(marker) {}
+  G1MarkStackClosure(G1FullGCMarker* marker) : _marker(marker) {}
   virtual void do_void();
 };
 

From 5e0ed3f408b6afd7496e0e0da207f7e372b0d446 Mon Sep 17 00:00:00 2001
From: Thomas Schatzl 
Date: Thu, 22 Jan 2026 11:51:37 +0000
Subject: [PATCH 142/328] 8375982: G1: Convert G1YoungCollector helper classes
 to use Atomic

Reviewed-by: kbarrett, shade
---
 src/hotspot/share/gc/g1/g1YoungCollector.cpp  | 19 ++++++++++---------
 .../gc/g1/g1YoungGCPostEvacuateTasks.cpp      |  7 ++++---
 2 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp
index fa5c617f1db..36cc44a8b7c 100644
--- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp
+++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026, 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
@@ -58,6 +58,7 @@
 #include "gc/shared/workerThread.hpp"
 #include "jfr/jfrEvents.hpp"
 #include "memory/resourceArea.hpp"
+#include "runtime/atomic.hpp"
 #include "runtime/threads.hpp"
 #include "utilities/ticks.hpp"
 
@@ -459,8 +460,8 @@ class G1PrepareEvacuationTask : public WorkerTask {
 
   G1CollectedHeap* _g1h;
   G1HeapRegionClaimer _claimer;
-  volatile uint _humongous_total;
-  volatile uint _humongous_candidates;
+  Atomic _humongous_total;
+  Atomic _humongous_candidates;
 
   G1MonotonicArenaMemoryStats _all_card_set_stats;
 
@@ -481,19 +482,19 @@ public:
   }
 
   void add_humongous_candidates(uint candidates) {
-    AtomicAccess::add(&_humongous_candidates, candidates);
+    _humongous_candidates.add_then_fetch(candidates);
   }
 
   void add_humongous_total(uint total) {
-    AtomicAccess::add(&_humongous_total, total);
+    _humongous_total.add_then_fetch(total);
   }
 
   uint humongous_candidates() {
-    return _humongous_candidates;
+    return _humongous_candidates.load_relaxed();
   }
 
   uint humongous_total() {
-    return _humongous_total;
+    return _humongous_total.load_relaxed();
   }
 
   const G1MonotonicArenaMemoryStats all_card_set_stats() const {
@@ -698,7 +699,7 @@ protected:
   virtual void evacuate_live_objects(G1ParScanThreadState* pss, uint worker_id) = 0;
 
 private:
-  volatile bool _pinned_regions_recorded;
+  Atomic _pinned_regions_recorded;
 
 public:
   G1EvacuateRegionsBaseTask(const char* name,
@@ -722,7 +723,7 @@ public:
       G1ParScanThreadState* pss = _per_thread_states->state_for_worker(worker_id);
       pss->set_ref_discoverer(_g1h->ref_processor_stw());
 
-      if (!AtomicAccess::cmpxchg(&_pinned_regions_recorded, false, true)) {
+      if (_pinned_regions_recorded.compare_set(false, true)) {
         record_pinned_regions(pss, worker_id);
       }
       scan_roots(pss, worker_id);
diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp
index ec5d2393d8c..46d12df575c 100644
--- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp
+++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp
@@ -46,6 +46,7 @@
 #include "oops/access.inline.hpp"
 #include "oops/compressedOops.inline.hpp"
 #include "oops/oop.inline.hpp"
+#include "runtime/atomic.hpp"
 #include "runtime/prefetch.inline.hpp"
 #include "runtime/threads.hpp"
 #include "runtime/threadSMR.hpp"
@@ -759,7 +760,7 @@ class G1PostEvacuateCollectionSetCleanupTask2::FreeCollectionSetTask : public G1
   const size_t*       _surviving_young_words;
   uint                _active_workers;
   G1EvacFailureRegions* _evac_failure_regions;
-  volatile uint       _num_retained_regions;
+  Atomic        _num_retained_regions;
 
   FreeCSetStats* worker_stats(uint worker) {
     return &_worker_stats[worker];
@@ -794,7 +795,7 @@ public:
   virtual ~FreeCollectionSetTask() {
     Ticks serial_time = Ticks::now();
 
-    bool has_new_retained_regions = AtomicAccess::load(&_num_retained_regions) != 0;
+    bool has_new_retained_regions = _num_retained_regions.load_relaxed() != 0;
     if (has_new_retained_regions) {
       G1CollectionSetCandidates* candidates = _g1h->collection_set()->candidates();
       candidates->sort_by_efficiency();
@@ -829,7 +830,7 @@ public:
     // Report per-region type timings.
     cl.report_timing();
 
-    AtomicAccess::add(&_num_retained_regions, cl.num_retained_regions(), memory_order_relaxed);
+    _num_retained_regions.add_then_fetch(cl.num_retained_regions(), memory_order_relaxed);
   }
 };
 

From 0d1d4d07b9fa2368f471f30e176d446698500115 Mon Sep 17 00:00:00 2001
From: Roland Westrelin 
Date: Thu, 22 Jan 2026 12:09:11 +0000
Subject: [PATCH 143/328] 8374725: C2: assert(x_ctrl ==
 get_late_ctrl_with_anti_dep(x->as_Load(), early_ctrl, x_ctrl)) failed:
 anti-dependences were already checked

Reviewed-by: chagedorn, qamai, dfenacci
---
 src/hotspot/share/opto/loopopts.cpp           | 10 +--
 .../loopopts/TestSinkingLoadInputOfPhi.java   | 63 +++++++++++++++++++
 2 files changed, 68 insertions(+), 5 deletions(-)
 create mode 100644 test/hotspot/jtreg/compiler/loopopts/TestSinkingLoadInputOfPhi.java

diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp
index 9e3d4681e7c..1855263539b 100644
--- a/src/hotspot/share/opto/loopopts.cpp
+++ b/src/hotspot/share/opto/loopopts.cpp
@@ -1922,11 +1922,6 @@ bool PhaseIdealLoop::ctrl_of_all_uses_out_of_loop(const Node* n, Node* n_ctrl, I
     if (u->is_Opaque1()) {
       return false;  // Found loop limit, bugfix for 4677003
     }
-    // We can't reuse tags in PhaseIdealLoop::dom_lca_for_get_late_ctrl_internal() so make sure calls to
-    // get_late_ctrl_with_anti_dep() use their own tag
-    _dom_lca_tags_round++;
-    assert(_dom_lca_tags_round != 0, "shouldn't wrap around");
-
     if (u->is_Phi()) {
       for (uint j = 1; j < u->req(); ++j) {
         if (u->in(j) == n && !ctrl_of_use_out_of_loop(n, n_ctrl, n_loop, u->in(0)->in(j))) {
@@ -1960,6 +1955,11 @@ bool PhaseIdealLoop::would_sink_below_pre_loop_exit(IdealLoopTree* n_loop, Node*
 
 bool PhaseIdealLoop::ctrl_of_use_out_of_loop(const Node* n, Node* n_ctrl, IdealLoopTree* n_loop, Node* ctrl) {
   if (n->is_Load()) {
+    // We can't reuse tags in PhaseIdealLoop::dom_lca_for_get_late_ctrl_internal() so make sure each call to
+    // get_late_ctrl_with_anti_dep() uses its own tag
+    _dom_lca_tags_round++;
+    assert(_dom_lca_tags_round != 0, "shouldn't wrap around");
+
     ctrl = get_late_ctrl_with_anti_dep(n->as_Load(), n_ctrl, ctrl);
   }
   IdealLoopTree *u_loop = get_loop(ctrl);
diff --git a/test/hotspot/jtreg/compiler/loopopts/TestSinkingLoadInputOfPhi.java b/test/hotspot/jtreg/compiler/loopopts/TestSinkingLoadInputOfPhi.java
new file mode 100644
index 00000000000..cd563e6caf2
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/loopopts/TestSinkingLoadInputOfPhi.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2026 IBM Corporation. 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 8374725
+ * @summary C2: assert(x_ctrl == get_late_ctrl_with_anti_dep(x->as_Load(), early_ctrl, x_ctrl)) failed: anti-dependences were already checked
+ * @run main/othervm  -XX:CompileCommand=compileonly,*TestSinkingLoadInputOfPhi*::* -XX:-TieredCompilation -Xcomp ${test.main.class}
+ * @run main ${test.main.class}
+ */
+
+package compiler.loopopts;
+
+public class TestSinkingLoadInputOfPhi {
+
+  static long lFld;
+  static int iFld = 55;
+  static int iFld2 = 10;
+  static void test() {
+    int iArr[] = new int[iFld2];
+
+    for (int i13 : iArr)
+      switch (iFld) {
+      case 69:
+      case 46:
+      case 65:
+        lFld = i13;
+      case 55: // taken
+        for (int i16 = 1; i16 < 30000; i16++)
+          ;
+      case 71:
+        iArr[iFld2] = 2; // OOB-access
+      }
+  }
+
+  public static void main(String[] strArr) {
+    try {
+      test();
+      } catch (ArrayIndexOutOfBoundsException e) {
+        // expected
+      }
+  }
+}

From eda15aa19c36142984edaa08850132ca6ae7a369 Mon Sep 17 00:00:00 2001
From: Weijun Wang 
Date: Thu, 22 Jan 2026 12:16:09 +0000
Subject: [PATCH 144/328] 8277489: Rewrite JAAS UnixLoginModule with FFM

Co-authored-by: Martin Doerr 
Reviewed-by: mdoerr, ascarpino, erikj
---
 make/modules/jdk.security.auth/Lib.gmk        |  17 +-
 src/java.base/share/classes/module-info.java  |   3 +-
 .../security/auth/module/UnixLoginModule.java |  32 +++-
 .../sun/security/auth/module/UnixSystem.java  | 180 ++++++++++++++++--
 .../unix/native/libjaas/Unix.c                | 130 -------------
 .../security/auth/module/AllPlatforms.java    |  23 ++-
 6 files changed, 220 insertions(+), 165 deletions(-)
 delete mode 100644 src/jdk.security.auth/unix/native/libjaas/Unix.c

diff --git a/make/modules/jdk.security.auth/Lib.gmk b/make/modules/jdk.security.auth/Lib.gmk
index 9ead32dbe12..96d609f08d6 100644
--- a/make/modules/jdk.security.auth/Lib.gmk
+++ b/make/modules/jdk.security.auth/Lib.gmk
@@ -31,13 +31,14 @@ include LibCommon.gmk
 ## Build libjaas
 ################################################################################
 
-$(eval $(call SetupJdkLibrary, BUILD_LIBJAAS, \
-    NAME := jaas, \
-    OPTIMIZATION := LOW, \
-    EXTRA_HEADER_DIRS := java.base:libjava, \
-    LIBS_windows := advapi32.lib mpr.lib netapi32.lib user32.lib, \
-))
-
-TARGETS += $(BUILD_LIBJAAS)
+ifeq ($(call isTargetOs, windows), true)
+  $(eval $(call SetupJdkLibrary, BUILD_LIBJAAS, \
+      NAME := jaas, \
+      OPTIMIZATION := LOW, \
+      EXTRA_HEADER_DIRS := java.base:libjava, \
+      LIBS_windows := advapi32.lib mpr.lib netapi32.lib user32.lib, \
+  ))
 
+  TARGETS += $(BUILD_LIBJAAS)
+endif
 ################################################################################
diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java
index 70a79390828..d20f6311bca 100644
--- a/src/java.base/share/classes/module-info.java
+++ b/src/java.base/share/classes/module-info.java
@@ -274,7 +274,8 @@ module java.base {
         jdk.httpserver,
         jdk.jlink,
         jdk.jpackage,
-        jdk.net;
+        jdk.net,
+        jdk.security.auth;
     exports sun.net to
         java.net.http,
         jdk.naming.dns;
diff --git a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/UnixLoginModule.java b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/UnixLoginModule.java
index 785b178e296..4f6d8ca25ef 100644
--- a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/UnixLoginModule.java
+++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/UnixLoginModule.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,6 @@
 package com.sun.security.auth.module;
 
 import java.util.*;
-import java.io.IOException;
 import javax.security.auth.*;
 import javax.security.auth.callback.*;
 import javax.security.auth.login.*;
@@ -34,6 +33,7 @@ import javax.security.auth.spi.*;
 import com.sun.security.auth.UnixPrincipal;
 import com.sun.security.auth.UnixNumericUserPrincipal;
 import com.sun.security.auth.UnixNumericGroupPrincipal;
+import jdk.internal.util.OperatingSystem;
 
 /**
  * This {@code LoginModule} imports a user's Unix
@@ -121,20 +121,34 @@ public class UnixLoginModule implements LoginModule {
      */
     public boolean login() throws LoginException {
 
-        long[] unixGroups = null;
+        // Fail immediately on Windows to avoid cygwin-like functions
+        // being loaded, which are not supported.
+        if (OperatingSystem.isWindows()) {
+            throw new FailedLoginException
+                    ("Failed in attempt to import " +
+                            "the underlying system identity information" +
+                            " on " + System.getProperty("os.name"));
+        }
 
         try {
             ss = new UnixSystem();
-        } catch (UnsatisfiedLinkError ule) {
+        } catch (ExceptionInInitializerError | UnsatisfiedLinkError ule) {
+            // Errors could happen in either static blocks or the constructor,
+            // both have a cause.
             succeeded = false;
-            throw new FailedLoginException
+            var error = new FailedLoginException
                                 ("Failed in attempt to import " +
                                 "the underlying system identity information" +
                                 " on " + System.getProperty("os.name"));
+            if (ule.getCause() != null) {
+                error.initCause(ule.getCause());
+            }
+            throw error;
         }
         userPrincipal = new UnixPrincipal(ss.getUsername());
         UIDPrincipal = new UnixNumericUserPrincipal(ss.getUid());
         GIDPrincipal = new UnixNumericGroupPrincipal(ss.getGid(), true);
+        long[] unixGroups = null;
         if (ss.getGroups() != null && ss.getGroups().length > 0) {
             unixGroups = ss.getGroups();
             for (int i = 0; i < unixGroups.length; i++) {
@@ -150,9 +164,11 @@ public class UnixLoginModule implements LoginModule {
                     "succeeded importing info: ");
             System.out.println("\t\t\tuid = " + ss.getUid());
             System.out.println("\t\t\tgid = " + ss.getGid());
-            unixGroups = ss.getGroups();
-            for (int i = 0; i < unixGroups.length; i++) {
-                System.out.println("\t\t\tsupp gid = " + unixGroups[i]);
+            System.out.println("\t\t\tusername = " + ss.getUsername());
+            if (unixGroups != null) {
+                for (int i = 0; i < unixGroups.length; i++) {
+                    System.out.println("\t\t\tsupp gid = " + unixGroups[i]);
+                }
             }
         }
         succeeded = true;
diff --git a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/UnixSystem.java b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/UnixSystem.java
index f3741c10404..c0e47fafc2c 100644
--- a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/UnixSystem.java
+++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/UnixSystem.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,38 +25,194 @@
 
 package com.sun.security.auth.module;
 
+import jdk.internal.util.Architecture;
+import jdk.internal.util.OperatingSystem;
+
+import java.lang.foreign.AddressLayout;
+import java.lang.foreign.Arena;
+import java.lang.foreign.FunctionDescriptor;
+import java.lang.foreign.GroupLayout;
+import java.lang.foreign.Linker;
+import java.lang.foreign.MemoryLayout;
+import java.lang.foreign.MemorySegment;
+import java.lang.foreign.StructLayout;
+import java.lang.foreign.SymbolLookup;
+import java.lang.foreign.ValueLayout;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.VarHandle;
+
+import static java.lang.foreign.MemoryLayout.PathElement.groupElement;
+
 /**
  * This class implementation retrieves and makes available Unix
  * UID/GID/groups information for the current user.
  *
  * @since 1.4
  */
+@SuppressWarnings("restricted")
 public class UnixSystem {
 
-    private native void getUnixInfo();
-
-    // Warning: the following 4 fields are used by Unix.c
-
-    /** The current username. */
+    /**
+     * The current username.
+     */
     protected String username;
 
-    /** The current user ID. */
+    /**
+     * The current user ID.
+     */
     protected long uid;
 
-    /** The current group ID. */
+    /**
+     * The current group ID.
+     */
     protected long gid;
 
-    /** The current list of groups. */
+    /**
+     * The current list of groups.
+     */
     protected long[] groups;
 
+    private static final Linker LINKER = Linker.nativeLinker();
+    private static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup()
+            .or(LINKER.defaultLookup());
+
+    private static final ValueLayout.OfByte C_CHAR
+            = (ValueLayout.OfByte) LINKER.canonicalLayouts().get("char");
+    private static final ValueLayout.OfInt C_INT
+            = (ValueLayout.OfInt) LINKER.canonicalLayouts().get("int");
+    private static final ValueLayout.OfLong C_LONG
+            = (ValueLayout.OfLong) LINKER.canonicalLayouts().get("long");
+    private static final AddressLayout C_POINTER
+            = ((AddressLayout) LINKER.canonicalLayouts().get("void*"))
+            .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, C_CHAR));
+    private static final ValueLayout C_SIZE_T
+            = (ValueLayout) LINKER.canonicalLayouts().get("size_t");
+
+    private static final StructLayout CAPTURE_STATE_LAYOUT
+            = Linker.Option.captureStateLayout();
+    private static final VarHandle VH_errno = CAPTURE_STATE_LAYOUT.varHandle(
+            MemoryLayout.PathElement.groupElement("errno"));
+
+    private static final MethodHandle MH_strerror
+            = LINKER.downcallHandle(SYMBOL_LOOKUP.findOrThrow("strerror"),
+                    FunctionDescriptor.of(C_POINTER, C_INT));
+
+    private static final MethodHandle MH_getgroups
+            = LINKER.downcallHandle(SYMBOL_LOOKUP.findOrThrow("getgroups"),
+                    FunctionDescriptor.of(C_INT, C_INT, C_POINTER),
+                    Linker.Option.captureCallState("errno"));
+    private static final MethodHandle MH_getuid
+            = LINKER.downcallHandle(SYMBOL_LOOKUP.findOrThrow("getuid"),
+                    FunctionDescriptor.of(C_INT));
+
+    // Some architectures require appropriate zero or sign extension to 64 bit.
+    // Use long directly before https://bugs.openjdk.org/browse/JDK-8336664 is resolved.
+    private static final boolean calling_convention_requires_int_as_long
+            = Architecture.isPPC64() || Architecture.isPPC64LE() || Architecture.isS390();
+
+    // getpwuid_r does not work on AIX, instead we use another similar function
+    // extern int _posix_getpwuid_r(uid_t, struct passwd *, char *, int, struct passwd **)
+    private static final MethodHandle MH_getpwuid_r
+            = LINKER.downcallHandle(SYMBOL_LOOKUP.findOrThrow(
+                            OperatingSystem.isAix() ? "_posix_getpwuid_r" : "getpwuid_r"),
+                    FunctionDescriptor.of(C_INT,
+                            calling_convention_requires_int_as_long ? C_LONG : C_INT,
+                            C_POINTER, C_POINTER,
+                            OperatingSystem.isAix() ? C_INT : C_SIZE_T,
+                            C_POINTER));
+
+    private static final GroupLayout ML_passwd = MemoryLayout.structLayout(
+            C_POINTER.withName("pw_name"),
+            C_POINTER.withName("pw_passwd"),
+            C_INT.withName("pw_uid"),
+            C_INT.withName("pw_gid"),
+            // Different platforms have different fields in `struct passwd`.
+            // While we don't need those fields here, the struct needs to be
+            // big enough to avoid buffer overflow when `getpwuid_r` is called.
+            MemoryLayout.paddingLayout(100));
+
+    private static final VarHandle VH_pw_uid
+            = ML_passwd.varHandle(groupElement("pw_uid"));
+    private static final VarHandle VH_pw_gid
+            = ML_passwd.varHandle(groupElement("pw_gid"));
+    private static final VarHandle VH_pw_name
+            = ML_passwd.varHandle(groupElement("pw_name"));
+
+    // The buffer size for the getpwuid_r function:
+    // 1. sysconf(_SC_GETPW_R_SIZE_MAX) on macOS is 4096 and 1024 on Linux,
+    //    so we choose a bigger one.
+    // 2. We do not call sysconf() here because even _SC_GETPW_R_SIZE_MAX
+    //    could be different on different platforms.
+    // 3. We choose int instead of long because the buffer_size argument
+    //    might be `int` or `long` and converting from `long` to `int`
+    //    requires an explicit cast.
+    private static final int GETPW_R_SIZE_MAX = 4096;
+
     /**
      * Instantiate a {@code UnixSystem} and load
      * the native library to access the underlying system information.
      */
-    @SuppressWarnings("restricted")
     public UnixSystem() {
-        System.loadLibrary("jaas");
-        getUnixInfo();
+        // The FFM code has only been tested on multiple platforms
+        // (including macOS, Linux, AIX, etc) and might fail on other
+        // *nix systems. Especially, the `passwd` struct could be defined
+        // differently. I've checked several and an extra 100 chars at the
+        // end seems enough.
+        try (Arena scope = Arena.ofConfined()) {
+            MemorySegment capturedState = scope.allocate(CAPTURE_STATE_LAYOUT);
+            int groupnum = (int) MH_getgroups.invokeExact(capturedState, 0, MemorySegment.NULL);
+            if (groupnum == -1) {
+                throw new RuntimeException("getgroups returns " + groupnum);
+            }
+
+            var gs = scope.allocate(C_INT, groupnum);
+            groupnum = (int) MH_getgroups.invokeExact(capturedState, groupnum, gs);
+            if (groupnum == -1) {
+                var errno = (int) VH_errno.get(capturedState, 0L);
+                var errMsg = (MemorySegment) MH_strerror.invokeExact(errno);
+                throw new RuntimeException("getgroups returns " + groupnum
+                        + ". Reason: " + errMsg.reinterpret(Long.MAX_VALUE).getString(0));
+            }
+
+            groups = new long[groupnum];
+            for (int i = 0; i < groupnum; i++) {
+                groups[i] = Integer.toUnsignedLong(gs.getAtIndex(C_INT, i));
+            }
+
+            var pwd = scope.allocate(ML_passwd);
+            var result = scope.allocate(C_POINTER);
+            var buffer = scope.allocate(GETPW_R_SIZE_MAX);
+
+            long tmpUid = Integer.toUnsignedLong((int) MH_getuid.invokeExact());
+
+            // Do not call invokeExact because the type of buffer_size is not
+            // always long in the underlying system.
+            int out;
+            if (calling_convention_requires_int_as_long) {
+                out = (int) MH_getpwuid_r.invoke(
+                        tmpUid, pwd, buffer, GETPW_R_SIZE_MAX, result);
+            } else {
+                out = (int) MH_getpwuid_r.invoke(
+                        (int) tmpUid, pwd, buffer, GETPW_R_SIZE_MAX, result);
+            }
+            if (out != 0) {
+                // If ERANGE (Result too large) is detected in a new platform,
+                // consider adjusting GETPW_R_SIZE_MAX.
+                var err = (MemorySegment) MH_strerror.invokeExact(out);
+                throw new RuntimeException(err.reinterpret(Long.MAX_VALUE).getString(0));
+            } else if (result.get(ValueLayout.ADDRESS, 0).equals(MemorySegment.NULL)) {
+                throw new RuntimeException("the requested entry is not found");
+            } else {
+                // uid_t and gid_t were defined unsigned.
+                uid = Integer.toUnsignedLong((int) VH_pw_uid.get(pwd, 0L));
+                gid = Integer.toUnsignedLong((int) VH_pw_gid.get(pwd, 0L));
+                username = ((MemorySegment) VH_pw_name.get(pwd, 0L)).getString(0);
+            }
+        } catch (Throwable t) {
+            var error = new UnsatisfiedLinkError("FFM calls failed");
+            error.initCause(t);
+            throw error;
+        }
     }
 
     /**
diff --git a/src/jdk.security.auth/unix/native/libjaas/Unix.c b/src/jdk.security.auth/unix/native/libjaas/Unix.c
deleted file mode 100644
index 3a93df9ffc9..00000000000
--- a/src/jdk.security.auth/unix/native/libjaas/Unix.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include 
-#include "jni_util.h"
-#include "com_sun_security_auth_module_UnixSystem.h"
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include 
-
-/*
- * Declare library specific JNI_Onload entry if static build
- */
-DEF_STATIC_JNI_OnLoad
-
-JNIEXPORT void JNICALL
-Java_com_sun_security_auth_module_UnixSystem_getUnixInfo
-                                                (JNIEnv *env, jobject obj) {
-
-    int i;
-    char pwd_buf[1024];
-    struct passwd *pwd = NULL;
-    struct passwd resbuf;
-    jfieldID userNameID;
-    jfieldID userID;
-    jfieldID groupID;
-    jfieldID supplementaryGroupID;
-
-    jstring jstr;
-    jlongArray jgroups;
-    jlong *jgroupsAsArray;
-    jsize numSuppGroups;
-    gid_t *groups;
-    jclass cls;
-
-    numSuppGroups = getgroups(0, NULL);
-    if (numSuppGroups == -1) {
-        return;
-    }
-    groups = (gid_t *)calloc(numSuppGroups, sizeof(gid_t));
-    if (groups == NULL) {
-        jclass cls = (*env)->FindClass(env,"java/lang/OutOfMemoryError");
-        if (cls != NULL) {
-            (*env)->ThrowNew(env, cls, NULL);
-        }
-        return;
-    }
-
-    cls = (*env)->GetObjectClass(env, obj);
-
-    supplementaryGroupID = (*env)->GetFieldID(env, cls, "groups", "[J");
-    if (supplementaryGroupID == 0) {
-        goto cleanUpAndReturn;
-    }
-
-    if (getgroups(numSuppGroups, groups) != -1) {
-        jgroups = (*env)->NewLongArray(env, numSuppGroups);
-        if (jgroups == NULL) {
-            goto cleanUpAndReturn;
-        }
-        jgroupsAsArray = (*env)->GetLongArrayElements(env, jgroups, 0);
-        if (jgroupsAsArray == NULL) {
-            goto cleanUpAndReturn;
-        }
-        for (i = 0; i < numSuppGroups; i++) {
-            jgroupsAsArray[i] = groups[i];
-        }
-        (*env)->ReleaseLongArrayElements(env, jgroups, jgroupsAsArray, 0);
-        (*env)->SetObjectField(env, obj, supplementaryGroupID, jgroups);
-    }
-
-    userNameID = (*env)->GetFieldID(env, cls, "username", "Ljava/lang/String;");
-    if (userNameID == 0) {
-        goto cleanUpAndReturn;
-    }
-
-    userID = (*env)->GetFieldID(env, cls, "uid", "J");
-    if (userID == 0) {
-        goto cleanUpAndReturn;
-    }
-
-    groupID = (*env)->GetFieldID(env, cls, "gid", "J");
-    if (groupID == 0) {
-        goto cleanUpAndReturn;
-    }
-
-    memset(pwd_buf, 0, sizeof(pwd_buf));
-    if (getpwuid_r(getuid(), &resbuf, pwd_buf, sizeof(pwd_buf), &pwd) == 0 &&
-            pwd != NULL) {
-        (*env)->SetLongField(env, obj, userID, pwd->pw_uid);
-        (*env)->SetLongField(env, obj, groupID, pwd->pw_gid);
-        jstr = (*env)->NewStringUTF(env, pwd->pw_name);
-        if (jstr == NULL) {
-            goto cleanUpAndReturn;
-        }
-        (*env)->SetObjectField(env, obj, userNameID, jstr);
-    } else {
-        (*env)->SetLongField(env, obj, userID, getuid());
-        (*env)->SetLongField(env, obj, groupID, getgid());
-    }
-cleanUpAndReturn:
-    free(groups);
-    return;
-}
diff --git a/test/jdk/com/sun/security/auth/module/AllPlatforms.java b/test/jdk/com/sun/security/auth/module/AllPlatforms.java
index 79eea7b4d23..6f7cbfb9c52 100644
--- a/test/jdk/com/sun/security/auth/module/AllPlatforms.java
+++ b/test/jdk/com/sun/security/auth/module/AllPlatforms.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,8 +25,11 @@
  * @test
  * @bug 8039951
  * @summary com.sun.security.auth.module missing classes on some platforms
+ * @modules java.base/jdk.internal.util
  * @run main/othervm AllPlatforms
  */
+import jdk.internal.util.OperatingSystem;
+
 import javax.security.auth.login.Configuration;
 import javax.security.auth.login.LoginContext;
 import java.nio.file.Files;
@@ -39,14 +42,14 @@ public class AllPlatforms {
     private static final String NT_MODULE = "NTLoginModule";
 
     public static void main(String[] args) throws Exception {
-        login("cross-platform",
+        login(true, "cross-platform",
                 UNIX_MODULE, "optional",
                 NT_MODULE, "optional");
-        login("windows", NT_MODULE, "required");
-        login("unix", UNIX_MODULE, "required");
+        login(OperatingSystem.isWindows(), "windows", NT_MODULE, "required");
+        login(!OperatingSystem.isWindows(), "unix", UNIX_MODULE, "required");
     }
 
-    static void login(String test, String... conf) throws Exception {
+    static void login(boolean shouldSucceed, String test, String... conf) throws Exception {
         System.out.println("Testing " + test + "...");
 
         StringBuilder sb = new StringBuilder();
@@ -68,11 +71,19 @@ public class AllPlatforms {
             lc.login();
             System.out.println(lc.getSubject());
             lc.logout();
+            if (!shouldSucceed) {
+                throw new RuntimeException("Should not succeed");
+            }
         } catch (FailedLoginException e) {
+            if (shouldSucceed) {
+                throw new RuntimeException("Should succeed");
+            }
             // This exception can occur in other platform module than the running one.
-            if(e.getMessage().startsWith("Failed in attempt to import")) {
+            if (e.getMessage().startsWith("Failed in attempt to import")) {
                 System.out.println("Expected Exception found.");
                 e.printStackTrace(System.out);
+            } else {
+                throw new RuntimeException("Unexpected error", e);
             }
         }
     }

From 025041ba04f3ae3a149b9d57d0dde4afaef37f4c Mon Sep 17 00:00:00 2001
From: Artur Barashev 
Date: Thu, 22 Jan 2026 13:11:42 +0000
Subject: [PATCH 145/328] 8370885: Default namedGroups values are not being
 filtered against algorithm constraints

Reviewed-by: hchao
---
 .../classes/sun/security/ssl/NamedGroup.java  | 177 ++++++++++--------
 .../ssl/CipherSuite/DefaultNamedGroups.java   |  85 +++++++++
 2 files changed, 189 insertions(+), 73 deletions(-)
 create mode 100644 test/jdk/sun/security/ssl/CipherSuite/DefaultNamedGroups.java

diff --git a/src/java.base/share/classes/sun/security/ssl/NamedGroup.java b/src/java.base/share/classes/sun/security/ssl/NamedGroup.java
index abf973727f3..02524e67656 100644
--- a/src/java.base/share/classes/sun/security/ssl/NamedGroup.java
+++ b/src/java.base/share/classes/sun/security/ssl/NamedGroup.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2026, 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,10 +30,12 @@ import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.ECParameterSpec;
 import java.security.spec.InvalidParameterSpecException;
 import java.security.spec.NamedParameterSpec;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.ArrayList;
+import java.util.Objects;
 import java.util.Set;
 import javax.crypto.KeyAgreement;
 import javax.crypto.spec.DHParameterSpec;
@@ -463,10 +465,9 @@ enum NamedGroup {
             AlgorithmConstraints constraints, NamedGroupSpec type) {
 
         boolean hasFFDHEGroups = false;
-        for (String ng : sslConfig.namedGroups) {
-            NamedGroup namedGroup = NamedGroup.nameOf(ng);
-            if (namedGroup != null &&
-                namedGroup.isAvailable && namedGroup.spec == type) {
+        for (NamedGroup namedGroup :
+                SupportedGroups.getGroupsFromConfig(sslConfig)) {
+            if (namedGroup.isAvailable && namedGroup.spec == type) {
                 if (namedGroup.isPermitted(constraints)) {
                     return true;
                 }
@@ -501,8 +502,8 @@ enum NamedGroup {
     // Is the named group supported?
     static boolean isEnabled(SSLConfiguration sslConfig,
                              NamedGroup namedGroup) {
-        for (String ng : sslConfig.namedGroups) {
-            if (namedGroup.name.equalsIgnoreCase(ng)) {
+        for (NamedGroup ng : SupportedGroups.getGroupsFromConfig(sslConfig)) {
+            if (namedGroup.equals(ng)) {
                 return true;
             }
         }
@@ -516,12 +517,10 @@ enum NamedGroup {
             SSLConfiguration sslConfig,
             ProtocolVersion negotiatedProtocol,
             AlgorithmConstraints constraints, NamedGroupSpec[] types) {
-        for (String name : sslConfig.namedGroups) {
-            NamedGroup ng = NamedGroup.nameOf(name);
-            if (ng != null && ng.isAvailable &&
-                    (NamedGroupSpec.arrayContains(types, ng.spec)) &&
-                    ng.isAvailable(negotiatedProtocol) &&
-                    ng.isPermitted(constraints)) {
+        for (NamedGroup ng : SupportedGroups.getGroupsFromConfig(sslConfig)) {
+            if (ng.isAvailable && NamedGroupSpec.arrayContains(types, ng.spec)
+                    && ng.isAvailable(negotiatedProtocol)
+                    && ng.isPermitted(constraints)) {
                 return ng;
             }
         }
@@ -857,19 +856,92 @@ enum NamedGroup {
         }
     }
 
+    // Inner class encapsulating supported named groups.
     static final class SupportedGroups {
-        // the supported named groups, non-null immutable list
+
+        // Default named groups.
+        private static final NamedGroup[] defaultGroups = new NamedGroup[]{
+                // Hybrid key agreement
+                X25519MLKEM768,
+
+                // Primary XDH (RFC 7748) curves
+                X25519,
+
+                // Primary NIST Suite B curves
+                SECP256_R1,
+                SECP384_R1,
+                SECP521_R1,
+
+                // Secondary XDH curves
+                X448,
+
+                // FFDHE (RFC 7919)
+                FFDHE_2048,
+                FFDHE_3072,
+                FFDHE_4096,
+                FFDHE_6144,
+                FFDHE_8192
+        };
+
+        // Filter default groups names against default constraints.
+        // Those are the values being displayed to the user with
+        // "java -XshowSettings:security:tls" command.
+        private static final String[] defaultNames = Arrays.stream(
+                        defaultGroups)
+                .filter(ng -> ng.isAvailable)
+                .filter(ng -> ng.isPermitted(SSLAlgorithmConstraints.DEFAULT))
+                .map(ng -> ng.name)
+                .toArray(String[]::new);
+
+        private static final NamedGroup[] customizedGroups =
+                getCustomizedNamedGroups();
+
+        // Note: user-passed groups are not being filtered against default
+        // algorithm constraints here. They will be displayed as-is.
+        private static final String[] customizedNames =
+                customizedGroups == null ?
+                        null : Arrays.stream(customizedGroups)
+                        .map(ng -> ng.name)
+                        .toArray(String[]::new);
+
+        // Named group names for SSLConfiguration.
         static final String[] namedGroups;
 
         static {
-            // The value of the System Property defines a list of enabled named
-            // groups in preference order, separated with comma.  For example:
-            //
-            //      jdk.tls.namedGroups="secp521r1, secp256r1, ffdhe2048"
-            //
-            // If the System Property is not defined or the value is empty, the
-            // default groups and preferences will be used.
+            if (customizedNames != null) {
+                namedGroups = customizedNames;
+            } else {
+                if (defaultNames.length == 0) {
+                    SSLLogger.logWarning("ssl", "No default named groups");
+                }
+                namedGroups = defaultNames;
+            }
+        }
+
+        // Avoid the group lookup for default and customized groups.
+        static NamedGroup[] getGroupsFromConfig(SSLConfiguration sslConfig) {
+            if (sslConfig.namedGroups == defaultNames) {
+                return defaultGroups;
+            } else if (sslConfig.namedGroups == customizedNames) {
+                return customizedGroups;
+            } else {
+                return Arrays.stream(sslConfig.namedGroups)
+                        .map(NamedGroup::nameOf)
+                        .filter(Objects::nonNull)
+                        .toArray(NamedGroup[]::new);
+            }
+        }
+
+        // The value of the System Property defines a list of enabled named
+        // groups in preference order, separated with comma.  For example:
+        //
+        //      jdk.tls.namedGroups="secp521r1, secp256r1, ffdhe2048"
+        //
+        // If the System Property is not defined or the value is empty, the
+        // default groups and preferences will be used.
+        private static NamedGroup[] getCustomizedNamedGroups() {
             String property = System.getProperty("jdk.tls.namedGroups");
+
             if (property != null && !property.isEmpty()) {
                 // remove double quote marks from beginning/end of the property
                 if (property.length() > 1 && property.charAt(0) == '"' &&
@@ -878,66 +950,25 @@ enum NamedGroup {
                 }
             }
 
-            ArrayList groupList;
             if (property != null && !property.isEmpty()) {
-                String[] groups = property.split(",");
-                groupList = new ArrayList<>(groups.length);
-                for (String group : groups) {
-                    group = group.trim();
-                    if (!group.isEmpty()) {
-                        NamedGroup namedGroup = nameOf(group);
-                        if (namedGroup != null) {
-                            if (namedGroup.isAvailable) {
-                                groupList.add(namedGroup.name);
-                            }
-                        }   // ignore unknown groups
-                    }
-                }
+                NamedGroup[] ret = Arrays.stream(property.split(","))
+                        .map(String::trim)
+                        .map(NamedGroup::nameOf)
+                        .filter(Objects::nonNull)
+                        .filter(ng -> ng.isAvailable)
+                        .toArray(NamedGroup[]::new);
 
-                if (groupList.isEmpty()) {
+                if (ret.length == 0) {
                     throw new IllegalArgumentException(
                             "System property jdk.tls.namedGroups(" +
-                            property + ") contains no supported named groups");
-                }
-            } else {        // default groups
-                NamedGroup[] groups = new NamedGroup[] {
-
-                        // Hybrid key agreement
-                        X25519MLKEM768,
-
-                        // Primary XDH (RFC 7748) curves
-                        X25519,
-
-                        // Primary NIST Suite B curves
-                        SECP256_R1,
-                        SECP384_R1,
-                        SECP521_R1,
-
-                        // Secondary XDH curves
-                        X448,
-
-                        // FFDHE (RFC 7919)
-                        FFDHE_2048,
-                        FFDHE_3072,
-                        FFDHE_4096,
-                        FFDHE_6144,
-                        FFDHE_8192,
-                    };
-
-                groupList = new ArrayList<>(groups.length);
-                for (NamedGroup group : groups) {
-                    if (group.isAvailable) {
-                        groupList.add(group.name);
-                    }
+                                    property
+                                    + ") contains no supported named groups");
                 }
 
-                if (groupList.isEmpty() &&
-                        SSLLogger.isOn() && SSLLogger.isOn("ssl")) {
-                    SSLLogger.warning("No default named groups");
-                }
+                return ret;
             }
 
-            namedGroups = groupList.toArray(new String[0]);
+            return null;
         }
     }
 }
diff --git a/test/jdk/sun/security/ssl/CipherSuite/DefaultNamedGroups.java b/test/jdk/sun/security/ssl/CipherSuite/DefaultNamedGroups.java
new file mode 100644
index 00000000000..44c9d566dc0
--- /dev/null
+++ b/test/jdk/sun/security/ssl/CipherSuite/DefaultNamedGroups.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import static jdk.test.lib.Asserts.assertFalse;
+import static jdk.test.lib.Asserts.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+import javax.net.ssl.SSLEngine;
+import jdk.test.lib.security.SecurityUtils;
+
+/*
+ * @test
+ * @bug 8370885
+ * @summary Default namedGroups values are not being filtered against
+ *          algorithm constraints
+ * @library /javax/net/ssl/templates
+ *          /test/lib
+ * @run main/othervm DefaultNamedGroups
+ */
+
+public class DefaultNamedGroups extends SSLEngineTemplate {
+
+    protected static final String DISABLED_NG = "secp256r1";
+    protected static final List REFERENCE_NG = Stream.of(
+                    "X25519MLKEM768",
+                    "x25519",
+                    "secp256r1",
+                    "secp384r1",
+                    "secp521r1",
+                    "x448",
+                    "ffdhe2048",
+                    "ffdhe3072",
+                    "ffdhe4096",
+                    "ffdhe6144",
+                    "ffdhe8192")
+            .sorted()
+            .toList();
+
+    protected DefaultNamedGroups() throws Exception {
+        super();
+    }
+
+    public static void main(String[] args) throws Exception {
+        SecurityUtils.addToDisabledTlsAlgs(DISABLED_NG);
+        var test = new DefaultNamedGroups();
+
+        for (SSLEngine engine :
+                new SSLEngine[]{test.serverEngine, test.clientEngine}) {
+            checkEngineDefaultNG(engine);
+        }
+    }
+
+    private static void checkEngineDefaultNG(SSLEngine engine) {
+        var defaultConfigNG = new ArrayList<>(List.of(
+                engine.getSSLParameters().getNamedGroups()));
+
+        assertFalse(defaultConfigNG.contains(DISABLED_NG));
+        defaultConfigNG.add(DISABLED_NG);
+        assertTrue(REFERENCE_NG.equals(
+                        defaultConfigNG.stream().sorted().toList()),
+                "Named groups returned by engine: " + defaultConfigNG);
+    }
+}

From 26aab3cccdbcf98c329c8d67093eb2dbf4b164e5 Mon Sep 17 00:00:00 2001
From: Patricio Chilano Mateo 
Date: Thu, 22 Jan 2026 14:56:23 +0000
Subject: [PATCH 146/328] 8373120: Virtual thread stuck in BLOCKED state

Co-authored-by: Alan Bateman 
Reviewed-by: alanb
---
 .../classes/java/lang/VirtualThread.java      |  25 ++--
 .../stress/NotifiedThenTimedOutWait.java      | 134 ++++++++++++++++++
 2 files changed, 148 insertions(+), 11 deletions(-)
 create mode 100644 test/jdk/java/lang/Thread/virtual/stress/NotifiedThenTimedOutWait.java

diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java
index 93862db9105..5526618c67b 100644
--- a/src/java.base/share/classes/java/lang/VirtualThread.java
+++ b/src/java.base/share/classes/java/lang/VirtualThread.java
@@ -620,9 +620,12 @@ final class VirtualThread extends BaseVirtualThread {
         // Object.wait
         if (s == WAITING || s == TIMED_WAITING) {
             int newState;
+            boolean blocked;
             boolean interruptible = interruptibleWait;
             if (s == WAITING) {
                 setState(newState = WAIT);
+                // may have been notified while in transition
+                blocked = notified && compareAndSetState(WAIT, BLOCKED);
             } else {
                 // For timed-wait, a timeout task is scheduled to execute. The timeout
                 // task will change the thread state to UNBLOCKED and submit the thread
@@ -637,22 +640,22 @@ final class VirtualThread extends BaseVirtualThread {
                     byte seqNo = ++timedWaitSeqNo;
                     timeoutTask = schedule(() -> waitTimeoutExpired(seqNo), timeout, MILLISECONDS);
                     setState(newState = TIMED_WAIT);
+                    // May have been notified while in transition. This must be done while
+                    // holding the monitor to avoid changing the state of a new timed wait call.
+                    blocked = notified && compareAndSetState(TIMED_WAIT, BLOCKED);
                 }
             }
 
-            // may have been notified while in transition to wait state
-            if (notified && compareAndSetState(newState, BLOCKED)) {
-                // may have even been unblocked already
+            if (blocked) {
+                // may have been unblocked already
                 if (blockPermit && compareAndSetState(BLOCKED, UNBLOCKED)) {
-                    submitRunContinuation();
+                    lazySubmitRunContinuation();
+                }
+            } else {
+                // may have been interrupted while in transition to wait state
+                if (interruptible && interrupted && compareAndSetState(newState, UNBLOCKED)) {
+                    lazySubmitRunContinuation();
                 }
-                return;
-            }
-
-            // may have been interrupted while in transition to wait state
-            if (interruptible && interrupted && compareAndSetState(newState, UNBLOCKED)) {
-                submitRunContinuation();
-                return;
             }
             return;
         }
diff --git a/test/jdk/java/lang/Thread/virtual/stress/NotifiedThenTimedOutWait.java b/test/jdk/java/lang/Thread/virtual/stress/NotifiedThenTimedOutWait.java
new file mode 100644
index 00000000000..0734a794b90
--- /dev/null
+++ b/test/jdk/java/lang/Thread/virtual/stress/NotifiedThenTimedOutWait.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2026, 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 8373120
+ * @summary Stress test two consecutive timed Object.wait calls where only the first one is notified.
+ * @run main/othervm -XX:CompileCommand=exclude,java.lang.VirtualThread::afterYield NotifiedThenTimedOutWait 1 100 100
+ */
+
+/*
+ * @test
+ * @run main/othervm -XX:CompileCommand=exclude,java.lang.VirtualThread::afterYield NotifiedThenTimedOutWait 2 100 100
+ */
+
+import java.time.Instant;
+import java.util.concurrent.Phaser;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadLocalRandom;
+
+public class NotifiedThenTimedOutWait {
+    public static void main(String[] args) throws Exception {
+        int race = (args.length > 0) ? Integer.parseInt(args[0]) : 1;
+        int nruns = (args.length > 1) ? Integer.parseInt(args[1]) : 100;
+        int iterations = (args.length > 2) ? Integer.parseInt(args[2]) : 100;
+
+        for (int i = 1; i <= nruns; i++) {
+            System.out.println(Instant.now() + " => " + i + " of " + nruns);
+            switch (race) {
+                case 1 -> race1(iterations);
+                case 2 -> race2(iterations);
+            }
+        }
+    }
+
+    /**
+     * Barrier in synchronized block.
+     */
+    private static void race1(int iterations) throws InterruptedException {
+        final int timeout = 1;
+        var lock = new Object();
+        var start = new Phaser(2);
+        var end = new Phaser(2);
+
+        var vthread = Thread.ofVirtual().start(() -> {
+            try {
+                for (int j = 0; j < iterations; j++) {
+                    synchronized (lock) {
+                        start.arriveAndAwaitAdvance();
+                        lock.wait(timeout);
+                        lock.wait(timeout);
+                    }
+                    end.arriveAndAwaitAdvance();
+                }
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        });
+
+        ThreadFactory factory = ThreadLocalRandom.current().nextBoolean()
+                    ? Thread.ofPlatform().factory() : Thread.ofVirtual().factory();
+        var notifier = factory.newThread(() -> {
+            for (int j = 0; j < iterations; j++) {
+                start.arriveAndAwaitAdvance();
+                synchronized (lock) {
+                    lock.notify();
+                }
+                end.arriveAndAwaitAdvance();
+            }
+        });
+        notifier.start();
+
+        vthread.join();
+        notifier.join();
+    }
+
+    /**
+     * Barrier before synchronized block.
+     */
+    private static void race2(int iterations) throws InterruptedException {
+        final int timeout = 1;
+        var lock = new Object();
+        var start = new Phaser(2);
+
+        var vthread = Thread.startVirtualThread(() -> {
+            try {
+                for (int i = 0; i < iterations; i++) {
+                    start.arriveAndAwaitAdvance();
+                    synchronized (lock) {
+                        lock.wait(timeout);
+                        lock.wait(timeout);
+                    }
+                }
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        });
+
+        ThreadFactory factory = ThreadLocalRandom.current().nextBoolean()
+                    ? Thread.ofPlatform().factory() : Thread.ofVirtual().factory();
+        var notifier = factory.newThread(() -> {
+            for (int i = 0; i < iterations; i++) {
+                start.arriveAndAwaitAdvance();
+                synchronized (lock) {
+                    lock.notify();
+                }
+            }
+        });
+        notifier.start();
+
+        vthread.join();
+        notifier.join();
+    }
+}

From 07f6617e0b2752b538b6c43250dd0bb65fd8c695 Mon Sep 17 00:00:00 2001
From: Brian Burkhalter 
Date: Thu, 22 Jan 2026 16:11:33 +0000
Subject: [PATCH 147/328] 8367284: (fs) Support current working directory
 target in SecureDirectoryStream.move

Reviewed-by: alanb
---
 .../java/nio/file/SecureDirectoryStream.java  | 15 ++++++-----
 .../sun/nio/fs/UnixSecureDirectoryStream.java | 15 ++++++-----
 .../nio/file/DirectoryStream/SecureDS.java    | 27 +++++++++++++++----
 3 files changed, 38 insertions(+), 19 deletions(-)

diff --git a/src/java.base/share/classes/java/nio/file/SecureDirectoryStream.java b/src/java.base/share/classes/java/nio/file/SecureDirectoryStream.java
index 4348c60f5e2..92a292bbac6 100644
--- a/src/java.base/share/classes/java/nio/file/SecureDirectoryStream.java
+++ b/src/java.base/share/classes/java/nio/file/SecureDirectoryStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2026, 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
@@ -185,8 +185,8 @@ public interface SecureDirectoryStream
     /**
      * Move a file from this directory to another directory.
      *
-     * 

This method works in a similar manner to {@link Files#move move} - * method when the {@link StandardCopyOption#ATOMIC_MOVE ATOMIC_MOVE} option + *

This method works in a similar manner to {@link Files#move Files.move} + * when the {@link StandardCopyOption#ATOMIC_MOVE ATOMIC_MOVE} option * is specified. That is, this method moves a file as an atomic file system * operation. If the {@code srcpath} parameter is an {@link Path#isAbsolute * absolute} path then it locates the source file. If the parameter is a @@ -194,14 +194,15 @@ public interface SecureDirectoryStream * the {@code targetpath} parameter is absolute then it locates the target * file (the {@code targetdir} parameter is ignored). If the parameter is * a relative path it is located relative to the open directory identified - * by the {@code targetdir} parameter. In all cases, if the target file - * exists then it is implementation specific if it is replaced or this - * method fails. + * by the {@code targetdir} parameter, unless {@code targetdir} is + * {@code null}, in which case it is located relative to the current + * working directory. In all cases, if the target file exists then it is + * implementation specific if it is replaced or this method fails. * * @param srcpath * the name of the file to move * @param targetdir - * the destination directory + * the destination directory; can be {@code null} * @param targetpath * the name to give the file in the destination directory * diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixSecureDirectoryStream.java b/src/java.base/unix/classes/sun/nio/fs/UnixSecureDirectoryStream.java index 5c0693870e6..bafcd06d9e7 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixSecureDirectoryStream.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixSecureDirectoryStream.java @@ -202,21 +202,21 @@ class UnixSecureDirectoryStream { UnixPath from = getName(fromObj); UnixPath to = getName(toObj); - if (dir == null) - throw new NullPointerException(); - if (!(dir instanceof UnixSecureDirectoryStream)) + if (dir != null && !(dir instanceof UnixSecureDirectoryStream)) throw new ProviderMismatchException(); UnixSecureDirectoryStream that = (UnixSecureDirectoryStream)dir; + int todfd = that != null ? that.dfd : AT_FDCWD; // lock ordering doesn't matter this.ds.readLock().lock(); try { - that.ds.readLock().lock(); + if (that != null) + that.ds.readLock().lock(); try { - if (!this.ds.isOpen() || !that.ds.isOpen()) + if (!this.ds.isOpen() || (that != null && !that.ds.isOpen())) throw new ClosedDirectoryStreamException(); try { - renameat(this.dfd, from.asByteArray(), that.dfd, to.asByteArray()); + renameat(this.dfd, from.asByteArray(), todfd, to.asByteArray()); } catch (UnixException x) { if (x.errno() == EXDEV) { throw new AtomicMoveNotSupportedException( @@ -225,7 +225,8 @@ class UnixSecureDirectoryStream x.rethrowAsIOException(from, to); } } finally { - that.ds.readLock().unlock(); + if (that != null) + that.ds.readLock().unlock(); } } finally { this.ds.readLock().unlock(); diff --git a/test/jdk/java/nio/file/DirectoryStream/SecureDS.java b/test/jdk/java/nio/file/DirectoryStream/SecureDS.java index d5d4b1904ea..21204ba980a 100644 --- a/test/jdk/java/nio/file/DirectoryStream/SecureDS.java +++ b/test/jdk/java/nio/file/DirectoryStream/SecureDS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, 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 @@ -292,6 +292,27 @@ public class SecureDS { } } + // Test: move to cwd + final String TEXT = "Sous le pont Mirabeau coule la Seine"; + Path file = Path.of("file"); + Path filepath = dir.resolve(file); + Path cwd = Path.of(System.getProperty("user.dir")); + Path result = cwd.resolve(file); + Files.writeString(filepath, TEXT); + try (DirectoryStream ds = Files.newDirectoryStream(dir);) { + if (ds instanceof SecureDirectoryStream sds) { + sds.move(file, null, file); + if (!TEXT.equals(Files.readString(result))) + throw new RuntimeException(result + " content incorrect"); + } else { + throw new RuntimeException("Not a SecureDirectoryStream"); + } + } finally { + boolean fileDeleted = Files.deleteIfExists(filepath); + if (!fileDeleted) + Files.deleteIfExists(result); + } + // clean-up delete(dir1); delete(dir2); @@ -334,10 +355,6 @@ public class SecureDS { stream.move(null, stream, file); shouldNotGetHere(); } catch (NullPointerException x) { } - try { - stream.move(file, null, file); - shouldNotGetHere(); - } catch (NullPointerException x) { } try { stream.move(file, stream, null); shouldNotGetHere(); From 8c82b58db960a178566514731e1f8dcbc59b0161 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Thu, 22 Jan 2026 16:36:24 +0000 Subject: [PATCH 148/328] 8286258: [Accessibility,macOS,VoiceOver] VoiceOver reads the spinner value wrong and sometime partially Reviewed-by: psadhukhan, asemenov --- .../awt/a11y/NavigableTextAccessibility.h | 3 +- .../awt/a11y/NavigableTextAccessibility.m | 27 +++++- .../awt/a11y/SpinboxAccessibility.m | 27 +++++- .../CustomSpinnerAccessibilityTest.java | 86 +++++++++++++++++++ 4 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 test/jdk/javax/accessibility/JSpinner/CustomSpinnerAccessibilityTest.java diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.h index ebf314c7394..9a528879a5d 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, JetBrains s.r.o.. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -29,5 +29,6 @@ @interface NavigableTextAccessibility : CommonComponentAccessibility @property(readonly) BOOL accessibleIsPasswordText; +@property BOOL announceEditUpdates; @end diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.m index 138d502f10f..8e241e65b96 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, JetBrains s.r.o.. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -60,6 +60,22 @@ static jmethodID sjm_getAccessibleEditableText = NULL; return [fJavaRole isEqualToString:@"passwordtext"]; } +- (id)init { + self = [super init]; + if (self) { + _announceEditUpdates = YES; + } + return self; +} + +- (void)suppressEditUpdates { + _announceEditUpdates = NO; +} + +- (void)resumeEditUpdates { + _announceEditUpdates = YES; +} + // NSAccessibilityElement protocol methods - (NSRect)accessibilityFrameForRange:(NSRange)range @@ -117,6 +133,9 @@ static jmethodID sjm_getAccessibleEditableText = NULL; - (NSString *)accessibilityStringForRange:(NSRange)range { + if (!_announceEditUpdates) { + return @""; + } JNIEnv *env = [ThreadUtilities getJNIEnv]; GET_CACCESSIBLETEXT_CLASS_RETURN(nil); DECLARE_STATIC_METHOD_RETURN(jm_getStringForRange, sjc_CAccessibleText, "getStringForRange", @@ -306,6 +325,12 @@ static jmethodID sjm_getAccessibleEditableText = NULL; return [super accessibilityParent]; } +- (void)postSelectedTextChanged +{ + [super postSelectedTextChanged]; + [self resumeEditUpdates]; +} + /* * Other text methods - (NSRange)accessibilitySharedCharacterRange; diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/SpinboxAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/SpinboxAccessibility.m index 4dac6bd93f9..0cec7f3eb2c 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/SpinboxAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/SpinboxAccessibility.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ */ #import "SpinboxAccessibility.h" +#import "ThreadUtilities.h" #define INCREMENT 0 #define DECREMENT 1 @@ -44,7 +45,15 @@ - (id _Nullable)accessibilityValue { - return [super accessibilityValue]; + id val = [super accessibilityValue]; + NSArray *clist = [super accessibilityChildren]; + for (NSUInteger i = 0; i < [clist count]; i++) { + id child = [clist objectAtIndex:i]; + if ([child conformsToProtocol:@protocol(NSAccessibilityNavigableStaticText)]) { + val = [child accessibilityValue]; + } + } + return val; } - (BOOL)accessibilityPerformIncrement @@ -68,4 +77,18 @@ return [super accessibilityParent]; } +- (void)postValueChanged +{ + AWT_ASSERT_APPKIT_THREAD; + NSAccessibilityPostNotification(self, NSAccessibilityValueChangedNotification); + NSArray *clist = [super accessibilityChildren]; + for (NSUInteger i = 0; i < [clist count]; i++) { + id child = [clist objectAtIndex:i]; + if ([child conformsToProtocol:@protocol(NSAccessibilityNavigableStaticText)]) { + NSAccessibilityPostNotification(child, NSAccessibilityLayoutChangedNotification); + [child suppressEditUpdates]; + } + } +} + @end diff --git a/test/jdk/javax/accessibility/JSpinner/CustomSpinnerAccessibilityTest.java b/test/jdk/javax/accessibility/JSpinner/CustomSpinnerAccessibilityTest.java new file mode 100644 index 00000000000..12c98c95110 --- /dev/null +++ b/test/jdk/javax/accessibility/JSpinner/CustomSpinnerAccessibilityTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2026, 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.awt.GridLayout; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.SpinnerListModel; + +/* + * @test + * @bug 8286258 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @requires (os.family == "mac") + * @summary Checks that JSpinner with custom model announces + * the value every time it is changed + * @run main/manual CustomSpinnerAccessibilityTest + */ + +public class CustomSpinnerAccessibilityTest extends JPanel { + private static final String INSTRUCTIONS = """ + 1. Turn on VoiceOver + 2. In the window named "Test UI" click on the text editor inside the + spinner component + 3. Using up and down arrows change current month + 4. Wait for the VoiceOver to finish speaking + 5. Repeat steps 3 and 4 couple more times + + If every time value of the spinner is changed VoiceOver + announces the new value click "Pass". + If instead the value is narrated only partially + and the new value is never fully narrated press "Fail". + """; + + public CustomSpinnerAccessibilityTest() { + super(new GridLayout(0, 2)); + String[] monthStrings = new java.text.DateFormatSymbols().getMonths(); + int lastIndex = monthStrings.length - 1; + if (monthStrings[lastIndex] == null + || monthStrings[lastIndex].length() <= 0) { + String[] tmp = new String[lastIndex]; + System.arraycopy(monthStrings, 0, + tmp, 0, lastIndex); + monthStrings = tmp; + } + + SpinnerListModel model = new SpinnerListModel(monthStrings); + JLabel label = new JLabel("Month: "); + add(label); + JSpinner spinner = new JSpinner(model); + label.setLabelFor(spinner); + add(spinner); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Custom Spinner Accessibility Test") + .instructions(INSTRUCTIONS) + .testUI(CustomSpinnerAccessibilityTest::new) + .build() + .awaitAndCheck(); + } +} From 5dfda66e13df5a88a66a6e4b1ae1bcd4e20ac674 Mon Sep 17 00:00:00 2001 From: Henry Jen Date: Thu, 22 Jan 2026 17:21:44 +0000 Subject: [PATCH 149/328] 8373928: 4 Dangling pointer defect groups in java.c Reviewed-by: bpb, alanb, jpai, jwaters --- src/java.base/share/native/libjli/java.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/native/libjli/java.c b/src/java.base/share/native/libjli/java.c index 6072bff50c6..4621ab588d1 100644 --- a/src/java.base/share/native/libjli/java.c +++ b/src/java.base/share/native/libjli/java.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2026, 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 @@ -1505,6 +1505,7 @@ InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn) r = ifn->CreateJavaVM(pvm, (void **)penv, &args); JLI_MemFree(options); + options = NULL; return r == JNI_OK; } @@ -2203,6 +2204,7 @@ FreeKnownVMs() knownVMs[i].name = NULL; } JLI_MemFree(knownVMs); + knownVMs = NULL; } /* @@ -2276,8 +2278,9 @@ ShowSplashScreen() (void)UnsetEnv(SPLASH_JAR_ENV_ENTRY); JLI_MemFree(splash_jar_entry); + splash_jar_entry = NULL; JLI_MemFree(splash_file_entry); - + splash_file_entry = NULL; } static const char* GetFullVersion() From 96a2649e29b8b4ff9b65b2314d430bc7637c5c61 Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Thu, 22 Jan 2026 17:41:00 +0000 Subject: [PATCH 150/328] 8373408: SHA1withECDSA is not required for ECDHE and ECDSA Reviewed-by: djelinski, ascarpino --- src/java.base/share/classes/sun/security/ssl/JsseJce.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/JsseJce.java b/src/java.base/share/classes/sun/security/ssl/JsseJce.java index 3ffc2d84168..1e610eeab1d 100644 --- a/src/java.base/share/classes/sun/security/ssl/JsseJce.java +++ b/src/java.base/share/classes/sun/security/ssl/JsseJce.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -165,7 +165,6 @@ final class JsseJce { static { boolean mediator = true; try { - Signature.getInstance(SIGNATURE_ECDSA); Signature.getInstance(SIGNATURE_RAWECDSA); KeyAgreement.getInstance("ECDH"); KeyFactory.getInstance("EC"); From f3121d10237a933087dde926f83a12ce826cde02 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 22 Jan 2026 20:16:44 +0000 Subject: [PATCH 151/328] 8373931: Test javax/sound/sampled/Clip/AutoCloseTimeCheck.java timed out Reviewed-by: dholmes, dnguyen, kizune --- test/jdk/javax/sound/sampled/Clip/AutoCloseTimeCheck.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/javax/sound/sampled/Clip/AutoCloseTimeCheck.java b/test/jdk/javax/sound/sampled/Clip/AutoCloseTimeCheck.java index f823175ede8..edacc50fa42 100644 --- a/test/jdk/javax/sound/sampled/Clip/AutoCloseTimeCheck.java +++ b/test/jdk/javax/sound/sampled/Clip/AutoCloseTimeCheck.java @@ -39,6 +39,7 @@ import static javax.sound.sampled.AudioSystem.NOT_SPECIFIED; /** * @test + * @key sound * @bug 8202264 */ public final class AutoCloseTimeCheck { From d6ebcf8a4f42b8e157083be90271e0df3b631033 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Thu, 22 Jan 2026 21:28:57 +0000 Subject: [PATCH 152/328] 8357471: GenShen: Share collector reserves between young and old Reviewed-by: wkemper --- .../shenandoahAdaptiveHeuristics.cpp | 7 +- .../shenandoahAdaptiveHeuristics.hpp | 6 +- .../shenandoahAggressiveHeuristics.cpp | 7 +- .../shenandoahAggressiveHeuristics.hpp | 6 +- .../shenandoahCompactHeuristics.cpp | 7 +- .../shenandoahCompactHeuristics.hpp | 6 +- .../shenandoahGenerationalHeuristics.cpp | 20 +- .../shenandoahGenerationalHeuristics.hpp | 2 +- .../heuristics/shenandoahGlobalHeuristics.cpp | 244 +++++++--- .../heuristics/shenandoahGlobalHeuristics.hpp | 6 +- .../heuristics/shenandoahHeuristics.cpp | 4 +- .../heuristics/shenandoahHeuristics.hpp | 13 +- .../heuristics/shenandoahOldHeuristics.cpp | 380 +++++++++------ .../heuristics/shenandoahOldHeuristics.hpp | 52 +- .../shenandoahPassiveHeuristics.cpp | 7 +- .../shenandoahPassiveHeuristics.hpp | 6 +- .../heuristics/shenandoahStaticHeuristics.cpp | 7 +- .../heuristics/shenandoahStaticHeuristics.hpp | 6 +- .../heuristics/shenandoahYoungHeuristics.cpp | 17 +- .../heuristics/shenandoahYoungHeuristics.hpp | 6 +- .../gc/shenandoah/shenandoahCollectionSet.cpp | 4 + .../gc/shenandoah/shenandoahCollectionSet.hpp | 7 + .../gc/shenandoah/shenandoahConcurrentGC.cpp | 12 +- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 452 ++++++++++-------- .../share/gc/shenandoah/shenandoahFreeSet.hpp | 94 ++-- .../share/gc/shenandoah/shenandoahFullGC.cpp | 10 +- .../gc/shenandoah/shenandoahGeneration.cpp | 135 +++--- .../gc/shenandoah/shenandoahGeneration.hpp | 21 +- .../shenandoahGenerationalFullGC.cpp | 10 +- .../shenandoah/shenandoahGenerationalHeap.cpp | 222 ++++++--- .../shenandoah/shenandoahGenerationalHeap.hpp | 2 +- .../share/gc/shenandoah/shenandoahHeap.cpp | 47 +- .../share/gc/shenandoah/shenandoahHeap.hpp | 2 + .../gc/shenandoah/shenandoahHeapRegion.cpp | 4 + .../share/gc/shenandoah/shenandoahOldGC.cpp | 9 +- .../gc/shenandoah/shenandoahOldGeneration.cpp | 3 +- .../gc/shenandoah/shenandoahOldGeneration.hpp | 4 +- .../shenandoah/shenandoahScanRemembered.cpp | 3 +- .../gc/shenandoah/shenandoahVerifier.cpp | 9 +- .../gc/shenandoah/shenandoah_globals.hpp | 35 +- .../test_shenandoahOldHeuristic.cpp | 48 +- 41 files changed, 1228 insertions(+), 714 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp index 7a8bd55c795..46d9f19d35f 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp @@ -68,9 +68,9 @@ ShenandoahAdaptiveHeuristics::ShenandoahAdaptiveHeuristics(ShenandoahSpaceInfo* ShenandoahAdaptiveHeuristics::~ShenandoahAdaptiveHeuristics() {} -void ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, - RegionData* data, size_t size, - size_t actual_free) { +size_t ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, + RegionData* data, size_t size, + size_t actual_free) { size_t garbage_threshold = ShenandoahHeapRegion::region_size_bytes() * ShenandoahGarbageThreshold / 100; // The logic for cset selection in adaptive is as follows: @@ -124,6 +124,7 @@ void ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(Shenand cur_garbage = new_garbage; } } + return 0; } void ShenandoahAdaptiveHeuristics::record_cycle_start() { diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp index 1ba18f37c2b..c4fdf819391 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp @@ -108,9 +108,9 @@ public: virtual ~ShenandoahAdaptiveHeuristics(); - virtual void choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, - RegionData* data, size_t size, - size_t actual_free) override; + virtual size_t choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, + RegionData* data, size_t size, + size_t actual_free) override; virtual void record_cycle_start() override; virtual void record_success_concurrent() override; diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp index a833e39631c..990b59ec853 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp @@ -39,15 +39,16 @@ ShenandoahAggressiveHeuristics::ShenandoahAggressiveHeuristics(ShenandoahSpaceIn SHENANDOAH_ERGO_ENABLE_FLAG(ShenandoahEvacReserveOverflow); } -void ShenandoahAggressiveHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, - RegionData* data, size_t size, - size_t free) { +size_t ShenandoahAggressiveHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, + RegionData* data, size_t size, + size_t free) { for (size_t idx = 0; idx < size; idx++) { ShenandoahHeapRegion* r = data[idx].get_region(); if (r->garbage() > 0) { cset->add_region(r); } } + return 0; } bool ShenandoahAggressiveHeuristics::should_start_gc() { diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.hpp index 5075258f1ce..25c8635489f 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.hpp @@ -35,9 +35,9 @@ class ShenandoahAggressiveHeuristics : public ShenandoahHeuristics { public: ShenandoahAggressiveHeuristics(ShenandoahSpaceInfo* space_info); - virtual void choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, - RegionData* data, size_t size, - size_t free); + virtual size_t choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, + RegionData* data, size_t size, + size_t free); virtual bool should_start_gc(); diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp index 28673b28612..09a8394a4b1 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp @@ -76,9 +76,9 @@ bool ShenandoahCompactHeuristics::should_start_gc() { return ShenandoahHeuristics::should_start_gc(); } -void ShenandoahCompactHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, - RegionData* data, size_t size, - size_t actual_free) { +size_t ShenandoahCompactHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, + RegionData* data, size_t size, + size_t actual_free) { // Do not select too large CSet that would overflow the available free space size_t max_cset = actual_free * 3 / 4; @@ -97,4 +97,5 @@ void ShenandoahCompactHeuristics::choose_collection_set_from_regiondata(Shenando cset->add_region(r); } } + return 0; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.hpp index 21ec99eabc0..4988d5d495d 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.hpp @@ -37,9 +37,9 @@ public: virtual bool should_start_gc(); - virtual void choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, - RegionData* data, size_t size, - size_t actual_free); + virtual size_t choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, + RegionData* data, size_t size, + size_t actual_free); virtual const char* name() { return "Compact"; } virtual bool is_diagnostic() { return false; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp index b14d72f249b..ee315ce5c7e 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp @@ -37,7 +37,7 @@ ShenandoahGenerationalHeuristics::ShenandoahGenerationalHeuristics(ShenandoahGen : ShenandoahAdaptiveHeuristics(generation), _generation(generation) { } -void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set) { +size_t ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set) { assert(collection_set->is_empty(), "Must be empty"); auto heap = ShenandoahGenerationalHeap::heap(); @@ -168,16 +168,12 @@ void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectio byte_size_in_proper_unit(total_garbage), proper_unit_for_byte_size(total_garbage)); size_t immediate_percent = (total_garbage == 0) ? 0 : (immediate_garbage * 100 / total_garbage); - bool doing_promote_in_place = (humongous_regions_promoted + regular_regions_promoted_in_place > 0); - if (doing_promote_in_place || (preselected_candidates > 0) || (immediate_percent <= ShenandoahImmediateThreshold)) { - // Only young collections need to prime the collection set. - if (_generation->is_young()) { - heap->old_generation()->heuristics()->prime_collection_set(collection_set); - } + size_t add_regions_to_old = 0; + if (doing_promote_in_place || (preselected_candidates > 0) || (immediate_percent <= ShenandoahImmediateThreshold)) { // Call the subclasses to add young-gen regions into the collection set. - choose_collection_set_from_regiondata(collection_set, candidates, cand_idx, immediate_garbage + free); + add_regions_to_old = choose_collection_set_from_regiondata(collection_set, candidates, cand_idx, immediate_garbage + free); } if (collection_set->has_old_regions()) { @@ -194,6 +190,7 @@ void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectio regular_regions_promoted_free, immediate_regions, immediate_garbage); + return add_regions_to_old; } @@ -210,13 +207,6 @@ size_t ShenandoahGenerationalHeuristics::add_preselected_regions_to_collection_s assert(ShenandoahGenerationalHeap::heap()->is_tenurable(r), "Preselected regions must have tenure age"); // Entire region will be promoted, This region does not impact young-gen or old-gen evacuation reserve. // This region has been pre-selected and its impact on promotion reserve is already accounted for. - - // r->used() is r->garbage() + r->get_live_data_bytes() - // Since all live data in this region is being evacuated from young-gen, it is as if this memory - // is garbage insofar as young-gen is concerned. Counting this as garbage reduces the need to - // reclaim highly utilized young-gen regions just for the sake of finding min_garbage to reclaim - // within young-gen memory. - cur_young_garbage += r->garbage(); cset->add_region(r); } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp index 31c016bb4b7..9b4c93af9b4 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp @@ -44,7 +44,7 @@ class ShenandoahGenerationalHeuristics : public ShenandoahAdaptiveHeuristics { public: explicit ShenandoahGenerationalHeuristics(ShenandoahGeneration* generation); - void choose_collection_set(ShenandoahCollectionSet* collection_set) override; + size_t choose_collection_set(ShenandoahCollectionSet* collection_set) override; protected: ShenandoahGeneration* _generation; diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp index 51805b205dd..f47371c14d5 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp @@ -24,6 +24,7 @@ */ #include "gc/shenandoah/heuristics/shenandoahGlobalHeuristics.hpp" +#include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp" #include "gc/shenandoah/shenandoahGlobalGeneration.hpp" @@ -35,13 +36,14 @@ ShenandoahGlobalHeuristics::ShenandoahGlobalHeuristics(ShenandoahGlobalGeneratio } -void ShenandoahGlobalHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, - RegionData* data, size_t size, - size_t actual_free) { +size_t ShenandoahGlobalHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, + RegionData* data, size_t size, + size_t actual_free) { // Better select garbage-first regions QuickSort::sort(data, (int) size, compare_by_garbage); choose_global_collection_set(cset, data, size, actual_free, 0 /* cur_young_garbage */); + return 0; } @@ -49,94 +51,212 @@ void ShenandoahGlobalHeuristics::choose_global_collection_set(ShenandoahCollecti const ShenandoahHeuristics::RegionData* data, size_t size, size_t actual_free, size_t cur_young_garbage) const { + shenandoah_assert_heaplocked_or_safepoint(); auto heap = ShenandoahGenerationalHeap::heap(); + auto free_set = heap->free_set(); size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes(); size_t capacity = heap->soft_max_capacity(); + size_t garbage_threshold = region_size_bytes * ShenandoahGarbageThreshold / 100; size_t ignore_threshold = region_size_bytes * ShenandoahIgnoreGarbageThreshold / 100; size_t young_evac_reserve = heap->young_generation()->get_evacuation_reserve(); + size_t original_young_evac_reserve = young_evac_reserve; size_t old_evac_reserve = heap->old_generation()->get_evacuation_reserve(); - size_t max_young_cset = (size_t) (young_evac_reserve / ShenandoahEvacWaste); - size_t young_cur_cset = 0; - size_t max_old_cset = (size_t) (old_evac_reserve / ShenandoahOldEvacWaste); - size_t old_cur_cset = 0; + size_t old_promo_reserve = heap->old_generation()->get_promoted_reserve(); - // Figure out how many unaffiliated young regions are dedicated to mutator and to evacuator. Allow the young - // collector's unaffiliated regions to be transferred to old-gen if old-gen has more easily reclaimed garbage - // than young-gen. At the end of this cycle, any excess regions remaining in old-gen will be transferred back - // to young. Do not transfer the mutator's unaffiliated regions to old-gen. Those must remain available - // to the mutator as it needs to be able to consume this memory during concurrent GC. - - size_t unaffiliated_young_regions = heap->young_generation()->free_unaffiliated_regions(); + size_t unaffiliated_young_regions = free_set->collector_unaffiliated_regions(); size_t unaffiliated_young_memory = unaffiliated_young_regions * region_size_bytes; + size_t unaffiliated_old_regions = free_set->old_collector_unaffiliated_regions(); + size_t unaffiliated_old_memory = unaffiliated_old_regions * region_size_bytes; - if (unaffiliated_young_memory > max_young_cset) { - size_t unaffiliated_mutator_memory = unaffiliated_young_memory - max_young_cset; - unaffiliated_young_memory -= unaffiliated_mutator_memory; - unaffiliated_young_regions = unaffiliated_young_memory / region_size_bytes; // round down - unaffiliated_young_memory = unaffiliated_young_regions * region_size_bytes; + // Figure out how many unaffiliated regions are dedicated to Collector and OldCollector reserves. Let these + // be shuffled between young and old generations in order to expedite evacuation of whichever regions have the + // most garbage, regardless of whether these garbage-first regions reside in young or old generation. + // Excess reserves will be transferred back to the mutator after collection set has been chosen. At the end + // of evacuation, any reserves not consumed by evacuation will also be transferred to the mutator free set. + + // Truncate reserves to only target unaffiliated memory + size_t shared_reserve_regions = 0; + if (young_evac_reserve > unaffiliated_young_memory) { + shared_reserve_regions += unaffiliated_young_regions; + } else { + size_t delta_regions = young_evac_reserve / region_size_bytes; + shared_reserve_regions += delta_regions; } + young_evac_reserve = 0; + size_t total_old_reserve = old_evac_reserve + old_promo_reserve; + if (total_old_reserve > unaffiliated_old_memory) { + // Give all the unaffiliated memory to the shared reserves. Leave the rest for promo reserve. + shared_reserve_regions += unaffiliated_old_regions; + old_promo_reserve = total_old_reserve - unaffiliated_old_memory; + } else { + size_t delta_regions = old_evac_reserve / region_size_bytes; + shared_reserve_regions += delta_regions; + } + old_evac_reserve = 0; + assert(shared_reserve_regions <= + (heap->young_generation()->free_unaffiliated_regions() + heap->old_generation()->free_unaffiliated_regions()), + "simple math"); - // We'll affiliate these unaffiliated regions with either old or young, depending on need. - max_young_cset -= unaffiliated_young_memory; + size_t shared_reserves = shared_reserve_regions * region_size_bytes; + size_t committed_from_shared_reserves = 0; - // Keep track of how many regions we plan to transfer from young to old. - size_t regions_transferred_to_old = 0; + size_t promo_bytes = 0; + size_t old_evac_bytes = 0; + size_t young_evac_bytes = 0; - size_t free_target = (capacity * ShenandoahMinFreeThreshold) / 100 + max_young_cset; + size_t consumed_by_promo = 0; // promo_bytes * ShenandoahPromoEvacWaste + size_t consumed_by_old_evac = 0; // old_evac_bytes * ShenandoahOldEvacWaste + size_t consumed_by_young_evac = 0; // young_evac_bytes * ShenandoahEvacWaste + + // Of the memory reclaimed by GC, some of this will need to be reserved for the next GC collection. Use the current + // young reserve as an approximation of the future Collector reserve requirement. Try to end with at least + // (capacity * ShenandoahMinFreeThreshold) / 100 bytes available to the mutator. + size_t free_target = (capacity * ShenandoahMinFreeThreshold) / 100 + original_young_evac_reserve; size_t min_garbage = (free_target > actual_free) ? (free_target - actual_free) : 0; - log_info(gc, ergo)("Adaptive CSet Selection for GLOBAL. Max Young Evacuation: %zu" - "%s, Max Old Evacuation: %zu%s, Max Either Evacuation: %zu%s, Actual Free: %zu%s.", - byte_size_in_proper_unit(max_young_cset), proper_unit_for_byte_size(max_young_cset), - byte_size_in_proper_unit(max_old_cset), proper_unit_for_byte_size(max_old_cset), - byte_size_in_proper_unit(unaffiliated_young_memory), proper_unit_for_byte_size(unaffiliated_young_memory), - byte_size_in_proper_unit(actual_free), proper_unit_for_byte_size(actual_free)); + size_t aged_regions_promoted = 0; + size_t young_regions_evacuated = 0; + size_t old_regions_evacuated = 0; + log_info(gc, ergo)("Adaptive CSet Selection for GLOBAL. Discretionary evacuation budget (for either old or young): %zu%s" + ", Actual Free: %zu%s.", + byte_size_in_proper_unit(shared_reserves), proper_unit_for_byte_size(shared_reserves), + byte_size_in_proper_unit(actual_free), proper_unit_for_byte_size(actual_free)); + + size_t cur_garbage = cur_young_garbage; for (size_t idx = 0; idx < size; idx++) { ShenandoahHeapRegion* r = data[idx].get_region(); assert(!cset->is_preselected(r->index()), "There should be no preselected regions during GLOBAL GC"); bool add_region = false; - if (r->is_old() || heap->is_tenurable(r)) { - size_t new_cset = old_cur_cset + r->get_live_data_bytes(); - if ((r->garbage() > garbage_threshold)) { - while ((new_cset > max_old_cset) && (unaffiliated_young_regions > 0)) { - unaffiliated_young_regions--; - regions_transferred_to_old++; - max_old_cset += region_size_bytes / ShenandoahOldEvacWaste; + size_t region_garbage = r->garbage(); + size_t new_garbage = cur_garbage + region_garbage; + bool add_regardless = (region_garbage > ignore_threshold) && (new_garbage < min_garbage); + size_t live_bytes = r->get_live_data_bytes(); + if (add_regardless || (region_garbage >= garbage_threshold)) { + if (r->is_old()) { + size_t anticipated_consumption = (size_t) (live_bytes * ShenandoahOldEvacWaste); + size_t new_old_consumption = consumed_by_old_evac + anticipated_consumption; + size_t new_old_evac_reserve = old_evac_reserve; + size_t proposed_old_region_expansion = 0; + while ((new_old_consumption > new_old_evac_reserve) && (committed_from_shared_reserves < shared_reserves)) { + committed_from_shared_reserves += region_size_bytes; + proposed_old_region_expansion++; + new_old_evac_reserve += region_size_bytes; } - } - if ((new_cset <= max_old_cset) && (r->garbage() > garbage_threshold)) { - add_region = true; - old_cur_cset = new_cset; - } - } else { - assert(r->is_young() && !heap->is_tenurable(r), "DeMorgan's law (assuming r->is_affiliated)"); - size_t new_cset = young_cur_cset + r->get_live_data_bytes(); - size_t region_garbage = r->garbage(); - size_t new_garbage = cur_young_garbage + region_garbage; - bool add_regardless = (region_garbage > ignore_threshold) && (new_garbage < min_garbage); - - if (add_regardless || (r->garbage() > garbage_threshold)) { - while ((new_cset > max_young_cset) && (unaffiliated_young_regions > 0)) { - unaffiliated_young_regions--; - max_young_cset += region_size_bytes / ShenandoahEvacWaste; + // If this region has free memory and we choose to place it in the collection set, its free memory is no longer + // available to hold promotion results. So we behave as if its free memory is consumed within the promotion reserve. + size_t anticipated_loss_from_promo_reserve = r->free(); + size_t new_promo_consumption = consumed_by_promo + anticipated_loss_from_promo_reserve; + size_t new_promo_reserve = old_promo_reserve; + while ((new_promo_consumption > new_promo_reserve) && (committed_from_shared_reserves < shared_reserves)) { + committed_from_shared_reserves += region_size_bytes; + proposed_old_region_expansion++; + new_promo_reserve += region_size_bytes; + } + if ((new_old_consumption <= new_old_evac_reserve) && (new_promo_consumption <= new_promo_reserve)) { + add_region = true; + old_evac_reserve = new_old_evac_reserve; + old_promo_reserve = new_promo_reserve; + old_evac_bytes += live_bytes; + consumed_by_old_evac = new_old_consumption; + consumed_by_promo = new_promo_consumption; + cur_garbage = new_garbage; + old_regions_evacuated++; + } else { + // We failed to sufficiently expand old so unwind proposed expansion + committed_from_shared_reserves -= proposed_old_region_expansion * region_size_bytes; + } + } else if (heap->is_tenurable(r)) { + size_t anticipated_consumption = (size_t) (live_bytes * ShenandoahPromoEvacWaste); + size_t new_promo_consumption = consumed_by_promo + anticipated_consumption; + size_t new_promo_reserve = old_promo_reserve; + size_t proposed_old_region_expansion = 0; + while ((new_promo_consumption > new_promo_reserve) && (committed_from_shared_reserves < shared_reserves)) { + committed_from_shared_reserves += region_size_bytes; + proposed_old_region_expansion++; + new_promo_reserve += region_size_bytes; + } + if (new_promo_consumption <= new_promo_reserve) { + add_region = true; + old_promo_reserve = new_promo_reserve; + promo_bytes += live_bytes; + consumed_by_promo = new_promo_consumption; + cur_garbage = new_garbage; + aged_regions_promoted++; + } else { + // We failed to sufficiently expand old so unwind proposed expansion + committed_from_shared_reserves -= proposed_old_region_expansion * region_size_bytes; + } + } else { + assert(r->is_young() && !heap->is_tenurable(r), "DeMorgan's law (assuming r->is_affiliated)"); + size_t anticipated_consumption = (size_t) (live_bytes * ShenandoahEvacWaste); + size_t new_young_evac_consumption = consumed_by_young_evac + anticipated_consumption; + size_t new_young_evac_reserve = young_evac_reserve; + size_t proposed_young_region_expansion = 0; + while ((new_young_evac_consumption > new_young_evac_reserve) && (committed_from_shared_reserves < shared_reserves)) { + committed_from_shared_reserves += region_size_bytes; + proposed_young_region_expansion++; + new_young_evac_reserve += region_size_bytes; + } + if (new_young_evac_consumption <= new_young_evac_reserve) { + add_region = true; + young_evac_reserve = new_young_evac_reserve; + young_evac_bytes += live_bytes; + consumed_by_young_evac = new_young_evac_consumption; + cur_garbage = new_garbage; + young_regions_evacuated++; + } else { + // We failed to sufficiently expand old so unwind proposed expansion + committed_from_shared_reserves -= proposed_young_region_expansion * region_size_bytes; } - } - if ((new_cset <= max_young_cset) && (add_regardless || (region_garbage > garbage_threshold))) { - add_region = true; - young_cur_cset = new_cset; - cur_young_garbage = new_garbage; } } if (add_region) { cset->add_region(r); } } - if (regions_transferred_to_old > 0) { - assert(young_evac_reserve > regions_transferred_to_old * region_size_bytes, "young reserve cannot be negative"); - heap->young_generation()->set_evacuation_reserve(young_evac_reserve - regions_transferred_to_old * region_size_bytes); - heap->old_generation()->set_evacuation_reserve(old_evac_reserve + regions_transferred_to_old * region_size_bytes); + + if (committed_from_shared_reserves < shared_reserves) { + // Give all the rest to promotion + old_promo_reserve += (shared_reserves - committed_from_shared_reserves); + // dead code: committed_from_shared_reserves = shared_reserves; } + + // Consider the effects of round-off: + // 1. We know that the sum over each evacuation mutiplied by Evacuation Waste is <= total evacuation reserve + // 2. However, the reserve for each individual evacuation may be rounded down. In the worst case, we will be over budget + // by the number of regions evacuated, since each region's reserve might be under-estimated by at most 1 + // 3. Likewise, if we take the sum of bytes evacuated and multiply this by the Evacuation Waste and then round down + // to nearest integer, the calculated reserve will underestimate the true reserve needs by at most 1. + // 4. This explains the adjustments to subtotals in the assert statements below. + assert(young_evac_bytes * ShenandoahEvacWaste <= young_evac_reserve + young_regions_evacuated, + "budget: %zu <= %zu", (size_t) (young_evac_bytes * ShenandoahEvacWaste), young_evac_reserve); + assert(old_evac_bytes * ShenandoahOldEvacWaste <= old_evac_reserve + old_regions_evacuated, + "budget: %zu <= %zu", (size_t) (old_evac_bytes * ShenandoahOldEvacWaste), old_evac_reserve); + assert(promo_bytes * ShenandoahPromoEvacWaste <= old_promo_reserve + aged_regions_promoted, + "budget: %zu <= %zu", (size_t) (promo_bytes * ShenandoahPromoEvacWaste), old_promo_reserve); + assert(young_evac_reserve + old_evac_reserve + old_promo_reserve <= + heap->young_generation()->get_evacuation_reserve() + heap->old_generation()->get_evacuation_reserve() + + heap->old_generation()->get_promoted_reserve(), "Exceeded budget"); + + if (heap->young_generation()->get_evacuation_reserve() < young_evac_reserve) { + size_t delta_bytes = young_evac_reserve - heap->young_generation()->get_evacuation_reserve(); + size_t delta_regions = delta_bytes / region_size_bytes; + size_t regions_to_transfer = MIN2(unaffiliated_old_regions, delta_regions); + log_info(gc)("Global GC moves %zu unaffiliated regions from old collector to young collector reserves", regions_to_transfer); + ssize_t negated_regions = -regions_to_transfer; + heap->free_set()->move_unaffiliated_regions_from_collector_to_old_collector(negated_regions); + } else if (heap->young_generation()->get_evacuation_reserve() > young_evac_reserve) { + size_t delta_bytes = heap->young_generation()->get_evacuation_reserve() - young_evac_reserve; + size_t delta_regions = delta_bytes / region_size_bytes; + size_t regions_to_transfer = MIN2(unaffiliated_young_regions, delta_regions); + log_info(gc)("Global GC moves %zu unaffiliated regions from young collector to old collector reserves", regions_to_transfer); + heap->free_set()->move_unaffiliated_regions_from_collector_to_old_collector(regions_to_transfer); + } + + heap->young_generation()->set_evacuation_reserve(young_evac_reserve); + heap->old_generation()->set_evacuation_reserve(old_evac_reserve); + heap->old_generation()->set_promoted_reserve(old_promo_reserve); } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.hpp index 1f95f75c521..e0513f60da9 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.hpp @@ -39,9 +39,9 @@ class ShenandoahGlobalHeuristics : public ShenandoahGenerationalHeuristics { public: ShenandoahGlobalHeuristics(ShenandoahGlobalGeneration* generation); - void choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, - RegionData* data, size_t size, - size_t actual_free) override; + size_t choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, + RegionData* data, size_t size, + size_t actual_free) override; private: void choose_global_collection_set(ShenandoahCollectionSet* cset, diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp index eb740cfac61..aeb64b6f1df 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp @@ -72,7 +72,7 @@ ShenandoahHeuristics::~ShenandoahHeuristics() { FREE_C_HEAP_ARRAY(RegionGarbage, _region_data); } -void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set) { +size_t ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set) { ShenandoahHeap* heap = ShenandoahHeap::heap(); assert(collection_set->is_empty(), "Must be empty"); @@ -153,8 +153,8 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec if (immediate_percent <= ShenandoahImmediateThreshold) { choose_collection_set_from_regiondata(collection_set, candidates, cand_idx, immediate_garbage + free); } - collection_set->summarize(total_garbage, immediate_garbage, immediate_regions); + return 0; } void ShenandoahHeuristics::record_cycle_start() { diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp index e1139765022..ae34a9743a9 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp @@ -183,9 +183,12 @@ protected: static int compare_by_garbage(RegionData a, RegionData b); - virtual void choose_collection_set_from_regiondata(ShenandoahCollectionSet* set, - RegionData* data, size_t data_size, - size_t free) = 0; + // This is a helper function to choose_collection_set(), returning the number of regions that need to be transferred to + // the old reserve from the young reserve in order to effectively evacuate the chosen collection set. In non-generational + // mode, the return value is 0. + virtual size_t choose_collection_set_from_regiondata(ShenandoahCollectionSet* set, + RegionData* data, size_t data_size, + size_t free) = 0; void adjust_penalty(intx step); @@ -233,7 +236,9 @@ public: virtual void record_requested_gc(); - virtual void choose_collection_set(ShenandoahCollectionSet* collection_set); + // Choose the collection set, returning the number of regions that need to be transferred to the old reserve from the young + // reserve in order to effectively evacuate the chosen collection set. In non-generational mode, the return value is 0. + virtual size_t choose_collection_set(ShenandoahCollectionSet* collection_set); virtual bool can_unload_classes(); diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp index f2c6e427ea8..f47d0cbe819 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp @@ -26,9 +26,11 @@ #include "gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" +#include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" +#include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "logging/log.hpp" #include "utilities/quickSort.hpp" @@ -77,15 +79,17 @@ ShenandoahOldHeuristics::ShenandoahOldHeuristics(ShenandoahOldGeneration* genera } bool ShenandoahOldHeuristics::prime_collection_set(ShenandoahCollectionSet* collection_set) { - if (unprocessed_old_collection_candidates() == 0) { - return false; - } + _mixed_evac_cset = collection_set; + _included_old_regions = 0; + _evacuated_old_bytes = 0; + _collected_old_bytes = 0; if (_old_generation->is_preparing_for_mark()) { // We have unprocessed old collection candidates, but the heuristic has given up on evacuating them. // This is most likely because they were _all_ pinned at the time of the last mixed evacuation (and // this in turn is most likely because there are just one or two candidate regions remaining). - log_info(gc, ergo)("Remaining " UINT32_FORMAT " old regions are being coalesced and filled", unprocessed_old_collection_candidates()); + log_info(gc, ergo)("Remaining " UINT32_FORMAT + " old regions are being coalesced and filled", unprocessed_old_collection_candidates()); return false; } @@ -111,150 +115,44 @@ bool ShenandoahOldHeuristics::prime_collection_set(ShenandoahCollectionSet* coll // of memory that can still be evacuated. We address this by reducing the evacuation budget by the amount // of live memory in that region and by the amount of unallocated memory in that region if the evacuation // budget is constrained by availability of free memory. - const size_t old_evacuation_reserve = _old_generation->get_evacuation_reserve(); - const size_t old_evacuation_budget = (size_t) ((double) old_evacuation_reserve / ShenandoahOldEvacWaste); - size_t unfragmented_available = _old_generation->free_unaffiliated_regions() * ShenandoahHeapRegion::region_size_bytes(); - size_t fragmented_available; - size_t excess_fragmented_available; + _old_evacuation_reserve = _old_generation->get_evacuation_reserve(); + _old_evacuation_budget = (size_t) ((double) _old_evacuation_reserve / ShenandoahOldEvacWaste); - if (unfragmented_available > old_evacuation_budget) { - unfragmented_available = old_evacuation_budget; - fragmented_available = 0; - excess_fragmented_available = 0; + // fragmented_available is the amount of memory within partially consumed old regions that may be required to + // hold the results of old evacuations. If all of the memory required by the old evacuation reserve is available + // in unfragmented regions (unaffiliated old regions), then fragmented_available is zero because we do not need + // to evacuate into the existing partially consumed old regions. + + // if fragmented_available is non-zero, excess_fragmented_old_budget represents the amount of fragmented memory + // that is available within old, but is not required to hold the resuilts of old evacuation. As old-gen regions + // are added into the collection set, their free memory is subtracted from excess_fragmented_old_budget until the + // excess is exhausted. For old-gen regions subsequently added to the collection set, their free memory is + // subtracted from fragmented_available and from the old_evacuation_budget (since the budget decreases when this + // fragmented_available memory decreases). After fragmented_available has been exhausted, any further old regions + // selected for the cset do not further decrease the old_evacuation_budget because all further evacuation is targeted + // to unfragmented regions. + + size_t unaffiliated_available = _old_generation->free_unaffiliated_regions() * ShenandoahHeapRegion::region_size_bytes(); + if (unaffiliated_available > _old_evacuation_reserve) { + _unspent_unfragmented_old_budget = _old_evacuation_budget; + _unspent_fragmented_old_budget = 0; + _excess_fragmented_old_budget = 0; } else { - assert(_old_generation->available() >= old_evacuation_budget, "Cannot budget more than is available"); - fragmented_available = _old_generation->available() - unfragmented_available; - assert(fragmented_available + unfragmented_available >= old_evacuation_budget, "Budgets do not add up"); - if (fragmented_available + unfragmented_available > old_evacuation_budget) { - excess_fragmented_available = (fragmented_available + unfragmented_available) - old_evacuation_budget; - fragmented_available -= excess_fragmented_available; + assert(_old_generation->available() >= _old_evacuation_reserve, "Cannot reserve more than is available"); + size_t affiliated_available = _old_generation->available() - unaffiliated_available; + assert(affiliated_available + unaffiliated_available >= _old_evacuation_reserve, "Budgets do not add up"); + if (affiliated_available + unaffiliated_available > _old_evacuation_reserve) { + _excess_fragmented_old_budget = (affiliated_available + unaffiliated_available) - _old_evacuation_reserve; + affiliated_available -= _excess_fragmented_old_budget; } + _unspent_fragmented_old_budget = (size_t) ((double) affiliated_available / ShenandoahOldEvacWaste); + _unspent_unfragmented_old_budget = (size_t) ((double) unaffiliated_available / ShenandoahOldEvacWaste); } - size_t remaining_old_evacuation_budget = old_evacuation_budget; - log_debug(gc)("Choose old regions for mixed collection: old evacuation budget: %zu%s, candidates: %u", - byte_size_in_proper_unit(old_evacuation_budget), proper_unit_for_byte_size(old_evacuation_budget), + log_debug(gc)("Choose old regions for mixed collection: old evacuation budget: " PROPERFMT ", candidates: %u", + PROPERFMTARGS(_old_evacuation_budget), unprocessed_old_collection_candidates()); - - size_t lost_evacuation_capacity = 0; - - // The number of old-gen regions that were selected as candidates for collection at the end of the most recent old-gen - // concurrent marking phase and have not yet been collected is represented by unprocessed_old_collection_candidates(). - // Candidate regions are ordered according to increasing amount of live data. If there is not sufficient room to - // evacuate region N, then there is no need to even consider evacuating region N+1. - while (unprocessed_old_collection_candidates() > 0) { - // Old collection candidates are sorted in order of decreasing garbage contained therein. - ShenandoahHeapRegion* r = next_old_collection_candidate(); - if (r == nullptr) { - break; - } - assert(r->is_regular(), "There should be no humongous regions in the set of mixed-evac candidates"); - - // If region r is evacuated to fragmented memory (to free memory within a partially used region), then we need - // to decrease the capacity of the fragmented memory by the scaled loss. - - const size_t live_data_for_evacuation = r->get_live_data_bytes(); - size_t lost_available = r->free(); - - if ((lost_available > 0) && (excess_fragmented_available > 0)) { - if (lost_available < excess_fragmented_available) { - excess_fragmented_available -= lost_available; - lost_evacuation_capacity -= lost_available; - lost_available = 0; - } else { - lost_available -= excess_fragmented_available; - lost_evacuation_capacity -= excess_fragmented_available; - excess_fragmented_available = 0; - } - } - size_t scaled_loss = (size_t) ((double) lost_available / ShenandoahOldEvacWaste); - if ((lost_available > 0) && (fragmented_available > 0)) { - if (scaled_loss + live_data_for_evacuation < fragmented_available) { - fragmented_available -= scaled_loss; - scaled_loss = 0; - } else { - // We will have to allocate this region's evacuation memory from unfragmented memory, so don't bother - // to decrement scaled_loss - } - } - if (scaled_loss > 0) { - // We were not able to account for the lost free memory within fragmented memory, so we need to take this - // allocation out of unfragmented memory. Unfragmented memory does not need to account for loss of free. - if (live_data_for_evacuation > unfragmented_available) { - // There is no room to evacuate this region or any that come after it in within the candidates array. - log_debug(gc, cset)("Not enough unfragmented memory (%zu) to hold evacuees (%zu) from region: (%zu)", - unfragmented_available, live_data_for_evacuation, r->index()); - break; - } else { - unfragmented_available -= live_data_for_evacuation; - } - } else { - // Since scaled_loss == 0, we have accounted for the loss of free memory, so we can allocate from either - // fragmented or unfragmented available memory. Use up the fragmented memory budget first. - size_t evacuation_need = live_data_for_evacuation; - - if (evacuation_need > fragmented_available) { - evacuation_need -= fragmented_available; - fragmented_available = 0; - } else { - fragmented_available -= evacuation_need; - evacuation_need = 0; - } - if (evacuation_need > unfragmented_available) { - // There is no room to evacuate this region or any that come after it in within the candidates array. - log_debug(gc, cset)("Not enough unfragmented memory (%zu) to hold evacuees (%zu) from region: (%zu)", - unfragmented_available, live_data_for_evacuation, r->index()); - break; - } else { - unfragmented_available -= evacuation_need; - // dead code: evacuation_need == 0; - } - } - collection_set->add_region(r); - included_old_regions++; - evacuated_old_bytes += live_data_for_evacuation; - collected_old_bytes += r->garbage(); - consume_old_collection_candidate(); - } - - if (_first_pinned_candidate != NOT_FOUND) { - // Need to deal with pinned regions - slide_pinned_regions_to_front(); - } - decrease_unprocessed_old_collection_candidates_live_memory(evacuated_old_bytes); - if (included_old_regions > 0) { - log_info(gc, ergo)("Old-gen piggyback evac (" UINT32_FORMAT " regions, evacuating " PROPERFMT ", reclaiming: " PROPERFMT ")", - included_old_regions, PROPERFMTARGS(evacuated_old_bytes), PROPERFMTARGS(collected_old_bytes)); - } - - if (unprocessed_old_collection_candidates() == 0) { - // We have added the last of our collection candidates to a mixed collection. - // Any triggers that occurred during mixed evacuations may no longer be valid. They can retrigger if appropriate. - clear_triggers(); - - _old_generation->complete_mixed_evacuations(); - } else if (included_old_regions == 0) { - // We have candidates, but none were included for evacuation - are they all pinned? - // or did we just not have enough room for any of them in this collection set? - // We don't want a region with a stuck pin to prevent subsequent old collections, so - // if they are all pinned we transition to a state that will allow us to make these uncollected - // (pinned) regions parsable. - if (all_candidates_are_pinned()) { - log_info(gc, ergo)("All candidate regions " UINT32_FORMAT " are pinned", unprocessed_old_collection_candidates()); - _old_generation->abandon_mixed_evacuations(); - } else { - log_info(gc, ergo)("No regions selected for mixed collection. " - "Old evacuation budget: " PROPERFMT ", Remaining evacuation budget: " PROPERFMT - ", Lost capacity: " PROPERFMT - ", Next candidate: " UINT32_FORMAT ", Last candidate: " UINT32_FORMAT, - PROPERFMTARGS(old_evacuation_reserve), - PROPERFMTARGS(remaining_old_evacuation_budget), - PROPERFMTARGS(lost_evacuation_capacity), - _next_old_collection_candidate, _last_old_collection_candidate); - } - } - - return (included_old_regions > 0); + return add_old_regions_to_cset(); } bool ShenandoahOldHeuristics::all_candidates_are_pinned() { @@ -328,6 +226,187 @@ void ShenandoahOldHeuristics::slide_pinned_regions_to_front() { _next_old_collection_candidate = write_index + 1; } +bool ShenandoahOldHeuristics::add_old_regions_to_cset() { + if (unprocessed_old_collection_candidates() == 0) { + return false; + } + _first_pinned_candidate = NOT_FOUND; + + // The number of old-gen regions that were selected as candidates for collection at the end of the most recent old-gen + // concurrent marking phase and have not yet been collected is represented by unprocessed_old_collection_candidates(). + // Candidate regions are ordered according to increasing amount of live data. If there is not sufficient room to + // evacuate region N, then there is no need to even consider evacuating region N+1. + while (unprocessed_old_collection_candidates() > 0) { + // Old collection candidates are sorted in order of decreasing garbage contained therein. + ShenandoahHeapRegion* r = next_old_collection_candidate(); + if (r == nullptr) { + break; + } + assert(r->is_regular(), "There should be no humongous regions in the set of mixed-evac candidates"); + + // If region r is evacuated to fragmented memory (to free memory within a partially used region), then we need + // to decrease the capacity of the fragmented memory by the scaled loss. + + const size_t live_data_for_evacuation = r->get_live_data_bytes(); + size_t lost_available = r->free(); + + ssize_t fragmented_delta = 0; + ssize_t unfragmented_delta = 0; + ssize_t excess_delta = 0; + + // We must decrease our mixed-evacuation budgets proportional to the lost available memory. This memory that is no + // longer available was likely "promised" to promotions, so we must decrease our mixed evacuations now. + // (e.g. if we loose 14 bytes of available old memory, we must decrease the evacuation budget by 10 bytes.) + size_t scaled_loss = (size_t) (((double) lost_available) / ShenandoahOldEvacWaste); + if (lost_available > 0) { + // We need to subtract lost_available from our working evacuation budgets + if (scaled_loss < _excess_fragmented_old_budget) { + excess_delta -= scaled_loss; + _excess_fragmented_old_budget -= scaled_loss; + } else { + excess_delta -= _excess_fragmented_old_budget; + _excess_fragmented_old_budget = 0; + } + + if (scaled_loss < _unspent_fragmented_old_budget) { + _unspent_fragmented_old_budget -= scaled_loss; + fragmented_delta = -scaled_loss; + scaled_loss = 0; + } else { + scaled_loss -= _unspent_fragmented_old_budget; + fragmented_delta = -_unspent_fragmented_old_budget; + _unspent_fragmented_old_budget = 0; + } + + if (scaled_loss < _unspent_unfragmented_old_budget) { + _unspent_unfragmented_old_budget -= scaled_loss; + unfragmented_delta = -scaled_loss; + scaled_loss = 0; + } else { + scaled_loss -= _unspent_unfragmented_old_budget; + fragmented_delta = -_unspent_unfragmented_old_budget; + _unspent_unfragmented_old_budget = 0; + } + } + + // Allocate replica from unfragmented memory if that exists + size_t evacuation_need = live_data_for_evacuation; + if (evacuation_need < _unspent_unfragmented_old_budget) { + _unspent_unfragmented_old_budget -= evacuation_need; + } else { + if (_unspent_unfragmented_old_budget > 0) { + evacuation_need -= _unspent_unfragmented_old_budget; + unfragmented_delta -= _unspent_unfragmented_old_budget; + _unspent_unfragmented_old_budget = 0; + } + // Take the remaining allocation out of fragmented available + if (_unspent_fragmented_old_budget > evacuation_need) { + _unspent_fragmented_old_budget -= evacuation_need; + } else { + // We cannot add this region into the collection set. We're done. Undo the adjustments to available. + _unspent_fragmented_old_budget -= fragmented_delta; + _unspent_unfragmented_old_budget -= unfragmented_delta; + _excess_fragmented_old_budget -= excess_delta; + break; + } + } + _mixed_evac_cset->add_region(r); + _included_old_regions++; + _evacuated_old_bytes += live_data_for_evacuation; + _collected_old_bytes += r->garbage(); + consume_old_collection_candidate(); + } + return true; +} + +bool ShenandoahOldHeuristics::finalize_mixed_evacs() { + if (_first_pinned_candidate != NOT_FOUND) { + // Need to deal with pinned regions + slide_pinned_regions_to_front(); + } + decrease_unprocessed_old_collection_candidates_live_memory(_evacuated_old_bytes); + if (_included_old_regions > 0) { + log_info(gc)("Old-gen mixed evac (%zu regions, evacuating %zu%s, reclaiming: %zu%s)", + _included_old_regions, + byte_size_in_proper_unit(_evacuated_old_bytes), proper_unit_for_byte_size(_evacuated_old_bytes), + byte_size_in_proper_unit(_collected_old_bytes), proper_unit_for_byte_size(_collected_old_bytes)); + } + + if (unprocessed_old_collection_candidates() == 0) { + // We have added the last of our collection candidates to a mixed collection. + // Any triggers that occurred during mixed evacuations may no longer be valid. They can retrigger if appropriate. + clear_triggers(); + _old_generation->complete_mixed_evacuations(); + } else if (_included_old_regions == 0) { + // We have candidates, but none were included for evacuation - are they all pinned? + // or did we just not have enough room for any of them in this collection set? + // We don't want a region with a stuck pin to prevent subsequent old collections, so + // if they are all pinned we transition to a state that will allow us to make these uncollected + // (pinned) regions parsable. + if (all_candidates_are_pinned()) { + log_info(gc)("All candidate regions " UINT32_FORMAT " are pinned", unprocessed_old_collection_candidates()); + _old_generation->abandon_mixed_evacuations(); + } else { + log_info(gc)("No regions selected for mixed collection. " + "Old evacuation budget: " PROPERFMT ", Next candidate: " UINT32_FORMAT ", Last candidate: " UINT32_FORMAT, + PROPERFMTARGS(_old_evacuation_reserve), + _next_old_collection_candidate, _last_old_collection_candidate); + } + } + return (_included_old_regions > 0); +} + +bool ShenandoahOldHeuristics::top_off_collection_set(size_t &add_regions_to_old) { + if (unprocessed_old_collection_candidates() == 0) { + add_regions_to_old = 0; + return false; + } else { + ShenandoahYoungGeneration* young_generation = _heap->young_generation(); + size_t young_unaffiliated_regions = young_generation->free_unaffiliated_regions(); + size_t max_young_cset = young_generation->get_evacuation_reserve(); + + // We have budgeted to assure the live_bytes_in_tenurable_regions() get evacuated into old generation. Young reserves + // only for untenurable region evacuations. + size_t planned_young_evac = _mixed_evac_cset->get_live_bytes_in_untenurable_regions(); + size_t consumed_from_young_cset = (size_t) (planned_young_evac * ShenandoahEvacWaste); + + size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes(); + size_t regions_required_for_collector_reserve = (consumed_from_young_cset + region_size_bytes - 1) / region_size_bytes; + + assert(consumed_from_young_cset <= max_young_cset, "sanity"); + assert(max_young_cset <= young_unaffiliated_regions * region_size_bytes, "sanity"); + + size_t regions_for_old_expansion; + if (consumed_from_young_cset < max_young_cset) { + size_t excess_young_reserves = max_young_cset - consumed_from_young_cset; + // We can only transfer empty regions from young to old. Furthermore, we must be careful to assure that the young + // Collector reserve that remains after transfer is comprised entirely of empty (unaffiliated) regions. + size_t consumed_unaffiliated_regions = (consumed_from_young_cset + region_size_bytes - 1) / region_size_bytes; + size_t available_unaffiliated_regions = ((young_unaffiliated_regions > consumed_unaffiliated_regions)? + young_unaffiliated_regions - consumed_unaffiliated_regions: 0); + regions_for_old_expansion = MIN2(available_unaffiliated_regions, excess_young_reserves / region_size_bytes); + } else { + regions_for_old_expansion = 0; + } + if (regions_for_old_expansion > 0) { + log_info(gc)("Augmenting old-gen evacuation budget from unexpended young-generation reserve by %zu regions", + regions_for_old_expansion); + add_regions_to_old = regions_for_old_expansion; + size_t budget_supplement = region_size_bytes * regions_for_old_expansion; + size_t supplement_without_waste = (size_t) (((double) budget_supplement) / ShenandoahOldEvacWaste); + _old_evacuation_budget += supplement_without_waste; + _unspent_unfragmented_old_budget += supplement_without_waste; + _old_generation->augment_evacuation_reserve(budget_supplement); + young_generation->set_evacuation_reserve(max_young_cset - budget_supplement); + + return add_old_regions_to_cset(); + } else { + add_regions_to_old = 0; + return false; + } + } +} + void ShenandoahOldHeuristics::prepare_for_old_collections() { ShenandoahHeap* heap = ShenandoahHeap::heap(); @@ -336,7 +415,6 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() { size_t immediate_garbage = 0; size_t immediate_regions = 0; size_t live_data = 0; - RegionData* candidates = _region_data; for (size_t i = 0; i < num_regions; i++) { ShenandoahHeapRegion* region = heap->get_region(i); @@ -355,10 +433,10 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() { // else, regions that were promoted in place had 0 old live data at mark start if (region->is_regular() || region->is_regular_pinned()) { - // Only place regular or pinned regions with live data into the candidate set. - // Pinned regions cannot be evacuated, but we are not actually choosing candidates - // for the collection set here. That happens later during the next young GC cycle, - // by which time, the pinned region may no longer be pinned. + // Only place regular or pinned regions with live data into the candidate set. + // Pinned regions cannot be evacuated, but we are not actually choosing candidates + // for the collection set here. That happens later during the next young GC cycle, + // by which time, the pinned region may no longer be pinned. if (!region->has_live()) { assert(!region->is_pinned(), "Pinned region should have live (pinned) objects."); region->make_trash_immediate(); @@ -561,6 +639,7 @@ unsigned int ShenandoahOldHeuristics::get_coalesce_and_fill_candidates(Shenandoa void ShenandoahOldHeuristics::abandon_collection_candidates() { _last_old_collection_candidate = 0; _next_old_collection_candidate = 0; + _live_bytes_in_unprocessed_candidates = 0; _last_old_region = 0; } @@ -805,8 +884,9 @@ bool ShenandoahOldHeuristics::is_experimental() { return true; } -void ShenandoahOldHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* set, - ShenandoahHeuristics::RegionData* data, - size_t data_size, size_t free) { +size_t ShenandoahOldHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* set, + ShenandoahHeuristics::RegionData* data, + size_t data_size, size_t free) { ShouldNotReachHere(); + return 0; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp index f38194c1ee7..97a5b1ebf24 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp @@ -102,6 +102,30 @@ private: size_t _fragmentation_first_old_region; size_t _fragmentation_last_old_region; + // State variables involved in construction of a mixed-evacuation collection set. These variables are initialized + // when client code invokes prime_collection_set(). They are consulted, and sometimes modified, when client code + // calls top_off_collection_set() to possibly expand the number of old-gen regions in a mixed evacuation cset, and by + // finalize_mixed_evacs(), which prepares the way for mixed evacuations to begin. + ShenandoahCollectionSet* _mixed_evac_cset; + size_t _evacuated_old_bytes; + size_t _collected_old_bytes; + size_t _included_old_regions; + size_t _old_evacuation_reserve; + size_t _old_evacuation_budget; + + // This represents the amount of memory that can be evacuated from old into initially empty regions during a mixed evacuation. + // This is the total amount of unfragmented free memory in old divided by ShenandoahOldEvacWaste. + size_t _unspent_unfragmented_old_budget; + + // This represents the amount of memory that can be evacuated from old into initially non-empty regions during a mixed + // evacuation. This is the total amount of initially fragmented free memory in old divided by ShenandoahOldEvacWaste. + size_t _unspent_fragmented_old_budget; + + // If there is more available memory in old than is required by the intended mixed evacuation, the amount of excess + // memory is represented by _excess_fragmented_old. To convert this value into a promotion budget, multiply by + // ShenandoahOldEvacWaste and divide by ShenandoahPromoWaste. + size_t _excess_fragmented_old_budget; + // The value of command-line argument ShenandoahOldGarbageThreshold represents the percent of garbage that must // be present within an old-generation region before that region is considered a good candidate for inclusion in // the collection set under normal circumstances. For our purposes, normal circustances are when the memory consumed @@ -131,7 +155,15 @@ private: void set_trigger_if_old_is_overgrown(); protected: - void choose_collection_set_from_regiondata(ShenandoahCollectionSet* set, RegionData* data, size_t data_size, size_t free) override; + size_t + choose_collection_set_from_regiondata(ShenandoahCollectionSet* set, RegionData* data, size_t data_size, size_t free) override; + + // This internal helper routine adds as many mixed evacuation candidate regions as fit within the old-gen evacuation budget + // to the collection set. This may be called twice to prepare for any given mixed evacuation cycle, the first time with + // a conservative old evacuation budget, and the second time with a larger more aggressive old evacuation budget. Returns + // true iff we need to finalize mixed evacs. (If no regions are added to the collection set, there is no need to finalize + // mixed evacuations.) + bool add_old_regions_to_cset(); public: explicit ShenandoahOldHeuristics(ShenandoahOldGeneration* generation, ShenandoahGenerationalHeap* gen_heap); @@ -139,8 +171,22 @@ public: // Prepare for evacuation of old-gen regions by capturing the mark results of a recently completed concurrent mark pass. void prepare_for_old_collections(); - // Return true iff the collection set is primed with at least one old-gen region. - bool prime_collection_set(ShenandoahCollectionSet* set); + // Initialize instance variables to support the preparation of a mixed-evacuation collection set. Adds as many + // old candidate regions into the collection set as can fit within the iniital conservative old evacuation budget. + // Returns true iff we need to finalize mixed evacs. + bool prime_collection_set(ShenandoahCollectionSet* collection_set); + + // If young evacuation did not consume all of its available evacuation reserve, add as many additional mixed- + // evacuation candidate regions into the collection set as will fit within this excess repurposed reserved. + // Returns true iff we need to finalize mixed evacs. Upon return, the var parameter regions_to_xfer holds the + // number of regions to transfer from young to old. + bool top_off_collection_set(size_t &add_regions_to_old); + + // Having added all eligible mixed-evacuation candidates to the collection set, this function updates the total count + // of how much old-gen memory remains to be evacuated and adjusts the representation of old-gen regions that remain to + // be evacuated, giving special attention to regions that are currently pinned. It outputs relevant log messages and + // returns true iff the collection set holds at least one unpinned mixed evacuation candidate. + bool finalize_mixed_evacs(); // How many old-collection candidates have not yet been processed? uint unprocessed_old_collection_candidates() const; diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp index b5e9cc433ea..d4a38278161 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp @@ -50,9 +50,9 @@ bool ShenandoahPassiveHeuristics::should_degenerate_cycle() { return ShenandoahDegeneratedGC; } -void ShenandoahPassiveHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, - RegionData* data, size_t size, - size_t actual_free) { +size_t ShenandoahPassiveHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, + RegionData* data, size_t size, + size_t actual_free) { assert(ShenandoahDegeneratedGC, "This path is only taken for Degenerated GC"); // Do not select too large CSet that would overflow the available free space. @@ -76,4 +76,5 @@ void ShenandoahPassiveHeuristics::choose_collection_set_from_regiondata(Shenando cset->add_region(r); } } + return 0; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.hpp index be4e91b1800..7a64fad7cc9 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.hpp @@ -46,9 +46,9 @@ public: virtual bool should_degenerate_cycle(); - virtual void choose_collection_set_from_regiondata(ShenandoahCollectionSet* set, - RegionData* data, size_t data_size, - size_t free); + virtual size_t choose_collection_set_from_regiondata(ShenandoahCollectionSet* set, + RegionData* data, size_t data_size, + size_t free); virtual const char* name() { return "Passive"; } virtual bool is_diagnostic() { return true; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp index d4d66fef6a1..3843e434781 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp @@ -59,9 +59,9 @@ bool ShenandoahStaticHeuristics::should_start_gc() { return ShenandoahHeuristics::should_start_gc(); } -void ShenandoahStaticHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, - RegionData* data, size_t size, - size_t free) { +size_t ShenandoahStaticHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, + RegionData* data, size_t size, + size_t free) { size_t threshold = ShenandoahHeapRegion::region_size_bytes() * ShenandoahGarbageThreshold / 100; for (size_t idx = 0; idx < size; idx++) { @@ -70,4 +70,5 @@ void ShenandoahStaticHeuristics::choose_collection_set_from_regiondata(Shenandoa cset->add_region(r); } } + return 0; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.hpp index 24cb5547921..27dc3c8e0ae 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.hpp @@ -40,9 +40,9 @@ public: virtual bool should_start_gc(); - virtual void choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, - RegionData* data, size_t size, - size_t free); + virtual size_t choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, + RegionData* data, size_t size, + size_t free); virtual const char* name() { return "Static"; } virtual bool is_diagnostic() { return false; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp index 15d1058d7cd..01c3873df72 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp @@ -33,11 +33,11 @@ #include "utilities/quickSort.hpp" ShenandoahYoungHeuristics::ShenandoahYoungHeuristics(ShenandoahYoungGeneration* generation) - : ShenandoahGenerationalHeuristics(generation) { + : ShenandoahGenerationalHeuristics(generation) { } -void ShenandoahYoungHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, +size_t ShenandoahYoungHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, RegionData* data, size_t size, size_t actual_free) { // See comments in ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(): @@ -48,6 +48,8 @@ void ShenandoahYoungHeuristics::choose_collection_set_from_regiondata(Shenandoah // array before younger regions that typically contain more garbage. This is one reason why, // for example, we continue examining regions even after rejecting a region that has // more live data than we can evacuate. + ShenandoahGenerationalHeap* heap = ShenandoahGenerationalHeap::heap(); + bool need_to_finalize_mixed = heap->old_generation()->heuristics()->prime_collection_set(cset); // Better select garbage-first regions QuickSort::sort(data, (int) size, compare_by_garbage); @@ -55,6 +57,17 @@ void ShenandoahYoungHeuristics::choose_collection_set_from_regiondata(Shenandoah size_t cur_young_garbage = add_preselected_regions_to_collection_set(cset, data, size); choose_young_collection_set(cset, data, size, actual_free, cur_young_garbage); + + // Especially when young-gen trigger is expedited in order to finish mixed evacuations, there may not be + // enough consolidated garbage to make effective use of young-gen evacuation reserve. If there is still + // young-gen reserve available following selection of the young-gen collection set, see if we can use + // this memory to expand the old-gen evacuation collection set. + size_t add_regions_to_old; + need_to_finalize_mixed |= heap->old_generation()->heuristics()->top_off_collection_set(add_regions_to_old); + if (need_to_finalize_mixed) { + heap->old_generation()->heuristics()->finalize_mixed_evacs(); + } + return add_regions_to_old; } void ShenandoahYoungHeuristics::choose_young_collection_set(ShenandoahCollectionSet* cset, diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp index b9d64059680..85587887663 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp @@ -38,9 +38,9 @@ public: explicit ShenandoahYoungHeuristics(ShenandoahYoungGeneration* generation); - void choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, - RegionData* data, size_t size, - size_t actual_free) override; + size_t choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, + RegionData* data, size_t size, + size_t actual_free) override; bool should_start_gc() override; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp index e58a7f40796..c1c6b876d90 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp @@ -50,6 +50,8 @@ ShenandoahCollectionSet::ShenandoahCollectionSet(ShenandoahHeap* heap, ReservedS _region_count(0), _old_garbage(0), _preselected_regions(nullptr), + _young_available_bytes_collected(0), + _old_available_bytes_collected(0), _current_index(0) { // The collection set map is reserved to cover the entire heap *and* zero addresses. @@ -104,6 +106,7 @@ void ShenandoahCollectionSet::add_region(ShenandoahHeapRegion* r) { } } else if (r->is_old()) { _old_bytes_to_evacuate += live; + _old_available_bytes_collected += free; _old_garbage += garbage; } @@ -140,6 +143,7 @@ void ShenandoahCollectionSet::clear() { _old_bytes_to_evacuate = 0; _young_available_bytes_collected = 0; + _old_available_bytes_collected = 0; _has_old_regions = false; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.hpp index a1b77baa2d3..c99271de1fb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.hpp @@ -75,6 +75,10 @@ private: // should be subtracted from what's available. size_t _young_available_bytes_collected; + // When a region having memory available to be allocated is added to the collection set, the region's available memory + // should be subtracted from what's available. + size_t _old_available_bytes_collected; + shenandoah_padding(0); volatile size_t _current_index; shenandoah_padding(1); @@ -121,6 +125,9 @@ public: // Returns the amount of free bytes in young regions in the collection set. size_t get_young_available_bytes_collected() const { return _young_available_bytes_collected; } + // Returns the amount of free bytes in old regions in the collection set. + size_t get_old_available_bytes_collected() const { return _old_available_bytes_collected; } + // Returns the amount of garbage in old regions in the collection set. inline size_t get_old_garbage() const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index cee8727a3f4..364279deafe 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -204,9 +204,8 @@ bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) { return false; } - entry_concurrent_update_refs_prepare(heap); - // Perform update-refs phase. + entry_concurrent_update_refs_prepare(heap); if (ShenandoahVerify) { vmop_entry_init_update_refs(); } @@ -227,6 +226,7 @@ bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) { // Update references freed up collection set, kick the cleanup to reclaim the space. entry_cleanup_complete(); } else { + _abbreviated = true; if (!entry_final_roots()) { assert(_degen_point != _degenerated_unset, "Need to know where to start degenerated cycle"); return false; @@ -235,7 +235,6 @@ bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) { if (VerifyAfterGC) { vmop_entry_verify_final_roots(); } - _abbreviated = true; } // We defer generation resizing actions until after cset regions have been recycled. We do this even following an @@ -282,7 +281,6 @@ bool ShenandoahConcurrentGC::complete_abbreviated_cycle() { return true; } - void ShenandoahConcurrentGC::vmop_entry_init_mark() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); TraceCollectorStats tcs(heap->monitoring_support()->stw_collection_counters()); @@ -536,6 +534,12 @@ void ShenandoahConcurrentGC::entry_cleanup_early() { // This phase does not use workers, no need for setup heap->try_inject_alloc_failure(); op_cleanup_early(); + if (!heap->is_evacuation_in_progress()) { + // This is an abbreviated cycle. Rebuild the freeset in order to establish reserves for the next GC cycle. Doing + // the rebuild ASAP also expedites availability of immediate trash, reducing the likelihood that we will degenerate + // during promote-in-place processing. + heap->rebuild_free_set(true /*concurrent*/); + } } void ShenandoahConcurrentGC::entry_evacuate() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index a8c97801824..c4fe9103fcb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -326,7 +326,7 @@ void ShenandoahRegionPartitions::initialize_old_collector() { } void ShenandoahRegionPartitions::make_all_regions_unavailable() { - shenandoah_assert_heaplocked(); + shenandoah_assert_heaplocked_or_safepoint(); for (size_t partition_id = 0; partition_id < IntNumPartitions; partition_id++) { _membership[partition_id].clear_all(); _leftmosts[partition_id] = _max; @@ -439,6 +439,13 @@ void ShenandoahRegionPartitions::set_capacity_of(ShenandoahFreeSetPartitionId wh _available[int(which_partition)] = value - _used[int(which_partition)]; } +void ShenandoahRegionPartitions::set_used_by(ShenandoahFreeSetPartitionId which_partition, size_t value) { + shenandoah_assert_heaplocked(); + assert (which_partition < NumPartitions, "selected free set must be valid"); + _used[int(which_partition)] = value; + _available[int(which_partition)] = _capacity[int(which_partition)] - value; +} + void ShenandoahRegionPartitions::increase_capacity(ShenandoahFreeSetPartitionId which_partition, size_t bytes) { shenandoah_assert_heaplocked(); @@ -900,7 +907,7 @@ idx_t ShenandoahRegionPartitions::rightmost_empty(ShenandoahFreeSetPartitionId w #ifdef ASSERT -void ShenandoahRegionPartitions::assert_bounds(bool validate_totals) { +void ShenandoahRegionPartitions::assert_bounds() { size_t capacities[UIntNumPartitions]; size_t used[UIntNumPartitions]; @@ -936,7 +943,7 @@ void ShenandoahRegionPartitions::assert_bounds(bool validate_totals) { switch (partition) { case ShenandoahFreeSetPartitionId::NotFree: { - assert(!validate_totals || (capacity != _region_size_bytes), "Should not be retired if empty"); + assert(capacity != _region_size_bytes, "Should not be retired if empty"); ShenandoahHeapRegion* r = ShenandoahHeap::heap()->get_region(i); if (r->is_humongous()) { if (r->is_old()) { @@ -976,12 +983,12 @@ void ShenandoahRegionPartitions::assert_bounds(bool validate_totals) { case ShenandoahFreeSetPartitionId::Collector: case ShenandoahFreeSetPartitionId::OldCollector: { + ShenandoahHeapRegion* r = ShenandoahHeap::heap()->get_region(i); assert(capacity > 0, "free regions must have allocation capacity"); bool is_empty = (capacity == _region_size_bytes); regions[int(partition)]++; used[int(partition)] += _region_size_bytes - capacity; capacities[int(partition)] += _region_size_bytes; - if (i < leftmosts[int(partition)]) { leftmosts[int(partition)] = i; } @@ -1020,20 +1027,20 @@ void ShenandoahRegionPartitions::assert_bounds(bool validate_totals) { idx_t beg_off = leftmosts[int(ShenandoahFreeSetPartitionId::Mutator)]; idx_t end_off = rightmosts[int(ShenandoahFreeSetPartitionId::Mutator)]; assert (beg_off >= leftmost(ShenandoahFreeSetPartitionId::Mutator), - "Mutator free regions before the leftmost: %zd, bound %zd", + "Mutator free region before the leftmost: %zd, bound %zd", beg_off, leftmost(ShenandoahFreeSetPartitionId::Mutator)); assert (end_off <= rightmost(ShenandoahFreeSetPartitionId::Mutator), - "Mutator free regions past the rightmost: %zd, bound %zd", + "Mutator free region past the rightmost: %zd, bound %zd", end_off, rightmost(ShenandoahFreeSetPartitionId::Mutator)); beg_off = empty_leftmosts[int(ShenandoahFreeSetPartitionId::Mutator)]; end_off = empty_rightmosts[int(ShenandoahFreeSetPartitionId::Mutator)]; - assert (beg_off >= leftmost_empty(ShenandoahFreeSetPartitionId::Mutator), - "Mutator free empty regions before the leftmost: %zd, bound %zd", - beg_off, leftmost_empty(ShenandoahFreeSetPartitionId::Mutator)); - assert (end_off <= rightmost_empty(ShenandoahFreeSetPartitionId::Mutator), - "Mutator free empty regions past the rightmost: %zd, bound %zd", - end_off, rightmost_empty(ShenandoahFreeSetPartitionId::Mutator)); + assert (beg_off >= _leftmosts_empty[int(ShenandoahFreeSetPartitionId::Mutator)], + "free empty region (%zd) before the leftmost bound %zd", + beg_off, _leftmosts_empty[int(ShenandoahFreeSetPartitionId::Mutator)]); + assert (end_off <= _rightmosts_empty[int(ShenandoahFreeSetPartitionId::Mutator)], + "free empty region (%zd) past the rightmost bound %zd", + end_off, _rightmosts_empty[int(ShenandoahFreeSetPartitionId::Mutator)]); // Performance invariants. Failing these would not break the free partition, but performance would suffer. assert (leftmost(ShenandoahFreeSetPartitionId::Collector) <= _max, "leftmost in bounds: %zd < %zd", @@ -1053,20 +1060,20 @@ void ShenandoahRegionPartitions::assert_bounds(bool validate_totals) { beg_off = leftmosts[int(ShenandoahFreeSetPartitionId::Collector)]; end_off = rightmosts[int(ShenandoahFreeSetPartitionId::Collector)]; assert (beg_off >= leftmost(ShenandoahFreeSetPartitionId::Collector), - "Collector free regions before the leftmost: %zd, bound %zd", + "Collector free region before the leftmost: %zd, bound %zd", beg_off, leftmost(ShenandoahFreeSetPartitionId::Collector)); assert (end_off <= rightmost(ShenandoahFreeSetPartitionId::Collector), - "Collector free regions past the rightmost: %zd, bound %zd", + "Collector free region past the rightmost: %zd, bound %zd", end_off, rightmost(ShenandoahFreeSetPartitionId::Collector)); beg_off = empty_leftmosts[int(ShenandoahFreeSetPartitionId::Collector)]; end_off = empty_rightmosts[int(ShenandoahFreeSetPartitionId::Collector)]; assert (beg_off >= _leftmosts_empty[int(ShenandoahFreeSetPartitionId::Collector)], - "Collector free empty regions before the leftmost: %zd, bound %zd", - beg_off, leftmost_empty(ShenandoahFreeSetPartitionId::Collector)); + "Collector free empty region before the leftmost: %zd, bound %zd", + beg_off, _leftmosts_empty[int(ShenandoahFreeSetPartitionId::Collector)]); assert (end_off <= _rightmosts_empty[int(ShenandoahFreeSetPartitionId::Collector)], - "Collector free empty regions past the rightmost: %zd, bound %zd", - end_off, rightmost_empty(ShenandoahFreeSetPartitionId::Collector)); + "Collector free empty region past the rightmost: %zd, bound %zd", + end_off, _rightmosts_empty[int(ShenandoahFreeSetPartitionId::Collector)]); // Performance invariants. Failing these would not break the free partition, but performance would suffer. assert (leftmost(ShenandoahFreeSetPartitionId::OldCollector) <= _max, "OldCollector leftmost in bounds: %zd < %zd", @@ -1083,106 +1090,109 @@ void ShenandoahRegionPartitions::assert_bounds(bool validate_totals) { ShenandoahFreeSetPartitionId::OldCollector), "OldCollector rightmost region should be free: %zd", rightmost(ShenandoahFreeSetPartitionId::OldCollector)); + // Concurrent recycling of trash recycles a region (changing its state from is_trash to is_empty without the heap lock), + // If OldCollector partition is empty, leftmosts will both equal max, rightmosts will both equal zero. // Likewise for empty region partitions. beg_off = leftmosts[int(ShenandoahFreeSetPartitionId::OldCollector)]; end_off = rightmosts[int(ShenandoahFreeSetPartitionId::OldCollector)]; - assert (beg_off >= leftmost(ShenandoahFreeSetPartitionId::OldCollector), - "OldCollector free regions before the leftmost: %zd, bound %zd", + assert (beg_off >= leftmost(ShenandoahFreeSetPartitionId::OldCollector), "free regions before the leftmost: %zd, bound %zd", beg_off, leftmost(ShenandoahFreeSetPartitionId::OldCollector)); - assert (end_off <= rightmost(ShenandoahFreeSetPartitionId::OldCollector), - "OldCollector free regions past the rightmost: %zd, bound %zd", + assert (end_off <= rightmost(ShenandoahFreeSetPartitionId::OldCollector), "free regions past the rightmost: %zd, bound %zd", end_off, rightmost(ShenandoahFreeSetPartitionId::OldCollector)); beg_off = empty_leftmosts[int(ShenandoahFreeSetPartitionId::OldCollector)]; end_off = empty_rightmosts[int(ShenandoahFreeSetPartitionId::OldCollector)]; assert (beg_off >= _leftmosts_empty[int(ShenandoahFreeSetPartitionId::OldCollector)], - "OldCollector free empty regions before the leftmost: %zd, bound %zd", - beg_off, leftmost_empty(ShenandoahFreeSetPartitionId::OldCollector)); + "free empty region (%zd) before the leftmost bound %zd, region %s trash", + beg_off, _leftmosts_empty[int(ShenandoahFreeSetPartitionId::OldCollector)], + ((beg_off >= _max)? "out of bounds is not": + (ShenandoahHeap::heap()->get_region(_leftmosts_empty[int(ShenandoahFreeSetPartitionId::OldCollector)])->is_trash()? + "is": "is not"))); assert (end_off <= _rightmosts_empty[int(ShenandoahFreeSetPartitionId::OldCollector)], - "OldCollector free empty regions past the rightmost: %zd, bound %zd", - end_off, rightmost_empty(ShenandoahFreeSetPartitionId::OldCollector)); + "free empty region (%zd) past the rightmost bound %zd, region %s trash", + end_off, _rightmosts_empty[int(ShenandoahFreeSetPartitionId::OldCollector)], + ((end_off < 0)? "out of bounds is not" : + (ShenandoahHeap::heap()->get_region(_rightmosts_empty[int(ShenandoahFreeSetPartitionId::OldCollector)])->is_trash()? + "is": "is not"))); - if (validate_totals) { - // young_retired_regions need to be added to either Mutator or Collector partitions, 100% used. - // Give enough of young_retired_regions, young_retired_capacity, young_retired_user - // to the Mutator partition to top it off so that it matches the running totals. - // - // Give any remnants to the Collector partition. After topping off the Collector partition, its values - // should also match running totals. + // young_retired_regions need to be added to either Mutator or Collector partitions, 100% used. + // Give enough of young_retired_regions, young_retired_capacity, young_retired_user + // to the Mutator partition to top it off so that it matches the running totals. + // + // Give any remnants to the Collector partition. After topping off the Collector partition, its values + // should also match running totals. + assert(young_retired_regions * _region_size_bytes == young_retired_capacity, "sanity"); + assert(young_retired_capacity == young_retired_used, "sanity"); - assert(young_retired_regions * _region_size_bytes == young_retired_capacity, "sanity"); - assert(young_retired_capacity == young_retired_used, "sanity"); + assert(capacities[int(ShenandoahFreeSetPartitionId::OldCollector)] + == _capacity[int(ShenandoahFreeSetPartitionId::OldCollector)], "Old collector capacities must match (%zu != %zu)", + capacities[int(ShenandoahFreeSetPartitionId::OldCollector)], + _capacity[int(ShenandoahFreeSetPartitionId::OldCollector)]); + assert(used[int(ShenandoahFreeSetPartitionId::OldCollector)] + == _used[int(ShenandoahFreeSetPartitionId::OldCollector)], "Old collector used must match"); + assert(regions[int(ShenandoahFreeSetPartitionId::OldCollector)] + == _capacity[int(ShenandoahFreeSetPartitionId::OldCollector)] / _region_size_bytes, "Old collector regions must match"); + assert(_capacity[int(ShenandoahFreeSetPartitionId::OldCollector)] + >= _used[int(ShenandoahFreeSetPartitionId::OldCollector)], "Old Collector capacity must be >= used"); + assert(_available[int(ShenandoahFreeSetPartitionId::OldCollector)] == + (_capacity[int(ShenandoahFreeSetPartitionId::OldCollector)] - _used[int(ShenandoahFreeSetPartitionId::OldCollector)]), + "Old Collector available must equal capacity minus used"); + assert(_humongous_waste[int(ShenandoahFreeSetPartitionId::OldCollector)] == + humongous_waste[int(ShenandoahFreeSetPartitionId::OldCollector)], "Old Collector humongous waste must match"); + assert(_capacity[int(ShenandoahFreeSetPartitionId::Mutator)] >= capacities[int(ShenandoahFreeSetPartitionId::Mutator)], + "Capacity total must be >= counted tally"); + size_t mutator_capacity_shortfall = + _capacity[int(ShenandoahFreeSetPartitionId::Mutator)] - capacities[int(ShenandoahFreeSetPartitionId::Mutator)]; + assert(mutator_capacity_shortfall <= young_retired_capacity, "sanity"); + capacities[int(ShenandoahFreeSetPartitionId::Mutator)] += mutator_capacity_shortfall; + young_retired_capacity -= mutator_capacity_shortfall; + capacities[int(ShenandoahFreeSetPartitionId::Collector)] += young_retired_capacity; - assert(capacities[int(ShenandoahFreeSetPartitionId::OldCollector)] - == _capacity[int(ShenandoahFreeSetPartitionId::OldCollector)], "Old collector capacities must match"); - assert(used[int(ShenandoahFreeSetPartitionId::OldCollector)] - == _used[int(ShenandoahFreeSetPartitionId::OldCollector)], "Old collector used must match"); - assert(regions[int(ShenandoahFreeSetPartitionId::OldCollector)] - == _capacity[int(ShenandoahFreeSetPartitionId::OldCollector)] / _region_size_bytes, "Old collector regions must match"); - assert(_capacity[int(ShenandoahFreeSetPartitionId::OldCollector)] - >= _used[int(ShenandoahFreeSetPartitionId::OldCollector)], "Old Collector capacity must be >= used"); - assert(_available[int(ShenandoahFreeSetPartitionId::OldCollector)] == - (_capacity[int(ShenandoahFreeSetPartitionId::OldCollector)] - _used[int(ShenandoahFreeSetPartitionId::OldCollector)]), - "Old Collector available must equal capacity minus used"); - assert(_humongous_waste[int(ShenandoahFreeSetPartitionId::OldCollector)] == - humongous_waste[int(ShenandoahFreeSetPartitionId::OldCollector)], "Old Collector humongous waste must match"); + assert(_used[int(ShenandoahFreeSetPartitionId::Mutator)] >= used[int(ShenandoahFreeSetPartitionId::Mutator)], + "Used total must be >= counted tally"); + size_t mutator_used_shortfall = + _used[int(ShenandoahFreeSetPartitionId::Mutator)] - used[int(ShenandoahFreeSetPartitionId::Mutator)]; + assert(mutator_used_shortfall <= young_retired_used, "sanity"); + used[int(ShenandoahFreeSetPartitionId::Mutator)] += mutator_used_shortfall; + young_retired_used -= mutator_used_shortfall; + used[int(ShenandoahFreeSetPartitionId::Collector)] += young_retired_used; - assert(_capacity[int(ShenandoahFreeSetPartitionId::Mutator)] >= capacities[int(ShenandoahFreeSetPartitionId::Mutator)], - "Capacity total must be >= counted tally"); - size_t mutator_capacity_shortfall = - _capacity[int(ShenandoahFreeSetPartitionId::Mutator)] - capacities[int(ShenandoahFreeSetPartitionId::Mutator)]; - assert(mutator_capacity_shortfall <= young_retired_capacity, "sanity"); - capacities[int(ShenandoahFreeSetPartitionId::Mutator)] += mutator_capacity_shortfall; - young_retired_capacity -= mutator_capacity_shortfall; - capacities[int(ShenandoahFreeSetPartitionId::Collector)] += young_retired_capacity; + assert(_capacity[int(ShenandoahFreeSetPartitionId::Mutator)] / _region_size_bytes + >= regions[int(ShenandoahFreeSetPartitionId::Mutator)], "Region total must be >= counted tally"); + size_t mutator_regions_shortfall = (_capacity[int(ShenandoahFreeSetPartitionId::Mutator)] / _region_size_bytes + - regions[int(ShenandoahFreeSetPartitionId::Mutator)]); + assert(mutator_regions_shortfall <= young_retired_regions, "sanity"); + regions[int(ShenandoahFreeSetPartitionId::Mutator)] += mutator_regions_shortfall; + young_retired_regions -= mutator_regions_shortfall; + regions[int(ShenandoahFreeSetPartitionId::Collector)] += young_retired_regions; + assert(capacities[int(ShenandoahFreeSetPartitionId::Collector)] == _capacity[int(ShenandoahFreeSetPartitionId::Collector)], + "Collector capacities must match"); + assert(used[int(ShenandoahFreeSetPartitionId::Collector)] == _used[int(ShenandoahFreeSetPartitionId::Collector)], + "Collector used must match"); + assert(regions[int(ShenandoahFreeSetPartitionId::Collector)] + == _capacity[int(ShenandoahFreeSetPartitionId::Collector)] / _region_size_bytes, "Collector regions must match"); + assert(_capacity[int(ShenandoahFreeSetPartitionId::Collector)] >= _used[int(ShenandoahFreeSetPartitionId::Collector)], + "Collector Capacity must be >= used"); + assert(_available[int(ShenandoahFreeSetPartitionId::Collector)] == + (_capacity[int(ShenandoahFreeSetPartitionId::Collector)] - _used[int(ShenandoahFreeSetPartitionId::Collector)]), + "Collector Available must equal capacity minus used"); - assert(_used[int(ShenandoahFreeSetPartitionId::Mutator)] >= used[int(ShenandoahFreeSetPartitionId::Mutator)], - "Used total must be >= counted tally"); - size_t mutator_used_shortfall = - _used[int(ShenandoahFreeSetPartitionId::Mutator)] - used[int(ShenandoahFreeSetPartitionId::Mutator)]; - assert(mutator_used_shortfall <= young_retired_used, "sanity"); - used[int(ShenandoahFreeSetPartitionId::Mutator)] += mutator_used_shortfall; - young_retired_used -= mutator_used_shortfall; - used[int(ShenandoahFreeSetPartitionId::Collector)] += young_retired_used; - - assert(_capacity[int(ShenandoahFreeSetPartitionId::Mutator)] / _region_size_bytes - >= regions[int(ShenandoahFreeSetPartitionId::Mutator)], "Region total must be >= counted tally"); - size_t mutator_regions_shortfall = (_capacity[int(ShenandoahFreeSetPartitionId::Mutator)] / _region_size_bytes - - regions[int(ShenandoahFreeSetPartitionId::Mutator)]); - assert(mutator_regions_shortfall <= young_retired_regions, "sanity"); - regions[int(ShenandoahFreeSetPartitionId::Mutator)] += mutator_regions_shortfall; - young_retired_regions -= mutator_regions_shortfall; - regions[int(ShenandoahFreeSetPartitionId::Collector)] += young_retired_regions; - - assert(capacities[int(ShenandoahFreeSetPartitionId::Collector)] == _capacity[int(ShenandoahFreeSetPartitionId::Collector)], - "Collector capacities must match"); - assert(used[int(ShenandoahFreeSetPartitionId::Collector)] == _used[int(ShenandoahFreeSetPartitionId::Collector)], - "Collector used must match"); - assert(regions[int(ShenandoahFreeSetPartitionId::Collector)] - == _capacity[int(ShenandoahFreeSetPartitionId::Collector)] / _region_size_bytes, "Collector regions must match"); - assert(_capacity[int(ShenandoahFreeSetPartitionId::Collector)] >= _used[int(ShenandoahFreeSetPartitionId::Collector)], - "Collector Capacity must be >= used"); - assert(_available[int(ShenandoahFreeSetPartitionId::Collector)] == - (_capacity[int(ShenandoahFreeSetPartitionId::Collector)] - _used[int(ShenandoahFreeSetPartitionId::Collector)]), - "Collector Available must equal capacity minus used"); - - assert(capacities[int(ShenandoahFreeSetPartitionId::Mutator)] == _capacity[int(ShenandoahFreeSetPartitionId::Mutator)], - "Mutator capacities must match"); - assert(used[int(ShenandoahFreeSetPartitionId::Mutator)] == _used[int(ShenandoahFreeSetPartitionId::Mutator)], - "Mutator used must match"); - assert(regions[int(ShenandoahFreeSetPartitionId::Mutator)] - == _capacity[int(ShenandoahFreeSetPartitionId::Mutator)] / _region_size_bytes, "Mutator regions must match"); - assert(_capacity[int(ShenandoahFreeSetPartitionId::Mutator)] >= _used[int(ShenandoahFreeSetPartitionId::Mutator)], - "Mutator capacity must be >= used"); - assert(_available[int(ShenandoahFreeSetPartitionId::Mutator)] == - (_capacity[int(ShenandoahFreeSetPartitionId::Mutator)] - _used[int(ShenandoahFreeSetPartitionId::Mutator)]), - "Mutator available must equal capacity minus used"); - assert(_humongous_waste[int(ShenandoahFreeSetPartitionId::Mutator)] == young_humongous_waste, - "Mutator humongous waste must match"); - } + assert(capacities[int(ShenandoahFreeSetPartitionId::Mutator)] == _capacity[int(ShenandoahFreeSetPartitionId::Mutator)], + "Mutator capacities must match"); + assert(used[int(ShenandoahFreeSetPartitionId::Mutator)] == _used[int(ShenandoahFreeSetPartitionId::Mutator)], + "Mutator used must match"); + assert(regions[int(ShenandoahFreeSetPartitionId::Mutator)] + == _capacity[int(ShenandoahFreeSetPartitionId::Mutator)] / _region_size_bytes, "Mutator regions must match"); + assert(_capacity[int(ShenandoahFreeSetPartitionId::Mutator)] >= _used[int(ShenandoahFreeSetPartitionId::Mutator)], + "Mutator capacity must be >= used"); + assert(_available[int(ShenandoahFreeSetPartitionId::Mutator)] == + (_capacity[int(ShenandoahFreeSetPartitionId::Mutator)] - _used[int(ShenandoahFreeSetPartitionId::Mutator)]), + "Mutator available must equal capacity minus used"); + assert(_humongous_waste[int(ShenandoahFreeSetPartitionId::Mutator)] == young_humongous_waste, + "Mutator humongous waste must match"); } #endif @@ -1206,6 +1216,36 @@ ShenandoahFreeSet::ShenandoahFreeSet(ShenandoahHeap* heap, size_t max_regions) : clear_internal(); } +void ShenandoahFreeSet::move_unaffiliated_regions_from_collector_to_old_collector(ssize_t count) { + shenandoah_assert_heaplocked(); + size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes(); + + size_t old_capacity = _partitions.get_capacity(ShenandoahFreeSetPartitionId::OldCollector); + size_t collector_capacity = _partitions.get_capacity(ShenandoahFreeSetPartitionId::Collector); + if (count > 0) { + size_t ucount = count; + size_t bytes_moved = ucount * region_size_bytes; + assert(collector_capacity >= bytes_moved, "Cannot transfer"); + assert(_partitions.get_empty_region_counts(ShenandoahFreeSetPartitionId::Collector) >= ucount, + "Cannot transfer %zu of %zu", ucount, _partitions.get_empty_region_counts(ShenandoahFreeSetPartitionId::Collector)); + _partitions.decrease_empty_region_counts(ShenandoahFreeSetPartitionId::Collector, ucount); + _partitions.set_capacity_of(ShenandoahFreeSetPartitionId::Collector, collector_capacity - bytes_moved); + _partitions.set_capacity_of(ShenandoahFreeSetPartitionId::OldCollector, old_capacity + bytes_moved); + _partitions.increase_empty_region_counts(ShenandoahFreeSetPartitionId::OldCollector, ucount); + } else if (count < 0) { + size_t ucount = -count; + size_t bytes_moved = ucount * region_size_bytes; + assert(old_capacity >= bytes_moved, "Cannot transfer"); + assert(_partitions.get_empty_region_counts(ShenandoahFreeSetPartitionId::OldCollector) >= ucount, + "Cannot transfer %zu of %zu", ucount, _partitions.get_empty_region_counts(ShenandoahFreeSetPartitionId::OldCollector)); + _partitions.decrease_empty_region_counts(ShenandoahFreeSetPartitionId::OldCollector, ucount); + _partitions.set_capacity_of(ShenandoahFreeSetPartitionId::OldCollector, old_capacity - bytes_moved); + _partitions.set_capacity_of(ShenandoahFreeSetPartitionId::Collector, collector_capacity + bytes_moved); + _partitions.increase_empty_region_counts(ShenandoahFreeSetPartitionId::Collector, ucount); + } + // else, do nothing +} + // was pip_pad_bytes void ShenandoahFreeSet::add_promoted_in_place_region_to_old_collector(ShenandoahHeapRegion* region) { shenandoah_assert_heaplocked(); @@ -1261,7 +1301,7 @@ void ShenandoahFreeSet::add_promoted_in_place_region_to_old_collector(Shenandoah /* CollectorSizeChanged */ true, /* OldCollectorSizeChanged */ true, /* AffiliatedChangesAreYoungNeutral */ false, /* AffiliatedChangesAreGlobalNeutral */ true, /* UnaffiliatedChangesAreYoungNeutral */ true>(); - _partitions.assert_bounds(true); + _partitions.assert_bounds(); } template @@ -1496,9 +1536,12 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah return nullptr; } HeapWord* result = nullptr; + // We must call try_recycle_under_lock() even if !r->is_trash(). The reason is that if r is being recycled at this + // moment by a GC worker thread, it may appear to be not trash even though it has not yet been fully recycled. If + // we proceed without waiting for the worker to finish recycling the region, the worker thread may overwrite the + // region's affiliation with FREE after we set the region's affiliation to req.afiliation() below r->try_recycle_under_lock(); in_new_region = r->is_empty(); - if (in_new_region) { log_debug(gc, free)("Using new region (%zu) for %s (" PTR_FORMAT ").", r->index(), req.type_string(), p2i(&req)); @@ -1668,7 +1711,7 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah default: assert(false, "won't happen"); } - _partitions.assert_bounds(true); + _partitions.assert_bounds(); return result; } @@ -1799,6 +1842,7 @@ HeapWord* ShenandoahFreeSet::allocate_contiguous(ShenandoahAllocRequest& req, bo increase_bytes_allocated(waste_bytes); } } + _partitions.increase_used(ShenandoahFreeSetPartitionId::Mutator, total_used); increase_bytes_allocated(total_used); req.set_actual_size(words_size); @@ -1819,14 +1863,16 @@ HeapWord* ShenandoahFreeSet::allocate_contiguous(ShenandoahAllocRequest& req, bo /* CollectorSizeChanged */ false, /* OldCollectorSizeChanged */ false, /* AffiliatedChangesAreYoungNeutral */ false, /* AffiliatedChangesAreGlobalNeutral */ false, /* UnaffiliatedChangesAreYoungNeutral */ false>(); - _partitions.assert_bounds(true); + _partitions.assert_bounds(); return _heap->get_region(beg)->bottom(); } class ShenandoahRecycleTrashedRegionClosure final : public ShenandoahHeapRegionClosure { public: void heap_region_do(ShenandoahHeapRegion* r) { - r->try_recycle(); + if (r->is_trash()) { + r->try_recycle(); + } } bool is_thread_safe() { @@ -1861,7 +1907,7 @@ bool ShenandoahFreeSet::transfer_one_region_from_mutator_to_old_collector(size_t /* CollectorSizeChanged */ false, /* OldCollectorSizeChanged */ true, /* AffiliatedChangesAreYoungNeutral */ true, /* AffiliatedChangesAreGlobalNeutral */ true, /* UnaffiliatedChangesAreYoungNeutral */ false>(); - _partitions.assert_bounds(true); + _partitions.assert_bounds(); return true; } else { return false; @@ -1914,7 +1960,7 @@ bool ShenandoahFreeSet::flip_to_old_gc(ShenandoahHeapRegion* r) { /* CollectorSizeChanged */ false, /* OldCollectorSizeChanged */ true, /* AffiliatedChangesAreYoungNeutral */ true, /* AffiliatedChangesAreGlobalNeutral */ true, /* UnaffiliatedChangesAreYoungNeutral */ false>(); - _partitions.assert_bounds(true); + _partitions.assert_bounds(); // 4. Do not adjust capacities for generations, we just swapped the regions that have already // been accounted for. However, we should adjust the evacuation reserves as those may have changed. shenandoah_assert_heaplocked(); @@ -1945,7 +1991,7 @@ void ShenandoahFreeSet::flip_to_gc(ShenandoahHeapRegion* r) { /* CollectorSizeChanged */ true, /* OldCollectorSizeChanged */ false, /* AffiliatedChangesAreYoungNeutral */ true, /* AffiliatedChangesAreGlobalNeutral */ true, /* UnaffiliatedChangesAreYoungNeutral */ true>(); - _partitions.assert_bounds(true); + _partitions.assert_bounds(); // We do not ensure that the region is no longer trash, relying on try_allocate_in(), which always comes next, // to recycle trash before attempting to allocate anything in the region. } @@ -2025,16 +2071,23 @@ void ShenandoahFreeSet::find_regions_with_alloc_capacity(size_t &young_trashed_r for (size_t idx = 0; idx < num_regions; idx++) { ShenandoahHeapRegion* region = _heap->get_region(idx); if (region->is_trash()) { - // Trashed regions represent immediate garbage identified by final mark and regions that had been in the collection - // partition but have not yet been "cleaned up" following update refs. + // Trashed regions represent regions that had been in the collection set (or may have been identified as immediate garbage) + // but have not yet been "cleaned up". The cset regions are not "trashed" until we have finished update refs. if (region->is_old()) { + // We're going to place this region into the Mutator set. We increment old_trashed_regions because this count represents + // regions that the old generation is entitled to without any transfer from young. We do not place this region into + // the OldCollector partition at this time. Instead, we let reserve_regions() decide whether to place this region + // into the OldCollector partition. Deferring the decision allows reserve_regions() to more effectively pack the + // OldCollector regions into high-address memory. We do not adjust capacities of old and young generations at this + // time. At the end of finish_rebuild(), the capacities are adjusted based on the results of reserve_regions(). old_trashed_regions++; } else { assert(region->is_young(), "Trashed region should be old or young"); young_trashed_regions++; } } else if (region->is_old()) { - // count both humongous and regular regions, but don't count trash (cset) regions. + // We count humongous and regular regions as "old regions". We do not count trashed regions that are old. Those + // are counted (above) as old_trashed_regions. old_region_count++; if (first_old_region > idx) { first_old_region = idx; @@ -2048,7 +2101,7 @@ void ShenandoahFreeSet::find_regions_with_alloc_capacity(size_t &young_trashed_r size_t ac = alloc_capacity(region); if (ac >= PLAB::min_size() * HeapWordSize) { if (region->is_trash() || !region->is_old()) { - // Both young and old collected regions (trashed) are placed into the Mutator set + // Both young and old (possibly immediately) collected regions (trashed) are placed into the Mutator set _partitions.raw_assign_membership(idx, ShenandoahFreeSetPartitionId::Mutator); if (idx < mutator_leftmost) { mutator_leftmost = idx; @@ -2111,10 +2164,19 @@ void ShenandoahFreeSet::find_regions_with_alloc_capacity(size_t &young_trashed_r assert(_partitions.membership(idx) == ShenandoahFreeSetPartitionId::NotFree, "Region should have been retired"); size_t humongous_waste_bytes = 0; if (region->is_humongous_start()) { - oop obj = cast_to_oop(region->bottom()); - size_t byte_size = obj->size() * HeapWordSize; - size_t region_span = ShenandoahHeapRegion::required_regions(byte_size); - humongous_waste_bytes = region_span * ShenandoahHeapRegion::region_size_bytes() - byte_size; + // Since rebuild does not necessarily happen at a safepoint, a newly allocated humongous object may not have been + // fully initialized. Therefore, we cannot safely consult its header. + ShenandoahHeapRegion* last_of_humongous_continuation = region; + size_t next_idx; + for (next_idx = idx + 1; next_idx < num_regions; next_idx++) { + ShenandoahHeapRegion* humongous_cont_candidate = _heap->get_region(next_idx); + if (!humongous_cont_candidate->is_humongous_continuation()) { + break; + } + last_of_humongous_continuation = humongous_cont_candidate; + } + // For humongous regions, used() is established while holding the global heap lock so it is reliable here + humongous_waste_bytes = ShenandoahHeapRegion::region_size_bytes() - last_of_humongous_continuation->used(); } if (region->is_old()) { old_collector_used += region_size_bytes; @@ -2183,7 +2245,7 @@ void ShenandoahFreeSet::find_regions_with_alloc_capacity(size_t &young_trashed_r /* CollectorSizeChanged */ true, /* OldCollectorSizeChanged */ true, /* AffiliatedChangesAreYoungNeutral */ false, /* AffiliatedChangesAreGlobalNeutral */ false, /* UnaffiliatedChangesAreYoungNeutral */ false>(); - _partitions.assert_bounds(true); + _partitions.assert_bounds(); #ifdef ASSERT if (_heap->mode()->is_generational()) { assert(young_affiliated_regions() == _heap->young_generation()->get_affiliated_region_count(), "sanity"); @@ -2221,7 +2283,7 @@ void ShenandoahFreeSet::transfer_humongous_regions_from_mutator_to_old_collector /* CollectorSizeChanged */ false, /* OldCollectorSizeChanged */ true, /* AffiliatedChangesAreYoungNeutral */ false, /* AffiliatedChangesAreGlobalNeutral */ true, /* UnaffiliatedChangesAreYoungNeutral */ true>(); - _partitions.assert_bounds(true); + _partitions.assert_bounds(); // global_used is unaffected by this transfer // No need to adjust ranges because humongous regions are not allocatable @@ -2303,7 +2365,7 @@ void ShenandoahFreeSet::transfer_empty_regions_from_to(ShenandoahFreeSetPartitio /* UnaffiliatedChangesAreYoungNeutral */ true>(); } } - _partitions.assert_bounds(true); + _partitions.assert_bounds(); } // Returns number of regions transferred, adds transferred bytes to var argument bytes_transferred @@ -2370,7 +2432,7 @@ size_t ShenandoahFreeSet::transfer_empty_regions_from_collector_set_to_mutator_s /* AffiliatedChangesAreYoungNeutral */ true, /* AffiliatedChangesAreGlobalNeutral */ true, /* UnaffiliatedChangesAreYoungNeutral */ true>(); } - _partitions.assert_bounds(true); + _partitions.assert_bounds(); return transferred_regions; } @@ -2445,7 +2507,7 @@ transfer_non_empty_regions_from_collector_set_to_mutator_set(ShenandoahFreeSetPa /* AffiliatedChangesAreYoungNeutral */ true, /* AffiliatedChangesAreGlobalNeutral */ true, /* UnaffiliatedChangesAreYoungNeutral */ true>(); } - _partitions.assert_bounds(true); + _partitions.assert_bounds(); return transferred_regions; } @@ -2507,14 +2569,13 @@ void ShenandoahFreeSet::prepare_to_rebuild(size_t &young_trashed_regions, size_t first_old_region, last_old_region, old_region_count); } -void ShenandoahFreeSet::finish_rebuild(size_t young_trashed_regions, size_t old_trashed_regions, size_t old_region_count, - bool have_evacuation_reserves) { + +void ShenandoahFreeSet::finish_rebuild(size_t young_cset_regions, size_t old_cset_regions, size_t old_region_count) { shenandoah_assert_heaplocked(); size_t young_reserve(0), old_reserve(0); if (_heap->mode()->is_generational()) { - compute_young_and_old_reserves(young_trashed_regions, old_trashed_regions, have_evacuation_reserves, - young_reserve, old_reserve); + compute_young_and_old_reserves(young_cset_regions, old_cset_regions, young_reserve, old_reserve); } else { young_reserve = (_heap->max_capacity() / 100) * ShenandoahEvacReserve; old_reserve = 0; @@ -2531,8 +2592,41 @@ void ShenandoahFreeSet::finish_rebuild(size_t young_trashed_regions, size_t old_ // Release the rebuild lock now. What remains in this function is read-only rebuild_lock()->unlock(); - _partitions.assert_bounds(true); + _partitions.assert_bounds(); log_status(); + if (_heap->mode()->is_generational()) { + // Clear the region balance until it is adjusted in preparation for a subsequent GC cycle. + _heap->old_generation()->set_region_balance(0); + } +} + + +// Reduce old reserve (when there are insufficient resources to satisfy the original request). +void ShenandoahFreeSet::reduce_old_reserve(size_t adjusted_old_reserve, size_t requested_old_reserve) { + ShenandoahOldGeneration* const old_generation = _heap->old_generation(); + size_t requested_promoted_reserve = old_generation->get_promoted_reserve(); + size_t requested_old_evac_reserve = old_generation->get_evacuation_reserve(); + assert(adjusted_old_reserve < requested_old_reserve, "Only allow reduction"); + assert(requested_promoted_reserve + requested_old_evac_reserve >= adjusted_old_reserve, "Sanity"); + size_t delta = requested_old_reserve - adjusted_old_reserve; + + if (requested_promoted_reserve >= delta) { + requested_promoted_reserve -= delta; + old_generation->set_promoted_reserve(requested_promoted_reserve); + } else { + delta -= requested_promoted_reserve; + requested_promoted_reserve = 0; + requested_old_evac_reserve -= delta; + old_generation->set_promoted_reserve(requested_promoted_reserve); + old_generation->set_evacuation_reserve(requested_old_evac_reserve); + } +} + +// Reduce young reserve (when there are insufficient resources to satisfy the original request). +void ShenandoahFreeSet::reduce_young_reserve(size_t adjusted_young_reserve, size_t requested_young_reserve) { + ShenandoahYoungGeneration* const young_generation = _heap->young_generation(); + assert(adjusted_young_reserve < requested_young_reserve, "Only allow reduction"); + young_generation->set_evacuation_reserve(adjusted_young_reserve); } /** @@ -2549,7 +2643,6 @@ void ShenandoahFreeSet::finish_rebuild(size_t young_trashed_regions, size_t old_ * this value should computed by ShenandoahGenerationalHeap::compute_old_generation_balance(). */ void ShenandoahFreeSet::compute_young_and_old_reserves(size_t young_trashed_regions, size_t old_trashed_regions, - bool have_evacuation_reserves, size_t& young_reserve_result, size_t& old_reserve_result) const { shenandoah_assert_generational(); shenandoah_assert_heaplocked(); @@ -2566,6 +2659,15 @@ void ShenandoahFreeSet::compute_young_and_old_reserves(size_t young_trashed_regi old_available += old_trashed_regions * region_size_bytes; young_unaffiliated_regions += young_trashed_regions; + assert(young_capacity >= young_generation->used(), + "Young capacity (%zu) must exceed used (%zu)", young_capacity, young_generation->used()); + + size_t young_available = young_capacity - young_generation->used(); + young_available += young_trashed_regions * region_size_bytes; + + assert(young_available >= young_unaffiliated_regions * region_size_bytes, "sanity"); + assert(old_available >= old_unaffiliated_regions * region_size_bytes, "sanity"); + // Consult old-region balance to make adjustments to current generation capacities and availability. // The generation region transfers take place after we rebuild. old_region_balance represents number of regions // to transfer from old to young. @@ -2585,6 +2687,7 @@ void ShenandoahFreeSet::compute_young_and_old_reserves(size_t young_trashed_regi ssize_t xfer_bytes = old_region_balance * checked_cast(region_size_bytes); old_available -= xfer_bytes; old_unaffiliated_regions -= old_region_balance; + young_available += xfer_bytes; young_capacity += xfer_bytes; young_unaffiliated_regions += old_region_balance; } @@ -2593,41 +2696,22 @@ void ShenandoahFreeSet::compute_young_and_old_reserves(size_t young_trashed_regi // promotions and evacuations. The partition between which old memory is reserved for evacuation and // which is reserved for promotion is enforced using thread-local variables that prescribe intentions for // each PLAB's available memory. - if (have_evacuation_reserves) { - // We are rebuilding at the end of final mark, having already established evacuation budgets for this GC pass. - const size_t promoted_reserve = old_generation->get_promoted_reserve(); - const size_t old_evac_reserve = old_generation->get_evacuation_reserve(); - young_reserve_result = young_generation->get_evacuation_reserve(); - old_reserve_result = promoted_reserve + old_evac_reserve; - if (old_reserve_result > old_available) { - // Try to transfer memory from young to old. - size_t old_deficit = old_reserve_result - old_available; - size_t old_region_deficit = (old_deficit + region_size_bytes - 1) / region_size_bytes; - if (young_unaffiliated_regions < old_region_deficit) { - old_region_deficit = young_unaffiliated_regions; - } - young_unaffiliated_regions -= old_region_deficit; - old_unaffiliated_regions += old_region_deficit; - old_region_balance -= old_region_deficit; - old_generation->set_region_balance(old_region_balance); - } - } else { - // We are rebuilding at end of GC, so we set aside budgets specified on command line (or defaults) - young_reserve_result = (young_capacity * ShenandoahEvacReserve) / 100; - // The auto-sizer has already made old-gen large enough to hold all anticipated evacuations and promotions. - // Affiliated old-gen regions are already in the OldCollector free set. Add in the relevant number of - // unaffiliated regions. - old_reserve_result = old_available; - } + const size_t promoted_reserve = old_generation->get_promoted_reserve(); + const size_t old_evac_reserve = old_generation->get_evacuation_reserve(); + young_reserve_result = young_generation->get_evacuation_reserve(); + old_reserve_result = promoted_reserve + old_evac_reserve; + assert(old_reserve_result + young_reserve_result <= old_available + young_available, + "Cannot reserve (%zu + %zu + %zu) more than is available: %zu + %zu", + promoted_reserve, old_evac_reserve, young_reserve_result, old_available, young_available); // Old available regions that have less than PLAB::min_size() of available memory are not placed into the OldCollector // free set. Because of this, old_available may not have enough memory to represent the intended reserve. Adjust // the reserve downward to account for this possibility. This loss is part of the reason why the original budget // was adjusted with ShenandoahOldEvacWaste and ShenandoahOldPromoWaste multipliers. if (old_reserve_result > - _partitions.capacity_of(ShenandoahFreeSetPartitionId::OldCollector) + old_unaffiliated_regions * region_size_bytes) { + _partitions.available_in(ShenandoahFreeSetPartitionId::OldCollector) + old_unaffiliated_regions * region_size_bytes) { old_reserve_result = - _partitions.capacity_of(ShenandoahFreeSetPartitionId::OldCollector) + old_unaffiliated_regions * region_size_bytes; + _partitions.available_in(ShenandoahFreeSetPartitionId::OldCollector) + old_unaffiliated_regions * region_size_bytes; } if (young_reserve_result > young_unaffiliated_regions * region_size_bytes) { @@ -2791,19 +2875,17 @@ void ShenandoahFreeSet::reserve_regions(size_t to_reserve, size_t to_reserve_old ShenandoahFreeSetPartitionId p = _partitions.membership(idx); size_t ac = alloc_capacity(r); assert(ac != region_size_bytes, "Empty regions should be in Mutator partion at entry to reserve_regions"); - if (p == ShenandoahFreeSetPartitionId::Collector) { - if (ac != region_size_bytes) { - young_used_regions++; - young_used_bytes = region_size_bytes - ac; - } - // else, unaffiliated region has no used - } else if (p == ShenandoahFreeSetPartitionId::OldCollector) { - if (ac != region_size_bytes) { - old_used_regions++; - old_used_bytes = region_size_bytes - ac; - } - // else, unaffiliated region has no used - } else if (p == ShenandoahFreeSetPartitionId::NotFree) { + assert(p != ShenandoahFreeSetPartitionId::Collector, "Collector regions must be converted from Mutator regions"); + if (p == ShenandoahFreeSetPartitionId::OldCollector) { + assert(!r->is_empty(), "Empty regions should be in Mutator partition at entry to reserve_regions"); + old_used_regions++; + old_used_bytes = region_size_bytes - ac; + // This region is within the range for OldCollector partition, as established by find_regions_with_alloc_capacity() + assert((_partitions.leftmost(ShenandoahFreeSetPartitionId::OldCollector) <= idx) && + (_partitions.rightmost(ShenandoahFreeSetPartitionId::OldCollector) >= idx), + "find_regions_with_alloc_capacity() should have established this is in range"); + } else { + assert(p == ShenandoahFreeSetPartitionId::NotFree, "sanity"); // This region has been retired if (r->is_old()) { old_used_regions++; @@ -2813,21 +2895,6 @@ void ShenandoahFreeSet::reserve_regions(size_t to_reserve, size_t to_reserve_old young_used_regions++; young_used_bytes += region_size_bytes - ac; } - } else { - assert(p == ShenandoahFreeSetPartitionId::OldCollector, "Not mutator and not NotFree, so must be OldCollector"); - assert(!r->is_empty(), "Empty regions should be in Mutator partition at entry to reserve_regions"); - if (idx < old_collector_low_idx) { - old_collector_low_idx = idx; - } - if (idx > old_collector_high_idx) { - old_collector_high_idx = idx; - } - if (idx < old_collector_empty_low_idx) { - old_collector_empty_low_idx = idx; - } - if (idx > old_collector_empty_high_idx) { - old_collector_empty_high_idx = idx; - } } } } @@ -2856,14 +2923,14 @@ void ShenandoahFreeSet::reserve_regions(size_t to_reserve, size_t to_reserve_old _partitions.increase_used(ShenandoahFreeSetPartitionId::OldCollector, used_to_old_collector); } - _partitions.expand_interval_if_range_modifies_either_boundary(ShenandoahFreeSetPartitionId::Collector, - collector_low_idx, collector_high_idx, - collector_empty_low_idx, collector_empty_high_idx); + _partitions.establish_interval(ShenandoahFreeSetPartitionId::Mutator, + mutator_low_idx, mutator_high_idx, mutator_empty_low_idx, mutator_empty_high_idx); + _partitions.establish_interval(ShenandoahFreeSetPartitionId::Collector, + collector_low_idx, collector_high_idx, collector_empty_low_idx, collector_empty_high_idx); + _partitions.expand_interval_if_range_modifies_either_boundary(ShenandoahFreeSetPartitionId::OldCollector, old_collector_low_idx, old_collector_high_idx, old_collector_empty_low_idx, old_collector_empty_high_idx); - _partitions.establish_interval(ShenandoahFreeSetPartitionId::Mutator, - mutator_low_idx, mutator_high_idx, mutator_empty_low_idx, mutator_empty_high_idx); recompute_total_used(); @@ -2872,17 +2939,22 @@ void ShenandoahFreeSet::reserve_regions(size_t to_reserve, size_t to_reserve_old /* CollectorSizeChanged */ true, /* OldCollectorSizeChanged */ true, /* AffiliatedChangesAreYoungNeutral */ false, /* AffiliatedChangesAreGlobalNeutral */ false, /* UnaffiliatedChangesAreYoungNeutral */ false>(); - _partitions.assert_bounds(true); + _partitions.assert_bounds(); if (LogTarget(Info, gc, free)::is_enabled()) { size_t old_reserve = _partitions.available_in(ShenandoahFreeSetPartitionId::OldCollector); if (old_reserve < to_reserve_old) { log_info(gc, free)("Wanted " PROPERFMT " for old reserve, but only reserved: " PROPERFMT, PROPERFMTARGS(to_reserve_old), PROPERFMTARGS(old_reserve)); + assert(_heap->mode()->is_generational(), "to_old_reserve > 0 implies generational mode"); + reduce_old_reserve(old_reserve, to_reserve_old); } size_t reserve = _partitions.available_in(ShenandoahFreeSetPartitionId::Collector); if (reserve < to_reserve) { + if (_heap->mode()->is_generational()) { + reduce_young_reserve(reserve, to_reserve); + } log_info(gc, free)("Wanted " PROPERFMT " for young reserve, but only reserved: " PROPERFMT, - PROPERFMTARGS(to_reserve), PROPERFMTARGS(reserve)); + PROPERFMTARGS(to_reserve), PROPERFMTARGS(reserve)); } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index 364637740f2..4e0aea80a9b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -224,6 +224,10 @@ public: void transfer_used_capacity_from_to(ShenandoahFreeSetPartitionId from_partition, ShenandoahFreeSetPartitionId to_partition, size_t regions); + // For recycled region r in the OldCollector partition but possibly not within the interval for empty OldCollector regions, + // expand the empty interval to include this region. + inline void adjust_interval_for_recycled_old_region_under_lock(ShenandoahHeapRegion* r); + const char* partition_membership_name(idx_t idx) const; // Return the index of the next available region >= start_index, or maximum_regions if not found. @@ -373,12 +377,7 @@ public: inline void set_capacity_of(ShenandoahFreeSetPartitionId which_partition, size_t value); - inline void set_used_by(ShenandoahFreeSetPartitionId which_partition, size_t value) { - shenandoah_assert_heaplocked(); - assert (which_partition < NumPartitions, "selected free set must be valid"); - _used[int(which_partition)] = value; - _available[int(which_partition)] = _capacity[int(which_partition)] - value; - } + inline void set_used_by(ShenandoahFreeSetPartitionId which_partition, size_t value); inline size_t count(ShenandoahFreeSetPartitionId which_partition) const { return _region_counts[int(which_partition)]; } @@ -402,7 +401,7 @@ public: // idx >= leftmost && // idx <= rightmost // } - void assert_bounds(bool validate_totals) NOT_DEBUG_RETURN; + void assert_bounds() NOT_DEBUG_RETURN; }; // Publicly, ShenandoahFreeSet represents memory that is available to mutator threads. The public capacity(), used(), @@ -634,7 +633,11 @@ private: void establish_old_collector_alloc_bias(); size_t get_usable_free_words(size_t free_bytes) const; + void reduce_young_reserve(size_t adjusted_young_reserve, size_t requested_young_reserve); + void reduce_old_reserve(size_t adjusted_old_reserve, size_t requested_old_reserve); + void log_freeset_stats(ShenandoahFreeSetPartitionId partition_id, LogStream& ls); + // log status, assuming lock has already been acquired by the caller. void log_status(); @@ -685,35 +688,46 @@ public: return _total_global_used; } - size_t global_unaffiliated_regions() { + // A negative argument results in moving from old_collector to collector + void move_unaffiliated_regions_from_collector_to_old_collector(ssize_t regions); + + inline size_t global_unaffiliated_regions() { return _global_unaffiliated_regions; } - size_t young_unaffiliated_regions() { + inline size_t young_unaffiliated_regions() { return _young_unaffiliated_regions; } - size_t old_unaffiliated_regions() { + inline size_t collector_unaffiliated_regions() { + return _partitions.get_empty_region_counts(ShenandoahFreeSetPartitionId::Collector); + } + + inline size_t old_collector_unaffiliated_regions() { return _partitions.get_empty_region_counts(ShenandoahFreeSetPartitionId::OldCollector); } - size_t young_affiliated_regions() { + inline size_t old_unaffiliated_regions() { + return _partitions.get_empty_region_counts(ShenandoahFreeSetPartitionId::OldCollector); + } + + inline size_t young_affiliated_regions() { return _young_affiliated_regions; } - size_t old_affiliated_regions() { + inline size_t old_affiliated_regions() { return _old_affiliated_regions; } - size_t global_affiliated_regions() { + inline size_t global_affiliated_regions() { return _global_affiliated_regions; } - size_t total_young_regions() { + inline size_t total_young_regions() { return _total_young_regions; } - size_t total_old_regions() { + inline size_t total_old_regions() { return _partitions.get_capacity(ShenandoahFreeSetPartitionId::OldCollector) / ShenandoahHeapRegion::region_size_bytes(); } @@ -725,36 +739,27 @@ public: // Examine the existing free set representation, capturing the current state into var arguments: // - // young_cset_regions is the number of regions currently in the young cset if we are starting to evacuate, or zero - // old_cset_regions is the number of regions currently in the old cset if we are starting a mixed evacuation, or zero + // young_trashed_regions is the number of trashed regions (immediate garbage at final mark, cset regions after update refs) + // old_trashed_regions is the number of trashed regions + // (immediate garbage at final old mark, cset regions after update refs for mixed evac) // first_old_region is the index of the first region that is part of the OldCollector set // last_old_region is the index of the last region that is part of the OldCollector set // old_region_count is the number of regions in the OldCollector set that have memory available to be allocated - void prepare_to_rebuild(size_t &young_cset_regions, size_t &old_cset_regions, + void prepare_to_rebuild(size_t &young_trashed_regions, size_t &old_trashed_regions, size_t &first_old_region, size_t &last_old_region, size_t &old_region_count); // At the end of final mark, but before we begin evacuating, heuristics calculate how much memory is required to - // hold the results of evacuating to young-gen and to old-gen, and have_evacuation_reserves should be true. - // These quantities, stored as reserves for their respective generations, are consulted prior to rebuilding - // the free set (ShenandoahFreeSet) in preparation for evacuation. When the free set is rebuilt, we make sure - // to reserve sufficient memory in the collector and old_collector sets to hold evacuations. + // hold the results of evacuating to young-gen and to old-gen. These quantities, stored in reserves for their + // respective generations, are consulted prior to rebuilding the free set (ShenandoahFreeSet) in preparation for + // evacuation. When the free set is rebuilt, we make sure to reserve sufficient memory in the collector and + // old_collector sets to hold evacuations. Likewise, at the end of update refs, we rebuild the free set in order + // to set aside reserves to be consumed during the next GC cycle. // - // We also rebuild the free set at the end of GC, as we prepare to idle GC until the next trigger. In this case, - // have_evacuation_reserves is false because we don't yet know how much memory will need to be evacuated in the - // next GC cycle. When have_evacuation_reserves is false, the free set rebuild operation reserves for the collector - // and old_collector sets based on alternative mechanisms, such as ShenandoahEvacReserve, ShenandoahOldEvacReserve, and - // ShenandoahOldCompactionReserve. In a future planned enhancement, the reserve for old_collector set when the - // evacuation reserves are unknown, is based in part on anticipated promotion as determined by analysis of live data - // found during the previous GC pass which is one less than the current tenure age. - // - // young_cset_regions is the number of regions currently in the young cset if we are starting to evacuate, or zero - // old_cset_regions is the number of regions currently in the old cset if we are starting a mixed evacuation, or zero + // young_trashed_regions is the number of trashed regions (immediate garbage at final mark, cset regions after update refs) + // old_trashed_regions is the number of trashed regions + // (immediate garbage at final old mark, cset regions after update refs for mixed evac) // num_old_regions is the number of old-gen regions that have available memory for further allocations (excluding old cset) - // have_evacuation_reserves is true iff the desired values of young-gen and old-gen evacuation reserves and old-gen - // promotion reserve have been precomputed (and can be obtained by invoking - // ->get_evacuation_reserve() or old_gen->get_promoted_reserve() - void finish_rebuild(size_t young_cset_regions, size_t old_cset_regions, size_t num_old_regions, - bool have_evacuation_reserves = false); + void finish_rebuild(size_t young_trashed_regions, size_t old_trashed_regions, size_t num_old_regions); // When a region is promoted in place, we add the region's available memory if it is greater than plab_min_size() // into the old collector partition by invoking this method. @@ -806,9 +811,18 @@ public: return _partitions.available_in_locked_for_rebuild(ShenandoahFreeSetPartitionId::Mutator); } + // Use this version of available() if the heap lock is held. + inline size_t available_locked() const { + return _partitions.available_in(ShenandoahFreeSetPartitionId::Mutator); + } + inline size_t total_humongous_waste() const { return _total_humongous_waste; } - inline size_t humongous_waste_in_mutator() const { return _partitions.humongous_waste(ShenandoahFreeSetPartitionId::Mutator); } - inline size_t humongous_waste_in_old() const { return _partitions.humongous_waste(ShenandoahFreeSetPartitionId::OldCollector); } + inline size_t humongous_waste_in_mutator() const { + return _partitions.humongous_waste(ShenandoahFreeSetPartitionId::Mutator); + } + inline size_t humongous_waste_in_old() const { + return _partitions.humongous_waste(ShenandoahFreeSetPartitionId::OldCollector); + } void decrease_humongous_waste_for_regular_bypass(ShenandoahHeapRegion* r, size_t waste); @@ -874,7 +888,7 @@ public: // Reserve space for evacuations, with regions reserved for old evacuations placed to the right // of regions reserved of young evacuations. - void compute_young_and_old_reserves(size_t young_cset_regions, size_t old_cset_regions, bool have_evacuation_reserves, + void compute_young_and_old_reserves(size_t young_cset_regions, size_t old_cset_regions, size_t &young_reserve_result, size_t &old_reserve_result) const; }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index fa3a7a42209..3c92750cc0c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -522,6 +522,7 @@ public: void heap_region_do(ShenandoahHeapRegion* r) override { if (r->is_trash()) { r->try_recycle_under_lock(); + // No need to adjust_interval_for_recycled_old_region. That will be taken care of during freeset rebuild. } if (r->is_cset()) { // Leave affiliation unchanged @@ -966,6 +967,7 @@ public: if (r->is_trash()) { live = 0; r->try_recycle_under_lock(); + // No need to adjust_interval_for_recycled_old_region. That will be taken care of during freeset rebuild. } else { if (r->is_old()) { ShenandoahGenerationalFullGC::account_for_region(r, _old_regions, _old_usage, _old_humongous_waste); @@ -1113,16 +1115,16 @@ void ShenandoahFullGC::phase5_epilog() { ShenandoahPostCompactClosure post_compact; heap->heap_region_iterate(&post_compact); heap->collection_set()->clear(); - size_t young_cset_regions, old_cset_regions, first_old, last_old, num_old; - ShenandoahFreeSet* free_set = heap->free_set(); { - free_set->prepare_to_rebuild(young_cset_regions, old_cset_regions, first_old, last_old, num_old); + ShenandoahFreeSet* free_set = heap->free_set(); + size_t young_trashed_regions, old_trashed_regions, first_old, last_old, num_old; + free_set->prepare_to_rebuild(young_trashed_regions, old_trashed_regions, first_old, last_old, num_old); // We also do not expand old generation size following Full GC because we have scrambled age populations and // no longer have objects separated by age into distinct regions. if (heap->mode()->is_generational()) { ShenandoahGenerationalFullGC::compute_balances(); } - free_set->finish_rebuild(young_cset_regions, old_cset_regions, num_old); + free_set->finish_rebuild(young_trashed_regions, old_trashed_regions, num_old); } // Set mark incomplete because the marking bitmaps have been reset except pinned regions. _generation->set_mark_incomplete(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index a5d8cca458d..cdc7e1a328a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -250,6 +250,7 @@ void ShenandoahGeneration::compute_evacuation_budgets(ShenandoahHeap* const heap ShenandoahOldGeneration* const old_generation = heap->old_generation(); ShenandoahYoungGeneration* const young_generation = heap->young_generation(); + const size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes(); // During initialization and phase changes, it is more likely that fewer objects die young and old-gen // memory is not yet full (or is in the process of being replaced). During these times especially, it @@ -263,15 +264,15 @@ void ShenandoahGeneration::compute_evacuation_budgets(ShenandoahHeap* const heap // First priority is to reclaim the easy garbage out of young-gen. - // maximum_young_evacuation_reserve is upper bound on memory to be evacuated out of young - const size_t maximum_young_evacuation_reserve = (young_generation->max_capacity() * ShenandoahEvacReserve) / 100; - size_t young_evacuation_reserve = MIN2(maximum_young_evacuation_reserve, young_generation->available_with_reserve()); + // maximum_young_evacuation_reserve is upper bound on memory to be evacuated into young Collector Reserve. This is + // bounded at the end of previous GC cycle, based on available memory and balancing of evacuation to old and young. + size_t maximum_young_evacuation_reserve = young_generation->get_evacuation_reserve(); // maximum_old_evacuation_reserve is an upper bound on memory evacuated from old and evacuated to old (promoted), // clamped by the old generation space available. // // Here's the algebra. - // Let SOEP = ShenandoahOldEvacRatioPercent, + // Let SOEP = ShenandoahOldEvacPercent, // OE = old evac, // YE = young evac, and // TE = total evac = OE + YE @@ -283,12 +284,14 @@ void ShenandoahGeneration::compute_evacuation_budgets(ShenandoahHeap* const heap // => OE = YE*SOEP/(100-SOEP) // We have to be careful in the event that SOEP is set to 100 by the user. - assert(ShenandoahOldEvacRatioPercent <= 100, "Error"); + assert(ShenandoahOldEvacPercent <= 100, "Error"); const size_t old_available = old_generation->available(); - const size_t maximum_old_evacuation_reserve = (ShenandoahOldEvacRatioPercent == 100) ? - old_available : MIN2((maximum_young_evacuation_reserve * ShenandoahOldEvacRatioPercent) / (100 - ShenandoahOldEvacRatioPercent), + const size_t maximum_old_evacuation_reserve = (ShenandoahOldEvacPercent == 100) ? + old_available : MIN2((maximum_young_evacuation_reserve * ShenandoahOldEvacPercent) / (100 - ShenandoahOldEvacPercent), old_available); + // In some cases, maximum_old_reserve < old_available (when limited by ShenandoahOldEvacPercent) + // This limit affects mixed evacuations, but does not affect promotions. // Second priority is to reclaim garbage out of old-gen if there are old-gen collection candidates. Third priority // is to promote as much as we have room to promote. However, if old-gen memory is in short supply, this means young @@ -305,10 +308,8 @@ void ShenandoahGeneration::compute_evacuation_budgets(ShenandoahHeap* const heap // evacuation and update-refs, we give emphasis to reclaiming garbage first, wherever that garbage is found. // Global GC will adjust generation sizes to accommodate the collection set it chooses. - // Set old_promo_reserve to enforce that no regions are preselected for promotion. Such regions typically - // have relatively high memory utilization. We still call select_aged_regions() because this will prepare for - // promotions in place, if relevant. - old_promo_reserve = 0; + // Use remnant of old_available to hold promotions. + old_promo_reserve = old_available - maximum_old_evacuation_reserve; // Dedicate all available old memory to old_evacuation reserve. This may be small, because old-gen is only // expanded based on an existing mixed evacuation workload at the end of the previous GC cycle. We'll expand @@ -319,43 +320,48 @@ void ShenandoahGeneration::compute_evacuation_budgets(ShenandoahHeap* const heap // mixed evacuation, reserve all of this memory for compaction of old-gen and do not promote. Prioritize compaction // over promotion in order to defragment OLD so that it will be better prepared to efficiently receive promoted memory. old_evacuation_reserve = maximum_old_evacuation_reserve; - old_promo_reserve = 0; + old_promo_reserve = old_available - maximum_old_evacuation_reserve; } else { // Make all old-evacuation memory for promotion, but if we can't use it all for promotion, we'll allow some evacuation. - old_evacuation_reserve = 0; + old_evacuation_reserve = old_available - maximum_old_evacuation_reserve; old_promo_reserve = maximum_old_evacuation_reserve; } assert(old_evacuation_reserve <= old_available, "Error"); + // We see too many old-evacuation failures if we force ourselves to evacuate into regions that are not initially empty. // So we limit the old-evacuation reserve to unfragmented memory. Even so, old-evacuation is free to fill in nooks and // crannies within existing partially used regions and it generally tries to do so. - const size_t old_free_unfragmented = old_generation->free_unaffiliated_regions() * ShenandoahHeapRegion::region_size_bytes(); + const size_t old_free_unfragmented = old_generation->free_unaffiliated_regions() * region_size_bytes; if (old_evacuation_reserve > old_free_unfragmented) { const size_t delta = old_evacuation_reserve - old_free_unfragmented; old_evacuation_reserve -= delta; - // Let promo consume fragments of old-gen memory if not global - if (!is_global()) { - old_promo_reserve += delta; - } + // Let promo consume fragments of old-gen memory + old_promo_reserve += delta; } - // Preselect regions for promotion by evacuation (obtaining the live data to seed promoted_reserve), - // and identify regions that will promote in place. These use the tenuring threshold. - const size_t consumed_by_advance_promotion = select_aged_regions(old_promo_reserve); - assert(consumed_by_advance_promotion <= maximum_old_evacuation_reserve, "Cannot promote more than available old-gen memory"); + // If is_global(), we let garbage-first heuristic determine cset membership. Otherwise, we give priority + // to tenurable regions by preselecting regions for promotion by evacuation (obtaining the live data to seed promoted_reserve). + // This also identifies regions that will be promoted in place. These use the tenuring threshold. + const size_t consumed_by_advance_promotion = select_aged_regions(is_global()? 0: old_promo_reserve); + assert(consumed_by_advance_promotion <= old_promo_reserve, "Do not promote more than budgeted"); + + // The young evacuation reserve can be no larger than young_unaffiliated. Planning to evacuate into partially consumed + // young regions is doomed to failure if any of those partially consumed regions is selected for the collection set. + size_t young_unaffiliated = young_generation->free_unaffiliated_regions() * region_size_bytes; // If any regions have been selected for promotion in place, this has the effect of decreasing available within mutator // and collector partitions, due to padding of remnant memory within each promoted in place region. This will affect // young_evacuation_reserve but not old_evacuation_reserve or consumed_by_advance_promotion. So recompute. - young_evacuation_reserve = MIN2(young_evacuation_reserve, young_generation->available_with_reserve()); + size_t young_evacuation_reserve = MIN2(maximum_young_evacuation_reserve, young_unaffiliated); // Note that unused old_promo_reserve might not be entirely consumed_by_advance_promotion. Do not transfer this // to old_evacuation_reserve because this memory is likely very fragmented, and we do not want to increase the likelihood - // of old evacuation failure. + // of old evacuation failure. Leave this memory in the promoted reserve as it may be targeted by opportunistic + // promotions (found during evacuation of young regions). young_generation->set_evacuation_reserve(young_evacuation_reserve); old_generation->set_evacuation_reserve(old_evacuation_reserve); - old_generation->set_promoted_reserve(consumed_by_advance_promotion); + old_generation->set_promoted_reserve(old_promo_reserve); // There is no need to expand OLD because all memory used here was set aside at end of previous GC, except in the // case of a GLOBAL gc. During choose_collection_set() of GLOBAL, old will be expanded on demand. @@ -363,8 +369,8 @@ void ShenandoahGeneration::compute_evacuation_budgets(ShenandoahHeap* const heap // Having chosen the collection set, adjust the budgets for generational mode based on its composition. Note // that young_generation->available() now knows about recently discovered immediate garbage. -// -void ShenandoahGeneration::adjust_evacuation_budgets(ShenandoahHeap* const heap, ShenandoahCollectionSet* const collection_set) { +void ShenandoahGeneration::adjust_evacuation_budgets(ShenandoahHeap* const heap, + ShenandoahCollectionSet* const collection_set, size_t add_regions_to_old) { shenandoah_assert_generational(); // We may find that old_evacuation_reserve and/or loaned_for_young_evacuation are not fully consumed, in which case we may // be able to increase regions_available_to_loan @@ -398,7 +404,8 @@ void ShenandoahGeneration::adjust_evacuation_budgets(ShenandoahHeap* const heap, // Leave old_evac_reserve as previously configured } else if (old_evacuated_committed < old_evacuation_reserve) { // This happens if the old-gen collection consumes less than full budget. - log_debug(gc, cset)("Shrinking old evac reserve to match old_evac_commited: " PROPERFMT, PROPERFMTARGS(old_evacuated_committed)); + log_debug(gc, cset)("Shrinking old evac reserve to match old_evac_commited: " PROPERFMT, + PROPERFMTARGS(old_evacuated_committed)); old_evacuation_reserve = old_evacuated_committed; old_generation->set_evacuation_reserve(old_evacuation_reserve); } @@ -409,11 +416,17 @@ void ShenandoahGeneration::adjust_evacuation_budgets(ShenandoahHeap* const heap, size_t young_evacuated = collection_set->get_live_bytes_in_untenurable_regions(); size_t young_evacuated_reserve_used = (size_t) (ShenandoahEvacWaste * double(young_evacuated)); - size_t total_young_available = young_generation->available_with_reserve(); - assert(young_evacuated_reserve_used <= total_young_available, "Cannot evacuate more than is available in young"); + size_t total_young_available = young_generation->available_with_reserve() - add_regions_to_old * region_size_bytes;; + assert(young_evacuated_reserve_used <= total_young_available, "Cannot evacuate (%zu) more than is available in young (%zu)", + young_evacuated_reserve_used, total_young_available); young_generation->set_evacuation_reserve(young_evacuated_reserve_used); - size_t old_available = old_generation->available(); + // We have not yet rebuilt the free set. Some of the memory that is thought to be avaiable within old may no + // longer be available if that memory had been free within regions that were selected for the collection set. + // Make the necessary adjustments to old_available. + size_t old_available = + old_generation->available() + add_regions_to_old * region_size_bytes - collection_set->get_old_available_bytes_collected(); + // Now that we've established the collection set, we know how much memory is really required by old-gen for evacuation // and promotion reserves. Try shrinking OLD now in case that gives us a bit more runway for mutator allocations during // evac and update phases. @@ -422,21 +435,27 @@ void ShenandoahGeneration::adjust_evacuation_budgets(ShenandoahHeap* const heap, if (old_available < old_consumed) { // This can happen due to round-off errors when adding the results of truncated integer arithmetic. // We've already truncated old_evacuated_committed. Truncate young_advance_promoted_reserve_used here. + assert(young_advance_promoted_reserve_used <= (33 * (old_available - old_evacuated_committed)) / 32, "Round-off errors should be less than 3.125%%, committed: %zu, reserved: %zu", young_advance_promoted_reserve_used, old_available - old_evacuated_committed); - young_advance_promoted_reserve_used = old_available - old_evacuated_committed; + if (old_available > old_evacuated_committed) { + young_advance_promoted_reserve_used = old_available - old_evacuated_committed; + } else { + young_advance_promoted_reserve_used = 0; + old_evacuated_committed = old_available; + } + // TODO: reserve for full promotion reserve, not just for advance (preselected) promotion old_consumed = old_evacuated_committed + young_advance_promoted_reserve_used; } assert(old_available >= old_consumed, "Cannot consume (%zu) more than is available (%zu)", old_consumed, old_available); size_t excess_old = old_available - old_consumed; - size_t unaffiliated_old_regions = old_generation->free_unaffiliated_regions(); + size_t unaffiliated_old_regions = old_generation->free_unaffiliated_regions() + add_regions_to_old; size_t unaffiliated_old = unaffiliated_old_regions * region_size_bytes; - assert(old_available >= unaffiliated_old, - "Unaffiliated old (%zu is %zu * %zu) is a subset of old available (%zu)", - unaffiliated_old, unaffiliated_old_regions, region_size_bytes, old_available); + assert(unaffiliated_old >= old_evacuated_committed, "Do not evacuate (%zu) more than unaffiliated old (%zu)", + old_evacuated_committed, unaffiliated_old); // Make sure old_evac_committed is unaffiliated if (old_evacuated_committed > 0) { @@ -454,20 +473,22 @@ void ShenandoahGeneration::adjust_evacuation_budgets(ShenandoahHeap* const heap, } // If we find that OLD has excess regions, give them back to YOUNG now to reduce likelihood we run out of allocation - // runway during evacuation and update-refs. - size_t regions_to_xfer = 0; + // runway during evacuation and update-refs. We may make further adjustments to balance. + ssize_t add_regions_to_young = 0; if (excess_old > unaffiliated_old) { // we can give back unaffiliated_old (all of unaffiliated is excess) if (unaffiliated_old_regions > 0) { - regions_to_xfer = unaffiliated_old_regions; + add_regions_to_young = unaffiliated_old_regions; } } else if (unaffiliated_old_regions > 0) { // excess_old < unaffiliated old: we can give back MIN(excess_old/region_size_bytes, unaffiliated_old_regions) size_t excess_regions = excess_old / region_size_bytes; - regions_to_xfer = MIN2(excess_regions, unaffiliated_old_regions); + add_regions_to_young = MIN2(excess_regions, unaffiliated_old_regions); } - if (regions_to_xfer > 0) { - excess_old -= regions_to_xfer * region_size_bytes; + + if (add_regions_to_young > 0) { + assert(excess_old >= add_regions_to_young * region_size_bytes, "Cannot xfer more than excess old"); + excess_old -= add_regions_to_young * region_size_bytes; log_debug(gc, ergo)("Before start of evacuation, total_promotion reserve is young_advance_promoted_reserve: %zu " "plus excess: old: %zu", young_advance_promoted_reserve_used, excess_old); } @@ -475,6 +496,7 @@ void ShenandoahGeneration::adjust_evacuation_budgets(ShenandoahHeap* const heap, // Add in the excess_old memory to hold unanticipated promotions, if any. If there are more unanticipated // promotions than fit in reserved memory, they will be deferred until a future GC pass. size_t total_promotion_reserve = young_advance_promoted_reserve_used + excess_old; + old_generation->set_promoted_reserve(total_promotion_reserve); old_generation->reset_promoted_expended(); } @@ -782,17 +804,13 @@ void ShenandoahGeneration::prepare_regions_and_collection_set(bool concurrent) { ShenandoahCollectionSetPreselector preselector(collection_set, heap->num_regions()); // Find the amount that will be promoted, regions that will be promoted in - // place, and preselect older regions that will be promoted by evacuation. + // place, and preselected older regions that will be promoted by evacuation. compute_evacuation_budgets(heap); - // Choose the collection set, including the regions preselected above for - // promotion into the old generation. - _heuristics->choose_collection_set(collection_set); - if (!collection_set->is_empty()) { - // only make use of evacuation budgets when we are evacuating - adjust_evacuation_budgets(heap, collection_set); - } - + // Choose the collection set, including the regions preselected above for promotion into the old generation. + size_t add_regions_to_old = _heuristics->choose_collection_set(collection_set); + // Even if collection_set->is_empty(), we want to adjust budgets, making reserves available to mutator. + adjust_evacuation_budgets(heap, collection_set, add_regions_to_old); if (is_global()) { // We have just chosen a collection set for a global cycle. The mark bitmap covering old regions is complete, so // the remembered set scan can use that to avoid walking into garbage. When the next old mark begins, we will @@ -816,17 +834,16 @@ void ShenandoahGeneration::prepare_regions_and_collection_set(bool concurrent) { ShenandoahPhaseTimings::degen_gc_final_rebuild_freeset); ShenandoahHeapLocker locker(heap->lock()); - // We are preparing for evacuation. At this time, we ignore cset region tallies. - size_t young_cset_regions, old_cset_regions, first_old, last_old, num_old; - _free_set->prepare_to_rebuild(young_cset_regions, old_cset_regions, first_old, last_old, num_old); - + // We are preparing for evacuation. + size_t young_trashed_regions, old_trashed_regions, first_old, last_old, num_old; + _free_set->prepare_to_rebuild(young_trashed_regions, old_trashed_regions, first_old, last_old, num_old); if (heap->mode()->is_generational()) { ShenandoahGenerationalHeap* gen_heap = ShenandoahGenerationalHeap::heap(); - gen_heap->compute_old_generation_balance(young_cset_regions, old_cset_regions); + size_t allocation_runway = + gen_heap->young_generation()->heuristics()->bytes_of_allocation_runway_before_gc_trigger(young_trashed_regions); + gen_heap->compute_old_generation_balance(allocation_runway, old_trashed_regions, young_trashed_regions); } - - // Free set construction uses reserve quantities, because they are known to be valid here - _free_set->finish_rebuild(young_cset_regions, old_cset_regions, num_old, true); + _free_set->finish_rebuild(young_trashed_regions, old_trashed_regions, num_old); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp index 06cf132f946..d49e3bed5f8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp @@ -63,9 +63,10 @@ private: // Compute evacuation budgets prior to choosing collection set. void compute_evacuation_budgets(ShenandoahHeap* heap); - // Adjust evacuation budgets after choosing collection set. + // Adjust evacuation budgets after choosing collection set. The argument regions_to_xfer represents regions to be + // transfered to old based on decisions made in top_off_collection_set() void adjust_evacuation_budgets(ShenandoahHeap* heap, - ShenandoahCollectionSet* collection_set); + ShenandoahCollectionSet* collection_set, size_t regions_to_xfer); // Preselect for possible inclusion into the collection set exactly the most // garbage-dense regions, including those that satisfy criteria 1 & 2 below, @@ -144,6 +145,22 @@ private: virtual void prepare_gc(); // Called during final mark, chooses collection set, rebuilds free set. + // Upon return from prepare_regions_and_collection_set(), certain parameters have been established to govern the + // evacuation efforts that are about to begin. In particular: + // + // old_generation->get_promoted_reserve() represents the amount of memory within old-gen's available memory that has + // been set aside to hold objects promoted from young-gen memory. This represents an estimated percentage + // of the live young-gen memory within the collection set. If there is more data ready to be promoted than + // can fit within this reserve, the promotion of some objects will be deferred until a subsequent evacuation + // pass. + // + // old_generation->get_evacuation_reserve() represents the amount of memory within old-gen's available memory that has been + // set aside to hold objects evacuated from the old-gen collection set. + // + // young_generation->get_evacuation_reserve() represents the amount of memory within young-gen's available memory that has + // been set aside to hold objects evacuated from the young-gen collection set. Conservatively, this value + // equals the entire amount of live young-gen memory within the collection set, even though some of this memory + // will likely be promoted. virtual void prepare_regions_and_collection_set(bool concurrent); // Cancel marking (used by Full collect and when cancelling cycle). diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp index 78672ee10a5..1b11c696d18 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp @@ -55,9 +55,6 @@ void ShenandoahGenerationalFullGC::prepare() { // Since we may arrive here from degenerated GC failure of either young or old, establish generation as GLOBAL. heap->set_active_generation(heap->global_generation()); - // No need for old_gen->increase_used() as this was done when plabs were allocated. - heap->reset_generation_reserves(); - // Full GC supersedes any marking or coalescing in old generation. heap->old_generation()->cancel_gc(); } @@ -156,8 +153,11 @@ void ShenandoahGenerationalFullGC::compute_balances() { // In case this Full GC resulted from degeneration, clear the tally on anticipated promotion. heap->old_generation()->set_promotion_potential(0); - // Invoke this in case we are able to transfer memory from OLD to YOUNG. - heap->compute_old_generation_balance(0, 0); + + // Invoke this in case we are able to transfer memory from OLD to YOUNG + size_t allocation_runway = + heap->young_generation()->heuristics()->bytes_of_allocation_runway_before_gc_trigger(0L); + heap->compute_old_generation_balance(allocation_runway, 0, 0); } ShenandoahPrepareForGenerationalCompactionObjectClosure::ShenandoahPrepareForGenerationalCompactionObjectClosure(PreservedMarks* preserved_marks, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index fa78e02e6af..36ea0b9e497 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -299,9 +299,9 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, uint alloc_from_lab = false; } // else, we leave copy equal to nullptr, signaling a promotion failure below if appropriate. - // We choose not to promote objects smaller than PLAB::min_size() by way of shared allocations, as this is too + // We choose not to promote objects smaller than size_threshold by way of shared allocations as this is too // costly. Instead, we'll simply "evacuate" to young-gen memory (using a GCLAB) and will promote in a future - // evacuation pass. This condition is denoted by: is_promotion && has_plab && (size <= PLAB::min_size()) + // evacuation pass. This condition is denoted by: is_promotion && has_plab && (size <= size_threshhold). } #ifdef ASSERT } @@ -576,19 +576,18 @@ void ShenandoahGenerationalHeap::retire_plab(PLAB* plab) { // Make sure old-generation is large enough, but no larger than is necessary, to hold mixed evacuations // and promotions, if we anticipate either. Any deficit is provided by the young generation, subject to -// xfer_limit, and any surplus is transferred to the young generation. -// -// xfer_limit is the maximum we're able to transfer from young to old based on either: -// 1. an assumption that we will be able to replenish memory "borrowed" from young at the end of collection, or -// 2. there is sufficient excess in the allocation runway during GC idle cycles -void ShenandoahGenerationalHeap::compute_old_generation_balance(size_t old_xfer_limit, size_t old_cset_regions) { - +// mutator_xfer_limit, and any surplus is transferred to the young generation. mutator_xfer_limit is +// the maximum we're able to transfer from young to old. This is called at the end of GC, as we prepare +// for the idle span that precedes the next GC. +void ShenandoahGenerationalHeap::compute_old_generation_balance(size_t mutator_xfer_limit, + size_t old_trashed_regions, size_t young_trashed_regions) { + shenandoah_assert_heaplocked(); // We can limit the old reserve to the size of anticipated promotions: // max_old_reserve is an upper bound on memory evacuated from old and promoted to old, // clamped by the old generation space available. // // Here's the algebra. - // Let SOEP = ShenandoahOldEvacRatioPercent, + // Let SOEP = ShenandoahOldEvacPercent, // OE = old evac, // YE = young evac, and // TE = total evac = OE + YE @@ -600,81 +599,171 @@ void ShenandoahGenerationalHeap::compute_old_generation_balance(size_t old_xfer_ // => OE = YE*SOEP/(100-SOEP) // We have to be careful in the event that SOEP is set to 100 by the user. - assert(ShenandoahOldEvacRatioPercent <= 100, "Error"); - const size_t old_available = old_generation()->available(); - // The free set will reserve this amount of memory to hold young evacuations - const size_t young_reserve = (young_generation()->max_capacity() * ShenandoahEvacReserve) / 100; - - // In the case that ShenandoahOldEvacRatioPercent equals 100, max_old_reserve is limited only by xfer_limit. - - const double bound_on_old_reserve = old_available + old_xfer_limit + young_reserve; - const double max_old_reserve = ((ShenandoahOldEvacRatioPercent == 100)? bound_on_old_reserve: - MIN2(double(young_reserve * ShenandoahOldEvacRatioPercent) - / double(100 - ShenandoahOldEvacRatioPercent), bound_on_old_reserve)); - + assert(ShenandoahOldEvacPercent <= 100, "Error"); const size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes(); + ShenandoahOldGeneration* old_gen = old_generation(); + size_t old_capacity = old_gen->max_capacity(); + size_t old_usage = old_gen->used(); // includes humongous waste + size_t old_available = ((old_capacity >= old_usage)? old_capacity - old_usage: 0) + old_trashed_regions * region_size_bytes; + + ShenandoahYoungGeneration* young_gen = young_generation(); + size_t young_capacity = young_gen->max_capacity(); + size_t young_usage = young_gen->used(); // includes humongous waste + size_t young_available = ((young_capacity >= young_usage)? young_capacity - young_usage: 0); + size_t freeset_available = free_set()->available_locked(); + if (young_available > freeset_available) { + young_available = freeset_available; + } + young_available += young_trashed_regions * region_size_bytes; + + // The free set will reserve this amount of memory to hold young evacuations (initialized to the ideal reserve) + size_t young_reserve = (young_generation()->max_capacity() * ShenandoahEvacReserve) / 100; + + // If ShenandoahOldEvacPercent equals 100, max_old_reserve is limited only by mutator_xfer_limit and young_reserve + const size_t bound_on_old_reserve = ((old_available + mutator_xfer_limit + young_reserve) * ShenandoahOldEvacPercent) / 100; + size_t proposed_max_old = ((ShenandoahOldEvacPercent == 100)? + bound_on_old_reserve: + MIN2((young_reserve * ShenandoahOldEvacPercent) / (100 - ShenandoahOldEvacPercent), + bound_on_old_reserve)); + if (young_reserve > young_available) { + young_reserve = young_available; + } + // Decide how much old space we should reserve for a mixed collection - double reserve_for_mixed = 0; - if (old_generation()->has_unprocessed_collection_candidates()) { + size_t reserve_for_mixed = 0; + const size_t old_fragmented_available = + old_available - (old_generation()->free_unaffiliated_regions() + old_trashed_regions) * region_size_bytes; + + if (old_fragmented_available > proposed_max_old) { + // After we've promoted regions in place, there may be an abundance of old-fragmented available memory, + // even more than the desired percentage for old reserve. We cannot transfer these fragmented regions back + // to young. Instead we make the best of the situation by using this fragmented memory for both promotions + // and evacuations. + proposed_max_old = old_fragmented_available; + } + size_t reserve_for_promo = old_fragmented_available; + const size_t max_old_reserve = proposed_max_old; + const size_t mixed_candidate_live_memory = old_generation()->unprocessed_collection_candidates_live_memory(); + const bool doing_mixed = (mixed_candidate_live_memory > 0); + if (doing_mixed) { // We want this much memory to be unfragmented in order to reliably evacuate old. This is conservative because we // may not evacuate the entirety of unprocessed candidates in a single mixed evacuation. - const double max_evac_need = - (double(old_generation()->unprocessed_collection_candidates_live_memory()) * ShenandoahOldEvacWaste); + const size_t max_evac_need = (size_t) (mixed_candidate_live_memory * ShenandoahOldEvacWaste); assert(old_available >= old_generation()->free_unaffiliated_regions() * region_size_bytes, "Unaffiliated available must be less than total available"); - const double old_fragmented_available = - double(old_available - old_generation()->free_unaffiliated_regions() * region_size_bytes); - reserve_for_mixed = max_evac_need + old_fragmented_available; - if (reserve_for_mixed > max_old_reserve) { - reserve_for_mixed = max_old_reserve; + + // We prefer to evacuate all of mixed into unfragmented memory, and will expand old in order to do so, unless + // we already have too much fragmented available memory in old. + reserve_for_mixed = max_evac_need; + if (reserve_for_mixed + reserve_for_promo > max_old_reserve) { + // In this case, we'll allow old-evac to target some of the fragmented old memory. + size_t excess_reserves = (reserve_for_mixed + reserve_for_promo) - max_old_reserve; + if (reserve_for_promo > excess_reserves) { + reserve_for_promo -= excess_reserves; + } else { + excess_reserves -= reserve_for_promo; + reserve_for_promo = 0; + reserve_for_mixed -= excess_reserves; + } } } - // Decide how much space we should reserve for promotions from young - size_t reserve_for_promo = 0; + // Decide how much additional space we should reserve for promotions from young. We give priority to mixed evacations + // over promotions. const size_t promo_load = old_generation()->get_promotion_potential(); const bool doing_promotions = promo_load > 0; if (doing_promotions) { - // We're promoting and have a bound on the maximum amount that can be promoted - assert(max_old_reserve >= reserve_for_mixed, "Sanity"); - const size_t available_for_promotions = max_old_reserve - reserve_for_mixed; - reserve_for_promo = MIN2((size_t)(promo_load * ShenandoahPromoEvacWaste), available_for_promotions); + // We've already set aside all of the fragmented available memory within old-gen to represent old objects + // to be promoted from young generation. promo_load represents the memory that we anticipate to be promoted + // from regions that have reached tenure age. In the ideal, we will always use fragmented old-gen memory + // to hold individually promoted objects and will use unfragmented old-gen memory to represent the old-gen + // evacuation workloa. + + // We're promoting and have an estimate of memory to be promoted from aged regions + assert(max_old_reserve >= (reserve_for_mixed + reserve_for_promo), "Sanity"); + const size_t available_for_additional_promotions = max_old_reserve - (reserve_for_mixed + reserve_for_promo); + size_t promo_need = (size_t)(promo_load * ShenandoahPromoEvacWaste); + if (promo_need > reserve_for_promo) { + reserve_for_promo += MIN2(promo_need - reserve_for_promo, available_for_additional_promotions); + } + // We've already reserved all the memory required for the promo_load, and possibly more. The excess + // can be consumed by objects promoted from regions that have not yet reached tenure age. } - // This is the total old we want to ideally reserve - const size_t old_reserve = reserve_for_mixed + reserve_for_promo; - assert(old_reserve <= max_old_reserve, "cannot reserve more than max for old evacuations"); + // This is the total old we want to reserve (initialized to the ideal reserve) + size_t old_reserve = reserve_for_mixed + reserve_for_promo; // We now check if the old generation is running a surplus or a deficit. - const size_t max_old_available = old_generation()->available() + old_cset_regions * region_size_bytes; - if (max_old_available >= old_reserve) { - // We are running a surplus, so the old region surplus can go to young - const size_t old_surplus = (max_old_available - old_reserve) / region_size_bytes; - const size_t unaffiliated_old_regions = old_generation()->free_unaffiliated_regions() + old_cset_regions; - const size_t old_region_surplus = MIN2(old_surplus, unaffiliated_old_regions); - old_generation()->set_region_balance(checked_cast(old_region_surplus)); - } else { - // We are running a deficit which we'd like to fill from young. - // Ignore that this will directly impact young_generation()->max_capacity(), - // indirectly impacting young_reserve and old_reserve. These computations are conservative. - // Note that deficit is rounded up by one region. - const size_t old_need = (old_reserve - max_old_available + region_size_bytes - 1) / region_size_bytes; - const size_t max_old_region_xfer = old_xfer_limit / region_size_bytes; + size_t old_region_deficit = 0; + size_t old_region_surplus = 0; - // Round down the regions we can transfer from young to old. If we're running short - // on young-gen memory, we restrict the xfer. Old-gen collection activities will be - // curtailed if the budget is restricted. - const size_t old_region_deficit = MIN2(old_need, max_old_region_xfer); + size_t mutator_region_xfer_limit = mutator_xfer_limit / region_size_bytes; + // align the mutator_xfer_limit on region size + mutator_xfer_limit = mutator_region_xfer_limit * region_size_bytes; + + if (old_available >= old_reserve) { + // We are running a surplus, so the old region surplus can go to young + const size_t old_surplus = old_available - old_reserve; + old_region_surplus = old_surplus / region_size_bytes; + const size_t unaffiliated_old_regions = old_generation()->free_unaffiliated_regions() + old_trashed_regions; + old_region_surplus = MIN2(old_region_surplus, unaffiliated_old_regions); + old_generation()->set_region_balance(checked_cast(old_region_surplus)); + } else if (old_available + mutator_xfer_limit >= old_reserve) { + // Mutator's xfer limit is sufficient to satisfy our need: transfer all memory from there + size_t old_deficit = old_reserve - old_available; + old_region_deficit = (old_deficit + region_size_bytes - 1) / region_size_bytes; + old_generation()->set_region_balance(0 - checked_cast(old_region_deficit)); + } else { + // We'll try to xfer from both mutator excess and from young collector reserve + size_t available_reserves = old_available + young_reserve + mutator_xfer_limit; + size_t old_entitlement = (available_reserves * ShenandoahOldEvacPercent) / 100; + + // Round old_entitlement down to nearest multiple of regions to be transferred to old + size_t entitled_xfer = old_entitlement - old_available; + entitled_xfer = region_size_bytes * (entitled_xfer / region_size_bytes); + size_t unaffiliated_young_regions = young_generation()->free_unaffiliated_regions(); + size_t unaffiliated_young_memory = unaffiliated_young_regions * region_size_bytes; + if (entitled_xfer > unaffiliated_young_memory) { + entitled_xfer = unaffiliated_young_memory; + } + old_entitlement = old_available + entitled_xfer; + if (old_entitlement < old_reserve) { + // There's not enough memory to satisfy our desire. Scale back our old-gen intentions. + size_t budget_overrun = old_reserve - old_entitlement;; + if (reserve_for_promo > budget_overrun) { + reserve_for_promo -= budget_overrun; + old_reserve -= budget_overrun; + } else { + budget_overrun -= reserve_for_promo; + reserve_for_promo = 0; + reserve_for_mixed = (reserve_for_mixed > budget_overrun)? reserve_for_mixed - budget_overrun: 0; + old_reserve = reserve_for_promo + reserve_for_mixed; + } + } + + // Because of adjustments above, old_reserve may be smaller now than it was when we tested the branch + // condition above: "(old_available + mutator_xfer_limit >= old_reserve) + // Therefore, we do NOT know that: mutator_xfer_limit < old_reserve - old_available + + size_t old_deficit = old_reserve - old_available; + old_region_deficit = (old_deficit + region_size_bytes - 1) / region_size_bytes; + + // Shrink young_reserve to account for loan to old reserve + const size_t reserve_xfer_regions = old_region_deficit - mutator_region_xfer_limit; + young_reserve -= reserve_xfer_regions * region_size_bytes; old_generation()->set_region_balance(0 - checked_cast(old_region_deficit)); } -} -void ShenandoahGenerationalHeap::reset_generation_reserves() { - ShenandoahHeapLocker locker(lock()); - young_generation()->set_evacuation_reserve(0); - old_generation()->set_evacuation_reserve(0); - old_generation()->set_promoted_reserve(0); + assert(old_region_deficit == 0 || old_region_surplus == 0, "Only surplus or deficit, never both"); + assert(young_reserve + reserve_for_mixed + reserve_for_promo <= old_available + young_available, + "Cannot reserve more memory than is available: %zu + %zu + %zu <= %zu + %zu", + young_reserve, reserve_for_mixed, reserve_for_promo, old_available, young_available); + + // deficit/surplus adjustments to generation sizes will precede rebuild + young_generation()->set_evacuation_reserve(young_reserve); + old_generation()->set_evacuation_reserve(reserve_for_mixed); + old_generation()->set_promoted_reserve(reserve_for_promo); } void ShenandoahGenerationalHeap::coalesce_and_fill_old_regions(bool concurrent) { @@ -1015,10 +1104,6 @@ void ShenandoahGenerationalHeap::final_update_refs_update_region_states() { void ShenandoahGenerationalHeap::complete_degenerated_cycle() { shenandoah_assert_heaplocked_or_safepoint(); - // In case degeneration interrupted concurrent evacuation or update references, we need to clean up - // transient state. Otherwise, these actions have no effect. - reset_generation_reserves(); - if (!old_generation()->is_parsable()) { ShenandoahGCPhase phase(ShenandoahPhaseTimings::degen_gc_coalesce_and_fill); coalesce_and_fill_old_regions(false); @@ -1036,7 +1121,6 @@ void ShenandoahGenerationalHeap::complete_concurrent_cycle() { // throw off the heuristics. entry_global_coalesce_and_fill(); } - reset_generation_reserves(); } void ShenandoahGenerationalHeap::entry_global_coalesce_and_fill() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp index a2ae4a68cd0..719bae52a83 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp @@ -136,7 +136,7 @@ public: void reset_generation_reserves(); // Computes the optimal size for the old generation, represented as a surplus or deficit of old regions - void compute_old_generation_balance(size_t old_xfer_limit, size_t old_cset_regions); + void compute_old_generation_balance(size_t old_xfer_limit, size_t old_trashed_regions, size_t young_trashed_regions); // Balances generations, coalesces and fills old regions if necessary void complete_degenerated_cycle(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 683e2959a92..ef99bd98c93 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -425,20 +425,29 @@ jint ShenandoahHeap::initialize() { _affiliations[i] = ShenandoahAffiliation::FREE; } + + if (mode()->is_generational()) { + size_t young_reserve = (soft_max_capacity() * ShenandoahEvacReserve) / 100; + young_generation()->set_evacuation_reserve(young_reserve); + old_generation()->set_evacuation_reserve((size_t) 0); + old_generation()->set_promoted_reserve((size_t) 0); + } + _free_set = new ShenandoahFreeSet(this, _num_regions); post_initialize_heuristics(); + // We are initializing free set. We ignore cset region tallies. - size_t young_cset_regions, old_cset_regions, first_old, last_old, num_old; - _free_set->prepare_to_rebuild(young_cset_regions, old_cset_regions, first_old, last_old, num_old); + size_t young_trashed_regions, old_trashed_regions, first_old, last_old, num_old; + _free_set->prepare_to_rebuild(young_trashed_regions, old_trashed_regions, first_old, last_old, num_old); if (mode()->is_generational()) { ShenandoahGenerationalHeap* gen_heap = ShenandoahGenerationalHeap::heap(); // We cannot call // gen_heap->young_generation()->heuristics()->bytes_of_allocation_runway_before_gc_trigger(young_cset_regions) // until after the heap is fully initialized. So we make up a safe value here. size_t allocation_runway = InitialHeapSize / 2; - gen_heap->compute_old_generation_balance(allocation_runway, old_cset_regions); + gen_heap->compute_old_generation_balance(allocation_runway, old_trashed_regions, young_trashed_regions); } - _free_set->finish_rebuild(young_cset_regions, old_cset_regions, num_old); + _free_set->finish_rebuild(young_trashed_regions, old_trashed_regions, num_old); } if (AlwaysPreTouch) { @@ -2521,13 +2530,10 @@ void ShenandoahHeap::final_update_refs_update_region_states() { parallel_heap_region_iterate(&cl); } -void ShenandoahHeap::rebuild_free_set(bool concurrent) { - ShenandoahGCPhase phase(concurrent ? - ShenandoahPhaseTimings::final_update_refs_rebuild_freeset : - ShenandoahPhaseTimings::degen_gc_final_update_refs_rebuild_freeset); +void ShenandoahHeap::rebuild_free_set_within_phase() { ShenandoahHeapLocker locker(lock()); - size_t young_cset_regions, old_cset_regions, first_old_region, last_old_region, old_region_count; - _free_set->prepare_to_rebuild(young_cset_regions, old_cset_regions, first_old_region, last_old_region, old_region_count); + size_t young_trashed_regions, old_trashed_regions, first_old_region, last_old_region, old_region_count; + _free_set->prepare_to_rebuild(young_trashed_regions, old_trashed_regions, first_old_region, last_old_region, old_region_count); // If there are no old regions, first_old_region will be greater than last_old_region assert((first_old_region > last_old_region) || ((last_old_region + 1 - first_old_region >= old_region_count) && @@ -2546,19 +2552,11 @@ void ShenandoahHeap::rebuild_free_set(bool concurrent) { // available for transfer to old. Note that transfer of humongous regions does not impact available. ShenandoahGenerationalHeap* gen_heap = ShenandoahGenerationalHeap::heap(); size_t allocation_runway = - gen_heap->young_generation()->heuristics()->bytes_of_allocation_runway_before_gc_trigger(young_cset_regions); - gen_heap->compute_old_generation_balance(allocation_runway, old_cset_regions); - - // Total old_available may have been expanded to hold anticipated promotions. We trigger if the fragmented available - // memory represents more than 16 regions worth of data. Note that fragmentation may increase when we promote regular - // regions in place when many of these regular regions have an abundant amount of available memory within them. - // Fragmentation will decrease as promote-by-copy consumes the available memory within these partially consumed regions. - // - // We consider old-gen to have excessive fragmentation if more than 12.5% of old-gen is free memory that resides - // within partially consumed regions of memory. + gen_heap->young_generation()->heuristics()->bytes_of_allocation_runway_before_gc_trigger(young_trashed_regions); + gen_heap->compute_old_generation_balance(allocation_runway, old_trashed_regions, young_trashed_regions); } // Rebuild free set based on adjusted generation sizes. - _free_set->finish_rebuild(young_cset_regions, old_cset_regions, old_region_count); + _free_set->finish_rebuild(young_trashed_regions, old_trashed_regions, old_region_count); if (mode()->is_generational()) { ShenandoahGenerationalHeap* gen_heap = ShenandoahGenerationalHeap::heap(); @@ -2567,6 +2565,13 @@ void ShenandoahHeap::rebuild_free_set(bool concurrent) { } } +void ShenandoahHeap::rebuild_free_set(bool concurrent) { + ShenandoahGCPhase phase(concurrent ? + ShenandoahPhaseTimings::final_update_refs_rebuild_freeset : + ShenandoahPhaseTimings::degen_gc_final_update_refs_rebuild_freeset); + rebuild_free_set_within_phase(); +} + bool ShenandoahHeap::is_bitmap_slice_committed(ShenandoahHeapRegion* r, bool skip_self) { size_t slice = r->index() / _bitmap_regions_per_slice; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 65e3803627c..174001170f4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -481,7 +481,9 @@ private: void rendezvous_threads(const char* name); void recycle_trash(); public: + // The following two functions rebuild the free set at the end of GC, in preparation for an idle phase. void rebuild_free_set(bool concurrent); + void rebuild_free_set_within_phase(); void notify_gc_progress(); void notify_gc_no_progress(); size_t get_gc_no_progress_count() const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp index e794a86e473..6bb8382de0a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp @@ -595,6 +595,8 @@ void ShenandoahHeapRegion::try_recycle_under_lock() { _recycling.unset(); } else { // Ensure recycling is unset before returning to mutator to continue memory allocation. + // Otherwise, the mutator might see region as fully recycled and might change its affiliation only to have + // the racing GC worker thread overwrite its affiliation to FREE. while (_recycling.is_set()) { if (os::is_MP()) { SpinPause(); @@ -605,6 +607,8 @@ void ShenandoahHeapRegion::try_recycle_under_lock() { } } +// Note that return from try_recycle() does not mean the region has been recycled. It only means that +// some GC worker thread has taken responsibility to recycle the region, eventually. void ShenandoahHeapRegion::try_recycle() { shenandoah_assert_not_heaplocked(); if (is_trash() && _recycling.try_set()) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp index a44a831ef3d..ff441a0c868 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp @@ -128,8 +128,6 @@ bool ShenandoahOldGC::collect(GCCause::Cause cause) { // the space. This would be the last action if there is nothing to evacuate. entry_cleanup_early(); - heap->free_set()->log_status_under_lock(); - assert(!heap->is_concurrent_strong_root_in_progress(), "No evacuations during old gc."); // We must execute this vm operation if we completed final mark. We cannot @@ -138,7 +136,10 @@ bool ShenandoahOldGC::collect(GCCause::Cause cause) { // collection. heap->concurrent_final_roots(); - size_t allocation_runway = heap->young_generation()->heuristics()->bytes_of_allocation_runway_before_gc_trigger(0); - heap->compute_old_generation_balance(allocation_runway, 0); + // After concurrent old marking finishes, we reclaim immediate garbage. Further, we may also want to expand OLD in order + // to make room for anticipated promotions and/or for mixed evacuations. Mixed evacuations are especially likely to + // follow the end of OLD marking. + heap->rebuild_free_set_within_phase(); + heap->free_set()->log_status_under_lock(); return true; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index c795eda3d96..aed768b9db1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -427,8 +427,7 @@ void ShenandoahOldGeneration::prepare_regions_and_collection_set(bool concurrent ShenandoahGenerationalHeap* gen_heap = ShenandoahGenerationalHeap::heap(); size_t allocation_runway = gen_heap->young_generation()->heuristics()->bytes_of_allocation_runway_before_gc_trigger(young_trash_regions); - gen_heap->compute_old_generation_balance(allocation_runway, old_trash_regions); - + gen_heap->compute_old_generation_balance(allocation_runway, old_trash_regions, young_trash_regions); heap->free_set()->finish_rebuild(young_trash_regions, old_trash_regions, num_old); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp index 90c1458ac97..633d2c9f617 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp @@ -66,8 +66,8 @@ private: // remaining in a PLAB when it is retired. size_t _promoted_expended; - // Represents the quantity of live bytes we expect to promote during the next evacuation - // cycle. This value is used by the young heuristic to trigger mixed collections. + // Represents the quantity of live bytes we expect to promote during the next GC cycle, either by + // evacuation or by promote-in-place. This value is used by the young heuristic to trigger mixed collections. // It is also used when computing the optimum size for the old generation. size_t _promotion_potential; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp index a3c96a7d53b..05af25f13ad 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp @@ -243,8 +243,7 @@ HeapWord* ShenandoahCardCluster::first_object_start(const size_t card_index, con #ifdef ASSERT assert(ShenandoahHeap::heap()->mode()->is_generational(), "Do not use in non-generational mode"); assert(region->is_old(), "Do not use for young regions"); - // For HumongousRegion:s it's more efficient to jump directly to the - // start region. + // For humongous regions it's more efficient to jump directly to the start region. assert(!region->is_humongous(), "Use region->humongous_start_region() instead"); #endif diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index 543df2422c0..0cc6d4c6ed4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -420,7 +420,14 @@ public: // span is the total memory affiliated with these stats (some of which is in use and other is available) size_t span() const { return _regions * ShenandoahHeapRegion::region_size_bytes(); } - size_t non_trashed_span() const { return (_regions - _trashed_regions) * ShenandoahHeapRegion::region_size_bytes(); } + size_t non_trashed_span() const { + assert(_regions >= _trashed_regions, "sanity"); + return (_regions - _trashed_regions) * ShenandoahHeapRegion::region_size_bytes(); + } + size_t non_trashed_committed() const { + assert(_committed >= _trashed_regions * ShenandoahHeapRegion::region_size_bytes(), "sanity"); + return _committed - (_trashed_regions * ShenandoahHeapRegion::region_size_bytes()); + } }; class ShenandoahGenerationStatsClosure : public ShenandoahHeapRegionClosure { diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index 254483d1923..3eb1a06a911 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -400,27 +400,20 @@ "reserve/waste is incorrect, at the risk that application " \ "runs out of memory too early.") \ \ - product(uintx, ShenandoahOldEvacRatioPercent, 75, EXPERIMENTAL, \ - "The maximum proportion of evacuation from old-gen memory, " \ - "expressed as a percentage. The default value 75 denotes that " \ - "no more than 75% of the collection set evacuation workload may " \ - "be towards evacuation of old-gen heap regions. This limits both "\ - "the promotion of aged regions and the compaction of existing " \ - "old regions. A value of 75 denotes that the total evacuation " \ - "work may increase to up to four times the young gen evacuation " \ - "work. A larger value allows quicker promotion and allows " \ - "a smaller number of mixed evacuations to process " \ - "the entire list of old-gen collection candidates at the cost " \ - "of an increased disruption of the normal cadence of young-gen " \ - "collections. A value of 100 allows a mixed evacuation to " \ - "focus entirely on old-gen memory, allowing no young-gen " \ - "regions to be collected, likely resulting in subsequent " \ - "allocation failures because the allocation pool is not " \ - "replenished. A value of 0 allows a mixed evacuation to " \ - "focus entirely on young-gen memory, allowing no old-gen " \ - "regions to be collected, likely resulting in subsequent " \ - "promotion failures and triggering of stop-the-world full GC " \ - "events.") \ + product(uintx, ShenandoahOldEvacPercent, 75, EXPERIMENTAL, \ + "The maximum evacuation to old-gen expressed as a percent of " \ + "the total live memory within the collection set. With the " \ + "default setting, if collection set evacuates X, no more than " \ + "75% of X may hold objects evacuated from old or promoted to " \ + "old from young. A value of 100 allows the entire collection " \ + "set to be comprised of old-gen regions and young regions that " \ + "have reached the tenure age. Larger values allow fewer mixed " \ + "evacuations to reclaim all the garbage from old. Smaller " \ + "values result in less variation in GC cycle times between " \ + "young vs. mixed cycles. A value of 0 prevents mixed " \ + "evacations from running and blocks promotion of aged regions " \ + "by evacuation. Setting the value to 0 does not prevent " \ + "regions from being promoted in place.") \ range(0,100) \ \ product(bool, ShenandoahEvacTracking, false, DIAGNOSTIC, \ diff --git a/test/hotspot/gtest/gc/shenandoah/test_shenandoahOldHeuristic.cpp b/test/hotspot/gtest/gc/shenandoah/test_shenandoahOldHeuristic.cpp index b184b19ce6c..c0ec1bcf3c9 100644 --- a/test/hotspot/gtest/gc/shenandoah/test_shenandoahOldHeuristic.cpp +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahOldHeuristic.cpp @@ -201,7 +201,9 @@ TEST_VM_F(ShenandoahOldHeuristicTest, prime_one_old_region) { size_t garbage = make_garbage_above_collection_threshold(10); _heuristics->prepare_for_old_collections(); - _heuristics->prime_collection_set(_collection_set); + if (_heuristics->prime_collection_set(_collection_set)) { + _heuristics->finalize_mixed_evacs(); + } EXPECT_TRUE(collection_set_is(10UL)); EXPECT_EQ(garbage, _collection_set->get_old_garbage()); @@ -214,7 +216,9 @@ TEST_VM_F(ShenandoahOldHeuristicTest, prime_many_old_regions) { size_t g1 = make_garbage_above_collection_threshold(100); size_t g2 = make_garbage_above_collection_threshold(101); _heuristics->prepare_for_old_collections(); - _heuristics->prime_collection_set(_collection_set); + if (_heuristics->prime_collection_set(_collection_set)) { + _heuristics->finalize_mixed_evacs(); + } EXPECT_TRUE(collection_set_is(100UL, 101UL)); EXPECT_EQ(g1 + g2, _collection_set->get_old_garbage()); @@ -226,7 +230,9 @@ TEST_VM_F(ShenandoahOldHeuristicTest, require_multiple_mixed_evacuations) { size_t garbage = create_too_much_garbage_for_one_mixed_evacuation(); _heuristics->prepare_for_old_collections(); - _heuristics->prime_collection_set(_collection_set); + if (_heuristics->prime_collection_set(_collection_set)) { + _heuristics->finalize_mixed_evacs(); + } EXPECT_LT(_collection_set->get_old_garbage(), garbage); EXPECT_GT(_heuristics->unprocessed_old_collection_candidates(), 0UL); @@ -248,7 +254,9 @@ TEST_VM_F(ShenandoahOldHeuristicTest, skip_pinned_regions) { ASSERT_EQ(3UL, _heuristics->unprocessed_old_collection_candidates()); // Here the region is still pinned, so it cannot be added to the collection set. - _heuristics->prime_collection_set(_collection_set); + if (_heuristics->prime_collection_set(_collection_set)) { + _heuristics->finalize_mixed_evacs(); + } // The two unpinned regions should be added to the collection set and the pinned // region should be retained at the front of the list of candidates as it would be @@ -261,7 +269,9 @@ TEST_VM_F(ShenandoahOldHeuristicTest, skip_pinned_regions) { // the now unpinned region should be added to the collection set. make_unpinned(1); _collection_set->clear(); - _heuristics->prime_collection_set(_collection_set); + if (_heuristics->prime_collection_set(_collection_set)) { + _heuristics->finalize_mixed_evacs(); + } EXPECT_EQ(_collection_set->get_old_garbage(), g2); EXPECT_TRUE(collection_set_is(1UL)); @@ -278,14 +288,18 @@ TEST_VM_F(ShenandoahOldHeuristicTest, pinned_region_is_first) { make_pinned(0); _heuristics->prepare_for_old_collections(); - _heuristics->prime_collection_set(_collection_set); + if (_heuristics->prime_collection_set(_collection_set)) { + _heuristics->finalize_mixed_evacs(); + } EXPECT_TRUE(collection_set_is(1UL, 2UL)); EXPECT_EQ(_heuristics->unprocessed_old_collection_candidates(), 1UL); make_unpinned(0); _collection_set->clear(); - _heuristics->prime_collection_set(_collection_set); + if (_heuristics->prime_collection_set(_collection_set)) { + _heuristics->finalize_mixed_evacs(); + } EXPECT_TRUE(collection_set_is(0UL)); EXPECT_EQ(_heuristics->unprocessed_old_collection_candidates(), 0UL); @@ -301,7 +315,9 @@ TEST_VM_F(ShenandoahOldHeuristicTest, pinned_region_is_last) { make_pinned(2); _heuristics->prepare_for_old_collections(); - _heuristics->prime_collection_set(_collection_set); + if (_heuristics->prime_collection_set(_collection_set)) { + _heuristics->finalize_mixed_evacs(); + } EXPECT_TRUE(collection_set_is(0UL, 1UL)); EXPECT_EQ(_collection_set->get_old_garbage(), g1 + g2); @@ -309,7 +325,9 @@ TEST_VM_F(ShenandoahOldHeuristicTest, pinned_region_is_last) { make_unpinned(2); _collection_set->clear(); - _heuristics->prime_collection_set(_collection_set); + if (_heuristics->prime_collection_set(_collection_set)) { + _heuristics->finalize_mixed_evacs(); + } EXPECT_TRUE(collection_set_is(2UL)); EXPECT_EQ(_collection_set->get_old_garbage(), g3); @@ -327,7 +345,9 @@ TEST_VM_F(ShenandoahOldHeuristicTest, unpinned_region_is_middle) { make_pinned(0); make_pinned(2); _heuristics->prepare_for_old_collections(); - _heuristics->prime_collection_set(_collection_set); + if (_heuristics->prime_collection_set(_collection_set)) { + _heuristics->finalize_mixed_evacs(); + } EXPECT_TRUE(collection_set_is(1UL)); EXPECT_EQ(_collection_set->get_old_garbage(), g2); @@ -336,7 +356,9 @@ TEST_VM_F(ShenandoahOldHeuristicTest, unpinned_region_is_middle) { make_unpinned(0); make_unpinned(2); _collection_set->clear(); - _heuristics->prime_collection_set(_collection_set); + if (_heuristics->prime_collection_set(_collection_set)) { + _heuristics->finalize_mixed_evacs(); + } EXPECT_TRUE(collection_set_is(0UL, 2UL)); EXPECT_EQ(_collection_set->get_old_garbage(), g1 + g3); @@ -354,7 +376,9 @@ TEST_VM_F(ShenandoahOldHeuristicTest, all_candidates_are_pinned) { make_pinned(1); make_pinned(2); _heuristics->prepare_for_old_collections(); - _heuristics->prime_collection_set(_collection_set); + if (_heuristics->prime_collection_set(_collection_set)) { + _heuristics->finalize_mixed_evacs(); + } // In the case when all candidates are pinned, we want to abandon // this set of mixed collection candidates so that another old collection From 25d2b52ab97d116024872e567c1c1ffd814616d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Thu, 22 Jan 2026 21:48:28 +0000 Subject: [PATCH 153/328] 8328046: Need to keep leading zeros in TlsPremasterSecret of TLS1.3 DHKeyAgreement Reviewed-by: hchao --- .../share/classes/sun/security/ssl/KAKeyDerivation.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java b/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java index 39e82b50435..af62faf4706 100644 --- a/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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 @@ -214,13 +214,13 @@ public class KAKeyDerivation implements SSLKeyDerivation { var decapsulator = kem.newDecapsulator(localPrivateKey); sharedSecret = decapsulator.decapsulate( keyshare, 0, decapsulator.secretSize(), - "TlsPremasterSecret"); + "Generic"); } else { // Using traditional DH-style Key Agreement KeyAgreement ka = KeyAgreement.getInstance(algorithmName); ka.init(localPrivateKey); ka.doPhase(peerPublicKey, true); - sharedSecret = ka.generateSecret("TlsPremasterSecret"); + sharedSecret = ka.generateSecret("Generic"); } return deriveHandshakeSecret(type, sharedSecret); From 0f087a7fef2d3979badefde02a1e85351379f18c Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Fri, 23 Jan 2026 00:57:25 +0000 Subject: [PATCH 154/328] 8376051: gc/stress/TestStressG1Uncommit.java fails assertLessThan: expected that xxx < xxx Reviewed-by: tschatzl, shade --- test/hotspot/jtreg/gc/stress/TestStressG1Uncommit.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/gc/stress/TestStressG1Uncommit.java b/test/hotspot/jtreg/gc/stress/TestStressG1Uncommit.java index 9d1f95aa411..4e2b9dd5be7 100644 --- a/test/hotspot/jtreg/gc/stress/TestStressG1Uncommit.java +++ b/test/hotspot/jtreg/gc/stress/TestStressG1Uncommit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ public class TestStressG1Uncommit { public static void main(String[] args) throws Exception { ArrayList options = new ArrayList<>(); Collections.addAll(options, + "-XX:MinHeapFreeRatio=40", + "-XX:MaxHeapFreeRatio=70", "-Xlog:gc,gc+heap+region=debug", "-XX:+UseG1GC", "-Xmx1g", From 7f2aa59f8220f302a3f8662eeca3291dcf86d2ad Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Fri, 23 Jan 2026 06:24:47 +0000 Subject: [PATCH 155/328] 8375654: Exclude all array classes from dynamic CDS archive Reviewed-by: kvn, vlivanov --- src/hotspot/share/cds/archiveBuilder.cpp | 7 +- test/hotspot/jtreg/ProblemList-AotJdk.txt | 29 ++++++++ .../appcds/dynamicArchive/ArraySuperTest.java | 73 +++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArraySuperTest.java diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 6bbefea5cd9..328bed1ccfb 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -571,7 +571,12 @@ ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref } if (is_excluded(klass)) { ResourceMark rm; - log_debug(cds, dynamic)("Skipping class (excluded): %s", klass->external_name()); + aot_log_trace(aot)("pointer set to null: class (excluded): %s", klass->external_name()); + return set_to_null; + } + if (klass->is_array_klass() && CDSConfig::is_dumping_dynamic_archive()) { + ResourceMark rm; + aot_log_trace(aot)("pointer set to null: array class not supported in dynamic region: %s", klass->external_name()); return set_to_null; } } diff --git a/test/hotspot/jtreg/ProblemList-AotJdk.txt b/test/hotspot/jtreg/ProblemList-AotJdk.txt index af3994289df..e27e85645f5 100644 --- a/test/hotspot/jtreg/ProblemList-AotJdk.txt +++ b/test/hotspot/jtreg/ProblemList-AotJdk.txt @@ -1,3 +1,32 @@ +# +# Copyright (c) 2024, 2026, 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. +# + +############################################################################# +# +# List of quarantined tests for testing in AOT_JDK mode. +# +############################################################################# + runtime/modules/PatchModule/PatchModuleClassList.java 0000000 generic-all runtime/NMT/NMTWithCDS.java 0000000 generic-all runtime/symbols/TestSharedArchiveConfigFile.java 0000000 generic-all diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArraySuperTest.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArraySuperTest.java new file mode 100644 index 00000000000..5274c140f32 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArraySuperTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2026, 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 8304147 + * @summary make sure dynamic archive does not archive array classes with incorrect values in + * Array::_secondary_supers + * @requires vm.cds + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @build ArraySuperTest jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar ArraySuperApp.jar ArraySuperApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. ArraySuperTest + */ + +import java.util.function.Predicate; +import jdk.test.lib.helpers.ClassFileInstaller; + +public class ArraySuperTest extends DynamicArchiveTestBase { + + public static void main(String[] args) throws Exception { + runTest(ArraySuperTest::test); + } + + static void test() throws Exception { + String topArchiveName = getNewArchiveName(); + String appJar = ClassFileInstaller.getJarPath("ArraySuperApp.jar"); + String mainClass = ArraySuperApp.class.getName(); + + dump(topArchiveName, "-cp", appJar, mainClass).assertNormalExit(); + run(topArchiveName, "-cp", appJar, "-Xshare:off", mainClass, "withDynamicArchive").assertNormalExit(); + run(topArchiveName, "-cp", appJar, mainClass, "withDynamicArchive").assertNormalExit(); + } +} + +class ArraySuperApp implements Predicate { + static volatile Object array; + public boolean test(Object o) { + return true; + } + static void main(String args[]) { + array = new ArraySuperApp[1]; + if (args.length > 0) { + Predicate[] p = new Predicate[0]; + System.out.println(p.getClass().isInstance(array)); + p = (Predicate[])array; + p[0] = new ArraySuperApp(); + System.out.println("All tests passed"); + } + } +} From 39f0e6d6f91bf7e75862851ca0e00fc62780f938 Mon Sep 17 00:00:00 2001 From: Julian Waters Date: Fri, 23 Jan 2026 07:07:51 +0000 Subject: [PATCH 156/328] 8375241: Simplify --with-native-debug-symbols-level option implementation Reviewed-by: erikj, shade --- make/autoconf/flags-cflags.m4 | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index 5a9fdc57c74..639c3852212 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -69,22 +69,18 @@ AC_DEFUN([FLAGS_SETUP_DEBUG_SYMBOLS], # Debug prefix mapping if supported by compiler DEBUG_PREFIX_CFLAGS= - UTIL_ARG_WITH(NAME: native-debug-symbols-level, TYPE: string, - DEFAULT: "", - RESULT: DEBUG_SYMBOLS_LEVEL, + UTIL_ARG_WITH(NAME: native-debug-symbols-level, TYPE: literal, + DEFAULT: [auto], VALID_VALUES: [auto 1 2 3], + CHECK_AVAILABLE: [ + if test x$TOOLCHAIN_TYPE = xmicrosoft; then + AVAILABLE=false + fi + ], DESC: [set the native debug symbol level (GCC and Clang only)], - DEFAULT_DESC: [toolchain default]) - AC_SUBST(DEBUG_SYMBOLS_LEVEL) - - if test "x${TOOLCHAIN_TYPE}" = xgcc || \ - test "x${TOOLCHAIN_TYPE}" = xclang; then - DEBUG_SYMBOLS_LEVEL_FLAGS="-g" - if test "x${DEBUG_SYMBOLS_LEVEL}" != "x"; then - DEBUG_SYMBOLS_LEVEL_FLAGS="-g${DEBUG_SYMBOLS_LEVEL}" - FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${DEBUG_SYMBOLS_LEVEL_FLAGS}], - IF_FALSE: AC_MSG_ERROR("Debug info level ${DEBUG_SYMBOLS_LEVEL} is not supported")) - fi - fi + DEFAULT_DESC: [toolchain default], + IF_AUTO: [ + RESULT="" + ]) # Debug symbols if test "x$TOOLCHAIN_TYPE" = xgcc; then @@ -111,8 +107,8 @@ AC_DEFUN([FLAGS_SETUP_DEBUG_SYMBOLS], fi # Debug info level should follow the debug format to be effective. - CFLAGS_DEBUG_SYMBOLS="-gdwarf-4 ${DEBUG_SYMBOLS_LEVEL_FLAGS}" - ASFLAGS_DEBUG_SYMBOLS="${DEBUG_SYMBOLS_LEVEL_FLAGS}" + CFLAGS_DEBUG_SYMBOLS="-gdwarf-4 -g${NATIVE_DEBUG_SYMBOLS_LEVEL}" + ASFLAGS_DEBUG_SYMBOLS="-g${NATIVE_DEBUG_SYMBOLS_LEVEL}" elif test "x$TOOLCHAIN_TYPE" = xclang; then if test "x$ALLOW_ABSOLUTE_PATHS_IN_OUTPUT" = "xfalse"; then # Check if compiler supports -fdebug-prefix-map. If so, use that to make @@ -132,8 +128,8 @@ AC_DEFUN([FLAGS_SETUP_DEBUG_SYMBOLS], IF_FALSE: [GDWARF_FLAGS=""]) # Debug info level should follow the debug format to be effective. - CFLAGS_DEBUG_SYMBOLS="${GDWARF_FLAGS} ${DEBUG_SYMBOLS_LEVEL_FLAGS}" - ASFLAGS_DEBUG_SYMBOLS="${DEBUG_SYMBOLS_LEVEL_FLAGS}" + CFLAGS_DEBUG_SYMBOLS="${GDWARF_FLAGS} -g${NATIVE_DEBUG_SYMBOLS_LEVEL}" + ASFLAGS_DEBUG_SYMBOLS="-g${NATIVE_DEBUG_SYMBOLS_LEVEL}" elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then CFLAGS_DEBUG_SYMBOLS="-Z7" fi From 315bf07b23ad6c5f86fc8fe976abd9e9a8548404 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 23 Jan 2026 07:40:52 +0000 Subject: [PATCH 157/328] 8375119: SwitchBoostraps.enumSwitch does not throw an NPE when lookup is null in some cases Reviewed-by: liach --- .../java/lang/runtime/SwitchBootstraps.java | 18 ++++++++---- .../lang/runtime/SwitchBootstrapsTest.java | 29 ++++++++++++++++++- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index 30b6df0073e..087d2cc23a9 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -188,13 +188,17 @@ public final class SwitchBootstraps { String invocationName, MethodType invocationType, Object... labels) { + requireNonNull(lookup); + requireNonNull(invocationType); + requireNonNull(labels); + Class selectorType = invocationType.parameterType(0); if (invocationType.parameterCount() != 2 || (!invocationType.returnType().equals(int.class)) || !invocationType.parameterType(1).equals(int.class)) throw new IllegalArgumentException("Illegal invocation type " + invocationType); - for (Object l : labels) { // implicit null-check + for (Object l : labels) { verifyLabel(l, selectorType); } @@ -292,6 +296,10 @@ public final class SwitchBootstraps { String invocationName, MethodType invocationType, Object... labels) { + requireNonNull(lookup); + requireNonNull(invocationType); + requireNonNull(labels); + if (invocationType.parameterCount() != 2 || (!invocationType.returnType().equals(int.class)) || invocationType.parameterType(0).isPrimitive() @@ -299,7 +307,7 @@ public final class SwitchBootstraps { || !invocationType.parameterType(1).equals(int.class)) throw new IllegalArgumentException("Illegal invocation type " + invocationType); - labels = labels.clone(); // implicit null check + labels = labels.clone(); Class enumClass = invocationType.parameterType(0); boolean constantsOnly = true; @@ -307,7 +315,7 @@ public final class SwitchBootstraps { for (int i = 0; i < len; i++) { Object convertedLabel = - convertEnumConstants(lookup, enumClass, labels[i]); + convertEnumConstants(enumClass, labels[i]); labels[i] = convertedLabel; if (constantsOnly) constantsOnly = convertedLabel instanceof EnumDesc; @@ -331,7 +339,7 @@ public final class SwitchBootstraps { return new ConstantCallSite(target); } - private static > Object convertEnumConstants(MethodHandles.Lookup lookup, Class enumClassTemplate, Object label) { + private static > Object convertEnumConstants(Class enumClassTemplate, Object label) { if (label == null) { throw new IllegalArgumentException("null label found"); } diff --git a/test/jdk/java/lang/runtime/SwitchBootstrapsTest.java b/test/jdk/java/lang/runtime/SwitchBootstrapsTest.java index 8c6132b2815..3a8608866dc 100644 --- a/test/jdk/java/lang/runtime/SwitchBootstrapsTest.java +++ b/test/jdk/java/lang/runtime/SwitchBootstrapsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -447,4 +447,31 @@ public class SwitchBootstrapsTest { }); }); } + + public void testNullLookup() throws Throwable { + try { + MethodType switchType = MethodType.methodType(int.class, Object.class, int.class); + BSM_TYPE_SWITCH.invoke(null, "", switchType, Object.class); + fail("Didn't get the expected exception."); + } catch (NullPointerException ex) { + //OK + } + enum E {} + try { + MethodType switchType = MethodType.methodType(int.class, E.class, int.class); + BSM_ENUM_SWITCH.invoke(null, "", switchType, + new Object[] {}); + fail("Didn't get the expected exception."); + } catch (NullPointerException ex) { + //OK + } + try { + MethodType switchType = MethodType.methodType(int.class, E.class, int.class); + BSM_ENUM_SWITCH.invoke(null, "", switchType, + new Object[] {"A"}); + fail("Didn't get the expected exception."); + } catch (NullPointerException ex) { + //OK + } + } } From ca37dba4d40bf3f71c5489829c893346faec1c56 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Fri, 23 Jan 2026 08:27:27 +0000 Subject: [PATCH 158/328] 8376089: Increase QUIC idle timeout in H3FixedThreadPoolTest to collect more diagnostic Reviewed-by: dfuchs, jpai --- .../net/httpclient/http3/H3FixedThreadPoolTest.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/net/httpclient/http3/H3FixedThreadPoolTest.java b/test/jdk/java/net/httpclient/http3/H3FixedThreadPoolTest.java index c513cd092c7..6c181186fda 100644 --- a/test/jdk/java/net/httpclient/http3/H3FixedThreadPoolTest.java +++ b/test/jdk/java/net/httpclient/http3/H3FixedThreadPoolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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,9 +30,17 @@ * jdk.test.lib.Utils * jdk.test.lib.net.SimpleSSLContext * @compile ../ReferenceTracker.java + * + * @comment This test failed on Tier 7, but the failure could not be reproduced. + * The QUIC idle timeout has been increased to a value higher than the + * JTreg on Tier 7 so that, if the client becomes wedged again, the + * JTreg timeout handlers can collect more diagnostic information. + * * @run testng/othervm -Djdk.internal.httpclient.debug=err * -Djdk.httpclient.HttpClient.log=ssl,headers,requests,responses,errors - * H3FixedThreadPoolTest + * -Djdk.httpclient.quic.idleTimeout=666666 + * -Djdk.test.server.quic.idleTimeout=666666 + * ${test.main.class} */ import java.net.URI; From fa20391e73102a5d6a5b0a760d95a4225c673e04 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 23 Jan 2026 08:31:31 +0000 Subject: [PATCH 159/328] 8375966: G1: Convert G1UpdateRegionLivenessAndSelectForRebuildTask to use Atomic Reviewed-by: kbarrett, shade --- src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.cpp | 5 ++--- src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.hpp | 9 ++++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.cpp index fdef4214622..4eb11f6d8f6 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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,6 @@ #include "gc/g1/g1HeapRegionPrinter.hpp" #include "gc/g1/g1RemSetTrackingPolicy.hpp" #include "logging/log.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/mutexLocker.hpp" struct G1UpdateRegionLivenessAndSelectForRebuildTask::G1OnRegionClosure : public G1HeapRegionClosure { @@ -154,7 +153,7 @@ void G1UpdateRegionLivenessAndSelectForRebuildTask::work(uint worker_id) { G1OnRegionClosure on_region_cl(_g1h, _cm, &local_cleanup_list); _g1h->heap_region_par_iterate_from_worker_offset(&on_region_cl, &_hrclaimer, worker_id); - AtomicAccess::add(&_total_selected_for_rebuild, on_region_cl._num_selected_for_rebuild); + _total_selected_for_rebuild.add_then_fetch(on_region_cl._num_selected_for_rebuild); // Update the old/humongous region sets _g1h->remove_from_old_gen_sets(on_region_cl._num_old_regions_removed, diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.hpp index 161f0b4b9f5..a256693ff1d 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -29,6 +29,7 @@ #include "gc/g1/g1HeapRegionManager.hpp" #include "gc/g1/g1HeapRegionSet.hpp" #include "gc/shared/workerThread.hpp" +#include "runtime/atomic.hpp" class G1CollectedHeap; class G1ConcurrentMark; @@ -41,7 +42,7 @@ class G1UpdateRegionLivenessAndSelectForRebuildTask : public WorkerTask { G1ConcurrentMark* _cm; G1HeapRegionClaimer _hrclaimer; - uint volatile _total_selected_for_rebuild; + Atomic _total_selected_for_rebuild; // Reclaimed empty regions G1FreeRegionList _cleanup_list; @@ -57,7 +58,9 @@ public: void work(uint worker_id) override; - uint total_selected_for_rebuild() const { return _total_selected_for_rebuild; } + uint total_selected_for_rebuild() const { + return _total_selected_for_rebuild.load_relaxed(); + } static uint desired_num_workers(uint num_regions); }; From 6f6966b28b2c5a18b001be49f5db429c667d7a8f Mon Sep 17 00:00:00 2001 From: Guanqiang Han Date: Fri, 23 Jan 2026 11:37:30 +0000 Subject: [PATCH 160/328] 8374862: assert(false) failed: Attempting to acquire lock MDOExtraData_lock/nosafepoint-1 out of order with lock tty_lock/tty -- possible deadlock (running with -XX:+Verbose -XX:+WizardMode -XX:+PrintDeoptimizationDetails) Reviewed-by: dholmes, dlong --- .../share/interpreter/bytecodeTracer.cpp | 12 +++--- .../share/interpreter/bytecodeTracer.hpp | 4 +- src/hotspot/share/oops/method.cpp | 10 ++--- src/hotspot/share/oops/method.hpp | 6 +-- src/hotspot/share/runtime/vframeArray.cpp | 15 ++++++- .../TestDeoptDetailsLockRank.java | 39 +++++++++++++++++++ 6 files changed, 69 insertions(+), 17 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/uncommontrap/TestDeoptDetailsLockRank.java diff --git a/src/hotspot/share/interpreter/bytecodeTracer.cpp b/src/hotspot/share/interpreter/bytecodeTracer.cpp index f9980e389e2..69fc93b6c0f 100644 --- a/src/hotspot/share/interpreter/bytecodeTracer.cpp +++ b/src/hotspot/share/interpreter/bytecodeTracer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -192,18 +192,20 @@ void BytecodeTracer::trace_interpreter(const methodHandle& method, address bcp, } #endif -void BytecodeTracer::print_method_codes(const methodHandle& method, int from, int to, outputStream* st, int flags) { +void BytecodeTracer::print_method_codes(const methodHandle& method, int from, int to, outputStream* st, int flags, bool buffered) { BytecodePrinter method_printer(flags); BytecodeStream s(method); s.set_interval(from, to); - // Keep output to st coherent: collect all lines and print at once. ResourceMark rm; stringStream ss; + outputStream* out = buffered ? &ss : st; while (s.next() >= 0) { - method_printer.trace(method, s.bcp(), &ss); + method_printer.trace(method, s.bcp(), out); + } + if (buffered) { + st->print("%s", ss.as_string()); } - st->print("%s", ss.as_string()); } void BytecodePrinter::print_constant(int cp_index, outputStream* st) { diff --git a/src/hotspot/share/interpreter/bytecodeTracer.hpp b/src/hotspot/share/interpreter/bytecodeTracer.hpp index b32e55abbcf..e199a2b7ea2 100644 --- a/src/hotspot/share/interpreter/bytecodeTracer.hpp +++ b/src/hotspot/share/interpreter/bytecodeTracer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -39,7 +39,7 @@ class BytecodeClosure; class BytecodeTracer: AllStatic { public: NOT_PRODUCT(static void trace_interpreter(const methodHandle& method, address bcp, uintptr_t tos, uintptr_t tos2, outputStream* st = tty);) - static void print_method_codes(const methodHandle& method, int from, int to, outputStream* st, int flags); + static void print_method_codes(const methodHandle& method, int from, int to, outputStream* st, int flags, bool buffered = true); }; #endif // SHARE_INTERPRETER_BYTECODETRACER_HPP diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 1a2e5f0bee4..949441585d8 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -1898,15 +1898,15 @@ void Method::print_name(outputStream* st) const { #endif // !PRODUCT || INCLUDE_JVMTI -void Method::print_codes_on(outputStream* st, int flags) const { - print_codes_on(0, code_size(), st, flags); +void Method::print_codes_on(outputStream* st, int flags, bool buffered) const { + print_codes_on(0, code_size(), st, flags, buffered); } -void Method::print_codes_on(int from, int to, outputStream* st, int flags) const { +void Method::print_codes_on(int from, int to, outputStream* st, int flags, bool buffered) const { Thread *thread = Thread::current(); ResourceMark rm(thread); methodHandle mh (thread, (Method*)this); - BytecodeTracer::print_method_codes(mh, from, to, st, flags); + BytecodeTracer::print_method_codes(mh, from, to, st, flags, buffered); } CompressedLineNumberReadStream::CompressedLineNumberReadStream(u_char* buffer) : CompressedReadStream(buffer) { diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index 4592cb8a8c0..add8e59b2be 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -466,8 +466,8 @@ public: // prints byte codes void print_codes(int flags = 0) const { print_codes_on(tty, flags); } - void print_codes_on(outputStream* st, int flags = 0) const; - void print_codes_on(int from, int to, outputStream* st, int flags = 0) const; + void print_codes_on(outputStream* st, int flags = 0, bool buffered = true) const; + void print_codes_on(int from, int to, outputStream* st, int flags = 0, bool buffered = true) const; // method parameters bool has_method_parameters() const diff --git a/src/hotspot/share/runtime/vframeArray.cpp b/src/hotspot/share/runtime/vframeArray.cpp index a68a0adf299..9f1c082ed8f 100644 --- a/src/hotspot/share/runtime/vframeArray.cpp +++ b/src/hotspot/share/runtime/vframeArray.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -491,6 +491,15 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, #ifndef PRODUCT if (PrintDeoptimizationDetails) { + const bool print_codes = WizardMode && Verbose; + ResourceMark rm(thread); + stringStream codes_ss; + if (print_codes) { + // print_codes_on() may acquire MDOExtraData_lock (rank nosafepoint-1). + // To keep the lock acquisition order correct, call it before taking tty_lock. + // Avoid double buffering: set buffered=false. + method()->print_codes_on(&codes_ss, 0, false); + } ttyLocker ttyl; tty->print_cr("[%d. Interpreted Frame]", ++unpack_counter); iframe()->print_on(tty); @@ -500,7 +509,9 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, RegisterMap::WalkContinuation::skip); vframe* f = vframe::new_vframe(iframe(), &map, thread); f->print(); - if (WizardMode && Verbose) method()->print_codes(); + if (print_codes) { + tty->print("%s", codes_ss.as_string()); + } tty->cr(); } #endif // !PRODUCT diff --git a/test/hotspot/jtreg/compiler/uncommontrap/TestDeoptDetailsLockRank.java b/test/hotspot/jtreg/compiler/uncommontrap/TestDeoptDetailsLockRank.java new file mode 100644 index 00000000000..2866a84ba46 --- /dev/null +++ b/test/hotspot/jtreg/compiler/uncommontrap/TestDeoptDetailsLockRank.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2026, 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 8374862 + * @summary Regression test for -XX:+Verbose -XX:+WizardMode -XX:+PrintDeoptimizationDetails crash + * @requires vm.debug + * @run main/othervm -XX:+Verbose -XX:+WizardMode -XX:+PrintDeoptimizationDetails compiler.uncommontrap.TestDeoptDetailsLockRank + */ + +package compiler.uncommontrap; + +public class TestDeoptDetailsLockRank { + + public static void main(String[] args) { + System.out.println("passed"); + } +} \ No newline at end of file From 3fb118a29ed68f2fbb64de45468b0f014fa01890 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Fri, 23 Jan 2026 16:55:38 +0000 Subject: [PATCH 161/328] 8375692: Hotspot container tests assert with non-ascii vendor name Reviewed-by: naoto, dholmes, syan --- test/hotspot/jtreg/containers/docker/TestJcmd.java | 3 ++- .../platform/docker/TestDockerMemoryMetricsSubgroup.java | 4 +++- test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/containers/docker/TestJcmd.java b/test/hotspot/jtreg/containers/docker/TestJcmd.java index 3cfe2945e92..fcd5c665f2b 100644 --- a/test/hotspot/jtreg/containers/docker/TestJcmd.java +++ b/test/hotspot/jtreg/containers/docker/TestJcmd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -143,6 +143,7 @@ public class TestJcmd { sb.append(String.format("FROM %s:%s\n", DockerfileConfig.getBaseImageName(), DockerfileConfig.getBaseImageVersion())); sb.append("COPY /jdk /jdk\n"); + sb.append("ENV LANG=C.UTF-8\n"); sb.append("ENV JAVA_HOME=/jdk\n"); if (!IS_PODMAN) { // only needed for docker diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java index 7d5dbca6f7c..4b487934169 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java @@ -91,7 +91,8 @@ public class TestDockerMemoryMetricsSubgroup { .addDockerOpts("--volume", Utils.TEST_JDK + ":/jdk") .addDockerOpts("--privileged") .addDockerOpts("--cgroupns=" + (privateNamespace ? "private" : "host")) - .addDockerOpts("--memory", outerGroupMemorySize); + .addDockerOpts("--memory", outerGroupMemorySize) + .addDockerOpts("-e", "LANG=C.UTF-8"); opts.addClassOptions("mkdir -p /sys/fs/cgroup/memory/test ; " + "echo " + innerSize + " > /sys/fs/cgroup/memory/test/memory.limit_in_bytes ; " + "echo $$ > /sys/fs/cgroup/memory/test/cgroup.procs ; " + @@ -112,6 +113,7 @@ public class TestDockerMemoryMetricsSubgroup { .addDockerOpts("--volume", Utils.TEST_JDK + ":/jdk") .addDockerOpts("--privileged") .addDockerOpts("--cgroupns=" + (privateNamespace ? "private" : "host")) + .addDockerOpts("-e", "LANG=C.UTF-8") .addDockerOpts("--memory", outerGroupMemorySize); opts.addClassOptions("mkdir -p /sys/fs/cgroup/memory/test ; " + "echo $$ > /sys/fs/cgroup/memory/test/cgroup.procs ; " + diff --git a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java index b013561be0b..bd9a706e3a4 100644 --- a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java +++ b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -380,6 +380,7 @@ public class DockerTestUtils { } template = template + "COPY /jdk /jdk\n" + "ENV JAVA_HOME=/jdk\n" + + "ENV LANG=C.UTF-8\n" + "CMD [\"/bin/bash\"]\n"; String dockerFileStr = String.format(template, baseImage, baseImageVersion); Files.writeString(dockerfile, dockerFileStr); From 40f7a18b2dbf120a95432174664fa897331e8973 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 23 Jan 2026 17:32:53 +0000 Subject: [PATCH 162/328] 8373935: Migrate java/lang/invoke tests away from TestNG Reviewed-by: jvernee, alanb --- .../java/lang/invoke/8147078/Test8147078.java | 23 +- .../invoke/8177146/TestMethodHandleBind.java | 33 +- .../java/lang/invoke/AccessControlTest.java | 57 +-- .../lang/invoke/ArrayConstructorTest.java | 52 +-- .../jdk/java/lang/invoke/ArrayLengthTest.java | 58 +-- .../invoke/CallerSensitiveMethodHandle.java | 13 +- .../lang/invoke/ClassSpecializerTest.java | 15 +- .../invoke/CompileThresholdBootstrapTest.java | 20 +- .../lang/invoke/ConstantIdentityMHTest.java | 30 +- .../jdk/java/lang/invoke/DefineClassTest.java | 73 ++-- .../java/lang/invoke/DropArgumentsTest.java | 39 +- .../java/lang/invoke/DropLookupModeTest.java | 107 +++-- .../java/lang/invoke/FilterArgumentsTest.java | 22 +- test/jdk/java/lang/invoke/FindAccessTest.java | 32 +- test/jdk/java/lang/invoke/FoldTest.java | 18 +- .../java/lang/invoke/InvokeGenericTest.java | 66 +-- .../InvokeMethodHandleWithBadArgument.java | 98 +++-- .../lang/invoke/InvokeWithArgumentsTest.java | 40 +- .../java/lang/invoke/JavaDocExamplesTest.java | 12 +- .../invoke/JavaUtilConcurrentLookupTest.java | 7 +- .../java/lang/invoke/LoopCombinatorTest.java | 384 +++++++++--------- .../lang/invoke/MethodHandleInvokeUOE.java | 8 +- .../invoke/MethodHandleProxies/Driver.java | 4 +- .../invoke/MethodHandleProxies/Unnamed.java | 7 +- .../MethodHandleProxies/m1/module-info.java | 4 +- .../MethodHandleProxies/m1/p1/Main.java | 21 +- .../invoke/MethodHandles/TestDropReturn.java | 20 +- .../invoke/MethodHandles/TestTableSwitch.java | 64 +-- .../classData/ClassDataTest.java | 102 ++--- .../MethodHandles/ensureInitialized/Main.java | 21 +- .../MethodHandles/privateLookupIn/Driver.java | 4 +- .../privateLookupIn/test/module-info.java | 6 +- .../test/p/PrivateLookupInTests.java | 107 +++-- .../invoke/MethodHandlesCollectArgsTest.java | 23 +- .../lang/invoke/MethodHandlesGeneralTest.java | 8 +- test/jdk/java/lang/invoke/MethodTypeTest.java | 48 ++- .../invoke/PermuteArgsReturnVoidTest.java | 18 +- .../jdk/java/lang/invoke/PermuteArgsTest.java | 19 +- .../java/lang/invoke/SpreadCollectTest.java | 102 +++-- .../lang/invoke/TestVHInvokerCaching.java | 16 +- .../java/lang/invoke/ThrowExceptionsTest.java | 23 +- test/jdk/java/lang/invoke/TryFinallyTest.java | 62 ++- test/jdk/java/lang/invoke/VarArgsTest.java | 19 +- .../VarHandleBaseByteArrayTest.java | 11 +- .../invoke/VarHandles/VarHandleBaseTest.java | 47 +-- .../VarHandleMethodReferenceTest.java | 6 +- .../VarHandleTestAccessBoolean.java | 324 ++++++++------- .../VarHandles/VarHandleTestAccessByte.java | 360 ++++++++-------- .../VarHandles/VarHandleTestAccessChar.java | 360 ++++++++-------- .../VarHandles/VarHandleTestAccessDouble.java | 252 ++++++------ .../VarHandles/VarHandleTestAccessFloat.java | 252 ++++++------ .../VarHandles/VarHandleTestAccessInt.java | 360 ++++++++-------- .../VarHandles/VarHandleTestAccessLong.java | 360 ++++++++-------- .../VarHandleTestAccessModeMethodNames.java | 23 +- .../VarHandles/VarHandleTestAccessShort.java | 360 ++++++++-------- .../VarHandles/VarHandleTestAccessString.java | 216 +++++----- .../VarHandleTestByteArrayAsChar.java | 54 +-- .../VarHandleTestByteArrayAsDouble.java | 98 ++--- .../VarHandleTestByteArrayAsFloat.java | 98 ++--- .../VarHandleTestByteArrayAsInt.java | 146 +++---- .../VarHandleTestByteArrayAsLong.java | 146 +++---- .../VarHandleTestByteArrayAsShort.java | 54 +-- .../invoke/VarHandles/VarHandleTestExact.java | 49 ++- ...arHandleTestMethodHandleAccessBoolean.java | 280 +++++++------ .../VarHandleTestMethodHandleAccessByte.java | 316 +++++++------- .../VarHandleTestMethodHandleAccessChar.java | 316 +++++++------- ...VarHandleTestMethodHandleAccessDouble.java | 208 +++++----- .../VarHandleTestMethodHandleAccessFloat.java | 208 +++++----- .../VarHandleTestMethodHandleAccessInt.java | 316 +++++++------- .../VarHandleTestMethodHandleAccessLong.java | 316 +++++++------- .../VarHandleTestMethodHandleAccessShort.java | 316 +++++++------- ...VarHandleTestMethodHandleAccessString.java | 172 ++++---- .../VarHandleTestMethodTypeBoolean.java | 29 +- .../VarHandleTestMethodTypeByte.java | 29 +- .../VarHandleTestMethodTypeChar.java | 29 +- .../VarHandleTestMethodTypeDouble.java | 29 +- .../VarHandleTestMethodTypeFloat.java | 29 +- .../VarHandleTestMethodTypeInt.java | 29 +- .../VarHandleTestMethodTypeLong.java | 29 +- .../VarHandleTestMethodTypeShort.java | 29 +- .../VarHandleTestMethodTypeString.java | 29 +- .../VarHandles/VarHandleTestReflection.java | 56 +-- .../X-VarHandleTestAccess.java.template | 360 ++++++++-------- ...X-VarHandleTestByteArrayView.java.template | 146 +++---- ...HandleTestMethodHandleAccess.java.template | 316 +++++++------- .../X-VarHandleTestMethodType.java.template | 29 +- .../TestFieldLookupAccessibility.java | 26 +- .../java/lang/invoke/WrongMethodTypeTest.java | 36 +- .../TestAccessClass.java | 24 +- .../TestFindClass.java | 26 +- .../accessClassAndFindClass/TestLookup.java | 14 +- .../CallerSensitiveAccess.java | 142 ++++--- .../condy/BootstrapMethodJumboArgsTest.java | 24 +- .../lang/invoke/condy/CondyBSMException.java | 29 +- .../lang/invoke/condy/CondyBSMInvocation.java | 46 +-- .../invoke/condy/CondyBSMValidationTest.java | 35 +- .../CondyInterfaceWithOverpassMethods.java | 18 +- .../invoke/condy/CondyNameValidationTest.java | 40 +- .../lang/invoke/condy/CondyNestedTest.java | 38 +- .../condy/CondyRepeatFailedResolution.java | 60 ++- .../condy/CondyReturnPrimitiveTest.java | 34 +- .../condy/CondyStaticArgumentsTest.java | 17 +- .../invoke/condy/CondyTypeValidationTest.java | 31 +- .../invoke/condy/CondyWithGarbageTest.java | 17 +- .../lang/invoke/condy/CondyWrongType.java | 45 +- .../invoke/condy/ConstantBootstrapsTest.java | 115 +++--- .../invoke/defineHiddenClass/BasicTest.java | 175 ++++---- .../defineHiddenClass/HiddenNestmateTest.java | 44 +- .../LambdaNestedInnerTest.java | 29 +- .../defineHiddenClass/PreviewHiddenClass.java | 14 +- .../StaticInvocableTest.java | 6 +- .../defineHiddenClass/TypeDescriptorTest.java | 67 ++- .../defineHiddenClass/UnloadingTest.java | 20 +- .../invoke/findSpecial/FindSpecialTest.java | 12 +- .../LambdaFileEncodingSerialization.java | 15 +- .../invoke/lambda/LambdaHiddenCaller.java | 5 +- .../lambda/LogGeneratedClassesTest.java | 76 ++-- .../InvokeSpecialMethodTest.java | 22 +- .../InheritedProtectedMethod.java | 18 +- .../ProtectedMethodInOtherPackage.java | 26 +- .../lang/invoke/lookup/ChainedLookupTest.java | 10 +- .../lang/invoke/lookup/LookupClassTest.java | 30 +- .../lang/invoke/lookup/SpecialStatic.java | 12 +- test/jdk/java/lang/invoke/modules/Driver.java | 6 +- .../jdk/java/lang/invoke/modules/Driver1.java | 6 +- .../lang/invoke/modules/m1/module-info.java | 4 +- .../java/lang/invoke/modules/m1/p1/Main.java | 75 ++-- .../modules/m3/jdk/test/ModuleAccessTest.java | 173 ++++---- .../lang/invoke/modules/m3/module-info.java | 4 +- 129 files changed, 5276 insertions(+), 5487 deletions(-) diff --git a/test/jdk/java/lang/invoke/8147078/Test8147078.java b/test/jdk/java/lang/invoke/8147078/Test8147078.java index 08532d30929..51580aa6f10 100644 --- a/test/jdk/java/lang/invoke/8147078/Test8147078.java +++ b/test/jdk/java/lang/invoke/8147078/Test8147078.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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,17 +23,18 @@ /* @test * @bug 8147078 - * @run testng/othervm -ea -esa Test8147078 + * @run junit/othervm -ea -esa Test8147078 */ -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import static java.lang.invoke.MethodType.methodType; -import static org.testng.AssertJUnit.*; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class Test8147078 { @@ -65,16 +66,10 @@ public class Test8147078 { @Test public void testNoExceptionType() { - boolean caught = false; - try { + var cce = assertThrows(ClassCastException.class, () -> { MethodHandle eek = (MethodHandle) MH_catchException.invoke(MH_target, String.class, MH_handler); - } catch (ClassCastException cce) { - assertEquals("java.lang.String", cce.getMessage()); - caught = true; - } catch (Throwable t) { - fail("unexpected exception caught: " + t); - } - assertTrue(caught); + }); + assertEquals("java.lang.String", cce.getMessage()); } } \ No newline at end of file diff --git a/test/jdk/java/lang/invoke/8177146/TestMethodHandleBind.java b/test/jdk/java/lang/invoke/8177146/TestMethodHandleBind.java index 134cc9f7514..518d07b1518 100644 --- a/test/jdk/java/lang/invoke/8177146/TestMethodHandleBind.java +++ b/test/jdk/java/lang/invoke/8177146/TestMethodHandleBind.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,17 +23,16 @@ /* @test * @bug 8177146 - * @run testng/othervm TestMethodHandleBind + * @run junit/othervm TestMethodHandleBind */ -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import static java.lang.invoke.MethodHandles.lookup; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class TestMethodHandleBind extends pkg.A { static class B extends TestMethodHandleBind {} @@ -42,7 +41,7 @@ public class TestMethodHandleBind extends pkg.A { public void testInstanceOfCallerClass() throws Throwable { MethodHandle bound = lookup().bind(new TestMethodHandleBind() , "m1", MethodType.methodType(String.class)); String x = (String)bound.invoke(); - assertEquals(x, this.getClass().getSimpleName()); + assertEquals(this.getClass().getSimpleName(), x); } @Test @@ -50,47 +49,37 @@ public class TestMethodHandleBind extends pkg.A { MethodHandle bound = lookup().bind(new B() , "m1", MethodType.methodType(String.class)); // MethodHandle bound = lookup().findVirtual(B.class, "m1", MethodType.methodType(String.class)).bindTo(new B()); String x = (String)bound.invoke(); - assertEquals(x, "B"); + assertEquals("B", x); } @Test public void testInstanceOfReceiverClass() throws Throwable { - try { - MethodHandle bound = lookup().bind(new pkg.A() , "m1", MethodType.methodType(String.class)); - bound.invoke(); - fail("IllegalAccessException expected"); - } catch (IllegalAccessException e) { - } + assertThrows(IllegalAccessException.class, () -> lookup().bind(new pkg.A() , "m1", MethodType.methodType(String.class))); } @Test public void testPublicMethod() throws Throwable { MethodHandle bound = lookup().bind(new pkg.A() , "m2", MethodType.methodType(String.class)); String x = (String)bound.invoke(); - assertEquals(x, "A"); + assertEquals("A", x); } @Test public void testPublicMethod2() throws Throwable { MethodHandle bound = lookup().bind(new TestMethodHandleBind(), "m2", MethodType.methodType(String.class)); String x = (String)bound.invoke(); - assertEquals(x, this.getClass().getSimpleName()); + assertEquals(this.getClass().getSimpleName(), x); } @Test public void testInstanceOfCallerClassVarargs() throws Throwable { MethodHandle bound = lookup().bind(new TestMethodHandleBind() , "m3", MethodType.methodType(String.class, String[].class)); String x = (String)bound.invoke("a", "b", "c"); - assertEquals(x, this.getClass().getSimpleName() + "abc"); + assertEquals(this.getClass().getSimpleName() + "abc", x); } @Test public void testInstanceOfReceiverClassVarargs() throws Throwable { - try { - MethodHandle bound = lookup().bind(new pkg.A(), "m3", MethodType.methodType(String.class, String[].class)); - bound.invoke(); - fail("IllegalAccessException expected"); - } catch (IllegalAccessException e) { - } + assertThrows(IllegalAccessException.class, () -> lookup().bind(new pkg.A(), "m3", MethodType.methodType(String.class, String[].class))); } } diff --git a/test/jdk/java/lang/invoke/AccessControlTest.java b/test/jdk/java/lang/invoke/AccessControlTest.java index e177f08d876..fcd945a5d7f 100644 --- a/test/jdk/java/lang/invoke/AccessControlTest.java +++ b/test/jdk/java/lang/invoke/AccessControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* @test * @summary test access checking by java.lang.invoke.MethodHandles.Lookup * @compile AccessControlTest.java AccessControlTest_subpkg/Acquaintance_remote.java - * @run testng/othervm test.java.lang.invoke.AccessControlTest + * @run junit/othervm test.java.lang.invoke.AccessControlTest */ package test.java.lang.invoke; @@ -33,12 +33,13 @@ import java.lang.invoke.*; import java.lang.reflect.*; import java.lang.reflect.Modifier; import java.util.*; -import org.testng.annotations.*; import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodHandles.Lookup.*; import static java.lang.invoke.MethodType.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; import test.java.lang.invoke.AccessControlTest_subpkg.Acquaintance_remote; @@ -69,7 +70,7 @@ public class AccessControlTest { this.prevLookupClass = lookup.previousLookupClass(); this.lookupModes = lookup.lookupModes(); - assert(lookupString().equals(lookup.toString())); + assertEquals(lookupString(), lookup.toString()); numberOf(lookupClass().getClassLoader()); // assign CL# } public LookupCase(Class lookupClass, Class prevLookupClass, int lookupModes) { @@ -96,7 +97,7 @@ public class AccessControlTest { int cmp = c1.getName().compareTo(c2.getName()); if (cmp != 0) return cmp; cmp = numberOf(c1.getClassLoader()) - numberOf(c2.getClassLoader()); - assert(cmp != 0); + assertNotEquals(0, cmp); return cmp; } else if (p1 != p2){ if (p1 == null) @@ -106,7 +107,7 @@ public class AccessControlTest { int cmp = p1.getName().compareTo(p2.getName()); if (cmp != 0) return cmp; cmp = numberOf(p1.getClassLoader()) - numberOf(p2.getClassLoader()); - assert(cmp != 0); + assertNotEquals(0, cmp); return cmp; } return -(this.lookupModes() - that.lookupModes()); @@ -211,8 +212,8 @@ public class AccessControlTest { c1.getPackageName().equals(c2.getPackageName())); boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2)); boolean sameClass = (c1 == c2); - assert(samePackage || !sameTopLevel); - assert(sameTopLevel || !sameClass); + assertTrue(samePackage || !sameTopLevel); + assertTrue(sameTopLevel || !sameClass); boolean accessible = sameClass; if ((modes1 & PACKAGE) != 0) accessible |= samePackage; @@ -251,17 +252,17 @@ public class AccessControlTest { changed |= (PRIVATE|PROTECTED); // [A5] } if (sameClass) { - assert(changed == 0); // [A11] (no deprivation if same class) + assertEquals(0, changed); // [A11] (no deprivation if same class) } - if (accessible) assert((changed & PUBLIC) == 0); + if (accessible) assertEquals(0, changed & PUBLIC); int modes2 = modes1 & ~changed; Class plc = (m1 == m2) ? prevLookupClass() : c1; // [A9] [A10] if ((modes1 & UNCONDITIONAL) != 0) plc = null; // [A8] LookupCase l2 = new LookupCase(c2, plc, modes2); - assert(l2.lookupClass() == c2); // [A1] - assert((modes1 | modes2) == modes1); // [A1-a] (no elevation of access) - assert(l2.prevLookupClass() == null || (modes2 & MODULE) == 0); + assertSame(l2.lookupClass(), c2); // [A1] + assertEquals(modes1, modes1 | modes2); // [A1-a] (no elevation of access) + assertTrue(l2.prevLookupClass() == null || (modes2 & MODULE) == 0); return l2; } @@ -280,8 +281,8 @@ public class AccessControlTest { } if (newModes == oldModes) return this; // return self if no change LookupCase l2 = new LookupCase(lookupClass(), prevLookupClass(), newModes); - assert((oldModes | newModes) == oldModes); // [A2] (no elevation of access) - assert(l2.prevLookupClass() == null || (newModes & MODULE) == 0); + assertEquals(oldModes, oldModes | newModes); // [A2] (no elevation of access) + assertTrue(l2.prevLookupClass() == null || (newModes & MODULE) == 0); return l2; } @@ -331,7 +332,7 @@ public class AccessControlTest { && Modifier.isPublic(m.getModifiers()); } - assert(m1 == m2 && prevLookupClass == null); + assertNull(prevLookupClass); if (!willAccessClass(c2, false)) return false; @@ -380,7 +381,7 @@ public class AccessControlTest { && Modifier.isPublic(c2.getModifiers()); } - assert(m1 == m2 && prevLookupClass == null); + assertNull(prevLookupClass); LookupCase lc = this.in(c2); int modes1 = lc.lookupModes(); @@ -409,8 +410,8 @@ public class AccessControlTest { Class c = cls; for (Class ec; (ec = c.getEnclosingClass()) != null; ) c = ec; - assert(c.getEnclosingClass() == null); - assert(c == cls || cls.getEnclosingClass() != null); + assertNull(c.getEnclosingClass()); + assertTrue(c == cls || cls.getEnclosingClass() != null); return c; } @@ -443,14 +444,14 @@ public class AccessControlTest { if (edges == null) CASE_EDGES.put(l2, edges = new TreeSet<>()); if (edges.add(l1)) { Class c1 = l1.lookupClass(); - assert(l2.lookupClass() == c2); // [A1] + assertSame(l2.lookupClass(), c2); // [A1] int m1 = l1.lookupModes(); int m2 = l2.lookupModes(); - assert((m1 | m2) == m1); // [A2] (no elevation of access) + assertEquals(m1, (m1 | m2)); // [A2] (no elevation of access) LookupCase expect = dropAccess == 0 ? l1.in(c2) : l1.in(c2).dropLookupMode(dropAccess); if (!expect.equals(l2)) System.out.println("*** expect "+l1+" => "+expect+" but got "+l2); - assertEquals(l2, expect); + assertEquals(expect, l2); } } @@ -567,7 +568,7 @@ public class AccessControlTest { if (willAccess != didAccess) { System.out.println(sourceCase+" => "+targetClass.getSimpleName()+(isFindOrAccessClass?"":"."+methodName+methodType)); System.out.println("fail "+(isFindOrAccessClass?kind:"on "+method)+" ex="+accessError); - assertEquals(willAccess, didAccess); + assertEquals(didAccess, willAccess); } testCount++; if (!didAccess) testCountFails++; @@ -579,10 +580,10 @@ public class AccessControlTest { System.out.println(targetClass.getSimpleName()+"."+methodName+methodType); try { Method method = targetClass.getDeclaredMethod(methodName, methodType.parameterArray()); - assertEquals(method.getReturnType(), methodType.returnType()); + assertEquals(methodType.returnType(), method.getReturnType()); int haveMods = method.getModifiers(); - assert(Modifier.isStatic(haveMods)); - assert(targetAccess == fixMods(haveMods)); + assertTrue(Modifier.isStatic(haveMods)); + assertEquals(targetAccess, fixMods(haveMods)); return method; } catch (NoSuchMethodException ex) { throw new AssertionError(methodName, ex); @@ -604,7 +605,7 @@ public class AccessControlTest { case PACKAGE: return "pkg_in_"; case PRIVATE: return "pri_in_"; } - assert(false); + fail(); return "?"; } private static final int[] ACCESS_CASES = { diff --git a/test/jdk/java/lang/invoke/ArrayConstructorTest.java b/test/jdk/java/lang/invoke/ArrayConstructorTest.java index 749bb7926a0..313c2828380 100644 --- a/test/jdk/java/lang/invoke/ArrayConstructorTest.java +++ b/test/jdk/java/lang/invoke/ArrayConstructorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* @test * @bug 8155106 - * @run testng/othervm -ea -esa test.java.lang.invoke.ArrayConstructorTest + * @run junit/othervm -ea -esa test.java.lang.invoke.ArrayConstructorTest */ package test.java.lang.invoke; @@ -32,30 +32,22 @@ import java.lang.invoke.MethodHandles; import static java.lang.invoke.MethodType.methodType; -import static org.testng.AssertJUnit.*; - -import org.testng.annotations.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.*; public class ArrayConstructorTest { static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); @Test - public static void testFindConstructorArray() { - boolean caught = false; - try { - MethodHandle h = LOOKUP.findConstructor(Object[].class, methodType(void.class)); - } catch (NoSuchMethodException nsme) { - assertEquals("no constructor for array class: [Ljava.lang.Object;", nsme.getMessage()); - caught = true; - } catch (Exception e) { - throw new AssertionError("unexpected exception: " + e); - } - assertTrue(caught); + public void testFindConstructorArray() { + var nsme = assertThrows(NoSuchMethodException.class, () -> LOOKUP.findConstructor(Object[].class, methodType(void.class))); + assertEquals("no constructor for array class: [Ljava.lang.Object;", nsme.getMessage()); } - @DataProvider static Object[][] arrayConstructorNegative() { return new Object[][]{ {String.class, IllegalArgumentException.class, "not an array class: java.lang.String"}, @@ -63,34 +55,28 @@ public class ArrayConstructorTest { }; } - @Test(dataProvider = "arrayConstructorNegative") - public static void testArrayConstructorNegative(Class clazz, Class exceptionClass, String message) { - boolean caught = false; - try { - MethodHandle h = MethodHandles.arrayConstructor(clazz); - } catch (Exception e) { - assertEquals(exceptionClass, e.getClass()); - if (message != null) { - assertEquals(message, e.getMessage()); - } - caught = true; + @ParameterizedTest + @MethodSource("arrayConstructorNegative") + public void testArrayConstructorNegative(Class clazz, Class exceptionClass, String message) { + var e = assertThrowsExactly(exceptionClass, () -> MethodHandles.arrayConstructor(clazz)); + if (message != null) { + assertEquals(message, e.getMessage()); } - assertTrue(caught); } @Test - public static void testArrayConstructor() throws Throwable { + public void testArrayConstructor() throws Throwable { MethodHandle h = MethodHandles.arrayConstructor(String[].class); assertEquals(methodType(String[].class, int.class), h.type()); String[] a = (String[]) h.invoke(17); assertEquals(17, a.length); } - @Test(expectedExceptions = {NegativeArraySizeException.class}) - public static void testArrayConstructorNegativeIndex() throws Throwable { + @Test + public void testArrayConstructorNegativeIndex() throws Throwable { MethodHandle h = MethodHandles.arrayConstructor(String[].class); assertEquals(methodType(String[].class, int.class), h.type()); - h.invoke(-1); // throws exception + assertThrows(NegativeArraySizeException.class, () -> h.invoke(-1)); } } diff --git a/test/jdk/java/lang/invoke/ArrayLengthTest.java b/test/jdk/java/lang/invoke/ArrayLengthTest.java index 9f3cc6fe240..2ef97442638 100644 --- a/test/jdk/java/lang/invoke/ArrayLengthTest.java +++ b/test/jdk/java/lang/invoke/ArrayLengthTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,36 +22,39 @@ */ /* @test - * @run testng/othervm -ea -esa test.java.lang.invoke.ArrayLengthTest + * @run junit/othervm -ea -esa test.java.lang.invoke.ArrayLengthTest */ package test.java.lang.invoke; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; -import static org.testng.AssertJUnit.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -import org.testng.annotations.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class ArrayLengthTest { - @DataProvider - Object[][] arrayClasses() { - return new Object[][] { - {int[].class}, - {long[].class}, - {float[].class}, - {double[].class}, - {boolean[].class}, - {byte[].class}, - {short[].class}, - {char[].class}, - {Object[].class}, - {StringBuffer[].class} + static Object[] arrayClasses() { + return new Object[] { + int[].class, + long[].class, + float[].class, + double[].class, + boolean[].class, + byte[].class, + short[].class, + char[].class, + Object[].class, + StringBuffer[].class }; } - @Test(dataProvider = "arrayClasses") + @ParameterizedTest + @MethodSource("arrayClasses") public void testArrayLength(Class arrayClass) throws Throwable { MethodHandle arrayLength = MethodHandles.arrayLength(arrayClass); assertEquals(int.class, arrayLength.type().returnType()); @@ -60,25 +63,28 @@ public class ArrayLengthTest { assertEquals(10, arrayLength.invoke(array)); } - @Test(dataProvider = "arrayClasses", expectedExceptions = NullPointerException.class) + @ParameterizedTest + @MethodSource("arrayClasses") public void testArrayLengthInvokeNPE(Class arrayClass) throws Throwable { MethodHandle arrayLength = MethodHandles.arrayLength(arrayClass); - arrayLength.invoke(null); + assertThrows(NullPointerException.class, () -> arrayLength.invoke(null)); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testArrayLengthNoArray() { - MethodHandles.arrayLength(String.class); + assertThrows(IllegalArgumentException.class, () -> MethodHandles.arrayLength(String.class)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void testArrayLengthNPE() { - MethodHandles.arrayLength(null); + assertThrows(NullPointerException.class, () -> MethodHandles.arrayLength(null)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void testNullReference() throws Throwable { MethodHandle arrayLength = MethodHandles.arrayLength(String[].class); - int len = (int)arrayLength.invokeExact((String[])null); + assertThrows(NullPointerException.class, () -> { + int len = (int)arrayLength.invokeExact((String[])null); + }); } } diff --git a/test/jdk/java/lang/invoke/CallerSensitiveMethodHandle.java b/test/jdk/java/lang/invoke/CallerSensitiveMethodHandle.java index 369c2c2bea1..a2756fc2f23 100644 --- a/test/jdk/java/lang/invoke/CallerSensitiveMethodHandle.java +++ b/test/jdk/java/lang/invoke/CallerSensitiveMethodHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,20 +22,19 @@ */ /* @test - * @run testng/othervm CallerSensitiveMethodHandle + * @run junit/othervm CallerSensitiveMethodHandle * @summary Check Lookup findVirtual, findStatic and unreflect behavior with * caller sensitive methods with focus on AccessibleObject.setAccessible */ -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.reflect.Field; import static java.lang.invoke.MethodType.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class CallerSensitiveMethodHandle { private static int field = 0; @@ -46,7 +45,7 @@ public class CallerSensitiveMethodHandle { MethodHandle mh = l.findVirtual(Field.class, "setInt", methodType(void.class, Object.class, int.class)); int newValue = 5; mh.invokeExact(f, (Object) null, newValue); - assertTrue(field == newValue); + assertEquals(newValue, field); } @Test @@ -55,6 +54,6 @@ public class CallerSensitiveMethodHandle { MethodHandle MH_lookup2 = lookup.findStatic(MethodHandles.class, "lookup", methodType(Lookup.class)); Lookup lookup2 = (Lookup) MH_lookup2.invokeExact(); System.out.println(lookup2 + " original lookup class " + lookup.lookupClass()); - assertTrue(lookup2.lookupClass() == lookup.lookupClass()); + assertSame(lookup.lookupClass(), lookup2.lookupClass()); } } diff --git a/test/jdk/java/lang/invoke/ClassSpecializerTest.java b/test/jdk/java/lang/invoke/ClassSpecializerTest.java index 671cf39e217..8bc5c58ad52 100644 --- a/test/jdk/java/lang/invoke/ClassSpecializerTest.java +++ b/test/jdk/java/lang/invoke/ClassSpecializerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,15 +24,13 @@ /* @test * @summary Smoke-test class specializer, used to create BoundMethodHandle classes * @compile/module=java.base java/lang/invoke/ClassSpecializerHelper.java - * @run testng/othervm/timeout=250 -ea -esa ClassSpecializerTest + * @run junit/othervm/timeout=250 -ea -esa ClassSpecializerTest */ // Useful diagnostics to try: // -Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true // -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true - -import org.testng.annotations.*; import java.lang.invoke.*; import java.util.ArrayList; import java.util.Arrays; @@ -40,6 +38,11 @@ import java.util.List; import static java.lang.invoke.ClassSpecializerHelper.*; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; + public class ClassSpecializerTest { @Test @@ -58,12 +61,12 @@ public class ClassSpecializerTest { } args.set(0, key * 1000 + 42); Frob f = (Frob) mh.invokeWithArguments(args.toArray()); - assert(f.kind() == k); + assertSame(k, f.kind()); System.out.println("k.f(...) = " + f.toString()); List l = f.asList(); System.out.println("f.l = " + l); args.subList(0,1).clear(); // drop label - assert(args.equals(l)); + assertEquals(args, l); } } private static Object coughUpA(Class pt) throws Throwable { diff --git a/test/jdk/java/lang/invoke/CompileThresholdBootstrapTest.java b/test/jdk/java/lang/invoke/CompileThresholdBootstrapTest.java index 848264b83a3..c6e093bd09a 100644 --- a/test/jdk/java/lang/invoke/CompileThresholdBootstrapTest.java +++ b/test/jdk/java/lang/invoke/CompileThresholdBootstrapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,27 +26,19 @@ * @bug 8143232 * @summary Test verifies that LF bootstraps properly when run with COMPILE_THRESHOLD set * @compile CompileThresholdBootstrapTest.java - * @run testng/othervm -Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=30 test.java.lang.invoke.CompileThresholdBootstrapTest + * @run junit/othervm -Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=30 test.java.lang.invoke.CompileThresholdBootstrapTest */ package test.java.lang.invoke; import java.lang.invoke.MethodHandles; -import org.testng.*; -import org.testng.annotations.*; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public final class CompileThresholdBootstrapTest { @Test public void testBootstrap() throws Throwable { - Assert.assertEquals((int)MethodHandles.constant(int.class, (int)0).invokeExact(), 0); - } - - public static void main(String ... args) { - try { - CompileThresholdBootstrapTest test = new CompileThresholdBootstrapTest(); - test.testBootstrap(); - } catch (Throwable t) { - t.printStackTrace(); - } + assertEquals(0, (int)MethodHandles.constant(int.class, (int)0).invokeExact()); } } diff --git a/test/jdk/java/lang/invoke/ConstantIdentityMHTest.java b/test/jdk/java/lang/invoke/ConstantIdentityMHTest.java index 320fd29abe6..43770ea023b 100644 --- a/test/jdk/java/lang/invoke/ConstantIdentityMHTest.java +++ b/test/jdk/java/lang/invoke/ConstantIdentityMHTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* @test * @summary unit tests for java.lang.invoke.MethodHandles - * @run testng/othervm -ea -esa test.java.lang.invoke.ConstantIdentityMHTest + * @run junit/othervm -ea -esa test.java.lang.invoke.ConstantIdentityMHTest */ package test.java.lang.invoke; @@ -31,13 +31,14 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; -import static org.testng.Assert.*; -import org.testng.annotations.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class ConstantIdentityMHTest { - @DataProvider(name = "testZeroData") - private Object[][] testZeroData() { + private static Object[][] testZeroData() { return new Object[][] { {void.class, "()void"}, {int.class, "()int"}, @@ -52,26 +53,27 @@ public class ConstantIdentityMHTest { }; } - @Test(dataProvider = "testZeroData") + @ParameterizedTest + @MethodSource("testZeroData") public void testZero(Class expectedtype, String expected) throws Throwable { - assertEquals(MethodHandles.zero(expectedtype).type().toString(), expected); + assertEquals(expected, MethodHandles.zero(expectedtype).type().toString()); } - @Test(expectedExceptions={ NullPointerException.class }) + @Test public void testZeroNPE() { - MethodHandle mh = MethodHandles.zero(null); + assertThrows(NullPointerException.class, () -> MethodHandles.zero(null)); } @Test void testEmpty() throws Throwable { MethodHandle cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); - assertEquals((String)cat.invoke("x","y"), "xy"); + assertEquals("xy", (String)cat.invoke("x","y")); MethodHandle mhEmpty = MethodHandles.empty(cat.type()); - assertEquals((String)mhEmpty.invoke("x","y"), null); + assertNull((String) mhEmpty.invoke("x", "y")); } - @Test(expectedExceptions = { NullPointerException.class }) + @Test void testEmptyNPE() { - MethodHandle lenEmptyMH = MethodHandles.empty(null); + assertThrows(NullPointerException.class, () -> MethodHandles.empty(null)); } } diff --git a/test/jdk/java/lang/invoke/DefineClassTest.java b/test/jdk/java/lang/invoke/DefineClassTest.java index f712c945e59..889607f38f5 100644 --- a/test/jdk/java/lang/invoke/DefineClassTest.java +++ b/test/jdk/java/lang/invoke/DefineClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* @test * @modules java.base/java.lang:open - * @run testng/othervm test.DefineClassTest + * @run junit/othervm test.DefineClassTest * @summary Basic test for java.lang.invoke.MethodHandles.Lookup.defineClass */ @@ -38,7 +38,6 @@ import java.net.URLClassLoader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import org.testng.annotations.Test; import static java.lang.classfile.ClassFile.ACC_PUBLIC; import static java.lang.classfile.ClassFile.ACC_STATIC; @@ -48,7 +47,8 @@ import static java.lang.constant.ConstantDescs.INIT_NAME; import static java.lang.constant.ConstantDescs.MTD_void; import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodHandles.Lookup.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class DefineClassTest { private static final String THIS_PACKAGE = DefineClassTest.class.getPackageName(); @@ -60,9 +60,9 @@ public class DefineClassTest { * protection domain, as a lookup class. */ void testSameAbode(Class clazz, Class lc) { - assertTrue(clazz.getClassLoader() == lc.getClassLoader()); - assertEquals(clazz.getPackageName(), lc.getPackageName()); - assertTrue(clazz.getProtectionDomain() == lc.getProtectionDomain()); + assertSame(lc.getClassLoader(), clazz.getClassLoader()); + assertEquals(lc.getPackageName(), clazz.getPackageName()); + assertSame(lc.getProtectionDomain(), clazz.getProtectionDomain()); } /** @@ -72,8 +72,8 @@ public class DefineClassTest { void testDiscoverable(Class clazz, Lookup lookup) throws Exception { String cn = clazz.getName(); ClassLoader loader = clazz.getClassLoader(); - assertTrue(Class.forName(cn, false, loader) == clazz); - assertTrue(lookup.findClass(cn) == clazz); + assertSame(clazz, Class.forName(cn, false, loader)); + assertSame(clazz, lookup.findClass(cn)); } /** @@ -86,7 +86,7 @@ public class DefineClassTest { Class clazz = lookup.defineClass(generateClass(CLASS_NAME)); // test name - assertEquals(clazz.getName(), CLASS_NAME); + assertEquals(CLASS_NAME, clazz.getName()); // test loader/package/protection-domain testSameAbode(clazz, lookup.lookupClass()); @@ -95,10 +95,8 @@ public class DefineClassTest { testDiscoverable(clazz, lookup); // attempt defineClass again - try { - lookup.defineClass(generateClass(CLASS_NAME)); - assertTrue(false); - } catch (LinkageError expected) { } + var bytes = generateClass(CLASS_NAME); + assertThrows(LinkageError.class, () -> lookup.defineClass(bytes)); } /** @@ -126,10 +124,7 @@ public class DefineClassTest { classBytes = generateRunner(CLASS_NAME + nextNumber(), THIS_CLASS, "method4"); Class clazz = lookup.defineClass(classBytes); Runnable r = (Runnable) clazz.newInstance(); - try { - r.run(); - assertTrue(false); - } catch (IllegalAccessError expected) { } + assertThrows(IllegalAccessError.class, r::run); } public static void method1() { } @@ -154,12 +149,8 @@ public class DefineClassTest { Class clazz = lookup().defineClass(classBytes); // trigger initializer to run - try { - clazz.newInstance(); - assertTrue(false); - } catch (ExceptionInInitializerError e) { - assertTrue(e.getCause() instanceof IllegalCallerException); - } + var e = assertThrows(ExceptionInInitializerError.class, clazz::newInstance); + assertInstanceOf(IllegalCallerException.class, e.getCause()); } static void fail() { throw new IllegalCallerException(); } @@ -189,9 +180,9 @@ public class DefineClassTest { ClassLoader loader = new URLClassLoader(new URL[] { url1, url2 }); Class target1 = Class.forName("p.C1", false, loader); Class target2 = Class.forName("p.C2", false, loader); - assertTrue(target1.getClassLoader() == loader); - assertTrue(target1.getClassLoader() == loader); - assertNotEquals(target1.getProtectionDomain(), target2.getProtectionDomain()); + assertSame(loader, target1.getClassLoader()); + assertSame(loader, target1.getClassLoader()); + assertNotEquals(target2.getProtectionDomain(), target1.getProtectionDomain()); // protection domain 1 Lookup lookup1 = privateLookupIn(target1, lookup()); @@ -214,43 +205,43 @@ public class DefineClassTest { @Test public void testBootLoader() throws Exception { Lookup lookup = privateLookupIn(Thread.class, lookup()); - assertTrue(lookup.getClass().getClassLoader() == null); + assertNull(lookup.getClass().getClassLoader()); Class clazz = lookup.defineClass(generateClass("java.lang.Foo")); - assertEquals(clazz.getName(), "java.lang.Foo"); + assertEquals("java.lang.Foo", clazz.getName()); testSameAbode(clazz, Thread.class); testDiscoverable(clazz, lookup); } - @Test(expectedExceptions = { IllegalArgumentException.class }) + @Test public void testWrongPackage() throws Exception { - lookup().defineClass(generateClass("other.C")); + assertThrows(IllegalArgumentException.class, () -> lookup().defineClass(generateClass("other.C"))); } - @Test(expectedExceptions = { IllegalAccessException.class }) + @Test public void testNoPackageAccess() throws Exception { Lookup lookup = lookup().dropLookupMode(PACKAGE); - lookup.defineClass(generateClass(THIS_PACKAGE + ".C")); + assertThrows(IllegalAccessException.class, () -> lookup.defineClass(generateClass(THIS_PACKAGE + ".C"))); } - @Test(expectedExceptions = { ClassFormatError.class }) + @Test public void testTruncatedClassFile() throws Exception { - lookup().defineClass(new byte[0]); + assertThrows(ClassFormatError.class, () -> lookup().defineClass(new byte[0])); } - @Test(expectedExceptions = { NullPointerException.class }) + @Test public void testNull() throws Exception { - lookup().defineClass(null); + assertThrows(NullPointerException.class, () -> lookup().defineClass(null)); } - @Test(expectedExceptions = { NoClassDefFoundError.class }) + @Test public void testLinking() throws Exception { - lookup().defineClass(generateNonLinkableClass(THIS_PACKAGE + ".NonLinkableClass")); + assertThrows(NoClassDefFoundError.class, () -> lookup().defineClass(generateNonLinkableClass(THIS_PACKAGE + ".NonLinkableClass"))); } - @Test(expectedExceptions = { IllegalArgumentException.class }) + @Test public void testModuleInfo() throws Exception { - lookup().defineClass(generateModuleInfo()); + assertThrows(IllegalArgumentException.class, () -> lookup().defineClass(generateModuleInfo())); } /** diff --git a/test/jdk/java/lang/invoke/DropArgumentsTest.java b/test/jdk/java/lang/invoke/DropArgumentsTest.java index 2df9b5f63ba..fb82bb312cd 100644 --- a/test/jdk/java/lang/invoke/DropArgumentsTest.java +++ b/test/jdk/java/lang/invoke/DropArgumentsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,19 +24,24 @@ /* @test * @bug 8158169 * @summary unit tests for java.lang.invoke.MethodHandles - * @run testng test.java.lang.invoke.DropArgumentsTest + * @run junit test.java.lang.invoke.DropArgumentsTest */ package test.java.lang.invoke; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; -import static org.testng.AssertJUnit.*; -import org.testng.annotations.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class DropArgumentsTest { @@ -53,8 +58,7 @@ public class DropArgumentsTest { } - @DataProvider(name = "dropArgumentsToMatchNPEData") - private Object[][] dropArgumentsToMatchNPEData() + private static Object[][] dropArgumentsToMatchNPEData() throws NoSuchMethodException, IllegalAccessException { MethodHandle cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); return new Object[][] { @@ -63,13 +67,13 @@ public class DropArgumentsTest { }; } - @Test(dataProvider = "dropArgumentsToMatchNPEData", expectedExceptions = { NullPointerException.class }) + @ParameterizedTest + @MethodSource("dropArgumentsToMatchNPEData") public void dropArgumentsToMatchNPE(MethodHandle target, int pos, List> valueType, int skip) { - MethodHandles.dropArgumentsToMatch(target, pos, valueType , skip); + assertThrows(NullPointerException.class, () -> MethodHandles.dropArgumentsToMatch(target, pos, valueType, skip)); } - @DataProvider(name = "dropArgumentsToMatchIAEData") - private Object[][] dropArgumentsToMatchIAEData() + private static Object[][] dropArgumentsToMatchIAEData() throws NoSuchMethodException, IllegalAccessException { MethodHandle cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); MethodType bigType = cat.type().insertParameterTypes(0, String.class, String.class, int.class); @@ -82,17 +86,20 @@ public class DropArgumentsTest { }; } - @Test(dataProvider = "dropArgumentsToMatchIAEData", expectedExceptions = { IllegalArgumentException.class }) + @ParameterizedTest + @MethodSource("dropArgumentsToMatchIAEData") public void dropArgumentsToMatchIAE(MethodHandle target, int pos, List> valueType, int skip) { - MethodHandles.dropArgumentsToMatch(target, pos, valueType , skip); + assertThrows(IllegalArgumentException.class, () -> MethodHandles.dropArgumentsToMatch(target, pos, valueType, skip)); } - @Test(expectedExceptions = { IllegalArgumentException.class }) + @Test public void dropArgumentsToMatchTestWithVoid() throws Throwable { MethodHandle cat = lookup().findVirtual(String.class, "concat", - MethodType.methodType(String.class, String.class)); - MethodType bigTypewithVoid = cat.type().insertParameterTypes(0, void.class, String.class, int.class); - MethodHandle handle2 = MethodHandles.dropArgumentsToMatch(cat, 0, bigTypewithVoid.parameterList(), 1); + MethodType.methodType(String.class, String.class)); + List> bigTypewithVoid = new ArrayList<>(cat.type().parameterList()); + bigTypewithVoid.addAll(0, List.of(void.class, String.class, int.class)); + assertThrows(IllegalArgumentException.class, () -> + MethodHandles.dropArgumentsToMatch(cat, 0, bigTypewithVoid, 1)); } public static class MethodSet { diff --git a/test/jdk/java/lang/invoke/DropLookupModeTest.java b/test/jdk/java/lang/invoke/DropLookupModeTest.java index 1a4c311be8b..7619793c3c6 100644 --- a/test/jdk/java/lang/invoke/DropLookupModeTest.java +++ b/test/jdk/java/lang/invoke/DropLookupModeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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,9 +21,9 @@ * questions. */ -/** +/* * @test - * @run testng DropLookupModeTest + * @run junit DropLookupModeTest * @summary Basic unit tests Lookup::dropLookupMode */ @@ -31,83 +31,85 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import static java.lang.invoke.MethodHandles.Lookup.*; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; -@Test public class DropLookupModeTest { /** * Basic test of dropLookupMode */ + @Test public void testBasic() { final Lookup fullPowerLookup = MethodHandles.lookup(); final Class lc = fullPowerLookup.lookupClass(); - assertTrue(fullPowerLookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PROTECTED|PRIVATE|ORIGINAL)); + assertEquals(PUBLIC | MODULE | PACKAGE | PROTECTED | PRIVATE | ORIGINAL, fullPowerLookup.lookupModes()); Lookup lookup = fullPowerLookup.dropLookupMode(PRIVATE); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE)); + assertSame(lc, lookup.lookupClass()); + assertEquals(PUBLIC | MODULE | PACKAGE, lookup.lookupModes()); lookup = fullPowerLookup.dropLookupMode(PROTECTED); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PRIVATE)); + assertSame(lc, lookup.lookupClass()); + assertEquals(PUBLIC | MODULE | PACKAGE | PRIVATE, lookup.lookupModes()); lookup = fullPowerLookup.dropLookupMode(PACKAGE); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == (PUBLIC|MODULE)); + assertSame(lc, lookup.lookupClass()); + assertEquals(PUBLIC | MODULE, lookup.lookupModes()); lookup = fullPowerLookup.dropLookupMode(MODULE); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == (PUBLIC)); + assertSame(lc, lookup.lookupClass()); + assertEquals(PUBLIC, lookup.lookupModes()); lookup = fullPowerLookup.dropLookupMode(PUBLIC); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == 0); + assertSame(lc, lookup.lookupClass()); + assertEquals(0, lookup.lookupModes()); lookup = fullPowerLookup.dropLookupMode(UNCONDITIONAL); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PRIVATE)); + assertSame(lc, lookup.lookupClass()); + assertEquals(PUBLIC | MODULE | PACKAGE | PRIVATE, lookup.lookupModes()); } /** * Starting with a full power Lookup, use dropLookupMode to create new Lookups * with reduced access. */ + @Test public void testReducingAccess() { Lookup lookup = MethodHandles.lookup(); final Class lc = lookup.lookupClass(); - assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PROTECTED|PRIVATE|ORIGINAL)); + assertEquals(PUBLIC | MODULE | PACKAGE | PROTECTED | PRIVATE | ORIGINAL, lookup.lookupModes()); lookup = lookup.dropLookupMode(PROTECTED); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PRIVATE)); + assertSame(lc, lookup.lookupClass()); + assertEquals(PUBLIC | MODULE | PACKAGE | PRIVATE, lookup.lookupModes()); lookup = lookup.dropLookupMode(PRIVATE); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE)); + assertSame(lc, lookup.lookupClass()); + assertEquals(PUBLIC | MODULE | PACKAGE, lookup.lookupModes()); lookup = lookup.dropLookupMode(PACKAGE); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == (PUBLIC|MODULE)); + assertSame(lc, lookup.lookupClass()); + assertEquals(PUBLIC | MODULE, lookup.lookupModes()); lookup = lookup.dropLookupMode(MODULE); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == PUBLIC); + assertSame(lc, lookup.lookupClass()); + assertEquals(PUBLIC, lookup.lookupModes()); lookup = lookup.dropLookupMode(PUBLIC); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == 0); + assertSame(lc, lookup.lookupClass()); + assertEquals(0, lookup.lookupModes()); // repeat with lookup has no access lookup = lookup.dropLookupMode(PUBLIC); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == 0); + assertSame(lc, lookup.lookupClass()); + assertEquals(0, lookup.lookupModes()); } - @DataProvider(name = "unconditionals") - public Object[][] unconditionals() { + public static Object[][] unconditionals() { Lookup publicLookup = MethodHandles.publicLookup(); return new Object[][] { { publicLookup, Object.class }, @@ -120,9 +122,10 @@ public class DropLookupModeTest { * Test dropLookupMode on the lookup with public lookup * and UNCONDITIONAL */ - @Test(dataProvider = "unconditionals") + @ParameterizedTest + @MethodSource("unconditionals") public void testUnconditionalLookup(Lookup unconditionalLookup, Class expected) { - assertTrue(unconditionalLookup.lookupModes() == UNCONDITIONAL); + assertEquals(UNCONDITIONAL, unconditionalLookup.lookupModes()); assertPublicLookup(unconditionalLookup.dropLookupMode(PRIVATE), expected); assertPublicLookup(unconditionalLookup.dropLookupMode(PROTECTED), expected); @@ -132,31 +135,27 @@ public class DropLookupModeTest { // drop all access Lookup lookup = unconditionalLookup.dropLookupMode(UNCONDITIONAL); - assertTrue(lookup.lookupClass() == expected); - assertTrue(lookup.lookupModes() == 0); + assertSame(expected, lookup.lookupClass()); + assertEquals(0, lookup.lookupModes()); } private void assertPublicLookup(Lookup lookup, Class expected) { - assertTrue(lookup.lookupClass() == expected); - assertTrue(lookup.lookupModes() == UNCONDITIONAL); - } - - @DataProvider(name = "badInput") - public Object[][] badInput() { - return new Object[][] { - { 0, null }, - { (PACKAGE|PRIVATE), null }, // two modes - { Integer.MAX_VALUE, null }, - { Integer.MIN_VALUE, null }, - }; + assertSame(expected, lookup.lookupClass()); + assertEquals(UNCONDITIONAL, lookup.lookupModes()); } /** * Check that IllegalArgumentException is thrown for bad input */ - @Test(dataProvider = "badInput", expectedExceptions = {IllegalArgumentException.class}) - public void testBadInput(Integer modeToDrop, Object ignore) { - MethodHandles.lookup().dropLookupMode(modeToDrop); + @ParameterizedTest + @ValueSource(ints = { + 0, + (PACKAGE|PRIVATE), // two modes + Integer.MAX_VALUE, + Integer.MIN_VALUE, + }) + public void testBadInput(int modeToDrop) { + assertThrows(IllegalArgumentException.class, () -> MethodHandles.lookup().dropLookupMode(modeToDrop)); } } diff --git a/test/jdk/java/lang/invoke/FilterArgumentsTest.java b/test/jdk/java/lang/invoke/FilterArgumentsTest.java index 3c4884e7c6a..2326799cc1c 100644 --- a/test/jdk/java/lang/invoke/FilterArgumentsTest.java +++ b/test/jdk/java/lang/invoke/FilterArgumentsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @bug 8194554 - * @run testng/othervm test.java.lang.invoke.FilterArgumentsTest + * @run junit/othervm test.java.lang.invoke.FilterArgumentsTest */ package test.java.lang.invoke; @@ -37,40 +37,40 @@ import java.util.List; import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.methodType; -import org.testng.annotations.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class FilterArgumentsTest { @Test - public static void testFilterA_B_C() throws Throwable { + public void testFilterA_B_C() throws Throwable { FilterTest test = new FilterTest( filterArguments(MH_TEST, 0, MH_FILTER_A, MH_FILTER_B, MH_FILTER_C)); test.run(List.of("A", "B", "C")); } @Test - public static void testFilterA_B() throws Throwable { + public void testFilterA_B() throws Throwable { FilterTest test = new FilterTest( filterArguments(MH_TEST, 0, MH_FILTER_A, MH_FILTER_B)); test.run(List.of("A", "B")); } @Test - public static void testFilterB_C() throws Throwable { + public void testFilterB_C() throws Throwable { FilterTest test = new FilterTest( filterArguments(MH_TEST, 1, MH_FILTER_B, MH_FILTER_C)); test.run(List.of("B", "C")); } @Test - public static void testFilterB() throws Throwable { + public void testFilterB() throws Throwable { FilterTest test = new FilterTest(filterArguments(MH_TEST, 1, MH_FILTER_B)); test.run(List.of("B")); } @Test - public static void testFilterC() throws Throwable { + public void testFilterC() throws Throwable { FilterTest test = new FilterTest(filterArguments(MH_TEST, 2, MH_FILTER_C)); test.run(List.of("C")); } @@ -85,8 +85,8 @@ public class FilterArgumentsTest { void run(List expected) throws Throwable { filters.clear(); - assertEquals((String)mh.invokeExact("x", 0, 'z'), "x-0-z"); - assertEquals(filters, expected); + assertEquals("x-0-z", (String)mh.invokeExact("x", 0, 'z')); + assertEquals(expected, filters); } static String filterA(String s) { diff --git a/test/jdk/java/lang/invoke/FindAccessTest.java b/test/jdk/java/lang/invoke/FindAccessTest.java index f8602ee22bd..3bcff4f5324 100644 --- a/test/jdk/java/lang/invoke/FindAccessTest.java +++ b/test/jdk/java/lang/invoke/FindAccessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* @test * @bug 8139885 - * @run testng/othervm -ea -esa test.java.lang.invoke.FindAccessTest + * @run junit/othervm -ea -esa test.java.lang.invoke.FindAccessTest */ package test.java.lang.invoke; @@ -33,9 +33,10 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; -import static org.testng.AssertJUnit.*; +import org.junit.jupiter.api.Test; -import org.testng.annotations.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * Tests for Lookup.findClass/accessClass extensions added in JEP 274. @@ -45,7 +46,7 @@ public class FindAccessTest { static final Lookup LOOKUP = MethodHandles.lookup(); @Test - public static void testFindSpecial() throws Throwable { + public void testFindSpecial() throws Throwable { FindSpecial.C c = new FindSpecial.C(); assertEquals("I1.m", c.m()); MethodType t = MethodType.methodType(String.class); @@ -54,25 +55,18 @@ public class FindAccessTest { } @Test - public static void testFindSpecialAbstract() throws Throwable { + public void testFindSpecialAbstract() throws Throwable { FindSpecial.C c = new FindSpecial.C(); assertEquals("q", c.q()); MethodType t = MethodType.methodType(String.class); - boolean caught = false; - try { - MethodHandle ci3q = LOOKUP.findSpecial(FindSpecial.I3.class, "q", t, FindSpecial.C.class); - } catch (Throwable thrown) { - if (!(thrown instanceof IllegalAccessException) || !FindSpecial.ABSTRACT_ERROR.equals(thrown.getMessage())) { - throw new AssertionError(thrown.getMessage(), thrown); - } - caught = true; - } - assertTrue(caught); + var thrown = assertThrows(IllegalAccessException.class, + () -> LOOKUP.findSpecial(FindSpecial.I3.class, "q", t, FindSpecial.C.class)); + assertEquals(FindSpecial.ABSTRACT_ERROR, thrown.getMessage()); } - @Test(expectedExceptions = {ClassNotFoundException.class}) - public static void testFindClassCNFE() throws ClassNotFoundException, IllegalAccessException { - LOOKUP.findClass("does.not.Exist"); + @Test + public void testFindClassCNFE() throws ClassNotFoundException, IllegalAccessException { + assertThrows(ClassNotFoundException.class, () -> LOOKUP.findClass("does.not.Exist")); } static class FindSpecial { diff --git a/test/jdk/java/lang/invoke/FoldTest.java b/test/jdk/java/lang/invoke/FoldTest.java index 157cfbffe2e..92ba246ebc8 100644 --- a/test/jdk/java/lang/invoke/FoldTest.java +++ b/test/jdk/java/lang/invoke/FoldTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* @test * @bug 8139885 - * @run testng/othervm -ea -esa test.java.lang.invoke.FoldTest + * @run junit/othervm -ea -esa test.java.lang.invoke.FoldTest */ package test.java.lang.invoke; @@ -36,9 +36,9 @@ import java.lang.invoke.MethodType; import static java.lang.invoke.MethodType.methodType; -import static org.testng.AssertJUnit.*; +import org.junit.jupiter.api.Test; -import org.testng.annotations.*; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests for the new fold method handle combinator added in JEP 274. @@ -48,7 +48,7 @@ public class FoldTest { static final Lookup LOOKUP = MethodHandles.lookup(); @Test - public static void testFold0a() throws Throwable { + public void testFold0a() throws Throwable { // equivalence to foldArguments(MethodHandle,MethodHandle) MethodHandle fold = MethodHandles.foldArguments(Fold.MH_multer, 0, Fold.MH_adder); assertEquals(Fold.MT_folded1, fold.type()); @@ -56,7 +56,7 @@ public class FoldTest { } @Test - public static void testFold1a() throws Throwable { + public void testFold1a() throws Throwable { // test foldArguments for folding position 1 MethodHandle fold = MethodHandles.foldArguments(Fold.MH_multer, 1, Fold.MH_adder1); assertEquals(Fold.MT_folded1, fold.type()); @@ -64,7 +64,7 @@ public class FoldTest { } @Test - public static void testFold0b() throws Throwable { + public void testFold0b() throws Throwable { // test foldArguments equivalence with multiple types MethodHandle fold = MethodHandles.foldArguments(Fold.MH_str, 0, Fold.MH_comb); assertEquals(Fold.MT_folded2, fold.type()); @@ -72,7 +72,7 @@ public class FoldTest { } @Test - public static void testFold1b() throws Throwable { + public void testFold1b() throws Throwable { // test folgArguments for folding position 1, with multiple types MethodHandle fold = MethodHandles.foldArguments(Fold.MH_str, 1, Fold.MH_comb2); assertEquals(Fold.MT_folded3, fold.type()); @@ -81,7 +81,7 @@ public class FoldTest { } @Test - public static void testFoldArgumentsExample() throws Throwable { + public void testFoldArgumentsExample() throws Throwable { // test the JavaDoc foldArguments-with-pos example StringWriter swr = new StringWriter(); MethodHandle trace = LOOKUP.findVirtual(StringWriter.class, "write", methodType(void.class, String.class)).bindTo(swr); diff --git a/test/jdk/java/lang/invoke/InvokeGenericTest.java b/test/jdk/java/lang/invoke/InvokeGenericTest.java index ef201caead1..0be810506de 100644 --- a/test/jdk/java/lang/invoke/InvokeGenericTest.java +++ b/test/jdk/java/lang/invoke/InvokeGenericTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* @test * @summary unit tests for java.lang.invoke.MethodHandle.invoke * @compile InvokeGenericTest.java - * @run testng/othervm test.java.lang.invoke.InvokeGenericTest + * @run junit/othervm test.java.lang.invoke.InvokeGenericTest */ package test.java.lang.invoke; @@ -34,9 +34,13 @@ import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; import java.lang.reflect.*; import java.util.*; -import org.testng.*; -import static org.testng.AssertJUnit.*; -import org.testng.annotations.*; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; /** * @@ -68,7 +72,7 @@ public class InvokeGenericTest { String testName; static int allPosTests, allNegTests; int posTests, negTests; - @AfterMethod + @AfterEach public void printCounts() { if (verbosity >= 2 && (posTests | negTests) != 0) { System.out.println(); @@ -92,14 +96,14 @@ public class InvokeGenericTest { testName = name; } - @BeforeClass + @BeforeAll public static void setUpClass() throws Exception { calledLog.clear(); calledLog.add(null); nextArgVal = INITIAL_ARG_VAL; } - @AfterClass + @AfterAll public static void tearDownClass() throws Exception { int posTests = allPosTests, negTests = allNegTests; if (verbosity >= 2 && (posTests | negTests) != 0) { @@ -127,7 +131,7 @@ public class InvokeGenericTest { System.out.println("actual: "+actual); System.out.println("ex. types: "+getClasses(expected)); System.out.println("act. types: "+getClasses(actual)); - assertEquals("previous method call", expected, actual); + assertEquals(expected, actual, "previous method call"); } static void printCalled(MethodHandle target, String name, Object... args) { if (verbosity >= 3) @@ -389,8 +393,7 @@ public class InvokeGenericTest { } public void testWrongArgumentCount(List> expect, List> observe) throws Throwable { countTest(false); - if (expect.equals(observe)) - assert(false); + assertNotEquals(expect, observe); MethodHandle target = callable(expect); Object[] args = zeroArgs(observe); Object junk; @@ -473,28 +476,25 @@ public class InvokeGenericTest { mh = MethodHandles.filterReturnValue(mh, toString_MH); mh = mh.asType(type); Object res = null; - if (nargs == 2) { - res = mh.invoke((Object)args[0], (Object)args[1]); - assertEquals(expectString, res); - res = mh.invoke((String)args[0], (Object)args[1]); - assertEquals(expectString, res); - res = mh.invoke((Object)args[0], (String)args[1]); - assertEquals(expectString, res); - res = mh.invoke((String)args[0], (String)args[1]); - assertEquals(expectString, res); - res = mh.invoke((String)args[0], (CharSequence)args[1]); - assertEquals(expectString, res); - res = mh.invoke((CharSequence)args[0], (Object)args[1]); - assertEquals(expectString, res); - res = (String) mh.invoke((Object)args[0], (Object)args[1]); - assertEquals(expectString, res); - res = (String) mh.invoke((String)args[0], (Object)args[1]); - assertEquals(expectString, res); - res = (CharSequence) mh.invoke((String)args[0], (Object)args[1]); - assertEquals(expectString, res); - } else { - assert(false); // write this code - } + assertEquals(2, nargs); + res = mh.invoke((Object)args[0], (Object)args[1]); + assertEquals(expectString, res); + res = mh.invoke((String)args[0], (Object)args[1]); + assertEquals(expectString, res); + res = mh.invoke((Object)args[0], (String)args[1]); + assertEquals(expectString, res); + res = mh.invoke((String)args[0], (String)args[1]); + assertEquals(expectString, res); + res = mh.invoke((String)args[0], (CharSequence)args[1]); + assertEquals(expectString, res); + res = mh.invoke((CharSequence)args[0], (Object)args[1]); + assertEquals(expectString, res); + res = (String) mh.invoke((Object)args[0], (Object)args[1]); + assertEquals(expectString, res); + res = (String) mh.invoke((String)args[0], (Object)args[1]); + assertEquals(expectString, res); + res = (CharSequence) mh.invoke((String)args[0], (Object)args[1]); + assertEquals(expectString, res); //System.out.println(res); } diff --git a/test/jdk/java/lang/invoke/InvokeMethodHandleWithBadArgument.java b/test/jdk/java/lang/invoke/InvokeMethodHandleWithBadArgument.java index 2479c22b2f4..f2749cfb164 100644 --- a/test/jdk/java/lang/invoke/InvokeMethodHandleWithBadArgument.java +++ b/test/jdk/java/lang/invoke/InvokeMethodHandleWithBadArgument.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 8157246 * @summary Tests invocation of MethodHandle with invalid leading argument - * @run testng/othervm test.java.lang.invoke.InvokeMethodHandleWithBadArgument + * @run junit/othervm test.java.lang.invoke.InvokeMethodHandleWithBadArgument */ package test.java.lang.invoke; @@ -38,9 +38,9 @@ import java.lang.invoke.VarHandle; import static java.lang.invoke.MethodType.methodType; -import static org.testng.AssertJUnit.*; +import org.junit.jupiter.api.Test; -import org.testng.annotations.*; +import static org.junit.jupiter.api.Assertions.*; /** * Tests invocation of MethodHandle with invalid leading argument such as @@ -49,86 +49,100 @@ import org.testng.annotations.*; public class InvokeMethodHandleWithBadArgument { // ---- null array reference ---- - @Test(expectedExceptions = {NullPointerException.class}) - public static void testAsSpreaderPosInvokeWithNull() throws Throwable { + @Test + public void testAsSpreaderPosInvokeWithNull() throws Throwable { MethodHandle spreader = MH_spread.asSpreader(1, int[].class, 3); - spreader.invoke("A", null, "B"); + assertThrows(NullPointerException.class, () -> spreader.invoke("A", null, "B")); } - @Test(expectedExceptions = {NullPointerException.class}) - public static void testAsSpreaderInvokeWithNull() throws Throwable { + @Test + public void testAsSpreaderInvokeWithNull() throws Throwable { MethodHandle spreader = MH_String_equals.asSpreader(String[].class, 2); - assert ((boolean) spreader.invokeExact(new String[]{"me", "me"})); - boolean eq = (boolean) spreader.invokeExact((String[]) null); + assertTrue((boolean) spreader.invokeExact(new String[]{"me", "me"})); + assertThrows(NullPointerException.class, () -> { + boolean eq = (boolean) spreader.invokeExact((String[]) null); + }); } // ---- incorrect array element count ---- - @Test(expectedExceptions = {IllegalArgumentException.class}) - public static void testAsSpreaderPosInvokeWithBadElementCount() throws Throwable { + @Test + public void testAsSpreaderPosInvokeWithBadElementCount() throws Throwable { MethodHandle spreader = MH_spread.asSpreader(1, int[].class, 3); - spreader.invoke("A", new int[]{1, 2}, "B"); + assertThrows(IllegalArgumentException.class, () -> spreader.invoke("A", new int[]{1, 2}, "B")); } - @Test(expectedExceptions = {IllegalArgumentException.class}) - public static void testAsSpreaderInvokeWithBadElementCount() throws Throwable { + @Test + public void testAsSpreaderInvokeWithBadElementCount() throws Throwable { MethodHandle spreader = MH_String_equals.asSpreader(String[].class, 2); - assert (!(boolean) spreader.invokeExact(new String[]{"me", "thee"})); - boolean eq = (boolean) spreader.invokeExact(new String[0]); + assertFalse((boolean) spreader.invokeExact(new String[]{"me", "thee"})); + assertThrows(IllegalArgumentException.class, () -> { + boolean eq = (boolean) spreader.invokeExact(new String[0]); + }); } // ---- spread no argument ---- @Test - public static void testAsSpreaderPosInvokeWithZeroLength() throws Throwable { + public void testAsSpreaderPosInvokeWithZeroLength() throws Throwable { MethodHandle spreader = MH_spread.asSpreader(1, int[].class, 0); - assert("A123B".equals(spreader.invoke("A", (int[])null, 1, 2, 3, "B"))); + assertEquals("A123B", spreader.invoke("A", (int[]) null, 1, 2, 3, "B")); } @Test - public static void testAsSpreaderInvokeWithZeroLength() throws Throwable { + public void testAsSpreaderInvokeWithZeroLength() throws Throwable { MethodHandle spreader = MH_String_equals.asSpreader(String[].class, 0); - assert ((boolean) spreader.invokeExact("me", (Object)"me", new String[0])); + assertTrue((boolean) spreader.invokeExact("me", (Object)"me", new String[0])); boolean eq = (boolean) spreader.invokeExact("me", (Object)"me", (String[]) null); } // ---- invokers with null method/var handle argument ---- - @Test(expectedExceptions = {NullPointerException.class}) - public static void testInvokerWithNull() throws Throwable { + @Test + public void testInvokerWithNull() throws Throwable { MethodType type = methodType(int.class, int.class, int.class); MethodHandle invoker = MethodHandles.invoker(type); - assert((int) invoker.invoke(MH_add, 1, 2) == 3); - int sum = (int)invoker.invoke((MethodHandle)null, 1, 2); + assertEquals(3, (int) invoker.invoke(MH_add, 1, 2)); + assertThrows(NullPointerException.class, () -> { + int sum = (int)invoker.invoke((MethodHandle)null, 1, 2); + }); } - @Test(expectedExceptions = {NullPointerException.class}) - public static void testExactInvokerWithNull() throws Throwable { + @Test + public void testExactInvokerWithNull() throws Throwable { MethodType type = methodType(int.class, int.class, int.class); MethodHandle invoker = MethodHandles.exactInvoker(type); - assert((int) invoker.invoke(MH_add, 1, 2) == 3); - int sum = (int)invoker.invokeExact((MethodHandle)null, 1, 2); + assertEquals(3, (int) invoker.invoke(MH_add, 1, 2)); + assertThrows(NullPointerException.class, () -> { + int sum = (int)invoker.invokeExact((MethodHandle)null, 1, 2); + }); } - @Test(expectedExceptions = {NullPointerException.class}) - public static void testSpreadInvokerWithNull() throws Throwable { + @Test + public void testSpreadInvokerWithNull() throws Throwable { MethodType type = methodType(boolean.class, String.class, String.class); MethodHandle invoker = MethodHandles.spreadInvoker(type, 0); - assert ((boolean) invoker.invoke(MH_String_equals, new String[]{"me", "me"})); - boolean eq = (boolean) invoker.invoke((MethodHandle)null, new String[]{"me", "me"}); + assertTrue((boolean) invoker.invoke(MH_String_equals, new String[]{"me", "me"})); + assertThrows(NullPointerException.class, () -> { + boolean eq = (boolean) invoker.invoke((MethodHandle)null, new String[]{"me", "me"}); + }); } - @Test(expectedExceptions = {NullPointerException.class}) - public static void testVarHandleInvokerWithNull() throws Throwable { + @Test + public void testVarHandleInvokerWithNull() throws Throwable { VarHandle.AccessMode am = VarHandle.AccessMode.GET; MethodHandle invoker = MethodHandles.varHandleInvoker(am, VH_array.accessModeType(am)); - assert ((int) invoker.invoke(VH_array, array, 3) == 3); - int value = (int)invoker.invoke((VarHandle)null, array, 3); + assertEquals(3, (int) invoker.invoke(VH_array, array, 3)); + assertThrows(NullPointerException.class, () -> { + int value = (int)invoker.invoke((VarHandle)null, array, 3); + }); } - @Test(expectedExceptions = {NullPointerException.class}) - public static void testVarHandleExactInvokerWithNull() throws Throwable { + @Test + public void testVarHandleExactInvokerWithNull() throws Throwable { VarHandle.AccessMode am = VarHandle.AccessMode.GET; MethodHandle invoker = MethodHandles.varHandleExactInvoker(am, VH_array.accessModeType(am)); - assert ((int) invoker.invoke(VH_array, array, 3) == 3); - int value = (int)invoker.invokeExact((VarHandle)null, array, 3); + assertEquals(3, (int) invoker.invoke(VH_array, array, 3)); + assertThrows(NullPointerException.class, () -> { + int value = (int)invoker.invokeExact((VarHandle)null, array, 3); + }); } static final Lookup LOOKUP = MethodHandles.lookup(); diff --git a/test/jdk/java/lang/invoke/InvokeWithArgumentsTest.java b/test/jdk/java/lang/invoke/InvokeWithArgumentsTest.java index 63a2101bd67..3a705aca699 100644 --- a/test/jdk/java/lang/invoke/InvokeWithArgumentsTest.java +++ b/test/jdk/java/lang/invoke/InvokeWithArgumentsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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,19 +23,19 @@ /* @test * @summary basic tests for MethodHandle.invokeWithArguments - * @run testng test.java.lang.invoke.InvokeWithArgumentsTest + * @run junit test.java.lang.invoke.InvokeWithArgumentsTest */ package test.java.lang.invoke; -import org.testng.Assert; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.WrongMethodTypeException; import static java.lang.invoke.MethodType.methodType; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; public class InvokeWithArgumentsTest { static final MethodHandles.Lookup L = MethodHandles.lookup(); @@ -49,10 +49,7 @@ public class InvokeWithArgumentsTest { MethodHandle mh = L.findStatic(L.lookupClass(), "arity", methodType(Object[].class, Object.class, Object.class, Object[].class)); - try { - mh.invokeWithArguments(""); - Assert.fail("WrongMethodTypeException expected"); - } catch (WrongMethodTypeException e) {} + assertThrows(WrongMethodTypeException.class, () -> mh.invokeWithArguments("")); } static Object[] passThrough(String... a) { @@ -72,10 +69,10 @@ public class InvokeWithArgumentsTest { // Note: the actual array is not preserved, the elements will be // unpacked and then packed into a new array before invoking the method - String[] expected = (String[]) mh.invokeWithArguments(actual); + String[] result = (String[]) mh.invokeWithArguments(actual); - Assert.assertTrue(actual != expected, "Array should not pass through"); - Assert.assertEquals(actual, expected, "Array contents should be equal"); + assertNotSame(actual, result, "Array should not pass through"); + assertArrayEquals(actual, result, "Array contents should be equal"); } @Test @@ -89,8 +86,8 @@ public class InvokeWithArgumentsTest { // will cast to Object become the single element of a new Object[] array Object[] expected = (Object[]) mh.invokeWithArguments("", actual); - Assert.assertEquals(1, expected.length, "Array should contain just one element"); - Assert.assertTrue(actual == expected[0], "Array should pass through"); + assertEquals(1, expected.length, "Array should contain just one element"); + assertSame(actual, expected[0], "Array should pass through"); } static void intArray(int... a) { @@ -100,20 +97,14 @@ public class InvokeWithArgumentsTest { public void testPrimitiveArrayWithNull() throws Throwable { MethodHandle mh = L.findStatic(L.lookupClass(), "intArray", methodType(void.class, int[].class)); - try { - mh.invokeWithArguments(null, null); - Assert.fail("NullPointerException expected"); - } catch (NullPointerException e) {} + assertThrows(NullPointerException.class, () -> mh.invokeWithArguments(null, null)); } @Test public void testPrimitiveArrayWithRef() throws Throwable { MethodHandle mh = L.findStatic(L.lookupClass(), "intArray", methodType(void.class, int[].class)); - try { - mh.invokeWithArguments("A", "B"); - Assert.fail("ClassCastException expected"); - } catch (ClassCastException e) {} + assertThrows(ClassCastException.class, () -> mh.invokeWithArguments("A", "B")); } @@ -127,9 +118,6 @@ public class InvokeWithArgumentsTest { // All numbers, should not throw mh.invokeWithArguments(1, 1.0, 1.0F, 1L); - try { - mh.invokeWithArguments("A"); - Assert.fail("ClassCastException expected"); - } catch (ClassCastException e) {} + assertThrows(ClassCastException.class, () -> mh.invokeWithArguments("A")); } } diff --git a/test/jdk/java/lang/invoke/JavaDocExamplesTest.java b/test/jdk/java/lang/invoke/JavaDocExamplesTest.java index 53257d9876d..0fa2614c83f 100644 --- a/test/jdk/java/lang/invoke/JavaDocExamplesTest.java +++ b/test/jdk/java/lang/invoke/JavaDocExamplesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* @test * @summary example code used in javadoc for java.lang.invoke API * @compile JavaDocExamplesTest.java - * @run testng/othervm test.java.lang.invoke.JavaDocExamplesTest + * @run junit/othervm test.java.lang.invoke.JavaDocExamplesTest */ package test.java.lang.invoke; @@ -36,8 +36,8 @@ import static java.lang.invoke.MethodType.*; import java.util.*; -import org.testng.*; -import org.testng.annotations.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * @author jrose @@ -350,14 +350,14 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); static void assertEquals(Object exp, Object act) { if (verbosity > 0) System.out.println("result: "+act); - Assert.assertEquals(exp, act); + Assertions.assertEquals(exp, act); } static void assertTrue(boolean b) { if (verbosity > 0) { System.out.println("result: " + b); } - Assert.assertTrue(b); + Assertions.assertTrue(b); } @Test public void testMethodHandlesSummary() throws Throwable { diff --git a/test/jdk/java/lang/invoke/JavaUtilConcurrentLookupTest.java b/test/jdk/java/lang/invoke/JavaUtilConcurrentLookupTest.java index 9715de8fd46..a9a6861bc05 100644 --- a/test/jdk/java/lang/invoke/JavaUtilConcurrentLookupTest.java +++ b/test/jdk/java/lang/invoke/JavaUtilConcurrentLookupTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,11 @@ * @summary Tests that Lookup can be produced from classes under java.util.concurrent * @bug 8154447 * @compile/module=java.base java/util/concurrent/LookupTester.java - * @run testng/othervm JavaUtilConcurrentLookupTest + * @run junit/othervm JavaUtilConcurrentLookupTest */ -import org.testng.annotations.Test; - import java.util.concurrent.LookupTester; +import org.junit.jupiter.api.Test; public class JavaUtilConcurrentLookupTest { diff --git a/test/jdk/java/lang/invoke/LoopCombinatorTest.java b/test/jdk/java/lang/invoke/LoopCombinatorTest.java index 15fb9d320a3..91a752f2666 100644 --- a/test/jdk/java/lang/invoke/LoopCombinatorTest.java +++ b/test/jdk/java/lang/invoke/LoopCombinatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ * @bug 8154751 * @bug 8154754 * @bug 8167974 - * @run testng/othervm -ea -esa test.java.lang.invoke.LoopCombinatorTest + * @run junit/othervm -ea -esa test.java.lang.invoke.LoopCombinatorTest */ package test.java.lang.invoke; @@ -45,9 +45,12 @@ import java.util.*; import static java.lang.invoke.MethodType.methodType; -import static org.testng.AssertJUnit.*; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -import org.testng.annotations.*; +import static org.junit.jupiter.api.Assertions.*; /** * Tests for the loop combinators introduced in JEP 274. @@ -57,7 +60,7 @@ public class LoopCombinatorTest { static final Lookup LOOKUP = MethodHandles.lookup(); @Test - public static void testLoopFac() throws Throwable { + public void testLoopFac() throws Throwable { MethodHandle[] counterClause = new MethodHandle[]{Fac.MH_zero, Fac.MH_inc}; MethodHandle[] accumulatorClause = new MethodHandle[]{Fac.MH_one, Fac.MH_mult, Fac.MH_pred, Fac.MH_fin}; MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause); @@ -66,7 +69,7 @@ public class LoopCombinatorTest { } @Test - public static void testLoopFacNullInit() throws Throwable { + public void testLoopFacNullInit() throws Throwable { // null initializer for counter, should initialize to 0 MethodHandle[] counterClause = new MethodHandle[]{null, Fac.MH_inc}; MethodHandle[] accumulatorClause = new MethodHandle[]{Fac.MH_one, Fac.MH_mult, Fac.MH_pred, Fac.MH_fin}; @@ -76,7 +79,7 @@ public class LoopCombinatorTest { } @Test - public static void testLoopNullInit() throws Throwable { + public void testLoopNullInit() throws Throwable { // null initializer for counter, should initialize to 0, one-clause loop MethodHandle[] counterClause = new MethodHandle[]{null, Loop.MH_inc, Loop.MH_pred, Loop.MH_fin}; MethodHandle loop = MethodHandles.loop(counterClause); @@ -85,7 +88,7 @@ public class LoopCombinatorTest { } @Test - public static void testLoopVoid1() throws Throwable { + public void testLoopVoid1() throws Throwable { // construct a post-checked loop that only does one iteration and has a void body and void local state MethodHandle loop = MethodHandles.loop(new MethodHandle[]{Empty.MH_f, Empty.MH_f, Empty.MH_pred, null}); assertEquals(MethodType.methodType(void.class), loop.type()); @@ -93,7 +96,7 @@ public class LoopCombinatorTest { } @Test - public static void testLoopVoid2() throws Throwable { + public void testLoopVoid2() throws Throwable { // construct a post-checked loop that only does one iteration and has a void body and void local state, // initialized implicitly from the step type MethodHandle loop = MethodHandles.loop(new MethodHandle[]{null, Empty.MH_f, Empty.MH_pred, null}); @@ -102,7 +105,7 @@ public class LoopCombinatorTest { } @Test - public static void testLoopVoid3() throws Throwable { + public void testLoopVoid3() throws Throwable { // construct a post-checked loop that only does one iteration and has a void body and void local state, // and that has a void finalizer MethodHandle loop = MethodHandles.loop(new MethodHandle[]{null, Empty.MH_f, Empty.MH_pred, Empty.MH_f}); @@ -111,7 +114,7 @@ public class LoopCombinatorTest { } @Test - public static void testLoopFacWithVoidState() throws Throwable { + public void testLoopFacWithVoidState() throws Throwable { // like testLoopFac, but with additional void state that outputs a dot MethodHandle[] counterClause = new MethodHandle[]{Fac.MH_zero, Fac.MH_inc}; MethodHandle[] accumulatorClause = new MethodHandle[]{Fac.MH_one, Fac.MH_mult, Fac.MH_pred, Fac.MH_fin}; @@ -122,7 +125,7 @@ public class LoopCombinatorTest { } @Test - public static void testLoopVoidInt() throws Throwable { + public void testLoopVoidInt() throws Throwable { // construct a post-checked loop that only does one iteration and has a void body and void local state, // and that returns a constant MethodHandle loop = MethodHandles.loop(new MethodHandle[]{null, Empty.MH_f, Empty.MH_pred, Empty.MH_c}); @@ -131,7 +134,7 @@ public class LoopCombinatorTest { } @Test - public static void testLoopWithVirtuals() throws Throwable { + public void testLoopWithVirtuals() throws Throwable { // construct a loop (to calculate factorial) that uses a mix of static and virtual methods MethodHandle[] counterClause = new MethodHandle[]{null, LoopWithVirtuals.permute(LoopWithVirtuals.MH_inc)}; MethodHandle[] accumulatorClause = new MethodHandle[]{ @@ -147,7 +150,7 @@ public class LoopCombinatorTest { } @Test - public static void testLoopOmitPred() throws Throwable { + public void testLoopOmitPred() throws Throwable { // construct a loop to calculate factorial that omits a predicate MethodHandle[] counterClause = new MethodHandle[]{null, Fac.MH_inc, null, Fac.MH_fin}; MethodHandle[] accumulatorClause = new MethodHandle[]{Fac.MH_one, Fac.MH_mult, Fac.MH_pred, Fac.MH_fin}; @@ -156,7 +159,6 @@ public class LoopCombinatorTest { assertEquals(120, loop.invoke(5)); } - @DataProvider static Object[][] negativeTestData() { MethodHandle i0 = MethodHandles.constant(int.class, 0); MethodHandle ii = MethodHandles.dropArguments(i0, 0, int.class, int.class); @@ -214,36 +216,36 @@ public class LoopCombinatorTest { } } - @Test(dataProvider = "negativeTestData") - public static void testLoopNegative(MethodHandle[][] clauses, String expectedMessage) throws Throwable { - boolean caught = false; - try { - MH_loop.invokeWithArguments((Object[]) clauses); - } catch (IllegalArgumentException iae) { - assertEquals(expectedMessage, iae.getMessage()); - caught = true; - } - assertTrue(caught); + @ParameterizedTest + @MethodSource("negativeTestData") + public void testLoopNegative(MethodHandle[][] clauses, String expectedMessage) throws Throwable { + var iae = assertThrows(IllegalArgumentException.class, () -> MH_loop.invokeWithArguments((Object[]) clauses)); + assertEquals(expectedMessage, iae.getMessage()); } - @Test(dataProvider = "whileLoopTestData") - public static void testWhileLoop(MethodHandle MH_zero, - MethodHandle MH_pred, - MethodHandle MH_step, - String messageOrNull) throws Throwable { + @ParameterizedTest + @MethodSource("whileLoopPassData") + public void testWhileLoop(MethodHandle MH_zero, + MethodHandle MH_pred, + MethodHandle MH_step) throws Throwable { // int i = 0; while (i < limit) { ++i; } return i; => limit - try { - MethodHandle loop = MethodHandles.whileLoop(MH_zero, MH_pred, MH_step); - assert messageOrNull == null; - if (MH_step.type().equals(While.MH_step.type())) - assertEquals(While.MT_while, loop.type()); - assertEquals(MH_step.type().dropParameterTypes(0, 1), loop.type()); - while (loop.type().parameterCount() > 1) loop = snip(loop); - assertEquals(23, loop.invoke(23)); - } catch (IllegalArgumentException iae) { - assert messageOrNull != null; - assertEqualsFIXME(messageOrNull, iae.getMessage()); - } + MethodHandle loop = MethodHandles.whileLoop(MH_zero, MH_pred, MH_step); + if (MH_step.type().equals(While.MH_step.type())) + assertEquals(While.MT_while, loop.type()); + assertEquals(MH_step.type().dropParameterTypes(0, 1), loop.type()); + while (loop.type().parameterCount() > 1) loop = snip(loop); + assertEquals(23, loop.invoke(23)); + } + + @ParameterizedTest + @MethodSource("whileLoopFailData") + public void testWhileLoopFail(MethodHandle MH_zero, + MethodHandle MH_pred, + MethodHandle MH_step, + String message) throws Throwable { + // int i = 0; while (i < limit) { ++i; } return i; => limit + var iae = assertThrows(IllegalArgumentException.class, () -> MethodHandles.whileLoop(MH_zero, MH_pred, MH_step)); + assertEqualsFIXME(message, iae.getMessage()); } static void assertEqualsFIXME(String expect, String actual) { @@ -253,8 +255,7 @@ public class LoopCombinatorTest { } } - @DataProvider - static Object[][] whileLoopTestData() { + static Object[][] whileLoopPassData() { MethodHandle zeroI = While.MH_zero, zeroX = snip(zeroI), @@ -268,28 +269,44 @@ public class LoopCombinatorTest { ; return new Object[][] { // normal while loop clauses, perhaps with effectively-identical reductions - {zeroI, predII, stepII, null}, - {zeroX, predII, stepII, null}, - {null, predII, stepII, null}, + {zeroI, predII, stepII}, + {zeroX, predII, stepII}, + {null, predII, stepII}, // expanded while loop clauses - {zeroIB, predIIB, stepIIB, null}, - {zeroI, predIIB, stepIIB, null}, - {null, predIIB, stepIIB, null}, - {zeroIB, predII, stepIIB, null}, - {zeroX, predII, stepIIB, null}, - {null, predII, stepIIB, null}, - // short step clauses cause errors - {zeroI, predII, stepIX, "loop predicate must match: (int,int)boolean != (int)boolean"}, - {zeroIB, predIX, stepIX, "loop initializer must match: (int,byte)int != ()int"}, - // bad body type - {zeroI, predII, tweak(stepII, -1, char.class), "body function must match: (int,int)char != (char,int,int)char"}, - {zeroI, predII, tweak(stepII, 0, char.class), "body function must match: (char,int)int != (int,char,int)int"}, - // bad pred type - {zeroI, tweak(predII, -1, char.class), stepII, "loop predicate must match: (int,int)char != (int,int)boolean"}, - {zeroI, tweak(predII, 0, char.class), stepII, "loop predicate must match: (char,int)boolean != (int,int)boolean"}, - // bad init type - {tweak(zeroI, -1, char.class), predII, stepII, "loop initializer must match: (int)char != (int)int"}, - {tweak(zeroI, 0, char.class), predII, stepII, "loop initializer must match: (char)int != (int)int"}, + {zeroIB, predIIB, stepIIB}, + {zeroI, predIIB, stepIIB}, + {null, predIIB, stepIIB}, + {zeroIB, predII, stepIIB}, + {zeroX, predII, stepIIB}, + {null, predII, stepIIB}, + }; + } + + static Object[][] whileLoopFailData() { + MethodHandle + zeroI = While.MH_zero, + zeroX = snip(zeroI), + zeroIB = slap(zeroI, byte.class), + predII = While.MH_pred, + predIX = snip(predII), + predIIB = slap(predII, byte.class), + stepII = While.MH_step, + stepIX = snip(stepII), + stepIIB = slap(stepII, byte.class) + ; + return new Object[][] { + // short step clauses cause errors + {zeroI, predII, stepIX, "loop predicate must match: (int,int)boolean != (int)boolean"}, + {zeroIB, predIX, stepIX, "loop initializer must match: (int,byte)int != ()int"}, + // bad body type + {zeroI, predII, tweak(stepII, -1, char.class), "body function must match: (int,int)char != (char,int,int)char"}, + {zeroI, predII, tweak(stepII, 0, char.class), "body function must match: (char,int)int != (int,char,int)int"}, + // bad pred type + {zeroI, tweak(predII, -1, char.class), stepII, "loop predicate must match: (int,int)char != (int,int)boolean"}, + {zeroI, tweak(predII, 0, char.class), stepII, "loop predicate must match: (char,int)boolean != (int,int)boolean"}, + // bad init type + {tweak(zeroI, -1, char.class), predII, stepII, "loop initializer must match: (int)char != (int)int"}, + {tweak(zeroI, 0, char.class), predII, stepII, "loop initializer must match: (char)int != (int)int"}, }; } @@ -323,53 +340,50 @@ public class LoopCombinatorTest { } @Test - public static void testWhileLoopNoIteration() throws Throwable { + public void testWhileLoopNoIteration() throws Throwable { // a while loop that never executes its body because the predicate evaluates to false immediately MethodHandle loop = MethodHandles.whileLoop(While.MH_initString, While.MH_predString, While.MH_stepString); assertEquals(While.MT_string, loop.type()); assertEquals("a", loop.invoke()); } - @Test(dataProvider = "whileLoopTestData") - public static void testDoWhileLoop(MethodHandle MH_zero, - MethodHandle MH_pred, - MethodHandle MH_step, - String messageOrNull) throws Throwable { + @ParameterizedTest + @MethodSource("whileLoopPassData") + public void testDoWhileLoopPass(MethodHandle MH_zero, + MethodHandle MH_pred, + MethodHandle MH_step) throws Throwable { // int i = 0; do { ++i; } while (i < limit); return i; => limit - try { - MethodHandle loop = MethodHandles.doWhileLoop(MH_zero, MH_step, MH_pred); - assert messageOrNull == null; - if (MH_step.type().equals(While.MH_step.type())) - assertEquals(While.MT_while, loop.type()); - assertEquals(MH_step.type().dropParameterTypes(0, 1), loop.type()); - while (loop.type().parameterCount() > 1) loop = snip(loop); - assertEquals(23, loop.invoke(23)); - } catch (IllegalArgumentException iae) { - assert messageOrNull != null; - if (!messageOrNull.equals(iae.getMessage())) { - // just issue a warning - System.out.println("*** "+messageOrNull+"\n != "+iae.getMessage()); - } - } + MethodHandle loop = MethodHandles.doWhileLoop(MH_zero, MH_step, MH_pred); + if (MH_step.type().equals(While.MH_step.type())) + assertEquals(While.MT_while, loop.type()); + assertEquals(MH_step.type().dropParameterTypes(0, 1), loop.type()); + while (loop.type().parameterCount() > 1) loop = snip(loop); + assertEquals(23, loop.invoke(23)); + } + + @ParameterizedTest + @MethodSource("whileLoopFailData") + public void testDoWhileLoopFail(MethodHandle MH_zero, + MethodHandle MH_pred, + MethodHandle MH_step, + String message) throws Throwable { + // int i = 0; do { ++i; } while (i < limit); return i; => limit + var iae = assertThrows(IllegalArgumentException.class, () -> MethodHandles.doWhileLoop(MH_zero, MH_step, MH_pred)); + assertEqualsFIXME(message, iae.getMessage()); } @Test - public static void testDoWhileBadInit() throws Throwable { - boolean caught = false; - try { - While w = new While(); - MethodHandle loop = MethodHandles.doWhileLoop(MethodHandles.empty(methodType(char.class)), - While.MH_voidBody.bindTo(w), - While.MH_voidPred.bindTo(w)); - } catch (IllegalArgumentException iae) { - assertEquals("loop initializer must match: ()char != (int)void", iae.getMessage()); - caught = true; - } - assertTrue(caught); + public void testDoWhileBadInit() throws Throwable { + While w = new While(); + var iae = assertThrows(IllegalArgumentException.class, () -> + MethodHandles.doWhileLoop(MethodHandles.empty(methodType(char.class)), + While.MH_voidBody.bindTo(w), + While.MH_voidPred.bindTo(w))); + assertEquals("loop initializer must match: ()char != (int)void", iae.getMessage()); } @Test - public static void testWhileZip() throws Throwable { + public void testWhileZip() throws Throwable { MethodHandle loop = MethodHandles.doWhileLoop(While.MH_zipInitZip, While.MH_zipStep, While.MH_zipPred); assertEquals(While.MT_zip, loop.type()); List a = Arrays.asList("a", "b", "c", "d"); @@ -379,22 +393,17 @@ public class LoopCombinatorTest { } @Test - public static void testWhileBadInit() throws Throwable { - boolean caught = false; - try { - While w = new While(); - MethodHandle loop = MethodHandles.whileLoop(MethodHandles.empty(methodType(void.class, char.class)), - While.MH_voidPred.bindTo(w), - While.MH_voidBody.bindTo(w)); - } catch (IllegalArgumentException iae) { - assertEquals("loop initializer must match: (char)void != (int)void", iae.getMessage()); - caught = true; - } - assertTrue(caught); + public void testWhileBadInit() throws Throwable { + While w = new While(); + var iae = assertThrows(IllegalArgumentException.class, () -> + MethodHandles.whileLoop(MethodHandles.empty(methodType(void.class, char.class)), + While.MH_voidPred.bindTo(w), + While.MH_voidBody.bindTo(w))); + assertEquals("loop initializer must match: (char)void != (int)void", iae.getMessage()); } @Test - public static void testWhileVoidInit() throws Throwable { + public void testWhileVoidInit() throws Throwable { While w = new While(); int v = 5; MethodHandle loop = MethodHandles.whileLoop(While.MH_voidInit.bindTo(w), While.MH_voidPred.bindTo(w), @@ -405,7 +414,7 @@ public class LoopCombinatorTest { } @Test - public static void testDoWhileVoidInit() throws Throwable { + public void testDoWhileVoidInit() throws Throwable { While w = new While(); int v = 5; MethodHandle loop = MethodHandles.doWhileLoop(While.MH_voidInit.bindTo(w), While.MH_voidBody.bindTo(w), @@ -415,24 +424,25 @@ public class LoopCombinatorTest { assertEquals(v, w.i); } - @DataProvider static Object[][] nullArgs() { MethodHandle c = MethodHandles.constant(int.class, 1); return new Object[][]{{null, c}, {c, null}}; } - @Test(dataProvider = "nullArgs", expectedExceptions = NullPointerException.class) - public static void testWhileNullArgs(MethodHandle pred, MethodHandle body) { - MethodHandles.whileLoop(null, pred, body); + @ParameterizedTest + @MethodSource("nullArgs") + public void testWhileNullArgs(MethodHandle pred, MethodHandle body) { + assertThrows(NullPointerException.class, () -> MethodHandles.whileLoop(null, pred, body)); } - @Test(dataProvider = "nullArgs", expectedExceptions = NullPointerException.class) - public static void testDoWhileNullArgs(MethodHandle body, MethodHandle pred) { - MethodHandles.whileLoop(null, body, pred); + @ParameterizedTest + @MethodSource("nullArgs") + public void testDoWhileNullArgs(MethodHandle body, MethodHandle pred) { + assertThrows(NullPointerException.class, () -> MethodHandles.whileLoop(null, body, pred)); } @Test - public static void testCountedLoop() throws Throwable { + public void testCountedLoop() throws Throwable { // String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s; => a variation on a well known theme MethodHandle fit13 = MethodHandles.dropArguments(MethodHandles.constant(int.class, 13), 0, String.class); MethodHandle loop = MethodHandles.countedLoop(fit13, Counted.MH_start, Counted.MH_step); @@ -441,7 +451,7 @@ public class LoopCombinatorTest { } @Test - public static void testCountedLoopVoidInit() throws Throwable { + public void testCountedLoopVoidInit() throws Throwable { MethodHandle fit5 = MethodHandles.constant(int.class, 5); for (int i = 0; i < 8; i++) { MethodHandle zero = MethodHandles.zero(void.class); @@ -465,7 +475,7 @@ public class LoopCombinatorTest { } @Test - public static void testCountedArrayLoop() throws Throwable { + public void testCountedArrayLoop() throws Throwable { // int[] a = new int[]{0}; for (int i = 0; i < 13; ++i) { ++a[0]; } => a[0] == 13 MethodHandle fit13 = MethodHandles.dropArguments(MethodHandles.constant(int.class, 13), 0, int[].class); MethodHandle loop = MethodHandles.countedLoop(fit13, null, Counted.MH_stepUpdateArray); @@ -476,37 +486,30 @@ public class LoopCombinatorTest { } @Test - public static void testCountedPrintingLoop() throws Throwable { + public void testCountedPrintingLoop() throws Throwable { MethodHandle fit5 = MethodHandles.constant(int.class, 5); MethodHandle loop = MethodHandles.countedLoop(fit5, null, Counted.MH_printHello); assertEquals(Counted.MT_countedPrinting, loop.type()); loop.invoke(); } - @Test(expectedExceptions = NullPointerException.class) - public static void testCountedLoopNullBody() throws Throwable { + @Test + public void testCountedLoopNullBody() throws Throwable { MethodHandle h5 = MethodHandles.constant(int.class, 5); MethodHandle h13 = MethodHandles.constant(int.class, 13); - MethodHandle loop = MethodHandles.countedLoop(h5, h13, null); - assertEquals(methodType(int.class), loop.type()); - assertEquals(13, loop.invoke()); + assertThrows(NullPointerException.class, () -> MethodHandles.countedLoop(h5, h13, null)); } - @Test(expectedExceptions = NullPointerException.class) - public static void testCountedLoopNullIterations() throws Throwable { - MethodHandle loop = MethodHandles.countedLoop(null, null, null); - assertEquals(methodType(void.class), loop.type()); - loop.invoke(); + @Test + public void testCountedLoopNullIterations() throws Throwable { + assertThrows(NullPointerException.class, () -> MethodHandles.countedLoop(null, null, null)); } - @Test(expectedExceptions = NullPointerException.class) - public static void testCountedLoopNullInitAndBody() throws Throwable { - MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, 5), null, null); - assertEquals(methodType(void.class), loop.type()); - loop.invoke(); + @Test + public void testCountedLoopNullInitAndBody() throws Throwable { + assertThrows(NullPointerException.class, () -> MethodHandles.countedLoop(MethodHandles.constant(int.class, 5), null, null)); } - @DataProvider static Object[][] countedLoopBodyParameters() { Class V = String.class, I = int.class, A = List.class; // return types are of these forms: @@ -531,8 +534,9 @@ public class LoopCombinatorTest { }; } - @Test(dataProvider = "countedLoopBodyParameters") - public static void testCountedLoopBodyParameters(MethodType countType, MethodType initType, MethodType bodyType) throws Throwable { + @ParameterizedTest + @MethodSource("countedLoopBodyParameters") + public void testCountedLoopBodyParameters(MethodType countType, MethodType initType, MethodType bodyType) throws Throwable { MethodHandle loop = MethodHandles.countedLoop( MethodHandles.empty(countType), initType == null ? null : MethodHandles.empty(initType), @@ -546,13 +550,14 @@ public class LoopCombinatorTest { assertEquals(expectType, loop.type()); } - @Test(dataProvider = "countedLoopBodyParameters") - public static void testCountedLoopBodyParametersNullInit(MethodType countType, MethodType initType, MethodType bodyType) throws Throwable { + @ParameterizedTest + @MethodSource("countedLoopBodyParameters") + public void testCountedLoopBodyParametersNullInit(MethodType countType, MethodType initType, MethodType bodyType) throws Throwable { testCountedLoopBodyParameters(countType, null, bodyType); } @Test - public static void testCountedLoopStateInitializedToNull() throws Throwable { + public void testCountedLoopStateInitializedToNull() throws Throwable { MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, 5), MethodHandles.empty(methodType(String.class)), Counted.MH_stateBody); assertEquals(Counted.MT_bodyDeterminesState, loop.type()); @@ -560,7 +565,7 @@ public class LoopCombinatorTest { } @Test - public static void testCountedLoopArgsDefinedByIterations() throws Throwable { + public void testCountedLoopArgsDefinedByIterations() throws Throwable { MethodHandle iterations = MethodHandles.dropArguments(MethodHandles.constant(int.class, 3), 0, String.class); MethodHandle loop = MethodHandles.countedLoop(iterations, @@ -570,7 +575,7 @@ public class LoopCombinatorTest { } @Test - public static void testCountedRangeLoop() throws Throwable { + public void testCountedRangeLoop() throws Throwable { // String s = "Lambdaman!"; for (int i = -5; i < 8; ++i) { s = "na " + s; } return s; => a well known theme MethodHandle fitm5 = MethodHandles.dropArguments(Counted.MH_m5, 0, String.class); MethodHandle fit8 = MethodHandles.dropArguments(Counted.MH_8, 0, String.class); @@ -580,7 +585,7 @@ public class LoopCombinatorTest { } @Test - public static void testCountedLoopCounterInit() throws Throwable { + public void testCountedLoopCounterInit() throws Throwable { // int x = 0; for (int i = 0; i < 5; ++i) { x += i; } return x; => 10 // (only if counter's first value in body is 0) MethodHandle iter = MethodHandles.constant(int.class, 5); @@ -592,7 +597,7 @@ public class LoopCombinatorTest { } @Test - public static void testCountedLoopEmpty() throws Throwable { + public void testCountedLoopEmpty() throws Throwable { // for (int i = 0; i < 5; ++i) { /* empty */ } MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, 5), null, MethodHandles.empty(methodType(void.class, int.class))); @@ -601,7 +606,7 @@ public class LoopCombinatorTest { } @Test - public static void testCountedRangeLoopEmpty() throws Throwable { + public void testCountedRangeLoopEmpty() throws Throwable { // for (int i = -5; i < 5; ++i) { /* empty */ } MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, -5), MethodHandles.constant(int.class, 5), null, MethodHandles.empty(methodType(void.class, int.class))); @@ -609,7 +614,6 @@ public class LoopCombinatorTest { loop.invoke(); } - @DataProvider static Object[][] countedLoopNegativeData() { MethodHandle dummy = MethodHandles.zero(void.class); MethodHandle one = MethodHandles.constant(int.class, 1); @@ -629,35 +633,30 @@ public class LoopCombinatorTest { }; } - @Test(dataProvider = "countedLoopNegativeData") - public static void testCountedLoopNegative(MethodHandle start, MethodHandle end, MethodHandle init, + @ParameterizedTest + @MethodSource("countedLoopNegativeData") + @Disabled //%%%FIXME%%%% + public void testCountedLoopNegative(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body, String msg) { - if (true) return; //%%%FIXME%%%% - boolean caught = false; - try { - MethodHandles.countedLoop(start, end, init, body); - } catch (IllegalArgumentException iae) { - assertEquals(msg, iae.getMessage()); - caught = true; - } - assertTrue(caught); + var iae = assertThrows(IllegalArgumentException.class, () -> MethodHandles.countedLoop(start, end, init, body)); + assertEquals(msg, iae.getMessage()); } @Test - public static void testIterateSum() throws Throwable { + public void testIterateSum() throws Throwable { // Integer[] a = new Integer[]{1,2,3,4,5,6}; int sum = 0; for (int e : a) { sum += e; } return sum; => 21 MethodHandle loop = MethodHandles.iteratedLoop(Iterate.MH_sumIterator, Iterate.MH_sumInit, Iterate.MH_sumStep); assertEquals(Iterate.MT_sum, loop.type()); assertEquals(21, loop.invoke(new Integer[]{1, 2, 3, 4, 5, 6})); } - @DataProvider static Object[][] iteratorInits() { return new Object[][]{{Iterate.MH_iteratorFromList}, {Iterate.MH_iteratorFromIterable}, {null}}; } - @Test(dataProvider = "iteratorInits") - public static void testIterateReverse(MethodHandle iterator) throws Throwable { + @ParameterizedTest + @MethodSource("iteratorInits") + public void testIterateReverse(MethodHandle iterator) throws Throwable { // this test uses List as its loop state type; don't try to change that if (iterator != null) iterator = iterator.asType(iterator.type().changeParameterType(0, List.class)); @@ -685,8 +684,9 @@ public class LoopCombinatorTest { } } - @Test(dataProvider = "iteratorInits") - public static void testIterateLength(MethodHandle iterator) throws Throwable { + @ParameterizedTest + @MethodSource("iteratorInits") + public void testIterateLength(MethodHandle iterator) throws Throwable { MethodHandle body = Iterate.MH_lengthStep; MethodHandle init = Iterate.MH_lengthInit; MethodType expectedType = Iterate.MT_length; @@ -708,8 +708,9 @@ public class LoopCombinatorTest { } } - @Test(dataProvider = "iteratorInits") - public static void testIterateMap(MethodHandle iterator) throws Throwable { + @ParameterizedTest + @MethodSource("iteratorInits") + public void testIterateMap(MethodHandle iterator) throws Throwable { MethodHandle body = Iterate.MH_mapStep; MethodHandle init = Iterate.MH_mapInit; MethodType expectedType = Iterate.MT_map; @@ -731,8 +732,9 @@ public class LoopCombinatorTest { } } - @Test(dataProvider = "iteratorInits") - public static void testIteratePrint(MethodHandle iterator) throws Throwable { + @ParameterizedTest + @MethodSource("iteratorInits") + public void testIteratePrint(MethodHandle iterator) throws Throwable { MethodHandle body = Iterate.MH_printStep; MethodType expectedType = Iterate.MT_print; int barity = body.type().parameterCount(); @@ -747,32 +749,28 @@ public class LoopCombinatorTest { loop.invoke(Arrays.asList("hello", "world")); } - @Test(expectedExceptions = NullPointerException.class) - public static void testIterateNullBody() { - MethodHandles.iteratedLoop(MethodHandles.empty(methodType(Iterator.class, int.class)), - MethodHandles.identity(int.class), null); + @Test + public void testIterateNullBody() { + assertThrows(NullPointerException.class, () -> + MethodHandles.iteratedLoop(MethodHandles.empty(methodType(Iterator.class, int.class)), + MethodHandles.identity(int.class), null)); } - @DataProvider static Object[][] wrongIteratorTypes() { return new Object[][]{{void.class}, {Object.class}, {Iterable.class}}; } - @Test(dataProvider = "wrongIteratorTypes") - public static void testIterateVoidIterator(Class it) { - boolean caught = false; + @ParameterizedTest + @MethodSource("wrongIteratorTypes") + public void testIterateVoidIterator(Class it) { MethodType v = methodType(it); - try { - MethodHandles.iteratedLoop(MethodHandles.empty(v), null, MethodHandles.empty(v)); - } catch(IllegalArgumentException iae) { - assertEqualsFIXME("iteratedLoop first argument must have Iterator return type", iae.getMessage()); - caught = true; - } - assertTrue(caught); + var iae = assertThrows(IllegalArgumentException.class, () -> MethodHandles.iteratedLoop(MethodHandles.empty(v), null, MethodHandles.empty(v))); + assertEqualsFIXME("iteratedLoop first argument must have Iterator return type", iae.getMessage()); } - @Test(dataProvider = "iteratorInits") - public static void testIterateVoidInit(MethodHandle iterator) throws Throwable { + @ParameterizedTest + @MethodSource("iteratorInits") + public void testIterateVoidInit(MethodHandle iterator) throws Throwable { // this test uses List as its loop state type; don't try to change that if (iterator != null) iterator = iterator.asType(iterator.type().changeParameterType(0, List.class)); @@ -781,7 +779,6 @@ public class LoopCombinatorTest { loop.invoke(Arrays.asList("hello", "world")); } - @DataProvider static Object[][] iterateParameters() { MethodType i = methodType(int.class); MethodType sil_v = methodType(void.class, String.class, int.class, List.class); @@ -811,8 +808,9 @@ public class LoopCombinatorTest { }; } - @Test(dataProvider = "iterateParameters") - public static void testIterateParameters(MethodType it, MethodType in, MethodType bo, String msg) { + @ParameterizedTest + @MethodSource("iterateParameters") + public void testIterateParameters(MethodType it, MethodType in, MethodType bo, String msg) { boolean negative = !msg.isEmpty(); MethodHandle iterator = it == null ? null : MethodHandles.empty(it); MethodHandle init = in == null ? null : MethodHandles.empty(in); @@ -855,7 +853,7 @@ public class LoopCombinatorTest { } @Test - public static void testIteratorSubclass() throws Throwable { + public void testIteratorSubclass() throws Throwable { MethodHandle loop = MethodHandles.iteratedLoop(MethodHandles.empty(methodType(BogusIterator.class, List.class)), null, MethodHandles.empty(methodType(void.class, String.class, List.class))); assertEquals(methodType(void.class, List.class), loop.type()); diff --git a/test/jdk/java/lang/invoke/MethodHandleInvokeUOE.java b/test/jdk/java/lang/invoke/MethodHandleInvokeUOE.java index e728516fe03..510a65acabf 100644 --- a/test/jdk/java/lang/invoke/MethodHandleInvokeUOE.java +++ b/test/jdk/java/lang/invoke/MethodHandleInvokeUOE.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,20 +24,18 @@ /* @test * @summary Test MethodHandle::invokeExact and MethodHandle::invoke throws * UnsupportedOperationException when called via Method::invoke - * @run testng test.java.lang.invoke.MethodHandleInvokeUOE + * @run junit test.java.lang.invoke.MethodHandleInvokeUOE */ package test.java.lang.invoke; -import org.testng.*; -import org.testng.annotations.*; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import static java.lang.invoke.MethodType.*; +import org.junit.jupiter.api.Test; public class MethodHandleInvokeUOE { @Test diff --git a/test/jdk/java/lang/invoke/MethodHandleProxies/Driver.java b/test/jdk/java/lang/invoke/MethodHandleProxies/Driver.java index 0e9c708e8e9..2d99db46c2c 100644 --- a/test/jdk/java/lang/invoke/MethodHandleProxies/Driver.java +++ b/test/jdk/java/lang/invoke/MethodHandleProxies/Driver.java @@ -25,8 +25,8 @@ * @test * @bug 8280377 * @build m1/* m2/* Unnamed - * @run testng/othervm m1/p1.Main - * @run main/othervm Unnamed + * @run junit/othervm m1/p1.Main + * @run junit/othervm Unnamed * @summary Test MethodHandleProxies::asInterfaceInstance with a default * method with varargs */ diff --git a/test/jdk/java/lang/invoke/MethodHandleProxies/Unnamed.java b/test/jdk/java/lang/invoke/MethodHandleProxies/Unnamed.java index f60f36ca9de..8cd9a37cc2f 100644 --- a/test/jdk/java/lang/invoke/MethodHandleProxies/Unnamed.java +++ b/test/jdk/java/lang/invoke/MethodHandleProxies/Unnamed.java @@ -26,13 +26,16 @@ import java.lang.invoke.MethodHandleProxies; import java.lang.invoke.MethodHandles; import java.lang.reflect.Method; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; /* * Test MethodHandleProxies::asInterfaceInstance with an inaccessible interface */ public class Unnamed { - public static void main(String... args) throws Throwable { + @Test + void testInaccessible() throws Throwable { MethodHandle target = MethodHandles.constant(String.class, "test"); Class intf = Class.forName("p2.TestIntf"); Object t = MethodHandleProxies.asInterfaceInstance(intf, target); diff --git a/test/jdk/java/lang/invoke/MethodHandleProxies/m1/module-info.java b/test/jdk/java/lang/invoke/MethodHandleProxies/m1/module-info.java index 1bdeddce28f..5e0174635fb 100644 --- a/test/jdk/java/lang/invoke/MethodHandleProxies/m1/module-info.java +++ b/test/jdk/java/lang/invoke/MethodHandleProxies/m1/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,6 @@ */ module m1 { requires m2; - requires org.testng; + requires org.junit.platform.console.standalone; exports p1; } diff --git a/test/jdk/java/lang/invoke/MethodHandleProxies/m1/p1/Main.java b/test/jdk/java/lang/invoke/MethodHandleProxies/m1/p1/Main.java index df71809996b..1e4ffcb4aac 100644 --- a/test/jdk/java/lang/invoke/MethodHandleProxies/m1/p1/Main.java +++ b/test/jdk/java/lang/invoke/MethodHandleProxies/m1/p1/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,9 +32,8 @@ import java.util.stream.Collectors; import p2.TestIntf; -import org.testng.annotations.Test; - -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class Main { public interface A { @@ -57,24 +56,24 @@ public class Main { * Test the invocation of default methods with varargs */ @Test - public static void testVarargsMethods() throws Throwable { + public void testVarargsMethods() throws Throwable { MethodHandle target = MethodHandles.lookup().findStatic(Main.class, "concat", MethodType.methodType(String.class, Object[].class)); C proxy = MethodHandleProxies.asInterfaceInstance(C.class, target); - assertEquals(proxy.c("a", "b", "c"), "abc"); - assertEquals(proxy.aConcat("a", "b", "c"), "[a, b, c]"); - assertEquals(proxy.aConcat(new Object[] { "a", "b", "c" }), "[a, b, c]"); - assertEquals(proxy.bConcat(new Object[] { "a", "b", "c" }), "[a, b, c]"); + assertEquals("abc", proxy.c("a", "b", "c")); + assertEquals("[a, b, c]", proxy.aConcat("a", "b", "c")); + assertEquals("[a, b, c]", proxy.aConcat(new Object[] { "a", "b", "c" })); + assertEquals("[a, b, c]", proxy.bConcat(new Object[] { "a", "b", "c" })); } /* * Test the invocation of a default method of an accessible interface */ @Test - public static void modulePrivateInterface() { + public void modulePrivateInterface() { MethodHandle target = MethodHandles.constant(String.class, "test"); TestIntf t = MethodHandleProxies.asInterfaceInstance(TestIntf.class, target); - assertEquals(t.test(), "test"); + assertEquals("test", t.test()); } } diff --git a/test/jdk/java/lang/invoke/MethodHandles/TestDropReturn.java b/test/jdk/java/lang/invoke/MethodHandles/TestDropReturn.java index ff31dd63f0b..1b8ef6331b3 100644 --- a/test/jdk/java/lang/invoke/MethodHandles/TestDropReturn.java +++ b/test/jdk/java/lang/invoke/MethodHandles/TestDropReturn.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,33 +24,33 @@ /* * @test * @bug 8255398 - * @run testng TestDropReturn + * @run junit TestDropReturn */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import static java.lang.invoke.MethodType.methodType; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class TestDropReturn { - @Test(dataProvider = "dropReturnCases") + @ParameterizedTest + @MethodSource("dropReturnCases") public void testDropReturn(Class cls, Object testValue) throws Throwable { MethodHandle mh = MethodHandles.identity(cls); - assertEquals(mh.type(), methodType(cls, cls)); + assertEquals(methodType(cls, cls), mh.type()); Object x = mh.invoke(testValue); - assertEquals(x, testValue); + assertEquals(testValue, x); mh = MethodHandles.dropReturn(mh); - assertEquals(mh.type(), methodType(void.class, cls)); + assertEquals(methodType(void.class, cls), mh.type()); mh.invoke(testValue); // should at least work } - @DataProvider public static Object[][] dropReturnCases() { return new Object[][]{ { boolean.class, true }, diff --git a/test/jdk/java/lang/invoke/MethodHandles/TestTableSwitch.java b/test/jdk/java/lang/invoke/MethodHandles/TestTableSwitch.java index 4ff1a99cc28..960d98fb387 100644 --- a/test/jdk/java/lang/invoke/MethodHandles/TestTableSwitch.java +++ b/test/jdk/java/lang/invoke/MethodHandles/TestTableSwitch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,13 +23,9 @@ /* * @test - * @run testng/othervm -Xverify:all TestTableSwitch + * @run junit/othervm -Xverify:all TestTableSwitch */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import javax.management.ObjectName; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -38,7 +34,11 @@ import java.util.List; import java.util.function.IntConsumer; import java.util.function.IntFunction; -import static org.testng.Assert.assertEquals; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.*; public class TestTableSwitch { @@ -111,7 +111,6 @@ public class TestTableSwitch { return args; } - @DataProvider public static Object[][] nonVoidCases() { List tests = new ArrayList<>(); @@ -126,10 +125,11 @@ public class TestTableSwitch { } private static void check(List testValues, Object[] collectedValues) { - assertEquals(collectedValues, testValues.toArray()); + assertArrayEquals(testValues.toArray(), collectedValues); } - @Test(dataProvider = "nonVoidCases") + @ParameterizedTest + @MethodSource("nonVoidCases") public void testNonVoidHandles(Class type, int numCases, List> additionalTypes) throws Throwable { MethodHandle collector = MH_check; List testArguments = new ArrayList<>(); @@ -158,19 +158,19 @@ public class TestTableSwitch { testArguments.add(testValue(additionalType)); } - assertEquals(mhSwitch.invokeWithArguments(testArguments(-1, testArguments)), defaultReturnValue); + assertEquals(defaultReturnValue, mhSwitch.invokeWithArguments(testArguments(-1, testArguments))); for (int i = 0; i < numCases; i++) { - assertEquals(mhSwitch.invokeWithArguments(testArguments(i, testArguments)), returnValues[i]); + assertEquals(returnValues[i], mhSwitch.invokeWithArguments(testArguments(i, testArguments))); } - assertEquals(mhSwitch.invokeWithArguments(testArguments(numCases, testArguments)), defaultReturnValue); + assertEquals(defaultReturnValue, mhSwitch.invokeWithArguments(testArguments(numCases, testArguments))); } @Test public void testVoidHandles() throws Throwable { IntFunction makeTestCase = expectedIndex -> { - IntConsumer test = actualIndex -> assertEquals(actualIndex, expectedIndex); + IntConsumer test = actualIndex -> assertEquals(expectedIndex, actualIndex); return MH_IntConsumer_accept.bindTo(test); }; @@ -187,48 +187,48 @@ public class TestTableSwitch { mhSwitch.invokeExact((int) 2); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void testNullDefaultHandle() { - MethodHandles.tableSwitch(null, simpleTestCase("test")); + assertThrows(NullPointerException.class, () -> MethodHandles.tableSwitch(null, simpleTestCase("test"))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void testNullCases() { MethodHandle[] cases = null; - MethodHandles.tableSwitch(simpleTestCase("default"), cases); + assertThrows(NullPointerException.class, () -> + MethodHandles.tableSwitch(simpleTestCase("default"), cases)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void testNullCase() { - MethodHandles.tableSwitch(simpleTestCase("default"), simpleTestCase("case"), null); + assertThrows(NullPointerException.class, () -> MethodHandles.tableSwitch(simpleTestCase("default"), simpleTestCase("case"), null)); } - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*Not enough cases.*") + @Test public void testNotEnoughCases() { - MethodHandles.tableSwitch(simpleTestCase("default")); + assertThrows(IllegalArgumentException.class, () -> MethodHandles.tableSwitch(simpleTestCase("default"))); } - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*Case actions must have int as leading parameter.*") + @Test public void testNotEnoughParameters() { MethodHandle empty = MethodHandles.empty(MethodType.methodType(void.class)); - MethodHandles.tableSwitch(empty, empty, empty); + assertThrows(IllegalArgumentException.class, () -> + MethodHandles.tableSwitch(empty, empty, empty)); } - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*Case actions must have int as leading parameter.*") + @Test public void testNoLeadingIntParameter() { MethodHandle empty = MethodHandles.empty(MethodType.methodType(void.class, double.class)); - MethodHandles.tableSwitch(empty, empty, empty); + assertThrows(IllegalArgumentException.class, () -> + MethodHandles.tableSwitch(empty, empty, empty)); } - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*Case actions must have the same type.*") + @Test public void testWrongCaseType() { // doesn't return a String MethodHandle wrongType = MethodHandles.empty(MethodType.methodType(void.class, int.class)); - MethodHandles.tableSwitch(simpleTestCase("default"), simpleTestCase("case"), wrongType); + assertThrows(IllegalArgumentException.class, () -> + MethodHandles.tableSwitch(simpleTestCase("default"), simpleTestCase("case"), wrongType)); } } diff --git a/test/jdk/java/lang/invoke/MethodHandles/classData/ClassDataTest.java b/test/jdk/java/lang/invoke/MethodHandles/classData/ClassDataTest.java index 5880761f925..f96a6f23162 100644 --- a/test/jdk/java/lang/invoke/MethodHandles/classData/ClassDataTest.java +++ b/test/jdk/java/lang/invoke/MethodHandles/classData/ClassDataTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 8230501 * @library /test/lib - * @run testng/othervm ClassDataTest + * @run junit/othervm ClassDataTest */ import java.io.IOException; @@ -54,13 +54,14 @@ import java.util.Map; import java.util.function.Consumer; import java.util.stream.Stream; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.classfile.ClassFile.*; import static java.lang.constant.ConstantDescs.*; import static java.lang.invoke.MethodHandles.Lookup.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class ClassDataTest { private static final Lookup LOOKUP = MethodHandles.lookup(); @@ -72,10 +73,10 @@ public class ClassDataTest { assertTrue(lookup.hasFullPrivilegeAccess()); int value = MethodHandles.classData(lookup, "_", int.class); - assertEquals(value, 20); + assertEquals(20, value); Integer i = MethodHandles.classData(lookup, "_", Integer.class); - assertEquals(i.intValue(), 20); + assertEquals(20, i.intValue()); } /* @@ -86,8 +87,7 @@ public class ClassDataTest { assertNull(MethodHandles.classData(LOOKUP, "_", Object.class)); } - @DataProvider(name = "teleportedLookup") - private Object[][] teleportedLookup() throws ReflectiveOperationException { + private static Object[][] teleportedLookup() throws ReflectiveOperationException { Lookup lookup = hiddenClass(30); Class hc = lookup.lookupClass(); assertClassData(lookup, 30); @@ -100,32 +100,33 @@ public class ClassDataTest { }; } - @Test(dataProvider = "teleportedLookup", expectedExceptions = { IllegalAccessException.class }) + @ParameterizedTest + @MethodSource("teleportedLookup") public void illegalAccess(Lookup lookup, int access) throws IllegalAccessException { int lookupModes = lookup.lookupModes(); - assertTrue((lookupModes & ORIGINAL) == 0); - assertEquals(lookupModes, access); - MethodHandles.classData(lookup, "_", int.class); + assertEquals(0, lookupModes & ORIGINAL); + assertEquals(access, lookupModes); + assertThrows(IllegalAccessException.class, () -> MethodHandles.classData(lookup, "_", int.class)); } - @Test(expectedExceptions = { ClassCastException.class }) + @Test public void incorrectType() throws IllegalAccessException { Lookup lookup = hiddenClass(20); - MethodHandles.classData(lookup, "_", Long.class); + assertThrows(ClassCastException.class, () -> MethodHandles.classData(lookup, "_", Long.class)); } - @Test(expectedExceptions = { IndexOutOfBoundsException.class }) + @Test public void invalidIndex() throws IllegalAccessException { Lookup lookup = hiddenClass(List.of()); - MethodHandles.classDataAt(lookup, "_", Object.class, 0); + assertThrows(IndexOutOfBoundsException.class, () -> MethodHandles.classDataAt(lookup, "_", Object.class, 0)); } - @Test(expectedExceptions = { NullPointerException.class }) + @Test public void unboxNull() throws IllegalAccessException { List list = new ArrayList<>(); list.add(null); Lookup lookup = hiddenClass(list); - MethodHandles.classDataAt(lookup, "_", int.class, 0); + assertThrows(NullPointerException.class, () -> MethodHandles.classDataAt(lookup, "_", int.class, 0)); } @Test @@ -133,7 +134,7 @@ public class ClassDataTest { List list = new ArrayList<>(); list.add(null); Lookup lookup = hiddenClass(list); - assertTrue(MethodHandles.classDataAt(lookup, "_", Object.class, 0) == null); + assertNull(MethodHandles.classDataAt(lookup, "_", Object.class, 0)); } @Test @@ -142,7 +143,7 @@ public class ClassDataTest { byte[] bytes = builder.classData(ACC_PUBLIC|ACC_STATIC, int.class).build(); Lookup lookup = LOOKUP.defineHiddenClassWithClassData(bytes, 100, true); int value = MethodHandles.classData(lookup, "_", int.class); - assertEquals(value, 100); + assertEquals(100, value); // call through condy assertClassData(lookup, 100); } @@ -153,7 +154,7 @@ public class ClassDataTest { byte[] bytes = builder.classData(ACC_PUBLIC|ACC_STATIC, float.class).build(); Lookup lookup = LOOKUP.defineHiddenClassWithClassData(bytes, 0.1234f, true); float value = MethodHandles.classData(lookup, "_", float.class); - assertEquals(value, 0.1234f); + assertEquals(0.1234f, value); // call through condy assertClassData(lookup, 0.1234f); } @@ -165,7 +166,7 @@ public class ClassDataTest { byte[] bytes = builder.classData(ACC_PUBLIC|ACC_STATIC, Class.class).build(); Lookup lookup = LOOKUP.defineHiddenClassWithClassData(bytes, hc, true); Class value = MethodHandles.classData(lookup, "_", Class.class); - assertEquals(value, hc); + assertEquals(hc, value); // call through condy assertClassData(lookup, hc); } @@ -181,7 +182,7 @@ public class ClassDataTest { colors[0] = "black"; // it will get back the modified class data String[] value = MethodHandles.classData(lookup, "_", String[].class); - assertEquals(value, colors); + assertArrayEquals(colors, value); // even call through condy as it's not a constant assertClassData(lookup, colors); } @@ -194,7 +195,7 @@ public class ClassDataTest { int expected = 102; // element at index=2 Lookup lookup = LOOKUP.defineHiddenClassWithClassData(bytes, cd, true); int value = MethodHandles.classDataAt(lookup, "_", int.class, 2); - assertEquals(value, expected); + assertEquals(expected, value); // call through condy assertClassData(lookup, expected); } @@ -208,7 +209,7 @@ public class ClassDataTest { int expected = 101; // element at index=1 Lookup lookup = LOOKUP.defineHiddenClassWithClassData(bytes, cd, true); int value = MethodHandles.classDataAt(lookup, "_", int.class, 1); - assertEquals(value, expected); + assertEquals(expected, value); // call through condy assertClassData(lookup, expected); } @@ -216,20 +217,12 @@ public class ClassDataTest { private static Lookup hiddenClass(int value) { ClassByteBuilder builder = new ClassByteBuilder("HC"); byte[] bytes = builder.classData(ACC_PUBLIC|ACC_STATIC, int.class).build(); - try { - return LOOKUP.defineHiddenClassWithClassData(bytes, value, true); - } catch (Throwable e) { - throw new RuntimeException(e); - } + return assertDoesNotThrow(() -> LOOKUP.defineHiddenClassWithClassData(bytes, value, true)); } private static Lookup hiddenClass(List list) { ClassByteBuilder builder = new ClassByteBuilder("HC"); byte[] bytes = builder.classData(ACC_PUBLIC|ACC_STATIC, List.class).build(); - try { - return LOOKUP.defineHiddenClassWithClassData(bytes, list, true); - } catch (Throwable e) { - throw new RuntimeException(e); - } + return assertDoesNotThrow(() -> LOOKUP.defineHiddenClassWithClassData(bytes, list, true)); } @Test @@ -242,7 +235,7 @@ public class ClassDataTest { Class hc = hcLookup.lookupClass(); Lookup lookup = LOOKUP.defineHiddenClassWithClassData(bytes, hc, true); Class value = MethodHandles.classData(lookup, "_", Class.class); - assertEquals(value, hc); + assertEquals(hc, value); // call through condy Class c = lookup.lookupClass(); assertClassData(lookup, c.newInstance(), hc); @@ -257,7 +250,7 @@ public class ClassDataTest { int expected = 102; // element at index=2 Lookup lookup = LOOKUP.defineHiddenClassWithClassData(bytes, cd, true); int value = MethodHandles.classDataAt(lookup, "_", int.class, 2); - assertEquals(value, expected); + assertEquals(expected, value); // call through condy Class c = lookup.lookupClass(); assertClassData(lookup, c.newInstance() ,expected); @@ -285,13 +278,13 @@ public class ClassDataTest { Class c = lookup.lookupClass(); assertClassData(lookup, c.newInstance(), mtype); // modify the class data - assertTrue(cd.remove(0) == mtype); + assertSame(mtype, cd.remove(0)); cd.add(0, MethodType.methodType(void.class)); MethodType newMType = cd.get(0); // loading the element using condy returns the original value assertClassData(lookup, c.newInstance(), mtype); // direct invocation of MethodHandles.classDataAt returns the modified value - assertEquals(MethodHandles.classDataAt(lookup, "_", MethodType.class, 0), newMType); + assertEquals(newMType, MethodHandles.classDataAt(lookup, "_", MethodType.class, 0)); } // helper method to extract from a class data map @@ -334,7 +327,7 @@ public class ClassDataTest { assertEquals(mh, v1); } - @Test(expectedExceptions = { IllegalArgumentException.class }) + @Test public void nonDefaultName() throws ReflectiveOperationException { ClassByteBuilder builder = new ClassByteBuilder("nonDefaultName"); byte[] bytes = builder.classData(ACC_PUBLIC|ACC_STATIC, Class.class) @@ -342,7 +335,7 @@ public class ClassDataTest { Lookup lookup = LOOKUP.defineHiddenClassWithClassData(bytes, ClassDataTest.class, true); assertClassData(lookup, ClassDataTest.class); // throw IAE - MethodHandles.classData(lookup, "non_default_name", Class.class); + assertThrows(IllegalArgumentException.class, () -> MethodHandles.classData(lookup, "non_default_name", Class.class)); } static class ClassByteBuilder { @@ -428,7 +421,7 @@ public class ClassDataTest { * Load an int constant from class data via condy and * verify it matches the given value. */ - private void assertClassData(Lookup lookup, int value) throws ReflectiveOperationException { + private static void assertClassData(Lookup lookup, int value) throws ReflectiveOperationException { Class c = lookup.lookupClass(); Method m = c.getMethod("classData"); int v = (int) m.invoke(null); @@ -439,7 +432,7 @@ public class ClassDataTest { * Load an int constant from class data via condy and * verify it matches the given value. */ - private void assertClassData(Lookup lookup, Object o, int value) throws ReflectiveOperationException { + private static void assertClassData(Lookup lookup, Object o, int value) throws ReflectiveOperationException { Class c = lookup.lookupClass(); Method m = c.getMethod("classData"); int v = (int) m.invoke(o); @@ -450,7 +443,7 @@ public class ClassDataTest { * Load a float constant from class data via condy and * verify it matches the given value. */ - private void assertClassData(Lookup lookup, float value) throws ReflectiveOperationException { + private static void assertClassData(Lookup lookup, float value) throws ReflectiveOperationException { Class c = lookup.lookupClass(); Method m = c.getMethod("classData"); float v = (float) m.invoke(null); @@ -461,7 +454,7 @@ public class ClassDataTest { * Load a Class constant from class data via condy and * verify it matches the given value. */ - private void assertClassData(Lookup lookup, Class value) throws ReflectiveOperationException { + private static void assertClassData(Lookup lookup, Class value) throws ReflectiveOperationException { Class c = lookup.lookupClass(); Method m = c.getMethod("classData"); Class v = (Class)m.invoke(null); @@ -472,7 +465,7 @@ public class ClassDataTest { * Load a Class from class data via condy and * verify it matches the given value. */ - private void assertClassData(Lookup lookup, Object o, Class value) throws ReflectiveOperationException { + private static void assertClassData(Lookup lookup, Object o, Class value) throws ReflectiveOperationException { Class c = lookup.lookupClass(); Method m = c.getMethod("classData"); Object v = m.invoke(o); @@ -483,18 +476,29 @@ public class ClassDataTest { * Load an Object from class data via condy and * verify it matches the given value. */ - private void assertClassData(Lookup lookup, Object value) throws ReflectiveOperationException { + private static void assertClassData(Lookup lookup, Object value) throws ReflectiveOperationException { Class c = lookup.lookupClass(); Method m = c.getMethod("classData"); Object v = m.invoke(null); assertEquals(value, v); } + /* + * Load an Object array from class data via condy and + * verify it matches the given value in content. + */ + private static void assertClassData(Lookup lookup, Object[] value) throws ReflectiveOperationException { + Class c = lookup.lookupClass(); + Method m = c.getMethod("classData"); + Object v = m.invoke(null); + assertArrayEquals(value, (Object[]) v); + } + /* * Load an Object from class data via condy and * verify it matches the given value. */ - private void assertClassData(Lookup lookup, Object o, Object value) throws ReflectiveOperationException { + private static void assertClassData(Lookup lookup, Object o, Object value) throws ReflectiveOperationException { Class c = lookup.lookupClass(); Method m = c.getMethod("classData"); Object v = m.invoke(o); diff --git a/test/jdk/java/lang/invoke/MethodHandles/ensureInitialized/Main.java b/test/jdk/java/lang/invoke/MethodHandles/ensureInitialized/Main.java index 58146286da1..afb628d31ba 100644 --- a/test/jdk/java/lang/invoke/MethodHandles/ensureInitialized/Main.java +++ b/test/jdk/java/lang/invoke/MethodHandles/ensureInitialized/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,16 +24,15 @@ import java.lang.invoke.MethodHandles; import java.lang.reflect.Method; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; /** * @test * @bug 8235521 * @summary Tests for Lookup::ensureClassInitialized * @build java.base/* m1/* m2/* Main - * @run testng/othervm --add-modules m1 Main + * @run junit/othervm --add-modules m1 Main */ public class Main { @@ -48,20 +47,20 @@ public class Main { } // access denied to package-private java.lang class - @Test(expectedExceptions = { IllegalAccessException.class }) + @Test public void testPackagePrivate() throws Exception { Class c = Class.forName("java.lang.DefaultInit", false, null); assertFalse(Helper.isInitialized(c)); // access denied - MethodHandles.lookup().ensureInitialized(c); + assertThrows(IllegalAccessException.class, () -> MethodHandles.lookup().ensureInitialized(c)); } // access denied to public class in a non-exported package - @Test(expectedExceptions = { IllegalAccessException.class }) + @Test public void testNonExportedPackage() throws Exception { Class c = Class.forName("jdk.internal.misc.VM", false, null); // access denied - MethodHandles.lookup().ensureInitialized(c); + assertThrows(IllegalAccessException.class, () -> MethodHandles.lookup().ensureInitialized(c)); } // invoke p1.Test::test to test module boundary access @@ -72,9 +71,9 @@ public class Main { m.invoke(null); } - @Test(expectedExceptions = { IllegalArgumentException.class }) + @Test public void testArrayType() throws Exception { Class arrayType = PublicInit.class.arrayType(); - MethodHandles.lookup().ensureInitialized(arrayType); + assertThrows(IllegalArgumentException.class, () -> MethodHandles.lookup().ensureInitialized(arrayType)); } } diff --git a/test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java b/test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java index 810351bae3e..bf3f1f40913 100644 --- a/test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java +++ b/test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,6 @@ /** * @test * @build test/* m1/* m2/* m3/* Unnamed - * @run testng/othervm test/p.PrivateLookupInTests + * @run junit/othervm test/p.PrivateLookupInTests * @summary Unit tests for MethodHandles.privateLookupIn */ diff --git a/test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/test/module-info.java b/test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/test/module-info.java index da93c879ef1..f364c761aa3 100644 --- a/test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/test/module-info.java +++ b/test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/test/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,6 @@ */ module test { - requires org.testng; - exports p to org.testng; // TestNG invokes the public methods + requires org.junit.platform.console.standalone; + exports p to org.junit.platform.console.standalone; // JUnit invokes the public methods in PrivateLookupInTests } diff --git a/test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java b/test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java index b17204de013..068d2fb534e 100644 --- a/test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java +++ b/test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -29,15 +29,14 @@ import java.lang.reflect.Modifier; import static java.lang.invoke.MethodHandles.Lookup.*; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; /** * Unit tests for MethodHandles.privateLookupIn */ -@Test public class PrivateLookupInTests { /** * A public and non-public types in the test module but in a different @@ -52,24 +51,25 @@ public class PrivateLookupInTests { * private static final Object obj = ... * } */ - private Class publicType; - private Class nonPublicType; + private static Class publicType; + private static Class nonPublicType; // initialize and sanity check publicType/nonPublicType - @BeforeTest - public void init() throws Exception { + @BeforeAll + public static void init() throws Exception { publicType = Class.forName("p.internal.PublicType"); - assertTrue(this.getClass().getModule() == publicType.getModule()); - assertNotEquals(this.getClass().getPackageName(), publicType.getPackageName()); + assertSame(PrivateLookupInTests.class.getModule(), publicType.getModule()); + assertNotEquals(publicType.getPackageName(), PrivateLookupInTests.class.getPackageName()); assertTrue(Modifier.isPublic(publicType.getModifiers())); nonPublicType = Class.forName("p.internal.NonPublicType"); - assertTrue(this.getClass().getModule() == nonPublicType.getModule()); - assertNotEquals(this.getClass().getPackageName(), nonPublicType.getPackageName()); + assertSame(PrivateLookupInTests.class.getModule(), nonPublicType.getModule()); + assertNotEquals(nonPublicType.getPackageName(), PrivateLookupInTests.class.getPackageName()); assertFalse(Modifier.isPublic(nonPublicType.getModifiers())); } // Invoke MethodHandles.privateLookupIn with a full-power caller + @Test public void testAllAccessCallerSameModule() throws Throwable { Lookup lookup = MethodHandles.privateLookupIn(nonPublicType, MethodHandles.lookup()); assertTrue(lookup.lookupClass() == nonPublicType); @@ -82,29 +82,31 @@ public class PrivateLookupInTests { } // Invoke MethodHandles.privateLookupIn with a reduced-power caller - @Test(expectedExceptions = {IllegalAccessException.class}) + @Test public void testReducedAccessCallerSameModule() throws Throwable { Lookup caller = MethodHandles.lookup().dropLookupMode(PACKAGE); - assertTrue((caller.lookupModes() & PRIVATE) == 0); - assertTrue((caller.lookupModes() & PACKAGE) == 0); - assertTrue((caller.lookupModes() & MODULE) != 0); - assertTrue((caller.lookupModes() & ORIGINAL) == 0); - - Lookup lookup = MethodHandles.privateLookupIn(nonPublicType, caller); + assertEquals(0, caller.lookupModes() & PRIVATE); + assertEquals(0, caller.lookupModes() & PACKAGE); + assertNotEquals(0, caller.lookupModes() & MODULE); + assertEquals(0, caller.lookupModes() & ORIGINAL); + assertThrows(IllegalAccessException.class, () -> + MethodHandles.privateLookupIn(nonPublicType, caller)); } // Invoke MethodHandles.privateLookupIn with the public lookup as caller - @Test(expectedExceptions = {IllegalAccessException.class}) + @Test public void testPublicLookupSameModule() throws Exception { Lookup caller = MethodHandles.publicLookup(); - Lookup lookup = MethodHandles.privateLookupIn(publicType, caller); + assertThrows(IllegalAccessException.class, () -> + MethodHandles.privateLookupIn(publicType, caller)); } // test reads m1, open module m1 containing p1 + @Test public void testTargetClassInOpenModule() throws Throwable { // m1/p1.Type Class clazz = Class.forName("p1.Type"); - assertEquals(clazz.getModule().getName(), "m1"); + assertEquals("m1", clazz.getModule().getName()); // ensure that this module reads m1 Module thisModule = getClass().getModule(); @@ -113,9 +115,9 @@ public class PrivateLookupInTests { assertTrue(m1.isOpen("p1", thisModule)); Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); - assertTrue(lookup.lookupClass() == clazz); - assertTrue((lookup.lookupModes() & PRIVATE) == PRIVATE); - assertTrue((lookup.lookupModes() & MODULE) == 0); + assertSame(clazz, lookup.lookupClass()); + assertEquals(PRIVATE, lookup.lookupModes() & PRIVATE); + assertEquals(0, lookup.lookupModes() & MODULE); // get obj field MethodHandle mh = lookup.findStaticGetter(clazz, "obj", Object.class); @@ -123,6 +125,7 @@ public class PrivateLookupInTests { } // test target class in unnamed module + @Test public void testTargetClassInUnnamedModule() throws Throwable { Class clazz = Class.forName("Unnamed"); assertFalse(clazz.getModule().isNamed()); @@ -130,76 +133,72 @@ public class PrivateLookupInTests { // thisModule does not read the unnamed module Module thisModule = getClass().getModule(); assertFalse(thisModule.canRead(clazz.getModule())); - try { - MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); - assertTrue(false); - } catch (IllegalAccessException expected) { } + var baseLookup = MethodHandles.lookup(); + assertThrows(IllegalAccessException.class, () -> MethodHandles.privateLookupIn(clazz, baseLookup)); // thisModule reads the unnamed module thisModule.addReads(clazz.getModule()); - Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); - assertTrue(lookup.lookupClass() == clazz); - assertTrue((lookup.lookupModes() & PRIVATE) == PRIVATE); - assertTrue((lookup.lookupModes() & MODULE) == 0); + Lookup lookup = MethodHandles.privateLookupIn(clazz, baseLookup); + assertSame(clazz, lookup.lookupClass()); + assertEquals(PRIVATE, (lookup.lookupModes() & PRIVATE)); + assertEquals(0, (lookup.lookupModes() & MODULE)); } // test does not read m2, m2 opens p2 to test - @Test(expectedExceptions = {IllegalAccessException.class}) + @Test public void testCallerDoesNotRead() throws Throwable { // m2/p2.Type Class clazz = Class.forName("p2.Type"); - assertEquals(clazz.getModule().getName(), "m2"); - + assertEquals("m2", clazz.getModule().getName()); Module thisModule = getClass().getModule(); Module m2 = clazz.getModule(); assertFalse(thisModule.canRead(m2)); assertTrue(m2.isOpen("p2", thisModule)); - - Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + assertThrows(IllegalAccessException.class, () -> + MethodHandles.privateLookupIn(clazz, MethodHandles.lookup())); } // test reads m3, m3 does not open p3 to test - @Test(expectedExceptions = {IllegalAccessException.class}) + @Test public void testNotOpenToCaller() throws Throwable { // m3/p2.Type Class clazz = Class.forName("p3.Type"); - assertEquals(clazz.getModule().getName(), "m3"); - + assertEquals("m3", clazz.getModule().getName()); Module thisModule = getClass().getModule(); Module m3 = clazz.getModule(); thisModule.addReads(clazz.getModule()); assertFalse(m3.isOpen("p3", thisModule)); - - Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + assertThrows(IllegalAccessException.class, () -> + MethodHandles.privateLookupIn(clazz, MethodHandles.lookup())); } // Invoke MethodHandles.privateLookupIn with a primitive class - @Test(expectedExceptions = {IllegalArgumentException.class}) + @Test public void testPrimitiveClassAsTargetClass() throws Exception { - MethodHandles.privateLookupIn(int.class, MethodHandles.lookup()); + assertThrows(IllegalArgumentException.class, () -> MethodHandles.privateLookupIn(int.class, MethodHandles.lookup())); } // Invoke MethodHandles.privateLookupIn with an array class - @Test(expectedExceptions = {IllegalArgumentException.class}) + @Test public void testArrayClassAsTargetClass() throws Exception { - MethodHandles.privateLookupIn(PrivateLookupInTests[].class, MethodHandles.lookup()); + assertThrows(IllegalArgumentException.class, () -> MethodHandles.privateLookupIn(PrivateLookupInTests[].class, MethodHandles.lookup())); } // Invoke MethodHandles.privateLookupIn with a primitive array class - @Test(expectedExceptions = {IllegalArgumentException.class}) + @Test public void testPrimitiveArrayClassAsTargetClass() throws Exception { - MethodHandles.privateLookupIn(int[].class, MethodHandles.lookup()); + assertThrows(IllegalArgumentException.class, () -> MethodHandles.privateLookupIn(int[].class, MethodHandles.lookup())); } // Invoke MethodHandles.privateLookupIn with null - @Test(expectedExceptions = {NullPointerException.class}) + @Test public void testNullTargetClass() throws Exception { - MethodHandles.privateLookupIn(null, MethodHandles.lookup()); + assertThrows(NullPointerException.class, () -> MethodHandles.privateLookupIn(null, MethodHandles.lookup())); } // Invoke MethodHandles.privateLookupIn with null - @Test(expectedExceptions = {NullPointerException.class}) + @Test public void testNullCaller() throws Exception { - MethodHandles.privateLookupIn(getClass(), null); + assertThrows(NullPointerException.class, () -> MethodHandles.privateLookupIn(getClass(), null)); } } diff --git a/test/jdk/java/lang/invoke/MethodHandlesCollectArgsTest.java b/test/jdk/java/lang/invoke/MethodHandlesCollectArgsTest.java index 5fc0083d5fb..20f03454d32 100644 --- a/test/jdk/java/lang/invoke/MethodHandlesCollectArgsTest.java +++ b/test/jdk/java/lang/invoke/MethodHandlesCollectArgsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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,18 +23,17 @@ /* @test * @bug 8259922 - * @run testng/othervm MethodHandlesCollectArgsTest + * @run junit/othervm MethodHandlesCollectArgsTest */ -import org.testng.annotations.Test; -import org.testng.annotations.DataProvider; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import static java.lang.invoke.MethodType.methodType; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class MethodHandlesCollectArgsTest { @@ -43,7 +42,6 @@ public class MethodHandlesCollectArgsTest { private static final MethodHandle FILTER_INT = MethodHandles.empty(methodType(int.class, String.class)); private static final MethodHandle FILTER_VOID = MethodHandles.empty(methodType(void.class, String.class)); - @DataProvider(name = "illegalPos") public static Object[][] illegalPos() { return new Object[][] { {TARGET_II_I, 2, FILTER_INT}, @@ -57,7 +55,6 @@ public class MethodHandlesCollectArgsTest { }; } - @DataProvider(name = "validPos") public static Object[][] validPos() { return new Object[][] { {TARGET_II_I, 0, FILTER_INT, methodType(int.class, String.class, int.class)}, @@ -69,14 +66,16 @@ public class MethodHandlesCollectArgsTest { }; } - @Test(dataProvider="illegalPos", expectedExceptions = {IllegalArgumentException.class}) + @ParameterizedTest + @MethodSource("illegalPos") public void illegalPosition(MethodHandle target, int position, MethodHandle filter) { - MethodHandles.collectArguments(target, position, filter); + assertThrows(IllegalArgumentException.class, () -> MethodHandles.collectArguments(target, position, filter)); } - @Test(dataProvider="validPos") + @ParameterizedTest + @MethodSource("validPos") public void legalPosition(MethodHandle target, int position, MethodHandle filter, MethodType expectedType) { MethodHandle result = MethodHandles.collectArguments(target, position, filter); - assertEquals(result.type(), expectedType); + assertEquals(expectedType, result.type()); } } diff --git a/test/jdk/java/lang/invoke/MethodHandlesGeneralTest.java b/test/jdk/java/lang/invoke/MethodHandlesGeneralTest.java index b60c35fc30b..588227fef15 100644 --- a/test/jdk/java/lang/invoke/MethodHandlesGeneralTest.java +++ b/test/jdk/java/lang/invoke/MethodHandlesGeneralTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -60,6 +60,7 @@ import java.util.Map; import static java.lang.invoke.MethodType.methodType; import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; public class MethodHandlesGeneralTest extends MethodHandlesTest { @@ -398,7 +399,7 @@ public class MethodHandlesGeneralTest extends MethodHandlesTest { Object obj = target.invokeWithArguments(args); if (!(defc == Example.class && params.length < 2)) assertCalled(defc.getSimpleName()+".", args); - assertTrue("instance of "+defc.getName(), defc.isInstance(obj)); + assertInstanceOf(defc, obj); } @Test @@ -971,8 +972,7 @@ public class MethodHandlesGeneralTest extends MethodHandlesTest { arrayToMH = new SubIntExample[length]; else return; // can't make an ArrayStoreException test - assert(arrayType.isInstance(arrayToMH)) - : Arrays.asList(arrayType, arrayToMH.getClass(), testSetter, negTest); + assertInstanceOf(arrayType, arrayToMH, () -> Arrays.asList(testSetter, negTest).toString()); break; } countTest(positive); diff --git a/test/jdk/java/lang/invoke/MethodTypeTest.java b/test/jdk/java/lang/invoke/MethodTypeTest.java index 8ac03d1a7fd..dccc82fa348 100644 --- a/test/jdk/java/lang/invoke/MethodTypeTest.java +++ b/test/jdk/java/lang/invoke/MethodTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @bug 8366028 * @summary unit tests for java.lang.invoke.MethodType * @compile MethodTypeTest.java - * @run testng/othervm test.java.lang.invoke.MethodTypeTest + * @run junit/othervm test.java.lang.invoke.MethodTypeTest */ package test.java.lang.invoke; @@ -35,11 +35,13 @@ import java.lang.invoke.MethodType; import java.lang.reflect.Method; import java.util.*; -import org.testng.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -import static org.testng.Assert.assertThrows; -import static org.testng.AssertJUnit.*; -import org.testng.annotations.*; +import static org.junit.jupiter.api.Assertions.*; /** * @@ -57,7 +59,7 @@ public class MethodTypeTest { private MethodType[] GALLERY; private Method compareTo; - @BeforeMethod + @BeforeEach public void setUp() throws Exception { rtype = void.class; ptypes = new Class[] { int.class, String.class }; @@ -98,7 +100,7 @@ public class MethodTypeTest { }; } - @AfterMethod + @AfterEach public void tearDown() throws Exception { } @@ -107,7 +109,7 @@ public class MethodTypeTest { public void testDistinct() { List gallery2 = new ArrayList<>(); for (MethodType mt : GALLERY) { - assertFalse(mt.toString(), gallery2.contains(mt)); + assertFalse(gallery2.contains(mt), mt.toString()); gallery2.add(mt); } // check self-equality also: @@ -198,9 +200,9 @@ public class MethodTypeTest { for (int i = 0; i < instances.length; i++) { MethodType instance = instances[i]; String result = instance.toMethodDescriptorString(); - assertEquals("#"+i, expResults[i], result); + assertEquals(expResults[i], result, "#"+i); MethodType parsed = MethodType.fromMethodDescriptorString(result, loader); - assertSame("--#"+i, instance, parsed); + assertSame(instance, parsed, "--#"+i); } } private static String concat(Object... parts) { @@ -221,8 +223,7 @@ public class MethodTypeTest { return sb.toString().replace('.', '/'); } - @DataProvider(name = "badMethodDescriptorStrings") - public String[] badMethodDescriptorStrings() { + public static String[] badMethodDescriptorStrings() { return new String[] { "(I)", "(V)V", @@ -239,9 +240,12 @@ public class MethodTypeTest { } // JDK-8366028 - @Test(dataProvider = "badMethodDescriptorStrings", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("badMethodDescriptorStrings") public void testFromMethodDescriptorStringNegatives(String desc) { - MethodType.fromMethodDescriptorString(desc, null); + assertThrows(IllegalArgumentException.class, () -> { + MethodType.fromMethodDescriptorString(desc, null); + }); } @Test @@ -251,7 +255,7 @@ public class MethodTypeTest { boolean[] expResults = {true, false, true, false, true, true, false, true}; for (int i = 0; i < instances.length; i++) { boolean result = instances[i].hasPrimitives(); - assertEquals("#"+i, expResults[i], result); + assertEquals(expResults[i], result, "#"+i); } } @@ -263,7 +267,7 @@ public class MethodTypeTest { for (int i = 0; i < instances.length; i++) { System.out.println(" hasWrappers "+instances[i]); boolean result = instances[i].hasWrappers(); - assertEquals("#"+i, expResults[i], result); + assertEquals(expResults[i], result, "#"+i); } } @@ -274,7 +278,7 @@ public class MethodTypeTest { MethodType[] expResults = {mt_viO, mt_OO2, mt_vv, mt_Ov, mt_iO2, mt_OOi, mt_OO2, mt_iOi}; for (int i = 0; i < instances.length; i++) { MethodType result = instances[i].erase(); - assertSame("#"+i, expResults[i], result); + assertSame(expResults[i], result, "#"+i); } } @@ -285,7 +289,7 @@ public class MethodTypeTest { MethodType[] expResults = {mt_OO2, mt_OO2, mt_Ov, mt_Ov, mt_OO2, mt_OO2, mt_OO2, mt_OO2}; for (int i = 0; i < instances.length; i++) { MethodType result = instances[i].generic(); - assertSame("#"+i, expResults[i], result); + assertSame(expResults[i], result, "#"+i); } } @@ -296,7 +300,7 @@ public class MethodTypeTest { MethodType[] expResults = {mt_VIS, mt_OO2, mt_Vv, mt_Ov, mt_ISI, mt_ISI, mt_ISI, mt_ISI}; for (int i = 0; i < instances.length; i++) { MethodType result = instances[i].wrap(); - assertSame("#"+i, expResults[i], result); + assertSame(expResults[i], result, "#"+i); } } @@ -307,7 +311,7 @@ public class MethodTypeTest { MethodType[] expResults = {mt_viS, mt_OO2, mt_vv, mt_Ov, mt_iSi, mt_iSi, mt_iSi, mt_iSi}; for (int i = 0; i < instances.length; i++) { MethodType result = instances[i].unwrap(); - assertSame("#"+i, expResults[i], result); + assertSame(expResults[i], result, "#"+i); } } @@ -436,7 +440,7 @@ public class MethodTypeTest { MethodType instance = instances[i]; String result = instance.toString(); System.out.println("#"+i+":"+result); - assertEquals("#"+i, expResults[i], result); + assertEquals(expResults[i], result, "#"+i); } } diff --git a/test/jdk/java/lang/invoke/PermuteArgsReturnVoidTest.java b/test/jdk/java/lang/invoke/PermuteArgsReturnVoidTest.java index b01a4aa2a99..6bd604dcd36 100644 --- a/test/jdk/java/lang/invoke/PermuteArgsReturnVoidTest.java +++ b/test/jdk/java/lang/invoke/PermuteArgsReturnVoidTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,21 +24,21 @@ /* @test * @bug 8184119 * @summary test permutation when return value is directly derived from an argument - * @run testng/othervm test.java.lang.invoke.PermuteArgsReturnVoidTest + * @run junit/othervm test.java.lang.invoke.PermuteArgsReturnVoidTest */ package test.java.lang.invoke; -import org.testng.Assert; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import static java.lang.invoke.MethodHandles.dropArguments; import static java.lang.invoke.MethodHandles.identity; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class PermuteArgsReturnVoidTest { @@ -65,8 +65,8 @@ public class PermuteArgsReturnVoidTest { MethodHandle p = MethodHandles.permuteArguments(f, MethodType.methodType(String.class, String.class, int.class, int.class), 0, 2, 1); String s = (String) p.invoke("IN", 0, 0); - Assert.assertEquals(s.getClass(), String.class); - Assert.assertEquals(s, "IN"); + assertEquals(String.class, s.getClass()); + assertEquals("IN", s); } @Test @@ -84,7 +84,7 @@ public class PermuteArgsReturnVoidTest { MethodHandle p = MethodHandles.permuteArguments(f, MethodType.methodType(String.class, String.class, int.class, int.class), 0, 2, 1); String s = (String) p.invoke("IN", 0, 0); - Assert.assertEquals(s.getClass(), String.class); - Assert.assertEquals(s, "IN"); + assertEquals(String.class, s.getClass()); + assertEquals("IN", s); } } diff --git a/test/jdk/java/lang/invoke/PermuteArgsTest.java b/test/jdk/java/lang/invoke/PermuteArgsTest.java index 3586dc9382f..77558714d11 100644 --- a/test/jdk/java/lang/invoke/PermuteArgsTest.java +++ b/test/jdk/java/lang/invoke/PermuteArgsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* @test * @summary unit tests for method handles which permute their arguments * @library /test/lib /java/lang/invoke/common - * @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -ea -esa -DPermuteArgsTest.MAX_ARITY=8 test.java.lang.invoke.PermuteArgsTest + * @run junit/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -ea -esa -DPermuteArgsTest.MAX_ARITY=8 test.java.lang.invoke.PermuteArgsTest */ /* Examples of manual runs: @@ -35,7 +35,6 @@ package test.java.lang.invoke; -import org.testng.annotations.Test; import test.java.lang.invoke.lib.CodeCacheOverflowProcessor; import java.lang.invoke.MethodHandle; @@ -52,6 +51,10 @@ import static java.lang.invoke.MethodHandles.Lookup; import static java.lang.invoke.MethodHandles.lookup; import static java.lang.invoke.MethodHandles.permuteArguments; import static java.lang.invoke.MethodType.methodType; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class PermuteArgsTest { private static final Class CLASS = PermuteArgsTest.class; @@ -259,11 +262,11 @@ public class PermuteArgsTest { reverse(perm, 0, perm.length); } switch (perm.length) { - case 2: assert(testCases - testCases0 == 2); break; - case 3: assert(testCases - testCases0 == 6); break; - case 4: assert(testCases - testCases0 == 24); break; - case 5: assert(testCases - testCases0 == 120); break; - case 6: assert(testCases - testCases0 > 720/3); break; + case 2 -> assertEquals(2, testCases - testCases0); + case 3 -> assertEquals(6, testCases - testCases0); + case 4 -> assertEquals(24, testCases - testCases0); + case 5 -> assertEquals(120, testCases - testCases0); + case 6 -> assertTrue(testCases - testCases0 > 720/3); } } diff --git a/test/jdk/java/lang/invoke/SpreadCollectTest.java b/test/jdk/java/lang/invoke/SpreadCollectTest.java index bcddcd449f8..d58ebab3611 100644 --- a/test/jdk/java/lang/invoke/SpreadCollectTest.java +++ b/test/jdk/java/lang/invoke/SpreadCollectTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* @test * @bug 8139885 * @bug 8143798 - * @run testng/othervm -ea -esa test.java.lang.invoke.SpreadCollectTest + * @run junit/othervm -ea -esa test.java.lang.invoke.SpreadCollectTest */ package test.java.lang.invoke; @@ -39,9 +39,11 @@ import java.util.*; import static java.lang.invoke.MethodType.methodType; -import static org.testng.AssertJUnit.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -import org.testng.annotations.*; +import static org.junit.jupiter.api.Assertions.*; /** * Tests for the new asSpreader/asCollector API added in JEP 274. @@ -51,14 +53,14 @@ public class SpreadCollectTest { static final Lookup LOOKUP = MethodHandles.lookup(); @Test - public static void testAsSpreader() throws Throwable { + public void testAsSpreader() throws Throwable { MethodHandle spreader = SpreadCollect.MH_forSpreading.asSpreader(1, int[].class, 3); assertEquals(SpreadCollect.MT_spreader, spreader.type()); assertEquals("A456B", (String) spreader.invoke("A", new int[]{4, 5, 6}, "B")); } @Test - public static void testAsSpreaderExample() throws Throwable { + public void testAsSpreaderExample() throws Throwable { // test the JavaDoc asSpreader-with-pos example MethodHandle compare = LOOKUP.findStatic(Objects.class, "compare", methodType(int.class, Object.class, Object.class, Comparator.class)); MethodHandle compare2FromArray = compare.asSpreader(0, Object[].class, 2); @@ -66,49 +68,43 @@ public class SpreadCollectTest { Comparator cmp = (a, b) -> a - b; assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 0, 2), cmp) < 0); assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 1, 3), cmp) > 0); - assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 2, 4), cmp) == 0); + assertEquals(0, (int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 2, 4), cmp)); } - @DataProvider static Object[][] asSpreaderIllegalPositions() { return new Object[][]{{-7}, {3}, {19}}; } - @Test(dataProvider = "asSpreaderIllegalPositions") - public static void testAsSpreaderIllegalPos(int p) throws Throwable { - boolean caught = false; - try { - SpreadCollect.MH_forSpreading.asSpreader(p, Object[].class, 3); - } catch (IllegalArgumentException iae) { - assertEquals("bad spread position", iae.getMessage()); - caught = true; - } - assertTrue(caught); - } - - @Test(expectedExceptions = {WrongMethodTypeException.class}) - public static void testAsSpreaderIllegalMethodType() { - MethodHandle h = MethodHandles.dropArguments(MethodHandles.constant(String.class, ""), 0, int.class, int.class); - MethodHandle s = h.asSpreader(String[].class, 1); - } - - @Test(expectedExceptions = {NullPointerException.class}) - public static void testAsSpreaderNullArrayType() { - SpreadCollect.MH_forSpreading.asSpreader(null, 0); - } - - @Test(expectedExceptions = {NullPointerException.class}) - public static void testAsSpreaderNullArrayNonZeroLength() { - SpreadCollect.MH_forSpreading.asSpreader(null, 1); - } - - @Test(expectedExceptions = {IllegalArgumentException.class}) - public static void testAsSpreaderTooManyParams() throws Throwable { - SpreadCollect.MH_forSpreading.asSpreader(1, int[].class, 6); + @ParameterizedTest + @MethodSource("asSpreaderIllegalPositions") + public void testAsSpreaderIllegalPos(int p) throws Throwable { + var iae = assertThrows(IllegalArgumentException.class, () -> SpreadCollect.MH_forSpreading.asSpreader(p, Object[].class, 3)); + assertEquals("bad spread position", iae.getMessage()); } @Test - public static void testAsCollector() throws Throwable { + public void testAsSpreaderIllegalMethodType() { + MethodHandle h = MethodHandles.dropArguments(MethodHandles.constant(String.class, ""), 0, int.class, int.class); + assertThrows(WrongMethodTypeException.class, () -> h.asSpreader(String[].class, 1)); + } + + @Test + public void testAsSpreaderNullArrayType() { + assertThrows(NullPointerException.class, () -> SpreadCollect.MH_forSpreading.asSpreader(null, 0)); + } + + @Test + public void testAsSpreaderNullArrayNonZeroLength() { + assertThrows(NullPointerException.class, () -> SpreadCollect.MH_forSpreading.asSpreader(null, 1)); + } + + @Test + public void testAsSpreaderTooManyParams() throws Throwable { + assertThrows(IllegalArgumentException.class, () -> SpreadCollect.MH_forSpreading.asSpreader(1, int[].class, 6)); + } + + @Test + public void testAsCollector() throws Throwable { MethodHandle collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 1); assertEquals(SpreadCollect.MT_collector1, collector.type()); assertEquals("A4B", (String) collector.invoke("A", 4, "B")); @@ -121,7 +117,7 @@ public class SpreadCollectTest { } @Test - public static void testAsCollectorInvokeWithArguments() throws Throwable { + public void testAsCollectorInvokeWithArguments() throws Throwable { MethodHandle collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 1); assertEquals(SpreadCollect.MT_collector1, collector.type()); assertEquals("A4B", (String) collector.invokeWithArguments("A", 4, "B")); @@ -134,7 +130,7 @@ public class SpreadCollectTest { } @Test - public static void testAsCollectorLeading() throws Throwable { + public void testAsCollectorLeading() throws Throwable { MethodHandle collector = SpreadCollect.MH_forCollectingLeading.asCollector(0, int[].class, 1); assertEquals(SpreadCollect.MT_collectorLeading1, collector.type()); assertEquals("7Q", (String) collector.invoke(7, "Q")); @@ -147,7 +143,7 @@ public class SpreadCollectTest { } @Test - public static void testAsCollectorLeadingInvokeWithArguments() throws Throwable { + public void testAsCollectorLeadingInvokeWithArguments() throws Throwable { MethodHandle collector = SpreadCollect.MH_forCollectingLeading.asCollector(0, int[].class, 1); assertEquals(SpreadCollect.MT_collectorLeading1, collector.type()); assertEquals("7Q", (String) collector.invokeWithArguments(7, "Q")); @@ -160,31 +156,25 @@ public class SpreadCollectTest { } @Test - public static void testAsCollectorNone() throws Throwable { + public void testAsCollectorNone() throws Throwable { MethodHandle collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 0); assertEquals(SpreadCollect.MT_collector0, collector.type()); assertEquals("AB", (String) collector.invoke("A", "B")); } - @DataProvider static Object[][] asCollectorIllegalPositions() { return new Object[][]{{-1}, {17}}; } - @Test(dataProvider = "asCollectorIllegalPositions") - public static void testAsCollectorIllegalPos(int p) { - boolean caught = false; - try { - SpreadCollect.MH_forCollecting.asCollector(p, int[].class, 0); - } catch (IllegalArgumentException iae) { - assertEquals("bad collect position", iae.getMessage()); - caught = true; - } - assertTrue(caught); + @ParameterizedTest + @MethodSource("asCollectorIllegalPositions") + public void testAsCollectorIllegalPos(int p) { + var iae = assertThrows(IllegalArgumentException.class, () -> SpreadCollect.MH_forCollecting.asCollector(p, int[].class, 0)); + assertEquals("bad collect position", iae.getMessage()); } @Test - public static void testAsCollectorExample() throws Throwable { + public void testAsCollectorExample() throws Throwable { // test the JavaDoc asCollector-with-pos example StringWriter swr = new StringWriter(); MethodHandle swWrite = LOOKUP. diff --git a/test/jdk/java/lang/invoke/TestVHInvokerCaching.java b/test/jdk/java/lang/invoke/TestVHInvokerCaching.java index 0a1ae5914ca..e5c7d50daa7 100644 --- a/test/jdk/java/lang/invoke/TestVHInvokerCaching.java +++ b/test/jdk/java/lang/invoke/TestVHInvokerCaching.java @@ -23,12 +23,9 @@ /* @test * @bug 8265079 - * @run testng/othervm -Xverify:all TestVHInvokerCaching + * @run junit/othervm -Xverify:all TestVHInvokerCaching */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; @@ -37,12 +34,16 @@ import java.util.ArrayList; import java.util.List; import static java.lang.invoke.MethodHandles.lookup; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class TestVHInvokerCaching { - @Test(dataProvider = "testHandles") - public static void testVHIInvokerCaching(VarHandle testHandle) throws Throwable { + @ParameterizedTest + @MethodSource("testHandles") + public void testVHIInvokerCaching(VarHandle testHandle) throws Throwable { for (VarHandle.AccessMode mode : VarHandle.AccessMode.values()) { MethodHandle handle1 = MethodHandles.varHandleInvoker(mode, testHandle.accessModeType(mode)); MethodHandle handle2 = MethodHandles.varHandleInvoker(mode, testHandle.accessModeType(mode)); @@ -56,7 +57,6 @@ public class TestVHInvokerCaching { } } - @DataProvider public static Object[][] testHandles() throws NoSuchFieldException, IllegalAccessException { List testHandles = new ArrayList<>(); diff --git a/test/jdk/java/lang/invoke/ThrowExceptionsTest.java b/test/jdk/java/lang/invoke/ThrowExceptionsTest.java index e12bb7040c4..627a056faec 100644 --- a/test/jdk/java/lang/invoke/ThrowExceptionsTest.java +++ b/test/jdk/java/lang/invoke/ThrowExceptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, 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,14 +23,11 @@ /* @test * @summary unit tests for method handles which permute their arguments - * @run testng test.java.lang.invoke.ThrowExceptionsTest + * @run junit test.java.lang.invoke.ThrowExceptionsTest */ package test.java.lang.invoke; -import org.testng.*; -import org.testng.annotations.*; - import java.util.*; import java.lang.reflect.*; @@ -38,6 +35,10 @@ import java.lang.invoke.*; import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + public class ThrowExceptionsTest { private static final Class CLASS = ThrowExceptionsTest.class; private static final Lookup LOOKUP = lookup(); @@ -51,7 +52,7 @@ public class ThrowExceptionsTest { // mostly call testWMTCallee, but sometimes call its void-returning variant MethodHandle mh = testWMTCallee(); MethodHandle mh1 = mh.asType(mh.type().changeReturnType(void.class)); - assert(mh1 != mh); + assertNotSame(mh, mh1); testWMT(mh, mh1, 1000); } @@ -108,7 +109,7 @@ public class ThrowExceptionsTest { MethodHandle[] cell = { null }; // recursion point MethodHandle getCell = insertArguments(arrayElementGetter(cell.getClass()), 0, cell, 0); MethodHandle invokeCell = foldArguments(exactInvoker(cellType), getCell); - assert(invokeCell.type() == cellType); + assertSame(cellType, invokeCell.type()); cell[0] = invokeCell; // make it conformable to any type: invokeCell = dropArguments(invokeCell, 0, Object[].class).asVarargsCollector(Object[].class); @@ -189,7 +190,6 @@ public class ThrowExceptionsTest { try { // FIXME: should not have to retype this n = (int) mh.invokeExact((Object)this, "x"); - assertEquals(n, i - catches); // Using the exact type for this causes endless deopt due to // 'non_cached_result' in SystemDictionary::find_method_handle_invoke. // The problem is that the compiler thread needs to access a cached @@ -198,7 +198,9 @@ public class ThrowExceptionsTest { } catch (Exception ex) { savedEx = ex; catches++; + continue; } + assertEquals(i - catches, n); } //VERBOSE: System.out.println("reps="+reps+" catches="+catches); return savedEx; @@ -220,9 +222,4 @@ public class ThrowExceptionsTest { } return savedEx; } - - private static void assertEquals(Object x, Object y) { - if (x == y || x != null && x.equals(y)) return; - throw new RuntimeException(x+" != "+y); - } } diff --git a/test/jdk/java/lang/invoke/TryFinallyTest.java b/test/jdk/java/lang/invoke/TryFinallyTest.java index 4a3c255201e..ebe276ede93 100644 --- a/test/jdk/java/lang/invoke/TryFinallyTest.java +++ b/test/jdk/java/lang/invoke/TryFinallyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* @test * @bug 8139885 8150824 8150825 8194238 8233920 - * @run testng/othervm -ea -esa -Xverify:all test.java.lang.invoke.TryFinallyTest + * @run junit/othervm -ea -esa -Xverify:all test.java.lang.invoke.TryFinallyTest */ package test.java.lang.invoke; @@ -35,9 +35,12 @@ import java.lang.invoke.MethodType; import static java.lang.invoke.MethodType.methodType; -import static org.testng.AssertJUnit.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -import org.testng.annotations.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * Tests for the tryFinally method handle combinator introduced in JEP 274. @@ -47,13 +50,12 @@ public class TryFinallyTest { static final Lookup LOOKUP = MethodHandles.lookup(); @Test - public static void testTryFinally() throws Throwable { + public void testTryFinally() throws Throwable { MethodHandle hello = MethodHandles.tryFinally(TryFinally.MH_greet, TryFinally.MH_exclaim); assertEquals(TryFinally.MT_hello, hello.type()); assertEquals("Hello, world!", hello.invoke("world")); } - @DataProvider static Object[][] tryFinallyArgs() { return new Object[][] { { boolean.class, true }, @@ -68,8 +70,9 @@ public class TryFinallyTest { }; } - @Test(dataProvider = "tryFinallyArgs") - public static void testTryFinally(Class argType, Object arg) throws Throwable { + @ParameterizedTest + @MethodSource("tryFinallyArgs") + public void testTryFinally(Class argType, Object arg) throws Throwable { MethodHandle identity = MethodHandles.identity(argType); MethodHandle tryFinally = MethodHandles.tryFinally( identity, @@ -78,31 +81,31 @@ public class TryFinallyTest { assertEquals(arg, tryFinally.invoke(arg)); } - @Test(dataProvider = "tryFinallyArgs", expectedExceptions = TryFinally.T1.class) - public static void testTryFinallyException(Class argType, Object arg) throws Throwable { + @ParameterizedTest + @MethodSource("tryFinallyArgs") + public void testTryFinallyException(Class argType, Object arg) throws Throwable { MethodHandle identity = TryFinally.MH_throwingTargetIdentity.asType(methodType(argType, argType)); MethodHandle tryFinally = MethodHandles.tryFinally( identity, MethodHandles.dropArguments(identity, 0, TryFinally.T1.class)); assertEquals(methodType(argType, argType), tryFinally.type()); - tryFinally.invoke(arg); // should throw + assertThrows(TryFinally.T1.class, () -> tryFinally.invoke(arg)); } @Test - public static void testTryFinallyVoid() throws Throwable { + public void testTryFinallyVoid() throws Throwable { MethodHandle tfVoid = MethodHandles.tryFinally(TryFinally.MH_print, TryFinally.MH_printMore); assertEquals(TryFinally.MT_printHello, tfVoid.type()); tfVoid.invoke("world"); } @Test - public static void testTryFinallySublist() throws Throwable { + public void testTryFinallySublist() throws Throwable { MethodHandle helloMore = MethodHandles.tryFinally(TryFinally.MH_greetMore, TryFinally.MH_exclaimMore); assertEquals(TryFinally.MT_moreHello, helloMore.type()); assertEquals("Hello, world and universe (but world first)!", helloMore.invoke("world", "universe")); } - @DataProvider static Object[][] omitTrailingArguments() { MethodHandle c = TryFinally.MH_voidCleanup; return new Object[][]{ @@ -114,13 +117,13 @@ public class TryFinallyTest { }; } - @Test(dataProvider = "omitTrailingArguments") - public static void testTryFinallyOmitTrailingArguments(MethodHandle cleanup) throws Throwable { + @ParameterizedTest + @MethodSource("omitTrailingArguments") + public void testTryFinallyOmitTrailingArguments(MethodHandle cleanup) throws Throwable { MethodHandle tf = MethodHandles.tryFinally(TryFinally.MH_dummyTarget, cleanup); tf.invoke(1, 2L, "a", 23, 42L, "b"); } - @DataProvider static Object[][] negativeTestData() { MethodHandle intid = MethodHandles.identity(int.class); MethodHandle intco = MethodHandles.constant(int.class, 0); @@ -145,29 +148,18 @@ public class TryFinallyTest { }; } - @Test(dataProvider = "negativeTestData") - public static void testTryFinallyNegative(MethodHandle target, MethodHandle cleanup, String expectedMessage) { - boolean caught = false; - try { - MethodHandles.tryFinally(target, cleanup); - } catch (IllegalArgumentException iae) { - assertEquals(expectedMessage, iae.getMessage()); - caught = true; - } - assertTrue(caught); + @ParameterizedTest + @MethodSource("negativeTestData") + public void testTryFinallyNegative(MethodHandle target, MethodHandle cleanup, String expectedMessage) { + var iae = assertThrows(IllegalArgumentException.class, () -> MethodHandles.tryFinally(target, cleanup)); + assertEquals(expectedMessage, iae.getMessage()); } @Test - public static void testTryFinallyThrowableCheck() { + public void testTryFinallyThrowableCheck() { MethodHandle mh = MethodHandles.tryFinally(TryFinally.MH_throwingTarget, TryFinally.MH_catchingCleanup); - try { - mh.invoke(); - fail("ClassCastException expected"); - } catch (Throwable t) { - assertTrue("Throwable not assignable to ClassCastException: " + t, - ClassCastException.class.isAssignableFrom(t.getClass())); - } + assertThrows(ClassCastException.class, mh::invoke); } static class TryFinally { diff --git a/test/jdk/java/lang/invoke/VarArgsTest.java b/test/jdk/java/lang/invoke/VarArgsTest.java index bb17881b514..bcea9a0b54e 100644 --- a/test/jdk/java/lang/invoke/VarArgsTest.java +++ b/test/jdk/java/lang/invoke/VarArgsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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,19 +23,18 @@ /* @test * @summary unit tests for java.lang.invoke.MethodHandles - * @run testng/othervm -ea -esa test.java.lang.invoke.VarArgsTest + * @run junit/othervm -ea -esa test.java.lang.invoke.VarArgsTest */ package test.java.lang.invoke; import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.util.Arrays; import java.util.List; import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; -import static org.testng.AssertJUnit.*; -import org.testng.annotations.*; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; public class VarArgsTest { @@ -61,17 +60,17 @@ public class VarArgsTest { MethodHandle asList = publicLookup() .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class)); MethodHandle asListWithVarargs = asList.withVarargs(asList.isVarargsCollector()); - assert(asListWithVarargs.isVarargsCollector()); + assertTrue(asListWithVarargs.isVarargsCollector()); assertEquals("[]", asListWithVarargs.invoke().toString()); assertEquals("[1]", asListWithVarargs.invoke(1).toString()); assertEquals("[two, too]", asListWithVarargs.invoke("two", "too").toString()); } - @Test(expectedExceptions = { IllegalArgumentException.class }) + @Test public void testWithVarargsIAE() throws Throwable { MethodHandle lenMH = publicLookup() - .findVirtual(String.class, "length", methodType(int.class)); - MethodHandle lenMHWithVarargs = lenMH.withVarargs(true); + .findVirtual(String.class, "length", methodType(int.class)); + assertThrows(IllegalArgumentException.class, () -> lenMH.withVarargs(true)); } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseByteArrayTest.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseByteArrayTest.java index f09ba518e48..c89fcc8289b 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseByteArrayTest.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseByteArrayTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,9 +21,6 @@ * questions. */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; - import java.lang.invoke.VarHandle; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -32,6 +29,7 @@ import java.util.Arrays; import java.util.EnumSet; import java.util.List; import java.util.function.Function; +import org.junit.jupiter.api.BeforeAll; public abstract class VarHandleBaseByteArrayTest extends VarHandleBaseTest { @@ -338,7 +336,7 @@ public abstract class VarHandleBaseByteArrayTest extends VarHandleBaseTest { bavss.add(dbb_offset_unaligned_ro); } - @BeforeClass + @BeforeAll public void setup() { setupByteSources(); vhss = setupVarHandleSources(true); @@ -346,13 +344,10 @@ public abstract class VarHandleBaseByteArrayTest extends VarHandleBaseTest { abstract List setupVarHandleSources(boolean same); - - @DataProvider public Object[][] varHandlesProvider() throws Exception { return vhss.stream().map(cvh -> new Object[]{cvh}).toArray(Object[][]::new); } - @DataProvider public Object[][] typesProvider() throws Exception { List> aepts = Arrays.asList(byte[].class, int.class); List> bbpts = Arrays.asList(ByteBuffer.class, int.class); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseTest.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseTest.java index 0c9a7fd3953..0e029b8f5f7 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseTest.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import java.util.Map; import java.util.stream.Stream; import static java.util.stream.Collectors.toList; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; abstract class VarHandleBaseTest { static final int ITERS = Integer.getInteger("iters", 1); @@ -136,18 +136,7 @@ abstract class VarHandleBaseTest { static void checkWithThrowable(Class re, Object message, ThrowingRunnable r) { - Throwable _e = null; - try { - r.run(); - } - catch (Throwable e) { - _e = e; - } - message = message == null ? "" : message + ". "; - assertNotNull(_e, String.format("%sNo throwable thrown. Expected %s", message, re)); - if (!re.isInstance(_e)) { - fail(String.format("%sIncorrect throwable thrown, %s. Expected %s", message, _e, re), _e); - } + assertThrows(re, r::run, message == null ? null : message.toString()); } @@ -277,11 +266,11 @@ abstract class VarHandleBaseTest { } private static MethodHandle bind(VarHandle vh, MethodHandle mh, MethodType emt) { - assertEquals(mh.type(), emt.insertParameterTypes(0, VarHandle.class), + assertEquals(emt.insertParameterTypes(0, VarHandle.class), mh.type(), "MethodHandle type differs from access mode type"); MethodHandleInfo info = MethodHandles.lookup().revealDirect(mh); - assertEquals(info.getMethodType(), emt, + assertEquals(emt, info.getMethodType(), "MethodHandleInfo method type differs from access mode type"); return mh.bindTo(vh); @@ -472,39 +461,39 @@ abstract class VarHandleBaseTest { for (TestAccessMode accessMode : testAccessModes()) { MethodType amt = vh.accessModeType(accessMode.toAccessMode()); - assertEquals(amt.parameterList().subList(0, pts.size()), pts); + assertEquals(pts, amt.parameterList().subList(0, pts.size())); } for (TestAccessMode testAccessMode : testAccessModesOfType(TestAccessType.GET)) { MethodType mt = vh.accessModeType(testAccessMode.toAccessMode()); - assertEquals(mt.returnType(), vh.varType()); - assertEquals(mt.parameterList(), pts); + assertEquals(vh.varType(), mt.returnType()); + assertEquals(pts, mt.parameterList()); } for (TestAccessMode testAccessMode : testAccessModesOfType(TestAccessType.SET)) { MethodType mt = vh.accessModeType(testAccessMode.toAccessMode()); - assertEquals(mt.returnType(), void.class); - assertEquals(mt.parameterType(mt.parameterCount() - 1), vh.varType()); + assertEquals(void.class, mt.returnType()); + assertEquals(vh.varType(), mt.parameterType(mt.parameterCount() - 1)); } for (TestAccessMode testAccessMode : testAccessModesOfType(TestAccessType.COMPARE_AND_SET)) { MethodType mt = vh.accessModeType(testAccessMode.toAccessMode()); - assertEquals(mt.returnType(), boolean.class); - assertEquals(mt.parameterType(mt.parameterCount() - 1), vh.varType()); - assertEquals(mt.parameterType(mt.parameterCount() - 2), vh.varType()); + assertEquals(boolean.class, mt.returnType()); + assertEquals(vh.varType(), mt.parameterType(mt.parameterCount() - 1)); + assertEquals(vh.varType(), mt.parameterType(mt.parameterCount() - 2)); } for (TestAccessMode testAccessMode : testAccessModesOfType(TestAccessType.COMPARE_AND_EXCHANGE)) { MethodType mt = vh.accessModeType(testAccessMode.toAccessMode()); - assertEquals(mt.returnType(), vh.varType()); - assertEquals(mt.parameterType(mt.parameterCount() - 1), vh.varType()); - assertEquals(mt.parameterType(mt.parameterCount() - 2), vh.varType()); + assertEquals(vh.varType(), mt.returnType()); + assertEquals(vh.varType(), mt.parameterType(mt.parameterCount() - 1)); + assertEquals(vh.varType(), mt.parameterType(mt.parameterCount() - 2)); } for (TestAccessMode testAccessMode : testAccessModesOfType(TestAccessType.GET_AND_SET, TestAccessType.GET_AND_ADD)) { MethodType mt = vh.accessModeType(testAccessMode.toAccessMode()); - assertEquals(mt.returnType(), vh.varType()); - assertEquals(mt.parameterType(mt.parameterCount() - 1), vh.varType()); + assertEquals(vh.varType(), mt.returnType()); + assertEquals(vh.varType(), mt.parameterType(mt.parameterCount() - 1)); } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleMethodReferenceTest.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleMethodReferenceTest.java index 02de5a3e186..23e46096073 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleMethodReferenceTest.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleMethodReferenceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,12 @@ * @test * @bug 8195650 * @summary Test linking of method references to VarHandle access methods. - * @run testng VarHandleMethodReferenceTest + * @run junit VarHandleMethodReferenceTest */ -import org.testng.annotations.Test; import java.lang.invoke.*; +import org.junit.jupiter.api.Test; public class VarHandleMethodReferenceTest { diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java index a9cd5a61655..548e008b09e 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,28 +23,30 @@ /* * @test - * @run testng/othervm -Diters=10 -Xint VarHandleTestAccessBoolean + * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessBoolean * * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds * - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessBoolean - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessBoolean - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessBoolean + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessBoolean + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessBoolean + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessBoolean */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestAccessBoolean extends VarHandleBaseTest { static final boolean static_final_v = true; @@ -108,7 +110,7 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { return vhs.toArray(new VarHandle[0]); } - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestAccessBoolean.class, "final_v", boolean.class); @@ -125,8 +127,6 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(boolean[].class); } - - @DataProvider public Object[][] varHandlesProvider() throws Exception { List vhs = new ArrayList<>(); vhs.add(vhField); @@ -156,7 +156,8 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("varHandlesProvider") public void testIsAccessModeSupported(VarHandle vh) { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET)); @@ -194,8 +195,6 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE)); } - - @DataProvider public Object[][] typesProvider() throws Exception { List types = new ArrayList<>(); types.add(new Object[] {vhField, Arrays.asList(VarHandleTestAccessBoolean.class)}); @@ -205,16 +204,16 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { return types.stream().toArray(Object[][]::new); } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), boolean.class); + assertEquals(boolean.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - @Test public void testLookupInstanceToStatic() { checkIAE("Lookup of static final field to instance final field", () -> { @@ -241,8 +240,6 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { }); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -284,7 +281,8 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -297,26 +295,26 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { // Plain { boolean x = (boolean) vh.get(recv); - assertEquals(x, true, "get boolean value"); + assertEquals(true, x, "get boolean value"); } // Volatile { boolean x = (boolean) vh.getVolatile(recv); - assertEquals(x, true, "getVolatile boolean value"); + assertEquals(true, x, "getVolatile boolean value"); } // Lazy { boolean x = (boolean) vh.getAcquire(recv); - assertEquals(x, true, "getRelease boolean value"); + assertEquals(true, x, "getRelease boolean value"); } // Opaque { boolean x = (boolean) vh.getOpaque(recv); - assertEquals(x, true, "getOpaque boolean value"); + assertEquals(true, x, "getOpaque boolean value"); } } @@ -357,26 +355,26 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { // Plain { boolean x = (boolean) vh.get(); - assertEquals(x, true, "get boolean value"); + assertEquals(true, x, "get boolean value"); } // Volatile { boolean x = (boolean) vh.getVolatile(); - assertEquals(x, true, "getVolatile boolean value"); + assertEquals(true, x, "getVolatile boolean value"); } // Lazy { boolean x = (boolean) vh.getAcquire(); - assertEquals(x, true, "getRelease boolean value"); + assertEquals(true, x, "getRelease boolean value"); } // Opaque { boolean x = (boolean) vh.getOpaque(); - assertEquals(x, true, "getOpaque boolean value"); + assertEquals(true, x, "getOpaque boolean value"); } } @@ -418,7 +416,7 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { { vh.set(recv, true); boolean x = (boolean) vh.get(recv); - assertEquals(x, true, "set boolean value"); + assertEquals(true, x, "set boolean value"); } @@ -426,21 +424,21 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { { vh.setVolatile(recv, false); boolean x = (boolean) vh.getVolatile(recv); - assertEquals(x, false, "setVolatile boolean value"); + assertEquals(false, x, "setVolatile boolean value"); } // Lazy { vh.setRelease(recv, true); boolean x = (boolean) vh.getAcquire(recv); - assertEquals(x, true, "setRelease boolean value"); + assertEquals(true, x, "setRelease boolean value"); } // Opaque { vh.setOpaque(recv, false); boolean x = (boolean) vh.getOpaque(recv); - assertEquals(x, false, "setOpaque boolean value"); + assertEquals(false, x, "setOpaque boolean value"); } vh.set(recv, true); @@ -450,56 +448,56 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { boolean r = vh.compareAndSet(recv, true, false); assertEquals(r, true, "success compareAndSet boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, false, "success compareAndSet boolean value"); + assertEquals(false, x, "success compareAndSet boolean value"); } { boolean r = vh.compareAndSet(recv, true, false); assertEquals(r, false, "failing compareAndSet boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, false, "failing compareAndSet boolean value"); + assertEquals(false, x, "failing compareAndSet boolean value"); } { boolean r = (boolean) vh.compareAndExchange(recv, false, true); assertEquals(r, false, "success compareAndExchange boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, true, "success compareAndExchange boolean value"); + assertEquals(true, x, "success compareAndExchange boolean value"); } { boolean r = (boolean) vh.compareAndExchange(recv, false, false); assertEquals(r, true, "failing compareAndExchange boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, true, "failing compareAndExchange boolean value"); + assertEquals(true, x, "failing compareAndExchange boolean value"); } { boolean r = (boolean) vh.compareAndExchangeAcquire(recv, true, false); assertEquals(r, true, "success compareAndExchangeAcquire boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, false, "success compareAndExchangeAcquire boolean value"); + assertEquals(false, x, "success compareAndExchangeAcquire boolean value"); } { boolean r = (boolean) vh.compareAndExchangeAcquire(recv, true, false); assertEquals(r, false, "failing compareAndExchangeAcquire boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, false, "failing compareAndExchangeAcquire boolean value"); + assertEquals(false, x, "failing compareAndExchangeAcquire boolean value"); } { boolean r = (boolean) vh.compareAndExchangeRelease(recv, false, true); assertEquals(r, false, "success compareAndExchangeRelease boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, true, "success compareAndExchangeRelease boolean value"); + assertEquals(true, x, "success compareAndExchangeRelease boolean value"); } { boolean r = (boolean) vh.compareAndExchangeRelease(recv, false, false); assertEquals(r, true, "failing compareAndExchangeRelease boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, true, "failing compareAndExchangeRelease boolean value"); + assertEquals(true, x, "failing compareAndExchangeRelease boolean value"); } { @@ -510,14 +508,14 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, false, "success weakCompareAndSetPlain boolean value"); + assertEquals(false, x, "success weakCompareAndSetPlain boolean value"); } { boolean success = vh.weakCompareAndSetPlain(recv, true, false); assertEquals(success, false, "failing weakCompareAndSetPlain boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, false, "failing weakCompareAndSetPlain boolean value"); + assertEquals(false, x, "failing weakCompareAndSetPlain boolean value"); } { @@ -528,14 +526,14 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, true, "success weakCompareAndSetAcquire boolean"); + assertEquals(true, x, "success weakCompareAndSetAcquire boolean"); } { boolean success = vh.weakCompareAndSetAcquire(recv, false, false); assertEquals(success, false, "failing weakCompareAndSetAcquire boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, true, "failing weakCompareAndSetAcquire boolean value"); + assertEquals(true, x, "failing weakCompareAndSetAcquire boolean value"); } { @@ -546,14 +544,14 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, false, "success weakCompareAndSetRelease boolean"); + assertEquals(false, x, "success weakCompareAndSetRelease boolean"); } { boolean success = vh.weakCompareAndSetRelease(recv, true, false); assertEquals(success, false, "failing weakCompareAndSetRelease boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, false, "failing weakCompareAndSetRelease boolean value"); + assertEquals(false, x, "failing weakCompareAndSetRelease boolean value"); } { @@ -564,14 +562,14 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, true, "success weakCompareAndSet boolean value"); + assertEquals(true, x, "success weakCompareAndSet boolean value"); } { boolean success = vh.weakCompareAndSet(recv, false, false); assertEquals(success, false, "failing weakCompareAndSet boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, true, "failing weakCompareAndSet boolean value"); + assertEquals(true, x, "failing weakCompareAndSet boolean value"); } // Compare set and get @@ -579,27 +577,27 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { vh.set(recv, true); boolean o = (boolean) vh.getAndSet(recv, false); - assertEquals(o, true, "getAndSet boolean"); + assertEquals(true, o, "getAndSet boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, false, "getAndSet boolean value"); + assertEquals(false, x, "getAndSet boolean value"); } { vh.set(recv, true); boolean o = (boolean) vh.getAndSetAcquire(recv, false); - assertEquals(o, true, "getAndSetAcquire boolean"); + assertEquals(true, o, "getAndSetAcquire boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, false, "getAndSetAcquire boolean value"); + assertEquals(false, x, "getAndSetAcquire boolean value"); } { vh.set(recv, true); boolean o = (boolean) vh.getAndSetRelease(recv, false); - assertEquals(o, true, "getAndSetRelease boolean"); + assertEquals(true, o, "getAndSetRelease boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, false, "getAndSetRelease boolean value"); + assertEquals(false, x, "getAndSetRelease boolean value"); } @@ -608,27 +606,27 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { vh.set(recv, true); boolean o = (boolean) vh.getAndBitwiseOr(recv, false); - assertEquals(o, true, "getAndBitwiseOr boolean"); + assertEquals(true, o, "getAndBitwiseOr boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOr boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOr boolean value"); } { vh.set(recv, true); boolean o = (boolean) vh.getAndBitwiseOrAcquire(recv, false); - assertEquals(o, true, "getAndBitwiseOrAcquire boolean"); + assertEquals(true, o, "getAndBitwiseOrAcquire boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOrAcquire boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOrAcquire boolean value"); } { vh.set(recv, true); boolean o = (boolean) vh.getAndBitwiseOrRelease(recv, false); - assertEquals(o, true, "getAndBitwiseOrRelease boolean"); + assertEquals(true, o, "getAndBitwiseOrRelease boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOrRelease boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOrRelease boolean value"); } // get and bitwise and @@ -636,27 +634,27 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { vh.set(recv, true); boolean o = (boolean) vh.getAndBitwiseAnd(recv, false); - assertEquals(o, true, "getAndBitwiseAnd boolean"); + assertEquals(true, o, "getAndBitwiseAnd boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAnd boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAnd boolean value"); } { vh.set(recv, true); boolean o = (boolean) vh.getAndBitwiseAndAcquire(recv, false); - assertEquals(o, true, "getAndBitwiseAndAcquire boolean"); + assertEquals(true, o, "getAndBitwiseAndAcquire boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAndAcquire boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAndAcquire boolean value"); } { vh.set(recv, true); boolean o = (boolean) vh.getAndBitwiseAndRelease(recv, false); - assertEquals(o, true, "getAndBitwiseAndRelease boolean"); + assertEquals(true, o, "getAndBitwiseAndRelease boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAndRelease boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAndRelease boolean value"); } // get and bitwise xor @@ -664,27 +662,27 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { vh.set(recv, true); boolean o = (boolean) vh.getAndBitwiseXor(recv, false); - assertEquals(o, true, "getAndBitwiseXor boolean"); + assertEquals(true, o, "getAndBitwiseXor boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXor boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXor boolean value"); } { vh.set(recv, true); boolean o = (boolean) vh.getAndBitwiseXorAcquire(recv, false); - assertEquals(o, true, "getAndBitwiseXorAcquire boolean"); + assertEquals(true, o, "getAndBitwiseXorAcquire boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXorAcquire boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXorAcquire boolean value"); } { vh.set(recv, true); boolean o = (boolean) vh.getAndBitwiseXorRelease(recv, false); - assertEquals(o, true, "getAndBitwiseXorRelease boolean"); + assertEquals(true, o, "getAndBitwiseXorRelease boolean"); boolean x = (boolean) vh.get(recv); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXorRelease boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXorRelease boolean value"); } } @@ -710,7 +708,7 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { { vh.set(true); boolean x = (boolean) vh.get(); - assertEquals(x, true, "set boolean value"); + assertEquals(true, x, "set boolean value"); } @@ -718,21 +716,21 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { { vh.setVolatile(false); boolean x = (boolean) vh.getVolatile(); - assertEquals(x, false, "setVolatile boolean value"); + assertEquals(false, x, "setVolatile boolean value"); } // Lazy { vh.setRelease(true); boolean x = (boolean) vh.getAcquire(); - assertEquals(x, true, "setRelease boolean value"); + assertEquals(true, x, "setRelease boolean value"); } // Opaque { vh.setOpaque(false); boolean x = (boolean) vh.getOpaque(); - assertEquals(x, false, "setOpaque boolean value"); + assertEquals(false, x, "setOpaque boolean value"); } vh.set(true); @@ -742,56 +740,56 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { boolean r = vh.compareAndSet(true, false); assertEquals(r, true, "success compareAndSet boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, false, "success compareAndSet boolean value"); + assertEquals(false, x, "success compareAndSet boolean value"); } { boolean r = vh.compareAndSet(true, false); assertEquals(r, false, "failing compareAndSet boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, false, "failing compareAndSet boolean value"); + assertEquals(false, x, "failing compareAndSet boolean value"); } { boolean r = (boolean) vh.compareAndExchange(false, true); assertEquals(r, false, "success compareAndExchange boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, true, "success compareAndExchange boolean value"); + assertEquals(true, x, "success compareAndExchange boolean value"); } { boolean r = (boolean) vh.compareAndExchange(false, false); assertEquals(r, true, "failing compareAndExchange boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, true, "failing compareAndExchange boolean value"); + assertEquals(true, x, "failing compareAndExchange boolean value"); } { boolean r = (boolean) vh.compareAndExchangeAcquire(true, false); assertEquals(r, true, "success compareAndExchangeAcquire boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, false, "success compareAndExchangeAcquire boolean value"); + assertEquals(false, x, "success compareAndExchangeAcquire boolean value"); } { boolean r = (boolean) vh.compareAndExchangeAcquire(true, false); assertEquals(r, false, "failing compareAndExchangeAcquire boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, false, "failing compareAndExchangeAcquire boolean value"); + assertEquals(false, x, "failing compareAndExchangeAcquire boolean value"); } { boolean r = (boolean) vh.compareAndExchangeRelease(false, true); assertEquals(r, false, "success compareAndExchangeRelease boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, true, "success compareAndExchangeRelease boolean value"); + assertEquals(true, x, "success compareAndExchangeRelease boolean value"); } { boolean r = (boolean) vh.compareAndExchangeRelease(false, false); assertEquals(r, true, "failing compareAndExchangeRelease boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, true, "failing compareAndExchangeRelease boolean value"); + assertEquals(true, x, "failing compareAndExchangeRelease boolean value"); } { @@ -802,14 +800,14 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, false, "success weakCompareAndSetPlain boolean value"); + assertEquals(false, x, "success weakCompareAndSetPlain boolean value"); } { boolean success = vh.weakCompareAndSetPlain(true, false); assertEquals(success, false, "failing weakCompareAndSetPlain boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, false, "failing weakCompareAndSetPlain boolean value"); + assertEquals(false, x, "failing weakCompareAndSetPlain boolean value"); } { @@ -820,14 +818,14 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, true, "success weakCompareAndSetAcquire boolean"); + assertEquals(true, x, "success weakCompareAndSetAcquire boolean"); } { boolean success = vh.weakCompareAndSetAcquire(false, false); assertEquals(success, false, "failing weakCompareAndSetAcquire boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, true, "failing weakCompareAndSetAcquire boolean value"); + assertEquals(true, x, "failing weakCompareAndSetAcquire boolean value"); } { @@ -838,14 +836,14 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, false, "success weakCompareAndSetRelease boolean"); + assertEquals(false, x, "success weakCompareAndSetRelease boolean"); } { boolean success = vh.weakCompareAndSetRelease(true, false); assertEquals(success, false, "failing weakCompareAndSetRelease boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, false, "failing weakCompareAndSetRelease boolean value"); + assertEquals(false, x, "failing weakCompareAndSetRelease boolean value"); } { @@ -856,14 +854,14 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, true, "success weakCompareAndSet boolean"); + assertEquals(true, x, "success weakCompareAndSet boolean"); } { boolean success = vh.weakCompareAndSet(false, false); assertEquals(success, false, "failing weakCompareAndSet boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, true, "failing weakCompareAndSet boolean value"); + assertEquals(true, x, "failing weakCompareAndSet boolean value"); } // Compare set and get @@ -871,27 +869,27 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { vh.set(true); boolean o = (boolean) vh.getAndSet(false); - assertEquals(o, true, "getAndSet boolean"); + assertEquals(true, o, "getAndSet boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, false, "getAndSet boolean value"); + assertEquals(false, x, "getAndSet boolean value"); } { vh.set(true); boolean o = (boolean) vh.getAndSetAcquire(false); - assertEquals(o, true, "getAndSetAcquire boolean"); + assertEquals(true, o, "getAndSetAcquire boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, false, "getAndSetAcquire boolean value"); + assertEquals(false, x, "getAndSetAcquire boolean value"); } { vh.set(true); boolean o = (boolean) vh.getAndSetRelease(false); - assertEquals(o, true, "getAndSetRelease boolean"); + assertEquals(true, o, "getAndSetRelease boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, false, "getAndSetRelease boolean value"); + assertEquals(false, x, "getAndSetRelease boolean value"); } @@ -900,27 +898,27 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { vh.set(true); boolean o = (boolean) vh.getAndBitwiseOr(false); - assertEquals(o, true, "getAndBitwiseOr boolean"); + assertEquals(true, o, "getAndBitwiseOr boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOr boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOr boolean value"); } { vh.set(true); boolean o = (boolean) vh.getAndBitwiseOrAcquire(false); - assertEquals(o, true, "getAndBitwiseOrAcquire boolean"); + assertEquals(true, o, "getAndBitwiseOrAcquire boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOrAcquire boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOrAcquire boolean value"); } { vh.set(true); boolean o = (boolean) vh.getAndBitwiseOrRelease(false); - assertEquals(o, true, "getAndBitwiseOrRelease boolean"); + assertEquals(true, o, "getAndBitwiseOrRelease boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOrRelease boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOrRelease boolean value"); } // get and bitwise and @@ -928,27 +926,27 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { vh.set(true); boolean o = (boolean) vh.getAndBitwiseAnd(false); - assertEquals(o, true, "getAndBitwiseAnd boolean"); + assertEquals(true, o, "getAndBitwiseAnd boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAnd boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAnd boolean value"); } { vh.set(true); boolean o = (boolean) vh.getAndBitwiseAndAcquire(false); - assertEquals(o, true, "getAndBitwiseAndAcquire boolean"); + assertEquals(true, o, "getAndBitwiseAndAcquire boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAndAcquire boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAndAcquire boolean value"); } { vh.set(true); boolean o = (boolean) vh.getAndBitwiseAndRelease(false); - assertEquals(o, true, "getAndBitwiseAndRelease boolean"); + assertEquals(true, o, "getAndBitwiseAndRelease boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAndRelease boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAndRelease boolean value"); } // get and bitwise xor @@ -956,27 +954,27 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { vh.set(true); boolean o = (boolean) vh.getAndBitwiseXor(false); - assertEquals(o, true, "getAndBitwiseXor boolean"); + assertEquals(true, o, "getAndBitwiseXor boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXor boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXor boolean value"); } { vh.set(true); boolean o = (boolean) vh.getAndBitwiseXorAcquire(false); - assertEquals(o, true, "getAndBitwiseXorAcquire boolean"); + assertEquals(true, o, "getAndBitwiseXorAcquire boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXorAcquire boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXorAcquire boolean value"); } { vh.set(true); boolean o = (boolean) vh.getAndBitwiseXorRelease(false); - assertEquals(o, true, "getAndBitwiseXorRelease boolean"); + assertEquals(true, o, "getAndBitwiseXorRelease boolean"); boolean x = (boolean) vh.get(); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXorRelease boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXorRelease boolean value"); } } @@ -1005,7 +1003,7 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { { vh.set(array, i, true); boolean x = (boolean) vh.get(array, i); - assertEquals(x, true, "get boolean value"); + assertEquals(true, x, "get boolean value"); } @@ -1013,21 +1011,21 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { { vh.setVolatile(array, i, false); boolean x = (boolean) vh.getVolatile(array, i); - assertEquals(x, false, "setVolatile boolean value"); + assertEquals(false, x, "setVolatile boolean value"); } // Lazy { vh.setRelease(array, i, true); boolean x = (boolean) vh.getAcquire(array, i); - assertEquals(x, true, "setRelease boolean value"); + assertEquals(true, x, "setRelease boolean value"); } // Opaque { vh.setOpaque(array, i, false); boolean x = (boolean) vh.getOpaque(array, i); - assertEquals(x, false, "setOpaque boolean value"); + assertEquals(false, x, "setOpaque boolean value"); } vh.set(array, i, true); @@ -1037,56 +1035,56 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { boolean r = vh.compareAndSet(array, i, true, false); assertEquals(r, true, "success compareAndSet boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, false, "success compareAndSet boolean value"); + assertEquals(false, x, "success compareAndSet boolean value"); } { boolean r = vh.compareAndSet(array, i, true, false); assertEquals(r, false, "failing compareAndSet boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, false, "failing compareAndSet boolean value"); + assertEquals(false, x, "failing compareAndSet boolean value"); } { boolean r = (boolean) vh.compareAndExchange(array, i, false, true); assertEquals(r, false, "success compareAndExchange boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, true, "success compareAndExchange boolean value"); + assertEquals(true, x, "success compareAndExchange boolean value"); } { boolean r = (boolean) vh.compareAndExchange(array, i, false, false); assertEquals(r, true, "failing compareAndExchange boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, true, "failing compareAndExchange boolean value"); + assertEquals(true, x, "failing compareAndExchange boolean value"); } { boolean r = (boolean) vh.compareAndExchangeAcquire(array, i, true, false); assertEquals(r, true, "success compareAndExchangeAcquire boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, false, "success compareAndExchangeAcquire boolean value"); + assertEquals(false, x, "success compareAndExchangeAcquire boolean value"); } { boolean r = (boolean) vh.compareAndExchangeAcquire(array, i, true, false); assertEquals(r, false, "failing compareAndExchangeAcquire boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, false, "failing compareAndExchangeAcquire boolean value"); + assertEquals(false, x, "failing compareAndExchangeAcquire boolean value"); } { boolean r = (boolean) vh.compareAndExchangeRelease(array, i, false, true); assertEquals(r, false, "success compareAndExchangeRelease boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, true, "success compareAndExchangeRelease boolean value"); + assertEquals(true, x, "success compareAndExchangeRelease boolean value"); } { boolean r = (boolean) vh.compareAndExchangeRelease(array, i, false, false); assertEquals(r, true, "failing compareAndExchangeRelease boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, true, "failing compareAndExchangeRelease boolean value"); + assertEquals(true, x, "failing compareAndExchangeRelease boolean value"); } { @@ -1097,14 +1095,14 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, false, "success weakCompareAndSetPlain boolean value"); + assertEquals(false, x, "success weakCompareAndSetPlain boolean value"); } { boolean success = vh.weakCompareAndSetPlain(array, i, true, false); assertEquals(success, false, "failing weakCompareAndSetPlain boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, false, "failing weakCompareAndSetPlain boolean value"); + assertEquals(false, x, "failing weakCompareAndSetPlain boolean value"); } { @@ -1115,14 +1113,14 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, true, "success weakCompareAndSetAcquire boolean"); + assertEquals(true, x, "success weakCompareAndSetAcquire boolean"); } { boolean success = vh.weakCompareAndSetAcquire(array, i, false, false); assertEquals(success, false, "failing weakCompareAndSetAcquire boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, true, "failing weakCompareAndSetAcquire boolean value"); + assertEquals(true, x, "failing weakCompareAndSetAcquire boolean value"); } { @@ -1133,14 +1131,14 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, false, "success weakCompareAndSetRelease boolean"); + assertEquals(false, x, "success weakCompareAndSetRelease boolean"); } { boolean success = vh.weakCompareAndSetRelease(array, i, true, false); assertEquals(success, false, "failing weakCompareAndSetRelease boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, false, "failing weakCompareAndSetRelease boolean value"); + assertEquals(false, x, "failing weakCompareAndSetRelease boolean value"); } { @@ -1151,14 +1149,14 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, true, "success weakCompareAndSet boolean"); + assertEquals(true, x, "success weakCompareAndSet boolean"); } { boolean success = vh.weakCompareAndSet(array, i, false, false); assertEquals(success, false, "failing weakCompareAndSet boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, true, "failing weakCompareAndSet boolean value"); + assertEquals(true, x, "failing weakCompareAndSet boolean value"); } // Compare set and get @@ -1166,27 +1164,27 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { vh.set(array, i, true); boolean o = (boolean) vh.getAndSet(array, i, false); - assertEquals(o, true, "getAndSet boolean"); + assertEquals(true, o, "getAndSet boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, false, "getAndSet boolean value"); + assertEquals(false, x, "getAndSet boolean value"); } { vh.set(array, i, true); boolean o = (boolean) vh.getAndSetAcquire(array, i, false); - assertEquals(o, true, "getAndSetAcquire boolean"); + assertEquals(true, o, "getAndSetAcquire boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, false, "getAndSetAcquire boolean value"); + assertEquals(false, x, "getAndSetAcquire boolean value"); } { vh.set(array, i, true); boolean o = (boolean) vh.getAndSetRelease(array, i, false); - assertEquals(o, true, "getAndSetRelease boolean"); + assertEquals(true, o, "getAndSetRelease boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, false, "getAndSetRelease boolean value"); + assertEquals(false, x, "getAndSetRelease boolean value"); } @@ -1195,27 +1193,27 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { vh.set(array, i, true); boolean o = (boolean) vh.getAndBitwiseOr(array, i, false); - assertEquals(o, true, "getAndBitwiseOr boolean"); + assertEquals(true, o, "getAndBitwiseOr boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOr boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOr boolean value"); } { vh.set(array, i, true); boolean o = (boolean) vh.getAndBitwiseOrAcquire(array, i, false); - assertEquals(o, true, "getAndBitwiseOrAcquire boolean"); + assertEquals(true, o, "getAndBitwiseOrAcquire boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOrAcquire boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOrAcquire boolean value"); } { vh.set(array, i, true); boolean o = (boolean) vh.getAndBitwiseOrRelease(array, i, false); - assertEquals(o, true, "getAndBitwiseOrRelease boolean"); + assertEquals(true, o, "getAndBitwiseOrRelease boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOrRelease boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOrRelease boolean value"); } // get and bitwise and @@ -1223,27 +1221,27 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { vh.set(array, i, true); boolean o = (boolean) vh.getAndBitwiseAnd(array, i, false); - assertEquals(o, true, "getAndBitwiseAnd boolean"); + assertEquals(true, o, "getAndBitwiseAnd boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAnd boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAnd boolean value"); } { vh.set(array, i, true); boolean o = (boolean) vh.getAndBitwiseAndAcquire(array, i, false); - assertEquals(o, true, "getAndBitwiseAndAcquire boolean"); + assertEquals(true, o, "getAndBitwiseAndAcquire boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAndAcquire boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAndAcquire boolean value"); } { vh.set(array, i, true); boolean o = (boolean) vh.getAndBitwiseAndRelease(array, i, false); - assertEquals(o, true, "getAndBitwiseAndRelease boolean"); + assertEquals(true, o, "getAndBitwiseAndRelease boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAndRelease boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAndRelease boolean value"); } // get and bitwise xor @@ -1251,27 +1249,27 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { vh.set(array, i, true); boolean o = (boolean) vh.getAndBitwiseXor(array, i, false); - assertEquals(o, true, "getAndBitwiseXor boolean"); + assertEquals(true, o, "getAndBitwiseXor boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXor boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXor boolean value"); } { vh.set(array, i, true); boolean o = (boolean) vh.getAndBitwiseXorAcquire(array, i, false); - assertEquals(o, true, "getAndBitwiseXorAcquire boolean"); + assertEquals(true, o, "getAndBitwiseXorAcquire boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXorAcquire boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXorAcquire boolean value"); } { vh.set(array, i, true); boolean o = (boolean) vh.getAndBitwiseXorRelease(array, i, false); - assertEquals(o, true, "getAndBitwiseXorRelease boolean"); + assertEquals(true, o, "getAndBitwiseXorRelease boolean"); boolean x = (boolean) vh.get(array, i); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXorRelease boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXorRelease boolean value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java index 5dc4bf2d1d5..42c465af75e 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,28 +23,30 @@ /* * @test - * @run testng/othervm -Diters=10 -Xint VarHandleTestAccessByte + * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessByte * * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds * - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessByte - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessByte - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessByte + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessByte + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessByte + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessByte */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestAccessByte extends VarHandleBaseTest { static final byte static_final_v = (byte)0x01; @@ -108,7 +110,7 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { return vhs.toArray(new VarHandle[0]); } - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestAccessByte.class, "final_v", byte.class); @@ -125,8 +127,6 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(byte[].class); } - - @DataProvider public Object[][] varHandlesProvider() throws Exception { List vhs = new ArrayList<>(); vhs.add(vhField); @@ -156,7 +156,8 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("varHandlesProvider") public void testIsAccessModeSupported(VarHandle vh) { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET)); @@ -194,8 +195,6 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE)); } - - @DataProvider public Object[][] typesProvider() throws Exception { List types = new ArrayList<>(); types.add(new Object[] {vhField, Arrays.asList(VarHandleTestAccessByte.class)}); @@ -205,16 +204,16 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { return types.stream().toArray(Object[][]::new); } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), byte.class); + assertEquals(byte.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - @Test public void testLookupInstanceToStatic() { checkIAE("Lookup of static final field to instance final field", () -> { @@ -241,8 +240,6 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { }); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -284,7 +281,8 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -297,26 +295,26 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { // Plain { byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x01, "get byte value"); + assertEquals((byte)0x01, x, "get byte value"); } // Volatile { byte x = (byte) vh.getVolatile(recv); - assertEquals(x, (byte)0x01, "getVolatile byte value"); + assertEquals((byte)0x01, x, "getVolatile byte value"); } // Lazy { byte x = (byte) vh.getAcquire(recv); - assertEquals(x, (byte)0x01, "getRelease byte value"); + assertEquals((byte)0x01, x, "getRelease byte value"); } // Opaque { byte x = (byte) vh.getOpaque(recv); - assertEquals(x, (byte)0x01, "getOpaque byte value"); + assertEquals((byte)0x01, x, "getOpaque byte value"); } } @@ -346,26 +344,26 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { // Plain { byte x = (byte) vh.get(); - assertEquals(x, (byte)0x01, "get byte value"); + assertEquals((byte)0x01, x, "get byte value"); } // Volatile { byte x = (byte) vh.getVolatile(); - assertEquals(x, (byte)0x01, "getVolatile byte value"); + assertEquals((byte)0x01, x, "getVolatile byte value"); } // Lazy { byte x = (byte) vh.getAcquire(); - assertEquals(x, (byte)0x01, "getRelease byte value"); + assertEquals((byte)0x01, x, "getRelease byte value"); } // Opaque { byte x = (byte) vh.getOpaque(); - assertEquals(x, (byte)0x01, "getOpaque byte value"); + assertEquals((byte)0x01, x, "getOpaque byte value"); } } @@ -396,7 +394,7 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { { vh.set(recv, (byte)0x01); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x01, "set byte value"); + assertEquals((byte)0x01, x, "set byte value"); } @@ -404,21 +402,21 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { { vh.setVolatile(recv, (byte)0x23); byte x = (byte) vh.getVolatile(recv); - assertEquals(x, (byte)0x23, "setVolatile byte value"); + assertEquals((byte)0x23, x, "setVolatile byte value"); } // Lazy { vh.setRelease(recv, (byte)0x01); byte x = (byte) vh.getAcquire(recv); - assertEquals(x, (byte)0x01, "setRelease byte value"); + assertEquals((byte)0x01, x, "setRelease byte value"); } // Opaque { vh.setOpaque(recv, (byte)0x23); byte x = (byte) vh.getOpaque(recv); - assertEquals(x, (byte)0x23, "setOpaque byte value"); + assertEquals((byte)0x23, x, "setOpaque byte value"); } vh.set(recv, (byte)0x01); @@ -428,56 +426,56 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { boolean r = vh.compareAndSet(recv, (byte)0x01, (byte)0x23); assertEquals(r, true, "success compareAndSet byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x23, "success compareAndSet byte value"); + assertEquals((byte)0x23, x, "success compareAndSet byte value"); } { boolean r = vh.compareAndSet(recv, (byte)0x01, (byte)0x45); assertEquals(r, false, "failing compareAndSet byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x23, "failing compareAndSet byte value"); + assertEquals((byte)0x23, x, "failing compareAndSet byte value"); } { byte r = (byte) vh.compareAndExchange(recv, (byte)0x23, (byte)0x01); assertEquals(r, (byte)0x23, "success compareAndExchange byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x01, "success compareAndExchange byte value"); + assertEquals((byte)0x01, x, "success compareAndExchange byte value"); } { byte r = (byte) vh.compareAndExchange(recv, (byte)0x23, (byte)0x45); assertEquals(r, (byte)0x01, "failing compareAndExchange byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x01, "failing compareAndExchange byte value"); + assertEquals((byte)0x01, x, "failing compareAndExchange byte value"); } { byte r = (byte) vh.compareAndExchangeAcquire(recv, (byte)0x01, (byte)0x23); assertEquals(r, (byte)0x01, "success compareAndExchangeAcquire byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x23, "success compareAndExchangeAcquire byte value"); + assertEquals((byte)0x23, x, "success compareAndExchangeAcquire byte value"); } { byte r = (byte) vh.compareAndExchangeAcquire(recv, (byte)0x01, (byte)0x45); assertEquals(r, (byte)0x23, "failing compareAndExchangeAcquire byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x23, "failing compareAndExchangeAcquire byte value"); + assertEquals((byte)0x23, x, "failing compareAndExchangeAcquire byte value"); } { byte r = (byte) vh.compareAndExchangeRelease(recv, (byte)0x23, (byte)0x01); assertEquals(r, (byte)0x23, "success compareAndExchangeRelease byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x01, "success compareAndExchangeRelease byte value"); + assertEquals((byte)0x01, x, "success compareAndExchangeRelease byte value"); } { byte r = (byte) vh.compareAndExchangeRelease(recv, (byte)0x23, (byte)0x45); assertEquals(r, (byte)0x01, "failing compareAndExchangeRelease byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x01, "failing compareAndExchangeRelease byte value"); + assertEquals((byte)0x01, x, "failing compareAndExchangeRelease byte value"); } { @@ -488,14 +486,14 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x23, "success weakCompareAndSetPlain byte value"); + assertEquals((byte)0x23, x, "success weakCompareAndSetPlain byte value"); } { boolean success = vh.weakCompareAndSetPlain(recv, (byte)0x01, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetPlain byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x23, "failing weakCompareAndSetPlain byte value"); + assertEquals((byte)0x23, x, "failing weakCompareAndSetPlain byte value"); } { @@ -506,14 +504,14 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x01, "success weakCompareAndSetAcquire byte"); + assertEquals((byte)0x01, x, "success weakCompareAndSetAcquire byte"); } { boolean success = vh.weakCompareAndSetAcquire(recv, (byte)0x23, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetAcquire byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x01, "failing weakCompareAndSetAcquire byte value"); + assertEquals((byte)0x01, x, "failing weakCompareAndSetAcquire byte value"); } { @@ -524,14 +522,14 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x23, "success weakCompareAndSetRelease byte"); + assertEquals((byte)0x23, x, "success weakCompareAndSetRelease byte"); } { boolean success = vh.weakCompareAndSetRelease(recv, (byte)0x01, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetRelease byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x23, "failing weakCompareAndSetRelease byte value"); + assertEquals((byte)0x23, x, "failing weakCompareAndSetRelease byte value"); } { @@ -542,14 +540,14 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x01, "success weakCompareAndSet byte value"); + assertEquals((byte)0x01, x, "success weakCompareAndSet byte value"); } { boolean success = vh.weakCompareAndSet(recv, (byte)0x23, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSet byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x01, "failing weakCompareAndSet byte value"); + assertEquals((byte)0x01, x, "failing weakCompareAndSet byte value"); } // Compare set and get @@ -557,27 +555,27 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { vh.set(recv, (byte)0x01); byte o = (byte) vh.getAndSet(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndSet byte"); + assertEquals((byte)0x01, o, "getAndSet byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x23, "getAndSet byte value"); + assertEquals((byte)0x23, x, "getAndSet byte value"); } { vh.set(recv, (byte)0x01); byte o = (byte) vh.getAndSetAcquire(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndSetAcquire byte"); + assertEquals((byte)0x01, o, "getAndSetAcquire byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x23, "getAndSetAcquire byte value"); + assertEquals((byte)0x23, x, "getAndSetAcquire byte value"); } { vh.set(recv, (byte)0x01); byte o = (byte) vh.getAndSetRelease(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndSetRelease byte"); + assertEquals((byte)0x01, o, "getAndSetRelease byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)0x23, "getAndSetRelease byte value"); + assertEquals((byte)0x23, x, "getAndSetRelease byte value"); } // get and add, add and get @@ -585,27 +583,27 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { vh.set(recv, (byte)0x01); byte o = (byte) vh.getAndAdd(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndAdd byte"); + assertEquals((byte)0x01, o, "getAndAdd byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAdd byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAdd byte value"); } { vh.set(recv, (byte)0x01); byte o = (byte) vh.getAndAddAcquire(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndAddAcquire byte"); + assertEquals((byte)0x01, o, "getAndAddAcquire byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAddAcquire byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAddAcquire byte value"); } { vh.set(recv, (byte)0x01); byte o = (byte) vh.getAndAddRelease(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndAddReleasebyte"); + assertEquals((byte)0x01, o, "getAndAddReleasebyte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAddRelease byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAddRelease byte value"); } // get and bitwise or @@ -613,27 +611,27 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { vh.set(recv, (byte)0x01); byte o = (byte) vh.getAndBitwiseOr(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOr byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOr byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOr byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOr byte value"); } { vh.set(recv, (byte)0x01); byte o = (byte) vh.getAndBitwiseOrAcquire(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOrAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOrAcquire byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOrAcquire byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOrAcquire byte value"); } { vh.set(recv, (byte)0x01); byte o = (byte) vh.getAndBitwiseOrRelease(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOrRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOrRelease byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOrRelease byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOrRelease byte value"); } // get and bitwise and @@ -641,27 +639,27 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { vh.set(recv, (byte)0x01); byte o = (byte) vh.getAndBitwiseAnd(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAnd byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAnd byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAnd byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAnd byte value"); } { vh.set(recv, (byte)0x01); byte o = (byte) vh.getAndBitwiseAndAcquire(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAndAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAndAcquire byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAndAcquire byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAndAcquire byte value"); } { vh.set(recv, (byte)0x01); byte o = (byte) vh.getAndBitwiseAndRelease(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAndRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAndRelease byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAndRelease byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAndRelease byte value"); } // get and bitwise xor @@ -669,27 +667,27 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { vh.set(recv, (byte)0x01); byte o = (byte) vh.getAndBitwiseXor(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXor byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXor byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXor byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXor byte value"); } { vh.set(recv, (byte)0x01); byte o = (byte) vh.getAndBitwiseXorAcquire(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXorAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXorAcquire byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXorAcquire byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXorAcquire byte value"); } { vh.set(recv, (byte)0x01); byte o = (byte) vh.getAndBitwiseXorRelease(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXorRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXorRelease byte"); byte x = (byte) vh.get(recv); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXorRelease byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXorRelease byte value"); } } @@ -704,7 +702,7 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { { vh.set((byte)0x01); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x01, "set byte value"); + assertEquals((byte)0x01, x, "set byte value"); } @@ -712,21 +710,21 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { { vh.setVolatile((byte)0x23); byte x = (byte) vh.getVolatile(); - assertEquals(x, (byte)0x23, "setVolatile byte value"); + assertEquals((byte)0x23, x, "setVolatile byte value"); } // Lazy { vh.setRelease((byte)0x01); byte x = (byte) vh.getAcquire(); - assertEquals(x, (byte)0x01, "setRelease byte value"); + assertEquals((byte)0x01, x, "setRelease byte value"); } // Opaque { vh.setOpaque((byte)0x23); byte x = (byte) vh.getOpaque(); - assertEquals(x, (byte)0x23, "setOpaque byte value"); + assertEquals((byte)0x23, x, "setOpaque byte value"); } vh.set((byte)0x01); @@ -736,56 +734,56 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { boolean r = vh.compareAndSet((byte)0x01, (byte)0x23); assertEquals(r, true, "success compareAndSet byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x23, "success compareAndSet byte value"); + assertEquals((byte)0x23, x, "success compareAndSet byte value"); } { boolean r = vh.compareAndSet((byte)0x01, (byte)0x45); assertEquals(r, false, "failing compareAndSet byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x23, "failing compareAndSet byte value"); + assertEquals((byte)0x23, x, "failing compareAndSet byte value"); } { byte r = (byte) vh.compareAndExchange((byte)0x23, (byte)0x01); assertEquals(r, (byte)0x23, "success compareAndExchange byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x01, "success compareAndExchange byte value"); + assertEquals((byte)0x01, x, "success compareAndExchange byte value"); } { byte r = (byte) vh.compareAndExchange((byte)0x23, (byte)0x45); assertEquals(r, (byte)0x01, "failing compareAndExchange byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x01, "failing compareAndExchange byte value"); + assertEquals((byte)0x01, x, "failing compareAndExchange byte value"); } { byte r = (byte) vh.compareAndExchangeAcquire((byte)0x01, (byte)0x23); assertEquals(r, (byte)0x01, "success compareAndExchangeAcquire byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x23, "success compareAndExchangeAcquire byte value"); + assertEquals((byte)0x23, x, "success compareAndExchangeAcquire byte value"); } { byte r = (byte) vh.compareAndExchangeAcquire((byte)0x01, (byte)0x45); assertEquals(r, (byte)0x23, "failing compareAndExchangeAcquire byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x23, "failing compareAndExchangeAcquire byte value"); + assertEquals((byte)0x23, x, "failing compareAndExchangeAcquire byte value"); } { byte r = (byte) vh.compareAndExchangeRelease((byte)0x23, (byte)0x01); assertEquals(r, (byte)0x23, "success compareAndExchangeRelease byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x01, "success compareAndExchangeRelease byte value"); + assertEquals((byte)0x01, x, "success compareAndExchangeRelease byte value"); } { byte r = (byte) vh.compareAndExchangeRelease((byte)0x23, (byte)0x45); assertEquals(r, (byte)0x01, "failing compareAndExchangeRelease byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x01, "failing compareAndExchangeRelease byte value"); + assertEquals((byte)0x01, x, "failing compareAndExchangeRelease byte value"); } { @@ -796,14 +794,14 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x23, "success weakCompareAndSetPlain byte value"); + assertEquals((byte)0x23, x, "success weakCompareAndSetPlain byte value"); } { boolean success = vh.weakCompareAndSetPlain((byte)0x01, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetPlain byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x23, "failing weakCompareAndSetPlain byte value"); + assertEquals((byte)0x23, x, "failing weakCompareAndSetPlain byte value"); } { @@ -814,14 +812,14 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x01, "success weakCompareAndSetAcquire byte"); + assertEquals((byte)0x01, x, "success weakCompareAndSetAcquire byte"); } { boolean success = vh.weakCompareAndSetAcquire((byte)0x23, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetAcquire byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x01, "failing weakCompareAndSetAcquire byte value"); + assertEquals((byte)0x01, x, "failing weakCompareAndSetAcquire byte value"); } { @@ -832,14 +830,14 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x23, "success weakCompareAndSetRelease byte"); + assertEquals((byte)0x23, x, "success weakCompareAndSetRelease byte"); } { boolean success = vh.weakCompareAndSetRelease((byte)0x01, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetRelease byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x23, "failing weakCompareAndSetRelease byte value"); + assertEquals((byte)0x23, x, "failing weakCompareAndSetRelease byte value"); } { @@ -850,14 +848,14 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x01, "success weakCompareAndSet byte"); + assertEquals((byte)0x01, x, "success weakCompareAndSet byte"); } { boolean success = vh.weakCompareAndSet((byte)0x23, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSet byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x01, "failing weakCompareAndSet byte value"); + assertEquals((byte)0x01, x, "failing weakCompareAndSet byte value"); } // Compare set and get @@ -865,27 +863,27 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { vh.set((byte)0x01); byte o = (byte) vh.getAndSet((byte)0x23); - assertEquals(o, (byte)0x01, "getAndSet byte"); + assertEquals((byte)0x01, o, "getAndSet byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x23, "getAndSet byte value"); + assertEquals((byte)0x23, x, "getAndSet byte value"); } { vh.set((byte)0x01); byte o = (byte) vh.getAndSetAcquire((byte)0x23); - assertEquals(o, (byte)0x01, "getAndSetAcquire byte"); + assertEquals((byte)0x01, o, "getAndSetAcquire byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x23, "getAndSetAcquire byte value"); + assertEquals((byte)0x23, x, "getAndSetAcquire byte value"); } { vh.set((byte)0x01); byte o = (byte) vh.getAndSetRelease((byte)0x23); - assertEquals(o, (byte)0x01, "getAndSetRelease byte"); + assertEquals((byte)0x01, o, "getAndSetRelease byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)0x23, "getAndSetRelease byte value"); + assertEquals((byte)0x23, x, "getAndSetRelease byte value"); } // get and add, add and get @@ -893,27 +891,27 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { vh.set((byte)0x01); byte o = (byte) vh.getAndAdd((byte)0x23); - assertEquals(o, (byte)0x01, "getAndAdd byte"); + assertEquals((byte)0x01, o, "getAndAdd byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAdd byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAdd byte value"); } { vh.set((byte)0x01); byte o = (byte) vh.getAndAddAcquire((byte)0x23); - assertEquals(o, (byte)0x01, "getAndAddAcquire byte"); + assertEquals((byte)0x01, o, "getAndAddAcquire byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAddAcquire byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAddAcquire byte value"); } { vh.set((byte)0x01); byte o = (byte) vh.getAndAddRelease((byte)0x23); - assertEquals(o, (byte)0x01, "getAndAddReleasebyte"); + assertEquals((byte)0x01, o, "getAndAddReleasebyte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAddRelease byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAddRelease byte value"); } // get and bitwise or @@ -921,27 +919,27 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { vh.set((byte)0x01); byte o = (byte) vh.getAndBitwiseOr((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOr byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOr byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOr byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOr byte value"); } { vh.set((byte)0x01); byte o = (byte) vh.getAndBitwiseOrAcquire((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOrAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOrAcquire byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOrAcquire byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOrAcquire byte value"); } { vh.set((byte)0x01); byte o = (byte) vh.getAndBitwiseOrRelease((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOrRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOrRelease byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOrRelease byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOrRelease byte value"); } // get and bitwise and @@ -949,27 +947,27 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { vh.set((byte)0x01); byte o = (byte) vh.getAndBitwiseAnd((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAnd byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAnd byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAnd byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAnd byte value"); } { vh.set((byte)0x01); byte o = (byte) vh.getAndBitwiseAndAcquire((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAndAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAndAcquire byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAndAcquire byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAndAcquire byte value"); } { vh.set((byte)0x01); byte o = (byte) vh.getAndBitwiseAndRelease((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAndRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAndRelease byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAndRelease byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAndRelease byte value"); } // get and bitwise xor @@ -977,27 +975,27 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { vh.set((byte)0x01); byte o = (byte) vh.getAndBitwiseXor((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXor byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXor byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXor byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXor byte value"); } { vh.set((byte)0x01); byte o = (byte) vh.getAndBitwiseXorAcquire((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXorAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXorAcquire byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXorAcquire byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXorAcquire byte value"); } { vh.set((byte)0x01); byte o = (byte) vh.getAndBitwiseXorRelease((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXorRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXorRelease byte"); byte x = (byte) vh.get(); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXorRelease byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXorRelease byte value"); } } @@ -1015,7 +1013,7 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { { vh.set(array, i, (byte)0x01); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x01, "get byte value"); + assertEquals((byte)0x01, x, "get byte value"); } @@ -1023,21 +1021,21 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { { vh.setVolatile(array, i, (byte)0x23); byte x = (byte) vh.getVolatile(array, i); - assertEquals(x, (byte)0x23, "setVolatile byte value"); + assertEquals((byte)0x23, x, "setVolatile byte value"); } // Lazy { vh.setRelease(array, i, (byte)0x01); byte x = (byte) vh.getAcquire(array, i); - assertEquals(x, (byte)0x01, "setRelease byte value"); + assertEquals((byte)0x01, x, "setRelease byte value"); } // Opaque { vh.setOpaque(array, i, (byte)0x23); byte x = (byte) vh.getOpaque(array, i); - assertEquals(x, (byte)0x23, "setOpaque byte value"); + assertEquals((byte)0x23, x, "setOpaque byte value"); } vh.set(array, i, (byte)0x01); @@ -1047,56 +1045,56 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { boolean r = vh.compareAndSet(array, i, (byte)0x01, (byte)0x23); assertEquals(r, true, "success compareAndSet byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x23, "success compareAndSet byte value"); + assertEquals((byte)0x23, x, "success compareAndSet byte value"); } { boolean r = vh.compareAndSet(array, i, (byte)0x01, (byte)0x45); assertEquals(r, false, "failing compareAndSet byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x23, "failing compareAndSet byte value"); + assertEquals((byte)0x23, x, "failing compareAndSet byte value"); } { byte r = (byte) vh.compareAndExchange(array, i, (byte)0x23, (byte)0x01); assertEquals(r, (byte)0x23, "success compareAndExchange byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x01, "success compareAndExchange byte value"); + assertEquals((byte)0x01, x, "success compareAndExchange byte value"); } { byte r = (byte) vh.compareAndExchange(array, i, (byte)0x23, (byte)0x45); assertEquals(r, (byte)0x01, "failing compareAndExchange byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x01, "failing compareAndExchange byte value"); + assertEquals((byte)0x01, x, "failing compareAndExchange byte value"); } { byte r = (byte) vh.compareAndExchangeAcquire(array, i, (byte)0x01, (byte)0x23); assertEquals(r, (byte)0x01, "success compareAndExchangeAcquire byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x23, "success compareAndExchangeAcquire byte value"); + assertEquals((byte)0x23, x, "success compareAndExchangeAcquire byte value"); } { byte r = (byte) vh.compareAndExchangeAcquire(array, i, (byte)0x01, (byte)0x45); assertEquals(r, (byte)0x23, "failing compareAndExchangeAcquire byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x23, "failing compareAndExchangeAcquire byte value"); + assertEquals((byte)0x23, x, "failing compareAndExchangeAcquire byte value"); } { byte r = (byte) vh.compareAndExchangeRelease(array, i, (byte)0x23, (byte)0x01); assertEquals(r, (byte)0x23, "success compareAndExchangeRelease byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x01, "success compareAndExchangeRelease byte value"); + assertEquals((byte)0x01, x, "success compareAndExchangeRelease byte value"); } { byte r = (byte) vh.compareAndExchangeRelease(array, i, (byte)0x23, (byte)0x45); assertEquals(r, (byte)0x01, "failing compareAndExchangeRelease byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x01, "failing compareAndExchangeRelease byte value"); + assertEquals((byte)0x01, x, "failing compareAndExchangeRelease byte value"); } { @@ -1107,14 +1105,14 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x23, "success weakCompareAndSetPlain byte value"); + assertEquals((byte)0x23, x, "success weakCompareAndSetPlain byte value"); } { boolean success = vh.weakCompareAndSetPlain(array, i, (byte)0x01, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetPlain byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x23, "failing weakCompareAndSetPlain byte value"); + assertEquals((byte)0x23, x, "failing weakCompareAndSetPlain byte value"); } { @@ -1125,14 +1123,14 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x01, "success weakCompareAndSetAcquire byte"); + assertEquals((byte)0x01, x, "success weakCompareAndSetAcquire byte"); } { boolean success = vh.weakCompareAndSetAcquire(array, i, (byte)0x23, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetAcquire byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x01, "failing weakCompareAndSetAcquire byte value"); + assertEquals((byte)0x01, x, "failing weakCompareAndSetAcquire byte value"); } { @@ -1143,14 +1141,14 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x23, "success weakCompareAndSetRelease byte"); + assertEquals((byte)0x23, x, "success weakCompareAndSetRelease byte"); } { boolean success = vh.weakCompareAndSetRelease(array, i, (byte)0x01, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetRelease byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x23, "failing weakCompareAndSetRelease byte value"); + assertEquals((byte)0x23, x, "failing weakCompareAndSetRelease byte value"); } { @@ -1161,14 +1159,14 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x01, "success weakCompareAndSet byte"); + assertEquals((byte)0x01, x, "success weakCompareAndSet byte"); } { boolean success = vh.weakCompareAndSet(array, i, (byte)0x23, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSet byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x01, "failing weakCompareAndSet byte value"); + assertEquals((byte)0x01, x, "failing weakCompareAndSet byte value"); } // Compare set and get @@ -1176,27 +1174,27 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { vh.set(array, i, (byte)0x01); byte o = (byte) vh.getAndSet(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndSet byte"); + assertEquals((byte)0x01, o, "getAndSet byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x23, "getAndSet byte value"); + assertEquals((byte)0x23, x, "getAndSet byte value"); } { vh.set(array, i, (byte)0x01); byte o = (byte) vh.getAndSetAcquire(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndSetAcquire byte"); + assertEquals((byte)0x01, o, "getAndSetAcquire byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x23, "getAndSetAcquire byte value"); + assertEquals((byte)0x23, x, "getAndSetAcquire byte value"); } { vh.set(array, i, (byte)0x01); byte o = (byte) vh.getAndSetRelease(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndSetRelease byte"); + assertEquals((byte)0x01, o, "getAndSetRelease byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)0x23, "getAndSetRelease byte value"); + assertEquals((byte)0x23, x, "getAndSetRelease byte value"); } // get and add, add and get @@ -1204,27 +1202,27 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { vh.set(array, i, (byte)0x01); byte o = (byte) vh.getAndAdd(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndAdd byte"); + assertEquals((byte)0x01, o, "getAndAdd byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAdd byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAdd byte value"); } { vh.set(array, i, (byte)0x01); byte o = (byte) vh.getAndAddAcquire(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndAddAcquire byte"); + assertEquals((byte)0x01, o, "getAndAddAcquire byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAddAcquire byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAddAcquire byte value"); } { vh.set(array, i, (byte)0x01); byte o = (byte) vh.getAndAddRelease(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndAddReleasebyte"); + assertEquals((byte)0x01, o, "getAndAddReleasebyte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAddRelease byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAddRelease byte value"); } // get and bitwise or @@ -1232,27 +1230,27 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { vh.set(array, i, (byte)0x01); byte o = (byte) vh.getAndBitwiseOr(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOr byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOr byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOr byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOr byte value"); } { vh.set(array, i, (byte)0x01); byte o = (byte) vh.getAndBitwiseOrAcquire(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOrAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOrAcquire byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOrAcquire byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOrAcquire byte value"); } { vh.set(array, i, (byte)0x01); byte o = (byte) vh.getAndBitwiseOrRelease(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOrRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOrRelease byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOrRelease byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOrRelease byte value"); } // get and bitwise and @@ -1260,27 +1258,27 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { vh.set(array, i, (byte)0x01); byte o = (byte) vh.getAndBitwiseAnd(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAnd byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAnd byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAnd byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAnd byte value"); } { vh.set(array, i, (byte)0x01); byte o = (byte) vh.getAndBitwiseAndAcquire(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAndAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAndAcquire byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAndAcquire byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAndAcquire byte value"); } { vh.set(array, i, (byte)0x01); byte o = (byte) vh.getAndBitwiseAndRelease(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAndRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAndRelease byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAndRelease byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAndRelease byte value"); } // get and bitwise xor @@ -1288,27 +1286,27 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { vh.set(array, i, (byte)0x01); byte o = (byte) vh.getAndBitwiseXor(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXor byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXor byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXor byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXor byte value"); } { vh.set(array, i, (byte)0x01); byte o = (byte) vh.getAndBitwiseXorAcquire(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXorAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXorAcquire byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXorAcquire byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXorAcquire byte value"); } { vh.set(array, i, (byte)0x01); byte o = (byte) vh.getAndBitwiseXorRelease(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXorRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXorRelease byte"); byte x = (byte) vh.get(array, i); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXorRelease byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXorRelease byte value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java index bafde057167..e17e7616609 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,28 +23,30 @@ /* * @test - * @run testng/othervm -Diters=10 -Xint VarHandleTestAccessChar + * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessChar * * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds * - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessChar - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessChar - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessChar + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessChar + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessChar + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessChar */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestAccessChar extends VarHandleBaseTest { static final char static_final_v = '\u0123'; @@ -108,7 +110,7 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { return vhs.toArray(new VarHandle[0]); } - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestAccessChar.class, "final_v", char.class); @@ -125,8 +127,6 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(char[].class); } - - @DataProvider public Object[][] varHandlesProvider() throws Exception { List vhs = new ArrayList<>(); vhs.add(vhField); @@ -156,7 +156,8 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("varHandlesProvider") public void testIsAccessModeSupported(VarHandle vh) { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET)); @@ -194,8 +195,6 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE)); } - - @DataProvider public Object[][] typesProvider() throws Exception { List types = new ArrayList<>(); types.add(new Object[] {vhField, Arrays.asList(VarHandleTestAccessChar.class)}); @@ -205,16 +204,16 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { return types.stream().toArray(Object[][]::new); } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), char.class); + assertEquals(char.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - @Test public void testLookupInstanceToStatic() { checkIAE("Lookup of static final field to instance final field", () -> { @@ -241,8 +240,6 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { }); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -284,7 +281,8 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -297,26 +295,26 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { // Plain { char x = (char) vh.get(recv); - assertEquals(x, '\u0123', "get char value"); + assertEquals('\u0123', x, "get char value"); } // Volatile { char x = (char) vh.getVolatile(recv); - assertEquals(x, '\u0123', "getVolatile char value"); + assertEquals('\u0123', x, "getVolatile char value"); } // Lazy { char x = (char) vh.getAcquire(recv); - assertEquals(x, '\u0123', "getRelease char value"); + assertEquals('\u0123', x, "getRelease char value"); } // Opaque { char x = (char) vh.getOpaque(recv); - assertEquals(x, '\u0123', "getOpaque char value"); + assertEquals('\u0123', x, "getOpaque char value"); } } @@ -346,26 +344,26 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { // Plain { char x = (char) vh.get(); - assertEquals(x, '\u0123', "get char value"); + assertEquals('\u0123', x, "get char value"); } // Volatile { char x = (char) vh.getVolatile(); - assertEquals(x, '\u0123', "getVolatile char value"); + assertEquals('\u0123', x, "getVolatile char value"); } // Lazy { char x = (char) vh.getAcquire(); - assertEquals(x, '\u0123', "getRelease char value"); + assertEquals('\u0123', x, "getRelease char value"); } // Opaque { char x = (char) vh.getOpaque(); - assertEquals(x, '\u0123', "getOpaque char value"); + assertEquals('\u0123', x, "getOpaque char value"); } } @@ -396,7 +394,7 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { { vh.set(recv, '\u0123'); char x = (char) vh.get(recv); - assertEquals(x, '\u0123', "set char value"); + assertEquals('\u0123', x, "set char value"); } @@ -404,21 +402,21 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { { vh.setVolatile(recv, '\u4567'); char x = (char) vh.getVolatile(recv); - assertEquals(x, '\u4567', "setVolatile char value"); + assertEquals('\u4567', x, "setVolatile char value"); } // Lazy { vh.setRelease(recv, '\u0123'); char x = (char) vh.getAcquire(recv); - assertEquals(x, '\u0123', "setRelease char value"); + assertEquals('\u0123', x, "setRelease char value"); } // Opaque { vh.setOpaque(recv, '\u4567'); char x = (char) vh.getOpaque(recv); - assertEquals(x, '\u4567', "setOpaque char value"); + assertEquals('\u4567', x, "setOpaque char value"); } vh.set(recv, '\u0123'); @@ -428,56 +426,56 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { boolean r = vh.compareAndSet(recv, '\u0123', '\u4567'); assertEquals(r, true, "success compareAndSet char"); char x = (char) vh.get(recv); - assertEquals(x, '\u4567', "success compareAndSet char value"); + assertEquals('\u4567', x, "success compareAndSet char value"); } { boolean r = vh.compareAndSet(recv, '\u0123', '\u89AB'); assertEquals(r, false, "failing compareAndSet char"); char x = (char) vh.get(recv); - assertEquals(x, '\u4567', "failing compareAndSet char value"); + assertEquals('\u4567', x, "failing compareAndSet char value"); } { char r = (char) vh.compareAndExchange(recv, '\u4567', '\u0123'); assertEquals(r, '\u4567', "success compareAndExchange char"); char x = (char) vh.get(recv); - assertEquals(x, '\u0123', "success compareAndExchange char value"); + assertEquals('\u0123', x, "success compareAndExchange char value"); } { char r = (char) vh.compareAndExchange(recv, '\u4567', '\u89AB'); assertEquals(r, '\u0123', "failing compareAndExchange char"); char x = (char) vh.get(recv); - assertEquals(x, '\u0123', "failing compareAndExchange char value"); + assertEquals('\u0123', x, "failing compareAndExchange char value"); } { char r = (char) vh.compareAndExchangeAcquire(recv, '\u0123', '\u4567'); assertEquals(r, '\u0123', "success compareAndExchangeAcquire char"); char x = (char) vh.get(recv); - assertEquals(x, '\u4567', "success compareAndExchangeAcquire char value"); + assertEquals('\u4567', x, "success compareAndExchangeAcquire char value"); } { char r = (char) vh.compareAndExchangeAcquire(recv, '\u0123', '\u89AB'); assertEquals(r, '\u4567', "failing compareAndExchangeAcquire char"); char x = (char) vh.get(recv); - assertEquals(x, '\u4567', "failing compareAndExchangeAcquire char value"); + assertEquals('\u4567', x, "failing compareAndExchangeAcquire char value"); } { char r = (char) vh.compareAndExchangeRelease(recv, '\u4567', '\u0123'); assertEquals(r, '\u4567', "success compareAndExchangeRelease char"); char x = (char) vh.get(recv); - assertEquals(x, '\u0123', "success compareAndExchangeRelease char value"); + assertEquals('\u0123', x, "success compareAndExchangeRelease char value"); } { char r = (char) vh.compareAndExchangeRelease(recv, '\u4567', '\u89AB'); assertEquals(r, '\u0123', "failing compareAndExchangeRelease char"); char x = (char) vh.get(recv); - assertEquals(x, '\u0123', "failing compareAndExchangeRelease char value"); + assertEquals('\u0123', x, "failing compareAndExchangeRelease char value"); } { @@ -488,14 +486,14 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain char"); char x = (char) vh.get(recv); - assertEquals(x, '\u4567', "success weakCompareAndSetPlain char value"); + assertEquals('\u4567', x, "success weakCompareAndSetPlain char value"); } { boolean success = vh.weakCompareAndSetPlain(recv, '\u0123', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetPlain char"); char x = (char) vh.get(recv); - assertEquals(x, '\u4567', "failing weakCompareAndSetPlain char value"); + assertEquals('\u4567', x, "failing weakCompareAndSetPlain char value"); } { @@ -506,14 +504,14 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire char"); char x = (char) vh.get(recv); - assertEquals(x, '\u0123', "success weakCompareAndSetAcquire char"); + assertEquals('\u0123', x, "success weakCompareAndSetAcquire char"); } { boolean success = vh.weakCompareAndSetAcquire(recv, '\u4567', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetAcquire char"); char x = (char) vh.get(recv); - assertEquals(x, '\u0123', "failing weakCompareAndSetAcquire char value"); + assertEquals('\u0123', x, "failing weakCompareAndSetAcquire char value"); } { @@ -524,14 +522,14 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease char"); char x = (char) vh.get(recv); - assertEquals(x, '\u4567', "success weakCompareAndSetRelease char"); + assertEquals('\u4567', x, "success weakCompareAndSetRelease char"); } { boolean success = vh.weakCompareAndSetRelease(recv, '\u0123', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetRelease char"); char x = (char) vh.get(recv); - assertEquals(x, '\u4567', "failing weakCompareAndSetRelease char value"); + assertEquals('\u4567', x, "failing weakCompareAndSetRelease char value"); } { @@ -542,14 +540,14 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet char"); char x = (char) vh.get(recv); - assertEquals(x, '\u0123', "success weakCompareAndSet char value"); + assertEquals('\u0123', x, "success weakCompareAndSet char value"); } { boolean success = vh.weakCompareAndSet(recv, '\u4567', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSet char"); char x = (char) vh.get(recv); - assertEquals(x, '\u0123', "failing weakCompareAndSet char value"); + assertEquals('\u0123', x, "failing weakCompareAndSet char value"); } // Compare set and get @@ -557,27 +555,27 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { vh.set(recv, '\u0123'); char o = (char) vh.getAndSet(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndSet char"); + assertEquals('\u0123', o, "getAndSet char"); char x = (char) vh.get(recv); - assertEquals(x, '\u4567', "getAndSet char value"); + assertEquals('\u4567', x, "getAndSet char value"); } { vh.set(recv, '\u0123'); char o = (char) vh.getAndSetAcquire(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndSetAcquire char"); + assertEquals('\u0123', o, "getAndSetAcquire char"); char x = (char) vh.get(recv); - assertEquals(x, '\u4567', "getAndSetAcquire char value"); + assertEquals('\u4567', x, "getAndSetAcquire char value"); } { vh.set(recv, '\u0123'); char o = (char) vh.getAndSetRelease(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndSetRelease char"); + assertEquals('\u0123', o, "getAndSetRelease char"); char x = (char) vh.get(recv); - assertEquals(x, '\u4567', "getAndSetRelease char value"); + assertEquals('\u4567', x, "getAndSetRelease char value"); } // get and add, add and get @@ -585,27 +583,27 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { vh.set(recv, '\u0123'); char o = (char) vh.getAndAdd(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndAdd char"); + assertEquals('\u0123', o, "getAndAdd char"); char x = (char) vh.get(recv); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAdd char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAdd char value"); } { vh.set(recv, '\u0123'); char o = (char) vh.getAndAddAcquire(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndAddAcquire char"); + assertEquals('\u0123', o, "getAndAddAcquire char"); char x = (char) vh.get(recv); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAddAcquire char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAddAcquire char value"); } { vh.set(recv, '\u0123'); char o = (char) vh.getAndAddRelease(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndAddReleasechar"); + assertEquals('\u0123', o, "getAndAddReleasechar"); char x = (char) vh.get(recv); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAddRelease char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAddRelease char value"); } // get and bitwise or @@ -613,27 +611,27 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { vh.set(recv, '\u0123'); char o = (char) vh.getAndBitwiseOr(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOr char"); + assertEquals('\u0123', o, "getAndBitwiseOr char"); char x = (char) vh.get(recv); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOr char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOr char value"); } { vh.set(recv, '\u0123'); char o = (char) vh.getAndBitwiseOrAcquire(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOrAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseOrAcquire char"); char x = (char) vh.get(recv); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOrAcquire char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOrAcquire char value"); } { vh.set(recv, '\u0123'); char o = (char) vh.getAndBitwiseOrRelease(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOrRelease char"); + assertEquals('\u0123', o, "getAndBitwiseOrRelease char"); char x = (char) vh.get(recv); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOrRelease char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOrRelease char value"); } // get and bitwise and @@ -641,27 +639,27 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { vh.set(recv, '\u0123'); char o = (char) vh.getAndBitwiseAnd(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAnd char"); + assertEquals('\u0123', o, "getAndBitwiseAnd char"); char x = (char) vh.get(recv); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAnd char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAnd char value"); } { vh.set(recv, '\u0123'); char o = (char) vh.getAndBitwiseAndAcquire(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAndAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseAndAcquire char"); char x = (char) vh.get(recv); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAndAcquire char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAndAcquire char value"); } { vh.set(recv, '\u0123'); char o = (char) vh.getAndBitwiseAndRelease(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAndRelease char"); + assertEquals('\u0123', o, "getAndBitwiseAndRelease char"); char x = (char) vh.get(recv); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAndRelease char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAndRelease char value"); } // get and bitwise xor @@ -669,27 +667,27 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { vh.set(recv, '\u0123'); char o = (char) vh.getAndBitwiseXor(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXor char"); + assertEquals('\u0123', o, "getAndBitwiseXor char"); char x = (char) vh.get(recv); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXor char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXor char value"); } { vh.set(recv, '\u0123'); char o = (char) vh.getAndBitwiseXorAcquire(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXorAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseXorAcquire char"); char x = (char) vh.get(recv); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXorAcquire char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXorAcquire char value"); } { vh.set(recv, '\u0123'); char o = (char) vh.getAndBitwiseXorRelease(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXorRelease char"); + assertEquals('\u0123', o, "getAndBitwiseXorRelease char"); char x = (char) vh.get(recv); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXorRelease char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXorRelease char value"); } } @@ -704,7 +702,7 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { { vh.set('\u0123'); char x = (char) vh.get(); - assertEquals(x, '\u0123', "set char value"); + assertEquals('\u0123', x, "set char value"); } @@ -712,21 +710,21 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { { vh.setVolatile('\u4567'); char x = (char) vh.getVolatile(); - assertEquals(x, '\u4567', "setVolatile char value"); + assertEquals('\u4567', x, "setVolatile char value"); } // Lazy { vh.setRelease('\u0123'); char x = (char) vh.getAcquire(); - assertEquals(x, '\u0123', "setRelease char value"); + assertEquals('\u0123', x, "setRelease char value"); } // Opaque { vh.setOpaque('\u4567'); char x = (char) vh.getOpaque(); - assertEquals(x, '\u4567', "setOpaque char value"); + assertEquals('\u4567', x, "setOpaque char value"); } vh.set('\u0123'); @@ -736,56 +734,56 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { boolean r = vh.compareAndSet('\u0123', '\u4567'); assertEquals(r, true, "success compareAndSet char"); char x = (char) vh.get(); - assertEquals(x, '\u4567', "success compareAndSet char value"); + assertEquals('\u4567', x, "success compareAndSet char value"); } { boolean r = vh.compareAndSet('\u0123', '\u89AB'); assertEquals(r, false, "failing compareAndSet char"); char x = (char) vh.get(); - assertEquals(x, '\u4567', "failing compareAndSet char value"); + assertEquals('\u4567', x, "failing compareAndSet char value"); } { char r = (char) vh.compareAndExchange('\u4567', '\u0123'); assertEquals(r, '\u4567', "success compareAndExchange char"); char x = (char) vh.get(); - assertEquals(x, '\u0123', "success compareAndExchange char value"); + assertEquals('\u0123', x, "success compareAndExchange char value"); } { char r = (char) vh.compareAndExchange('\u4567', '\u89AB'); assertEquals(r, '\u0123', "failing compareAndExchange char"); char x = (char) vh.get(); - assertEquals(x, '\u0123', "failing compareAndExchange char value"); + assertEquals('\u0123', x, "failing compareAndExchange char value"); } { char r = (char) vh.compareAndExchangeAcquire('\u0123', '\u4567'); assertEquals(r, '\u0123', "success compareAndExchangeAcquire char"); char x = (char) vh.get(); - assertEquals(x, '\u4567', "success compareAndExchangeAcquire char value"); + assertEquals('\u4567', x, "success compareAndExchangeAcquire char value"); } { char r = (char) vh.compareAndExchangeAcquire('\u0123', '\u89AB'); assertEquals(r, '\u4567', "failing compareAndExchangeAcquire char"); char x = (char) vh.get(); - assertEquals(x, '\u4567', "failing compareAndExchangeAcquire char value"); + assertEquals('\u4567', x, "failing compareAndExchangeAcquire char value"); } { char r = (char) vh.compareAndExchangeRelease('\u4567', '\u0123'); assertEquals(r, '\u4567', "success compareAndExchangeRelease char"); char x = (char) vh.get(); - assertEquals(x, '\u0123', "success compareAndExchangeRelease char value"); + assertEquals('\u0123', x, "success compareAndExchangeRelease char value"); } { char r = (char) vh.compareAndExchangeRelease('\u4567', '\u89AB'); assertEquals(r, '\u0123', "failing compareAndExchangeRelease char"); char x = (char) vh.get(); - assertEquals(x, '\u0123', "failing compareAndExchangeRelease char value"); + assertEquals('\u0123', x, "failing compareAndExchangeRelease char value"); } { @@ -796,14 +794,14 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain char"); char x = (char) vh.get(); - assertEquals(x, '\u4567', "success weakCompareAndSetPlain char value"); + assertEquals('\u4567', x, "success weakCompareAndSetPlain char value"); } { boolean success = vh.weakCompareAndSetPlain('\u0123', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetPlain char"); char x = (char) vh.get(); - assertEquals(x, '\u4567', "failing weakCompareAndSetPlain char value"); + assertEquals('\u4567', x, "failing weakCompareAndSetPlain char value"); } { @@ -814,14 +812,14 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire char"); char x = (char) vh.get(); - assertEquals(x, '\u0123', "success weakCompareAndSetAcquire char"); + assertEquals('\u0123', x, "success weakCompareAndSetAcquire char"); } { boolean success = vh.weakCompareAndSetAcquire('\u4567', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetAcquire char"); char x = (char) vh.get(); - assertEquals(x, '\u0123', "failing weakCompareAndSetAcquire char value"); + assertEquals('\u0123', x, "failing weakCompareAndSetAcquire char value"); } { @@ -832,14 +830,14 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease char"); char x = (char) vh.get(); - assertEquals(x, '\u4567', "success weakCompareAndSetRelease char"); + assertEquals('\u4567', x, "success weakCompareAndSetRelease char"); } { boolean success = vh.weakCompareAndSetRelease('\u0123', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetRelease char"); char x = (char) vh.get(); - assertEquals(x, '\u4567', "failing weakCompareAndSetRelease char value"); + assertEquals('\u4567', x, "failing weakCompareAndSetRelease char value"); } { @@ -850,14 +848,14 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet char"); char x = (char) vh.get(); - assertEquals(x, '\u0123', "success weakCompareAndSet char"); + assertEquals('\u0123', x, "success weakCompareAndSet char"); } { boolean success = vh.weakCompareAndSet('\u4567', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSet char"); char x = (char) vh.get(); - assertEquals(x, '\u0123', "failing weakCompareAndSet char value"); + assertEquals('\u0123', x, "failing weakCompareAndSet char value"); } // Compare set and get @@ -865,27 +863,27 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { vh.set('\u0123'); char o = (char) vh.getAndSet('\u4567'); - assertEquals(o, '\u0123', "getAndSet char"); + assertEquals('\u0123', o, "getAndSet char"); char x = (char) vh.get(); - assertEquals(x, '\u4567', "getAndSet char value"); + assertEquals('\u4567', x, "getAndSet char value"); } { vh.set('\u0123'); char o = (char) vh.getAndSetAcquire('\u4567'); - assertEquals(o, '\u0123', "getAndSetAcquire char"); + assertEquals('\u0123', o, "getAndSetAcquire char"); char x = (char) vh.get(); - assertEquals(x, '\u4567', "getAndSetAcquire char value"); + assertEquals('\u4567', x, "getAndSetAcquire char value"); } { vh.set('\u0123'); char o = (char) vh.getAndSetRelease('\u4567'); - assertEquals(o, '\u0123', "getAndSetRelease char"); + assertEquals('\u0123', o, "getAndSetRelease char"); char x = (char) vh.get(); - assertEquals(x, '\u4567', "getAndSetRelease char value"); + assertEquals('\u4567', x, "getAndSetRelease char value"); } // get and add, add and get @@ -893,27 +891,27 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { vh.set('\u0123'); char o = (char) vh.getAndAdd('\u4567'); - assertEquals(o, '\u0123', "getAndAdd char"); + assertEquals('\u0123', o, "getAndAdd char"); char x = (char) vh.get(); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAdd char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAdd char value"); } { vh.set('\u0123'); char o = (char) vh.getAndAddAcquire('\u4567'); - assertEquals(o, '\u0123', "getAndAddAcquire char"); + assertEquals('\u0123', o, "getAndAddAcquire char"); char x = (char) vh.get(); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAddAcquire char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAddAcquire char value"); } { vh.set('\u0123'); char o = (char) vh.getAndAddRelease('\u4567'); - assertEquals(o, '\u0123', "getAndAddReleasechar"); + assertEquals('\u0123', o, "getAndAddReleasechar"); char x = (char) vh.get(); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAddRelease char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAddRelease char value"); } // get and bitwise or @@ -921,27 +919,27 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { vh.set('\u0123'); char o = (char) vh.getAndBitwiseOr('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOr char"); + assertEquals('\u0123', o, "getAndBitwiseOr char"); char x = (char) vh.get(); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOr char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOr char value"); } { vh.set('\u0123'); char o = (char) vh.getAndBitwiseOrAcquire('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOrAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseOrAcquire char"); char x = (char) vh.get(); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOrAcquire char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOrAcquire char value"); } { vh.set('\u0123'); char o = (char) vh.getAndBitwiseOrRelease('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOrRelease char"); + assertEquals('\u0123', o, "getAndBitwiseOrRelease char"); char x = (char) vh.get(); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOrRelease char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOrRelease char value"); } // get and bitwise and @@ -949,27 +947,27 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { vh.set('\u0123'); char o = (char) vh.getAndBitwiseAnd('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAnd char"); + assertEquals('\u0123', o, "getAndBitwiseAnd char"); char x = (char) vh.get(); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAnd char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAnd char value"); } { vh.set('\u0123'); char o = (char) vh.getAndBitwiseAndAcquire('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAndAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseAndAcquire char"); char x = (char) vh.get(); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAndAcquire char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAndAcquire char value"); } { vh.set('\u0123'); char o = (char) vh.getAndBitwiseAndRelease('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAndRelease char"); + assertEquals('\u0123', o, "getAndBitwiseAndRelease char"); char x = (char) vh.get(); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAndRelease char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAndRelease char value"); } // get and bitwise xor @@ -977,27 +975,27 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { vh.set('\u0123'); char o = (char) vh.getAndBitwiseXor('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXor char"); + assertEquals('\u0123', o, "getAndBitwiseXor char"); char x = (char) vh.get(); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXor char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXor char value"); } { vh.set('\u0123'); char o = (char) vh.getAndBitwiseXorAcquire('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXorAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseXorAcquire char"); char x = (char) vh.get(); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXorAcquire char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXorAcquire char value"); } { vh.set('\u0123'); char o = (char) vh.getAndBitwiseXorRelease('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXorRelease char"); + assertEquals('\u0123', o, "getAndBitwiseXorRelease char"); char x = (char) vh.get(); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXorRelease char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXorRelease char value"); } } @@ -1015,7 +1013,7 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { { vh.set(array, i, '\u0123'); char x = (char) vh.get(array, i); - assertEquals(x, '\u0123', "get char value"); + assertEquals('\u0123', x, "get char value"); } @@ -1023,21 +1021,21 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { { vh.setVolatile(array, i, '\u4567'); char x = (char) vh.getVolatile(array, i); - assertEquals(x, '\u4567', "setVolatile char value"); + assertEquals('\u4567', x, "setVolatile char value"); } // Lazy { vh.setRelease(array, i, '\u0123'); char x = (char) vh.getAcquire(array, i); - assertEquals(x, '\u0123', "setRelease char value"); + assertEquals('\u0123', x, "setRelease char value"); } // Opaque { vh.setOpaque(array, i, '\u4567'); char x = (char) vh.getOpaque(array, i); - assertEquals(x, '\u4567', "setOpaque char value"); + assertEquals('\u4567', x, "setOpaque char value"); } vh.set(array, i, '\u0123'); @@ -1047,56 +1045,56 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { boolean r = vh.compareAndSet(array, i, '\u0123', '\u4567'); assertEquals(r, true, "success compareAndSet char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u4567', "success compareAndSet char value"); + assertEquals('\u4567', x, "success compareAndSet char value"); } { boolean r = vh.compareAndSet(array, i, '\u0123', '\u89AB'); assertEquals(r, false, "failing compareAndSet char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u4567', "failing compareAndSet char value"); + assertEquals('\u4567', x, "failing compareAndSet char value"); } { char r = (char) vh.compareAndExchange(array, i, '\u4567', '\u0123'); assertEquals(r, '\u4567', "success compareAndExchange char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u0123', "success compareAndExchange char value"); + assertEquals('\u0123', x, "success compareAndExchange char value"); } { char r = (char) vh.compareAndExchange(array, i, '\u4567', '\u89AB'); assertEquals(r, '\u0123', "failing compareAndExchange char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u0123', "failing compareAndExchange char value"); + assertEquals('\u0123', x, "failing compareAndExchange char value"); } { char r = (char) vh.compareAndExchangeAcquire(array, i, '\u0123', '\u4567'); assertEquals(r, '\u0123', "success compareAndExchangeAcquire char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u4567', "success compareAndExchangeAcquire char value"); + assertEquals('\u4567', x, "success compareAndExchangeAcquire char value"); } { char r = (char) vh.compareAndExchangeAcquire(array, i, '\u0123', '\u89AB'); assertEquals(r, '\u4567', "failing compareAndExchangeAcquire char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u4567', "failing compareAndExchangeAcquire char value"); + assertEquals('\u4567', x, "failing compareAndExchangeAcquire char value"); } { char r = (char) vh.compareAndExchangeRelease(array, i, '\u4567', '\u0123'); assertEquals(r, '\u4567', "success compareAndExchangeRelease char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u0123', "success compareAndExchangeRelease char value"); + assertEquals('\u0123', x, "success compareAndExchangeRelease char value"); } { char r = (char) vh.compareAndExchangeRelease(array, i, '\u4567', '\u89AB'); assertEquals(r, '\u0123', "failing compareAndExchangeRelease char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u0123', "failing compareAndExchangeRelease char value"); + assertEquals('\u0123', x, "failing compareAndExchangeRelease char value"); } { @@ -1107,14 +1105,14 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u4567', "success weakCompareAndSetPlain char value"); + assertEquals('\u4567', x, "success weakCompareAndSetPlain char value"); } { boolean success = vh.weakCompareAndSetPlain(array, i, '\u0123', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetPlain char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u4567', "failing weakCompareAndSetPlain char value"); + assertEquals('\u4567', x, "failing weakCompareAndSetPlain char value"); } { @@ -1125,14 +1123,14 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u0123', "success weakCompareAndSetAcquire char"); + assertEquals('\u0123', x, "success weakCompareAndSetAcquire char"); } { boolean success = vh.weakCompareAndSetAcquire(array, i, '\u4567', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetAcquire char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u0123', "failing weakCompareAndSetAcquire char value"); + assertEquals('\u0123', x, "failing weakCompareAndSetAcquire char value"); } { @@ -1143,14 +1141,14 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u4567', "success weakCompareAndSetRelease char"); + assertEquals('\u4567', x, "success weakCompareAndSetRelease char"); } { boolean success = vh.weakCompareAndSetRelease(array, i, '\u0123', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetRelease char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u4567', "failing weakCompareAndSetRelease char value"); + assertEquals('\u4567', x, "failing weakCompareAndSetRelease char value"); } { @@ -1161,14 +1159,14 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u0123', "success weakCompareAndSet char"); + assertEquals('\u0123', x, "success weakCompareAndSet char"); } { boolean success = vh.weakCompareAndSet(array, i, '\u4567', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSet char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u0123', "failing weakCompareAndSet char value"); + assertEquals('\u0123', x, "failing weakCompareAndSet char value"); } // Compare set and get @@ -1176,27 +1174,27 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { vh.set(array, i, '\u0123'); char o = (char) vh.getAndSet(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndSet char"); + assertEquals('\u0123', o, "getAndSet char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u4567', "getAndSet char value"); + assertEquals('\u4567', x, "getAndSet char value"); } { vh.set(array, i, '\u0123'); char o = (char) vh.getAndSetAcquire(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndSetAcquire char"); + assertEquals('\u0123', o, "getAndSetAcquire char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u4567', "getAndSetAcquire char value"); + assertEquals('\u4567', x, "getAndSetAcquire char value"); } { vh.set(array, i, '\u0123'); char o = (char) vh.getAndSetRelease(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndSetRelease char"); + assertEquals('\u0123', o, "getAndSetRelease char"); char x = (char) vh.get(array, i); - assertEquals(x, '\u4567', "getAndSetRelease char value"); + assertEquals('\u4567', x, "getAndSetRelease char value"); } // get and add, add and get @@ -1204,27 +1202,27 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { vh.set(array, i, '\u0123'); char o = (char) vh.getAndAdd(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndAdd char"); + assertEquals('\u0123', o, "getAndAdd char"); char x = (char) vh.get(array, i); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAdd char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAdd char value"); } { vh.set(array, i, '\u0123'); char o = (char) vh.getAndAddAcquire(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndAddAcquire char"); + assertEquals('\u0123', o, "getAndAddAcquire char"); char x = (char) vh.get(array, i); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAddAcquire char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAddAcquire char value"); } { vh.set(array, i, '\u0123'); char o = (char) vh.getAndAddRelease(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndAddReleasechar"); + assertEquals('\u0123', o, "getAndAddReleasechar"); char x = (char) vh.get(array, i); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAddRelease char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAddRelease char value"); } // get and bitwise or @@ -1232,27 +1230,27 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { vh.set(array, i, '\u0123'); char o = (char) vh.getAndBitwiseOr(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOr char"); + assertEquals('\u0123', o, "getAndBitwiseOr char"); char x = (char) vh.get(array, i); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOr char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOr char value"); } { vh.set(array, i, '\u0123'); char o = (char) vh.getAndBitwiseOrAcquire(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOrAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseOrAcquire char"); char x = (char) vh.get(array, i); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOrAcquire char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOrAcquire char value"); } { vh.set(array, i, '\u0123'); char o = (char) vh.getAndBitwiseOrRelease(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOrRelease char"); + assertEquals('\u0123', o, "getAndBitwiseOrRelease char"); char x = (char) vh.get(array, i); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOrRelease char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOrRelease char value"); } // get and bitwise and @@ -1260,27 +1258,27 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { vh.set(array, i, '\u0123'); char o = (char) vh.getAndBitwiseAnd(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAnd char"); + assertEquals('\u0123', o, "getAndBitwiseAnd char"); char x = (char) vh.get(array, i); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAnd char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAnd char value"); } { vh.set(array, i, '\u0123'); char o = (char) vh.getAndBitwiseAndAcquire(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAndAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseAndAcquire char"); char x = (char) vh.get(array, i); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAndAcquire char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAndAcquire char value"); } { vh.set(array, i, '\u0123'); char o = (char) vh.getAndBitwiseAndRelease(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAndRelease char"); + assertEquals('\u0123', o, "getAndBitwiseAndRelease char"); char x = (char) vh.get(array, i); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAndRelease char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAndRelease char value"); } // get and bitwise xor @@ -1288,27 +1286,27 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { vh.set(array, i, '\u0123'); char o = (char) vh.getAndBitwiseXor(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXor char"); + assertEquals('\u0123', o, "getAndBitwiseXor char"); char x = (char) vh.get(array, i); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXor char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXor char value"); } { vh.set(array, i, '\u0123'); char o = (char) vh.getAndBitwiseXorAcquire(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXorAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseXorAcquire char"); char x = (char) vh.get(array, i); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXorAcquire char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXorAcquire char value"); } { vh.set(array, i, '\u0123'); char o = (char) vh.getAndBitwiseXorRelease(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXorRelease char"); + assertEquals('\u0123', o, "getAndBitwiseXorRelease char"); char x = (char) vh.get(array, i); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXorRelease char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXorRelease char value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java index 0edb196076c..29fa6c2886d 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,28 +23,30 @@ /* * @test - * @run testng/othervm -Diters=10 -Xint VarHandleTestAccessDouble + * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessDouble * * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds * - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessDouble - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessDouble - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessDouble + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessDouble + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessDouble + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessDouble */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestAccessDouble extends VarHandleBaseTest { static final double static_final_v = 1.0d; @@ -108,7 +110,7 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { return vhs.toArray(new VarHandle[0]); } - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestAccessDouble.class, "final_v", double.class); @@ -125,8 +127,6 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(double[].class); } - - @DataProvider public Object[][] varHandlesProvider() throws Exception { List vhs = new ArrayList<>(); vhs.add(vhField); @@ -156,7 +156,8 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("varHandlesProvider") public void testIsAccessModeSupported(VarHandle vh) { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET)); @@ -194,8 +195,6 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE)); } - - @DataProvider public Object[][] typesProvider() throws Exception { List types = new ArrayList<>(); types.add(new Object[] {vhField, Arrays.asList(VarHandleTestAccessDouble.class)}); @@ -205,16 +204,16 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { return types.stream().toArray(Object[][]::new); } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), double.class); + assertEquals(double.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - @Test public void testLookupInstanceToStatic() { checkIAE("Lookup of static final field to instance final field", () -> { @@ -241,8 +240,6 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { }); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -284,7 +281,8 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -297,26 +295,26 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { // Plain { double x = (double) vh.get(recv); - assertEquals(x, 1.0d, "get double value"); + assertEquals(1.0d, x, "get double value"); } // Volatile { double x = (double) vh.getVolatile(recv); - assertEquals(x, 1.0d, "getVolatile double value"); + assertEquals(1.0d, x, "getVolatile double value"); } // Lazy { double x = (double) vh.getAcquire(recv); - assertEquals(x, 1.0d, "getRelease double value"); + assertEquals(1.0d, x, "getRelease double value"); } // Opaque { double x = (double) vh.getOpaque(recv); - assertEquals(x, 1.0d, "getOpaque double value"); + assertEquals(1.0d, x, "getOpaque double value"); } } @@ -381,26 +379,26 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { // Plain { double x = (double) vh.get(); - assertEquals(x, 1.0d, "get double value"); + assertEquals(1.0d, x, "get double value"); } // Volatile { double x = (double) vh.getVolatile(); - assertEquals(x, 1.0d, "getVolatile double value"); + assertEquals(1.0d, x, "getVolatile double value"); } // Lazy { double x = (double) vh.getAcquire(); - assertEquals(x, 1.0d, "getRelease double value"); + assertEquals(1.0d, x, "getRelease double value"); } // Opaque { double x = (double) vh.getOpaque(); - assertEquals(x, 1.0d, "getOpaque double value"); + assertEquals(1.0d, x, "getOpaque double value"); } } @@ -466,7 +464,7 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { { vh.set(recv, 1.0d); double x = (double) vh.get(recv); - assertEquals(x, 1.0d, "set double value"); + assertEquals(1.0d, x, "set double value"); } @@ -474,21 +472,21 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { { vh.setVolatile(recv, 2.0d); double x = (double) vh.getVolatile(recv); - assertEquals(x, 2.0d, "setVolatile double value"); + assertEquals(2.0d, x, "setVolatile double value"); } // Lazy { vh.setRelease(recv, 1.0d); double x = (double) vh.getAcquire(recv); - assertEquals(x, 1.0d, "setRelease double value"); + assertEquals(1.0d, x, "setRelease double value"); } // Opaque { vh.setOpaque(recv, 2.0d); double x = (double) vh.getOpaque(recv); - assertEquals(x, 2.0d, "setOpaque double value"); + assertEquals(2.0d, x, "setOpaque double value"); } vh.set(recv, 1.0d); @@ -498,56 +496,56 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { boolean r = vh.compareAndSet(recv, 1.0d, 2.0d); assertEquals(r, true, "success compareAndSet double"); double x = (double) vh.get(recv); - assertEquals(x, 2.0d, "success compareAndSet double value"); + assertEquals(2.0d, x, "success compareAndSet double value"); } { boolean r = vh.compareAndSet(recv, 1.0d, 3.0d); assertEquals(r, false, "failing compareAndSet double"); double x = (double) vh.get(recv); - assertEquals(x, 2.0d, "failing compareAndSet double value"); + assertEquals(2.0d, x, "failing compareAndSet double value"); } { double r = (double) vh.compareAndExchange(recv, 2.0d, 1.0d); assertEquals(r, 2.0d, "success compareAndExchange double"); double x = (double) vh.get(recv); - assertEquals(x, 1.0d, "success compareAndExchange double value"); + assertEquals(1.0d, x, "success compareAndExchange double value"); } { double r = (double) vh.compareAndExchange(recv, 2.0d, 3.0d); assertEquals(r, 1.0d, "failing compareAndExchange double"); double x = (double) vh.get(recv); - assertEquals(x, 1.0d, "failing compareAndExchange double value"); + assertEquals(1.0d, x, "failing compareAndExchange double value"); } { double r = (double) vh.compareAndExchangeAcquire(recv, 1.0d, 2.0d); assertEquals(r, 1.0d, "success compareAndExchangeAcquire double"); double x = (double) vh.get(recv); - assertEquals(x, 2.0d, "success compareAndExchangeAcquire double value"); + assertEquals(2.0d, x, "success compareAndExchangeAcquire double value"); } { double r = (double) vh.compareAndExchangeAcquire(recv, 1.0d, 3.0d); assertEquals(r, 2.0d, "failing compareAndExchangeAcquire double"); double x = (double) vh.get(recv); - assertEquals(x, 2.0d, "failing compareAndExchangeAcquire double value"); + assertEquals(2.0d, x, "failing compareAndExchangeAcquire double value"); } { double r = (double) vh.compareAndExchangeRelease(recv, 2.0d, 1.0d); assertEquals(r, 2.0d, "success compareAndExchangeRelease double"); double x = (double) vh.get(recv); - assertEquals(x, 1.0d, "success compareAndExchangeRelease double value"); + assertEquals(1.0d, x, "success compareAndExchangeRelease double value"); } { double r = (double) vh.compareAndExchangeRelease(recv, 2.0d, 3.0d); assertEquals(r, 1.0d, "failing compareAndExchangeRelease double"); double x = (double) vh.get(recv); - assertEquals(x, 1.0d, "failing compareAndExchangeRelease double value"); + assertEquals(1.0d, x, "failing compareAndExchangeRelease double value"); } { @@ -558,14 +556,14 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain double"); double x = (double) vh.get(recv); - assertEquals(x, 2.0d, "success weakCompareAndSetPlain double value"); + assertEquals(2.0d, x, "success weakCompareAndSetPlain double value"); } { boolean success = vh.weakCompareAndSetPlain(recv, 1.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetPlain double"); double x = (double) vh.get(recv); - assertEquals(x, 2.0d, "failing weakCompareAndSetPlain double value"); + assertEquals(2.0d, x, "failing weakCompareAndSetPlain double value"); } { @@ -576,14 +574,14 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire double"); double x = (double) vh.get(recv); - assertEquals(x, 1.0d, "success weakCompareAndSetAcquire double"); + assertEquals(1.0d, x, "success weakCompareAndSetAcquire double"); } { boolean success = vh.weakCompareAndSetAcquire(recv, 2.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetAcquire double"); double x = (double) vh.get(recv); - assertEquals(x, 1.0d, "failing weakCompareAndSetAcquire double value"); + assertEquals(1.0d, x, "failing weakCompareAndSetAcquire double value"); } { @@ -594,14 +592,14 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease double"); double x = (double) vh.get(recv); - assertEquals(x, 2.0d, "success weakCompareAndSetRelease double"); + assertEquals(2.0d, x, "success weakCompareAndSetRelease double"); } { boolean success = vh.weakCompareAndSetRelease(recv, 1.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetRelease double"); double x = (double) vh.get(recv); - assertEquals(x, 2.0d, "failing weakCompareAndSetRelease double value"); + assertEquals(2.0d, x, "failing weakCompareAndSetRelease double value"); } { @@ -612,14 +610,14 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet double"); double x = (double) vh.get(recv); - assertEquals(x, 1.0d, "success weakCompareAndSet double value"); + assertEquals(1.0d, x, "success weakCompareAndSet double value"); } { boolean success = vh.weakCompareAndSet(recv, 2.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSet double"); double x = (double) vh.get(recv); - assertEquals(x, 1.0d, "failing weakCompareAndSet double value"); + assertEquals(1.0d, x, "failing weakCompareAndSet double value"); } // Compare set and get @@ -627,27 +625,27 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { vh.set(recv, 1.0d); double o = (double) vh.getAndSet(recv, 2.0d); - assertEquals(o, 1.0d, "getAndSet double"); + assertEquals(1.0d, o, "getAndSet double"); double x = (double) vh.get(recv); - assertEquals(x, 2.0d, "getAndSet double value"); + assertEquals(2.0d, x, "getAndSet double value"); } { vh.set(recv, 1.0d); double o = (double) vh.getAndSetAcquire(recv, 2.0d); - assertEquals(o, 1.0d, "getAndSetAcquire double"); + assertEquals(1.0d, o, "getAndSetAcquire double"); double x = (double) vh.get(recv); - assertEquals(x, 2.0d, "getAndSetAcquire double value"); + assertEquals(2.0d, x, "getAndSetAcquire double value"); } { vh.set(recv, 1.0d); double o = (double) vh.getAndSetRelease(recv, 2.0d); - assertEquals(o, 1.0d, "getAndSetRelease double"); + assertEquals(1.0d, o, "getAndSetRelease double"); double x = (double) vh.get(recv); - assertEquals(x, 2.0d, "getAndSetRelease double value"); + assertEquals(2.0d, x, "getAndSetRelease double value"); } // get and add, add and get @@ -655,27 +653,27 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { vh.set(recv, 1.0d); double o = (double) vh.getAndAdd(recv, 2.0d); - assertEquals(o, 1.0d, "getAndAdd double"); + assertEquals(1.0d, o, "getAndAdd double"); double x = (double) vh.get(recv); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAdd double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAdd double value"); } { vh.set(recv, 1.0d); double o = (double) vh.getAndAddAcquire(recv, 2.0d); - assertEquals(o, 1.0d, "getAndAddAcquire double"); + assertEquals(1.0d, o, "getAndAddAcquire double"); double x = (double) vh.get(recv); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAddAcquire double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAddAcquire double value"); } { vh.set(recv, 1.0d); double o = (double) vh.getAndAddRelease(recv, 2.0d); - assertEquals(o, 1.0d, "getAndAddReleasedouble"); + assertEquals(1.0d, o, "getAndAddReleasedouble"); double x = (double) vh.get(recv); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAddRelease double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAddRelease double value"); } } @@ -726,7 +724,7 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { { vh.set(1.0d); double x = (double) vh.get(); - assertEquals(x, 1.0d, "set double value"); + assertEquals(1.0d, x, "set double value"); } @@ -734,21 +732,21 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { { vh.setVolatile(2.0d); double x = (double) vh.getVolatile(); - assertEquals(x, 2.0d, "setVolatile double value"); + assertEquals(2.0d, x, "setVolatile double value"); } // Lazy { vh.setRelease(1.0d); double x = (double) vh.getAcquire(); - assertEquals(x, 1.0d, "setRelease double value"); + assertEquals(1.0d, x, "setRelease double value"); } // Opaque { vh.setOpaque(2.0d); double x = (double) vh.getOpaque(); - assertEquals(x, 2.0d, "setOpaque double value"); + assertEquals(2.0d, x, "setOpaque double value"); } vh.set(1.0d); @@ -758,56 +756,56 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { boolean r = vh.compareAndSet(1.0d, 2.0d); assertEquals(r, true, "success compareAndSet double"); double x = (double) vh.get(); - assertEquals(x, 2.0d, "success compareAndSet double value"); + assertEquals(2.0d, x, "success compareAndSet double value"); } { boolean r = vh.compareAndSet(1.0d, 3.0d); assertEquals(r, false, "failing compareAndSet double"); double x = (double) vh.get(); - assertEquals(x, 2.0d, "failing compareAndSet double value"); + assertEquals(2.0d, x, "failing compareAndSet double value"); } { double r = (double) vh.compareAndExchange(2.0d, 1.0d); assertEquals(r, 2.0d, "success compareAndExchange double"); double x = (double) vh.get(); - assertEquals(x, 1.0d, "success compareAndExchange double value"); + assertEquals(1.0d, x, "success compareAndExchange double value"); } { double r = (double) vh.compareAndExchange(2.0d, 3.0d); assertEquals(r, 1.0d, "failing compareAndExchange double"); double x = (double) vh.get(); - assertEquals(x, 1.0d, "failing compareAndExchange double value"); + assertEquals(1.0d, x, "failing compareAndExchange double value"); } { double r = (double) vh.compareAndExchangeAcquire(1.0d, 2.0d); assertEquals(r, 1.0d, "success compareAndExchangeAcquire double"); double x = (double) vh.get(); - assertEquals(x, 2.0d, "success compareAndExchangeAcquire double value"); + assertEquals(2.0d, x, "success compareAndExchangeAcquire double value"); } { double r = (double) vh.compareAndExchangeAcquire(1.0d, 3.0d); assertEquals(r, 2.0d, "failing compareAndExchangeAcquire double"); double x = (double) vh.get(); - assertEquals(x, 2.0d, "failing compareAndExchangeAcquire double value"); + assertEquals(2.0d, x, "failing compareAndExchangeAcquire double value"); } { double r = (double) vh.compareAndExchangeRelease(2.0d, 1.0d); assertEquals(r, 2.0d, "success compareAndExchangeRelease double"); double x = (double) vh.get(); - assertEquals(x, 1.0d, "success compareAndExchangeRelease double value"); + assertEquals(1.0d, x, "success compareAndExchangeRelease double value"); } { double r = (double) vh.compareAndExchangeRelease(2.0d, 3.0d); assertEquals(r, 1.0d, "failing compareAndExchangeRelease double"); double x = (double) vh.get(); - assertEquals(x, 1.0d, "failing compareAndExchangeRelease double value"); + assertEquals(1.0d, x, "failing compareAndExchangeRelease double value"); } { @@ -818,14 +816,14 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain double"); double x = (double) vh.get(); - assertEquals(x, 2.0d, "success weakCompareAndSetPlain double value"); + assertEquals(2.0d, x, "success weakCompareAndSetPlain double value"); } { boolean success = vh.weakCompareAndSetPlain(1.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetPlain double"); double x = (double) vh.get(); - assertEquals(x, 2.0d, "failing weakCompareAndSetPlain double value"); + assertEquals(2.0d, x, "failing weakCompareAndSetPlain double value"); } { @@ -836,14 +834,14 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire double"); double x = (double) vh.get(); - assertEquals(x, 1.0d, "success weakCompareAndSetAcquire double"); + assertEquals(1.0d, x, "success weakCompareAndSetAcquire double"); } { boolean success = vh.weakCompareAndSetAcquire(2.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetAcquire double"); double x = (double) vh.get(); - assertEquals(x, 1.0d, "failing weakCompareAndSetAcquire double value"); + assertEquals(1.0d, x, "failing weakCompareAndSetAcquire double value"); } { @@ -854,14 +852,14 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease double"); double x = (double) vh.get(); - assertEquals(x, 2.0d, "success weakCompareAndSetRelease double"); + assertEquals(2.0d, x, "success weakCompareAndSetRelease double"); } { boolean success = vh.weakCompareAndSetRelease(1.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetRelease double"); double x = (double) vh.get(); - assertEquals(x, 2.0d, "failing weakCompareAndSetRelease double value"); + assertEquals(2.0d, x, "failing weakCompareAndSetRelease double value"); } { @@ -872,14 +870,14 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet double"); double x = (double) vh.get(); - assertEquals(x, 1.0d, "success weakCompareAndSet double"); + assertEquals(1.0d, x, "success weakCompareAndSet double"); } { boolean success = vh.weakCompareAndSet(2.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSet double"); double x = (double) vh.get(); - assertEquals(x, 1.0d, "failing weakCompareAndSet double value"); + assertEquals(1.0d, x, "failing weakCompareAndSet double value"); } // Compare set and get @@ -887,27 +885,27 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { vh.set(1.0d); double o = (double) vh.getAndSet(2.0d); - assertEquals(o, 1.0d, "getAndSet double"); + assertEquals(1.0d, o, "getAndSet double"); double x = (double) vh.get(); - assertEquals(x, 2.0d, "getAndSet double value"); + assertEquals(2.0d, x, "getAndSet double value"); } { vh.set(1.0d); double o = (double) vh.getAndSetAcquire(2.0d); - assertEquals(o, 1.0d, "getAndSetAcquire double"); + assertEquals(1.0d, o, "getAndSetAcquire double"); double x = (double) vh.get(); - assertEquals(x, 2.0d, "getAndSetAcquire double value"); + assertEquals(2.0d, x, "getAndSetAcquire double value"); } { vh.set(1.0d); double o = (double) vh.getAndSetRelease(2.0d); - assertEquals(o, 1.0d, "getAndSetRelease double"); + assertEquals(1.0d, o, "getAndSetRelease double"); double x = (double) vh.get(); - assertEquals(x, 2.0d, "getAndSetRelease double value"); + assertEquals(2.0d, x, "getAndSetRelease double value"); } // get and add, add and get @@ -915,27 +913,27 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { vh.set(1.0d); double o = (double) vh.getAndAdd(2.0d); - assertEquals(o, 1.0d, "getAndAdd double"); + assertEquals(1.0d, o, "getAndAdd double"); double x = (double) vh.get(); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAdd double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAdd double value"); } { vh.set(1.0d); double o = (double) vh.getAndAddAcquire(2.0d); - assertEquals(o, 1.0d, "getAndAddAcquire double"); + assertEquals(1.0d, o, "getAndAddAcquire double"); double x = (double) vh.get(); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAddAcquire double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAddAcquire double value"); } { vh.set(1.0d); double o = (double) vh.getAndAddRelease(2.0d); - assertEquals(o, 1.0d, "getAndAddReleasedouble"); + assertEquals(1.0d, o, "getAndAddReleasedouble"); double x = (double) vh.get(); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAddRelease double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAddRelease double value"); } } @@ -989,7 +987,7 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { { vh.set(array, i, 1.0d); double x = (double) vh.get(array, i); - assertEquals(x, 1.0d, "get double value"); + assertEquals(1.0d, x, "get double value"); } @@ -997,21 +995,21 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { { vh.setVolatile(array, i, 2.0d); double x = (double) vh.getVolatile(array, i); - assertEquals(x, 2.0d, "setVolatile double value"); + assertEquals(2.0d, x, "setVolatile double value"); } // Lazy { vh.setRelease(array, i, 1.0d); double x = (double) vh.getAcquire(array, i); - assertEquals(x, 1.0d, "setRelease double value"); + assertEquals(1.0d, x, "setRelease double value"); } // Opaque { vh.setOpaque(array, i, 2.0d); double x = (double) vh.getOpaque(array, i); - assertEquals(x, 2.0d, "setOpaque double value"); + assertEquals(2.0d, x, "setOpaque double value"); } vh.set(array, i, 1.0d); @@ -1021,56 +1019,56 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { boolean r = vh.compareAndSet(array, i, 1.0d, 2.0d); assertEquals(r, true, "success compareAndSet double"); double x = (double) vh.get(array, i); - assertEquals(x, 2.0d, "success compareAndSet double value"); + assertEquals(2.0d, x, "success compareAndSet double value"); } { boolean r = vh.compareAndSet(array, i, 1.0d, 3.0d); assertEquals(r, false, "failing compareAndSet double"); double x = (double) vh.get(array, i); - assertEquals(x, 2.0d, "failing compareAndSet double value"); + assertEquals(2.0d, x, "failing compareAndSet double value"); } { double r = (double) vh.compareAndExchange(array, i, 2.0d, 1.0d); assertEquals(r, 2.0d, "success compareAndExchange double"); double x = (double) vh.get(array, i); - assertEquals(x, 1.0d, "success compareAndExchange double value"); + assertEquals(1.0d, x, "success compareAndExchange double value"); } { double r = (double) vh.compareAndExchange(array, i, 2.0d, 3.0d); assertEquals(r, 1.0d, "failing compareAndExchange double"); double x = (double) vh.get(array, i); - assertEquals(x, 1.0d, "failing compareAndExchange double value"); + assertEquals(1.0d, x, "failing compareAndExchange double value"); } { double r = (double) vh.compareAndExchangeAcquire(array, i, 1.0d, 2.0d); assertEquals(r, 1.0d, "success compareAndExchangeAcquire double"); double x = (double) vh.get(array, i); - assertEquals(x, 2.0d, "success compareAndExchangeAcquire double value"); + assertEquals(2.0d, x, "success compareAndExchangeAcquire double value"); } { double r = (double) vh.compareAndExchangeAcquire(array, i, 1.0d, 3.0d); assertEquals(r, 2.0d, "failing compareAndExchangeAcquire double"); double x = (double) vh.get(array, i); - assertEquals(x, 2.0d, "failing compareAndExchangeAcquire double value"); + assertEquals(2.0d, x, "failing compareAndExchangeAcquire double value"); } { double r = (double) vh.compareAndExchangeRelease(array, i, 2.0d, 1.0d); assertEquals(r, 2.0d, "success compareAndExchangeRelease double"); double x = (double) vh.get(array, i); - assertEquals(x, 1.0d, "success compareAndExchangeRelease double value"); + assertEquals(1.0d, x, "success compareAndExchangeRelease double value"); } { double r = (double) vh.compareAndExchangeRelease(array, i, 2.0d, 3.0d); assertEquals(r, 1.0d, "failing compareAndExchangeRelease double"); double x = (double) vh.get(array, i); - assertEquals(x, 1.0d, "failing compareAndExchangeRelease double value"); + assertEquals(1.0d, x, "failing compareAndExchangeRelease double value"); } { @@ -1081,14 +1079,14 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain double"); double x = (double) vh.get(array, i); - assertEquals(x, 2.0d, "success weakCompareAndSetPlain double value"); + assertEquals(2.0d, x, "success weakCompareAndSetPlain double value"); } { boolean success = vh.weakCompareAndSetPlain(array, i, 1.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetPlain double"); double x = (double) vh.get(array, i); - assertEquals(x, 2.0d, "failing weakCompareAndSetPlain double value"); + assertEquals(2.0d, x, "failing weakCompareAndSetPlain double value"); } { @@ -1099,14 +1097,14 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire double"); double x = (double) vh.get(array, i); - assertEquals(x, 1.0d, "success weakCompareAndSetAcquire double"); + assertEquals(1.0d, x, "success weakCompareAndSetAcquire double"); } { boolean success = vh.weakCompareAndSetAcquire(array, i, 2.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetAcquire double"); double x = (double) vh.get(array, i); - assertEquals(x, 1.0d, "failing weakCompareAndSetAcquire double value"); + assertEquals(1.0d, x, "failing weakCompareAndSetAcquire double value"); } { @@ -1117,14 +1115,14 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease double"); double x = (double) vh.get(array, i); - assertEquals(x, 2.0d, "success weakCompareAndSetRelease double"); + assertEquals(2.0d, x, "success weakCompareAndSetRelease double"); } { boolean success = vh.weakCompareAndSetRelease(array, i, 1.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetRelease double"); double x = (double) vh.get(array, i); - assertEquals(x, 2.0d, "failing weakCompareAndSetRelease double value"); + assertEquals(2.0d, x, "failing weakCompareAndSetRelease double value"); } { @@ -1135,14 +1133,14 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet double"); double x = (double) vh.get(array, i); - assertEquals(x, 1.0d, "success weakCompareAndSet double"); + assertEquals(1.0d, x, "success weakCompareAndSet double"); } { boolean success = vh.weakCompareAndSet(array, i, 2.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSet double"); double x = (double) vh.get(array, i); - assertEquals(x, 1.0d, "failing weakCompareAndSet double value"); + assertEquals(1.0d, x, "failing weakCompareAndSet double value"); } // Compare set and get @@ -1150,27 +1148,27 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { vh.set(array, i, 1.0d); double o = (double) vh.getAndSet(array, i, 2.0d); - assertEquals(o, 1.0d, "getAndSet double"); + assertEquals(1.0d, o, "getAndSet double"); double x = (double) vh.get(array, i); - assertEquals(x, 2.0d, "getAndSet double value"); + assertEquals(2.0d, x, "getAndSet double value"); } { vh.set(array, i, 1.0d); double o = (double) vh.getAndSetAcquire(array, i, 2.0d); - assertEquals(o, 1.0d, "getAndSetAcquire double"); + assertEquals(1.0d, o, "getAndSetAcquire double"); double x = (double) vh.get(array, i); - assertEquals(x, 2.0d, "getAndSetAcquire double value"); + assertEquals(2.0d, x, "getAndSetAcquire double value"); } { vh.set(array, i, 1.0d); double o = (double) vh.getAndSetRelease(array, i, 2.0d); - assertEquals(o, 1.0d, "getAndSetRelease double"); + assertEquals(1.0d, o, "getAndSetRelease double"); double x = (double) vh.get(array, i); - assertEquals(x, 2.0d, "getAndSetRelease double value"); + assertEquals(2.0d, x, "getAndSetRelease double value"); } // get and add, add and get @@ -1178,27 +1176,27 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { vh.set(array, i, 1.0d); double o = (double) vh.getAndAdd(array, i, 2.0d); - assertEquals(o, 1.0d, "getAndAdd double"); + assertEquals(1.0d, o, "getAndAdd double"); double x = (double) vh.get(array, i); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAdd double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAdd double value"); } { vh.set(array, i, 1.0d); double o = (double) vh.getAndAddAcquire(array, i, 2.0d); - assertEquals(o, 1.0d, "getAndAddAcquire double"); + assertEquals(1.0d, o, "getAndAddAcquire double"); double x = (double) vh.get(array, i); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAddAcquire double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAddAcquire double value"); } { vh.set(array, i, 1.0d); double o = (double) vh.getAndAddRelease(array, i, 2.0d); - assertEquals(o, 1.0d, "getAndAddReleasedouble"); + assertEquals(1.0d, o, "getAndAddReleasedouble"); double x = (double) vh.get(array, i); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAddRelease double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAddRelease double value"); } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java index c77a8d68008..750a1bbc408 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,28 +23,30 @@ /* * @test - * @run testng/othervm -Diters=10 -Xint VarHandleTestAccessFloat + * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessFloat * * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds * - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessFloat - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessFloat - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessFloat + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessFloat + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessFloat + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessFloat */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestAccessFloat extends VarHandleBaseTest { static final float static_final_v = 1.0f; @@ -108,7 +110,7 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { return vhs.toArray(new VarHandle[0]); } - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestAccessFloat.class, "final_v", float.class); @@ -125,8 +127,6 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(float[].class); } - - @DataProvider public Object[][] varHandlesProvider() throws Exception { List vhs = new ArrayList<>(); vhs.add(vhField); @@ -156,7 +156,8 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("varHandlesProvider") public void testIsAccessModeSupported(VarHandle vh) { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET)); @@ -194,8 +195,6 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE)); } - - @DataProvider public Object[][] typesProvider() throws Exception { List types = new ArrayList<>(); types.add(new Object[] {vhField, Arrays.asList(VarHandleTestAccessFloat.class)}); @@ -205,16 +204,16 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { return types.stream().toArray(Object[][]::new); } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), float.class); + assertEquals(float.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - @Test public void testLookupInstanceToStatic() { checkIAE("Lookup of static final field to instance final field", () -> { @@ -241,8 +240,6 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { }); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -284,7 +281,8 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -297,26 +295,26 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { // Plain { float x = (float) vh.get(recv); - assertEquals(x, 1.0f, "get float value"); + assertEquals(1.0f, x, "get float value"); } // Volatile { float x = (float) vh.getVolatile(recv); - assertEquals(x, 1.0f, "getVolatile float value"); + assertEquals(1.0f, x, "getVolatile float value"); } // Lazy { float x = (float) vh.getAcquire(recv); - assertEquals(x, 1.0f, "getRelease float value"); + assertEquals(1.0f, x, "getRelease float value"); } // Opaque { float x = (float) vh.getOpaque(recv); - assertEquals(x, 1.0f, "getOpaque float value"); + assertEquals(1.0f, x, "getOpaque float value"); } } @@ -381,26 +379,26 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { // Plain { float x = (float) vh.get(); - assertEquals(x, 1.0f, "get float value"); + assertEquals(1.0f, x, "get float value"); } // Volatile { float x = (float) vh.getVolatile(); - assertEquals(x, 1.0f, "getVolatile float value"); + assertEquals(1.0f, x, "getVolatile float value"); } // Lazy { float x = (float) vh.getAcquire(); - assertEquals(x, 1.0f, "getRelease float value"); + assertEquals(1.0f, x, "getRelease float value"); } // Opaque { float x = (float) vh.getOpaque(); - assertEquals(x, 1.0f, "getOpaque float value"); + assertEquals(1.0f, x, "getOpaque float value"); } } @@ -466,7 +464,7 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { { vh.set(recv, 1.0f); float x = (float) vh.get(recv); - assertEquals(x, 1.0f, "set float value"); + assertEquals(1.0f, x, "set float value"); } @@ -474,21 +472,21 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { { vh.setVolatile(recv, 2.0f); float x = (float) vh.getVolatile(recv); - assertEquals(x, 2.0f, "setVolatile float value"); + assertEquals(2.0f, x, "setVolatile float value"); } // Lazy { vh.setRelease(recv, 1.0f); float x = (float) vh.getAcquire(recv); - assertEquals(x, 1.0f, "setRelease float value"); + assertEquals(1.0f, x, "setRelease float value"); } // Opaque { vh.setOpaque(recv, 2.0f); float x = (float) vh.getOpaque(recv); - assertEquals(x, 2.0f, "setOpaque float value"); + assertEquals(2.0f, x, "setOpaque float value"); } vh.set(recv, 1.0f); @@ -498,56 +496,56 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { boolean r = vh.compareAndSet(recv, 1.0f, 2.0f); assertEquals(r, true, "success compareAndSet float"); float x = (float) vh.get(recv); - assertEquals(x, 2.0f, "success compareAndSet float value"); + assertEquals(2.0f, x, "success compareAndSet float value"); } { boolean r = vh.compareAndSet(recv, 1.0f, 3.0f); assertEquals(r, false, "failing compareAndSet float"); float x = (float) vh.get(recv); - assertEquals(x, 2.0f, "failing compareAndSet float value"); + assertEquals(2.0f, x, "failing compareAndSet float value"); } { float r = (float) vh.compareAndExchange(recv, 2.0f, 1.0f); assertEquals(r, 2.0f, "success compareAndExchange float"); float x = (float) vh.get(recv); - assertEquals(x, 1.0f, "success compareAndExchange float value"); + assertEquals(1.0f, x, "success compareAndExchange float value"); } { float r = (float) vh.compareAndExchange(recv, 2.0f, 3.0f); assertEquals(r, 1.0f, "failing compareAndExchange float"); float x = (float) vh.get(recv); - assertEquals(x, 1.0f, "failing compareAndExchange float value"); + assertEquals(1.0f, x, "failing compareAndExchange float value"); } { float r = (float) vh.compareAndExchangeAcquire(recv, 1.0f, 2.0f); assertEquals(r, 1.0f, "success compareAndExchangeAcquire float"); float x = (float) vh.get(recv); - assertEquals(x, 2.0f, "success compareAndExchangeAcquire float value"); + assertEquals(2.0f, x, "success compareAndExchangeAcquire float value"); } { float r = (float) vh.compareAndExchangeAcquire(recv, 1.0f, 3.0f); assertEquals(r, 2.0f, "failing compareAndExchangeAcquire float"); float x = (float) vh.get(recv); - assertEquals(x, 2.0f, "failing compareAndExchangeAcquire float value"); + assertEquals(2.0f, x, "failing compareAndExchangeAcquire float value"); } { float r = (float) vh.compareAndExchangeRelease(recv, 2.0f, 1.0f); assertEquals(r, 2.0f, "success compareAndExchangeRelease float"); float x = (float) vh.get(recv); - assertEquals(x, 1.0f, "success compareAndExchangeRelease float value"); + assertEquals(1.0f, x, "success compareAndExchangeRelease float value"); } { float r = (float) vh.compareAndExchangeRelease(recv, 2.0f, 3.0f); assertEquals(r, 1.0f, "failing compareAndExchangeRelease float"); float x = (float) vh.get(recv); - assertEquals(x, 1.0f, "failing compareAndExchangeRelease float value"); + assertEquals(1.0f, x, "failing compareAndExchangeRelease float value"); } { @@ -558,14 +556,14 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain float"); float x = (float) vh.get(recv); - assertEquals(x, 2.0f, "success weakCompareAndSetPlain float value"); + assertEquals(2.0f, x, "success weakCompareAndSetPlain float value"); } { boolean success = vh.weakCompareAndSetPlain(recv, 1.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetPlain float"); float x = (float) vh.get(recv); - assertEquals(x, 2.0f, "failing weakCompareAndSetPlain float value"); + assertEquals(2.0f, x, "failing weakCompareAndSetPlain float value"); } { @@ -576,14 +574,14 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire float"); float x = (float) vh.get(recv); - assertEquals(x, 1.0f, "success weakCompareAndSetAcquire float"); + assertEquals(1.0f, x, "success weakCompareAndSetAcquire float"); } { boolean success = vh.weakCompareAndSetAcquire(recv, 2.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetAcquire float"); float x = (float) vh.get(recv); - assertEquals(x, 1.0f, "failing weakCompareAndSetAcquire float value"); + assertEquals(1.0f, x, "failing weakCompareAndSetAcquire float value"); } { @@ -594,14 +592,14 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease float"); float x = (float) vh.get(recv); - assertEquals(x, 2.0f, "success weakCompareAndSetRelease float"); + assertEquals(2.0f, x, "success weakCompareAndSetRelease float"); } { boolean success = vh.weakCompareAndSetRelease(recv, 1.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetRelease float"); float x = (float) vh.get(recv); - assertEquals(x, 2.0f, "failing weakCompareAndSetRelease float value"); + assertEquals(2.0f, x, "failing weakCompareAndSetRelease float value"); } { @@ -612,14 +610,14 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet float"); float x = (float) vh.get(recv); - assertEquals(x, 1.0f, "success weakCompareAndSet float value"); + assertEquals(1.0f, x, "success weakCompareAndSet float value"); } { boolean success = vh.weakCompareAndSet(recv, 2.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSet float"); float x = (float) vh.get(recv); - assertEquals(x, 1.0f, "failing weakCompareAndSet float value"); + assertEquals(1.0f, x, "failing weakCompareAndSet float value"); } // Compare set and get @@ -627,27 +625,27 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { vh.set(recv, 1.0f); float o = (float) vh.getAndSet(recv, 2.0f); - assertEquals(o, 1.0f, "getAndSet float"); + assertEquals(1.0f, o, "getAndSet float"); float x = (float) vh.get(recv); - assertEquals(x, 2.0f, "getAndSet float value"); + assertEquals(2.0f, x, "getAndSet float value"); } { vh.set(recv, 1.0f); float o = (float) vh.getAndSetAcquire(recv, 2.0f); - assertEquals(o, 1.0f, "getAndSetAcquire float"); + assertEquals(1.0f, o, "getAndSetAcquire float"); float x = (float) vh.get(recv); - assertEquals(x, 2.0f, "getAndSetAcquire float value"); + assertEquals(2.0f, x, "getAndSetAcquire float value"); } { vh.set(recv, 1.0f); float o = (float) vh.getAndSetRelease(recv, 2.0f); - assertEquals(o, 1.0f, "getAndSetRelease float"); + assertEquals(1.0f, o, "getAndSetRelease float"); float x = (float) vh.get(recv); - assertEquals(x, 2.0f, "getAndSetRelease float value"); + assertEquals(2.0f, x, "getAndSetRelease float value"); } // get and add, add and get @@ -655,27 +653,27 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { vh.set(recv, 1.0f); float o = (float) vh.getAndAdd(recv, 2.0f); - assertEquals(o, 1.0f, "getAndAdd float"); + assertEquals(1.0f, o, "getAndAdd float"); float x = (float) vh.get(recv); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAdd float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAdd float value"); } { vh.set(recv, 1.0f); float o = (float) vh.getAndAddAcquire(recv, 2.0f); - assertEquals(o, 1.0f, "getAndAddAcquire float"); + assertEquals(1.0f, o, "getAndAddAcquire float"); float x = (float) vh.get(recv); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAddAcquire float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAddAcquire float value"); } { vh.set(recv, 1.0f); float o = (float) vh.getAndAddRelease(recv, 2.0f); - assertEquals(o, 1.0f, "getAndAddReleasefloat"); + assertEquals(1.0f, o, "getAndAddReleasefloat"); float x = (float) vh.get(recv); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAddRelease float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAddRelease float value"); } } @@ -726,7 +724,7 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { { vh.set(1.0f); float x = (float) vh.get(); - assertEquals(x, 1.0f, "set float value"); + assertEquals(1.0f, x, "set float value"); } @@ -734,21 +732,21 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { { vh.setVolatile(2.0f); float x = (float) vh.getVolatile(); - assertEquals(x, 2.0f, "setVolatile float value"); + assertEquals(2.0f, x, "setVolatile float value"); } // Lazy { vh.setRelease(1.0f); float x = (float) vh.getAcquire(); - assertEquals(x, 1.0f, "setRelease float value"); + assertEquals(1.0f, x, "setRelease float value"); } // Opaque { vh.setOpaque(2.0f); float x = (float) vh.getOpaque(); - assertEquals(x, 2.0f, "setOpaque float value"); + assertEquals(2.0f, x, "setOpaque float value"); } vh.set(1.0f); @@ -758,56 +756,56 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { boolean r = vh.compareAndSet(1.0f, 2.0f); assertEquals(r, true, "success compareAndSet float"); float x = (float) vh.get(); - assertEquals(x, 2.0f, "success compareAndSet float value"); + assertEquals(2.0f, x, "success compareAndSet float value"); } { boolean r = vh.compareAndSet(1.0f, 3.0f); assertEquals(r, false, "failing compareAndSet float"); float x = (float) vh.get(); - assertEquals(x, 2.0f, "failing compareAndSet float value"); + assertEquals(2.0f, x, "failing compareAndSet float value"); } { float r = (float) vh.compareAndExchange(2.0f, 1.0f); assertEquals(r, 2.0f, "success compareAndExchange float"); float x = (float) vh.get(); - assertEquals(x, 1.0f, "success compareAndExchange float value"); + assertEquals(1.0f, x, "success compareAndExchange float value"); } { float r = (float) vh.compareAndExchange(2.0f, 3.0f); assertEquals(r, 1.0f, "failing compareAndExchange float"); float x = (float) vh.get(); - assertEquals(x, 1.0f, "failing compareAndExchange float value"); + assertEquals(1.0f, x, "failing compareAndExchange float value"); } { float r = (float) vh.compareAndExchangeAcquire(1.0f, 2.0f); assertEquals(r, 1.0f, "success compareAndExchangeAcquire float"); float x = (float) vh.get(); - assertEquals(x, 2.0f, "success compareAndExchangeAcquire float value"); + assertEquals(2.0f, x, "success compareAndExchangeAcquire float value"); } { float r = (float) vh.compareAndExchangeAcquire(1.0f, 3.0f); assertEquals(r, 2.0f, "failing compareAndExchangeAcquire float"); float x = (float) vh.get(); - assertEquals(x, 2.0f, "failing compareAndExchangeAcquire float value"); + assertEquals(2.0f, x, "failing compareAndExchangeAcquire float value"); } { float r = (float) vh.compareAndExchangeRelease(2.0f, 1.0f); assertEquals(r, 2.0f, "success compareAndExchangeRelease float"); float x = (float) vh.get(); - assertEquals(x, 1.0f, "success compareAndExchangeRelease float value"); + assertEquals(1.0f, x, "success compareAndExchangeRelease float value"); } { float r = (float) vh.compareAndExchangeRelease(2.0f, 3.0f); assertEquals(r, 1.0f, "failing compareAndExchangeRelease float"); float x = (float) vh.get(); - assertEquals(x, 1.0f, "failing compareAndExchangeRelease float value"); + assertEquals(1.0f, x, "failing compareAndExchangeRelease float value"); } { @@ -818,14 +816,14 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain float"); float x = (float) vh.get(); - assertEquals(x, 2.0f, "success weakCompareAndSetPlain float value"); + assertEquals(2.0f, x, "success weakCompareAndSetPlain float value"); } { boolean success = vh.weakCompareAndSetPlain(1.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetPlain float"); float x = (float) vh.get(); - assertEquals(x, 2.0f, "failing weakCompareAndSetPlain float value"); + assertEquals(2.0f, x, "failing weakCompareAndSetPlain float value"); } { @@ -836,14 +834,14 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire float"); float x = (float) vh.get(); - assertEquals(x, 1.0f, "success weakCompareAndSetAcquire float"); + assertEquals(1.0f, x, "success weakCompareAndSetAcquire float"); } { boolean success = vh.weakCompareAndSetAcquire(2.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetAcquire float"); float x = (float) vh.get(); - assertEquals(x, 1.0f, "failing weakCompareAndSetAcquire float value"); + assertEquals(1.0f, x, "failing weakCompareAndSetAcquire float value"); } { @@ -854,14 +852,14 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease float"); float x = (float) vh.get(); - assertEquals(x, 2.0f, "success weakCompareAndSetRelease float"); + assertEquals(2.0f, x, "success weakCompareAndSetRelease float"); } { boolean success = vh.weakCompareAndSetRelease(1.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetRelease float"); float x = (float) vh.get(); - assertEquals(x, 2.0f, "failing weakCompareAndSetRelease float value"); + assertEquals(2.0f, x, "failing weakCompareAndSetRelease float value"); } { @@ -872,14 +870,14 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet float"); float x = (float) vh.get(); - assertEquals(x, 1.0f, "success weakCompareAndSet float"); + assertEquals(1.0f, x, "success weakCompareAndSet float"); } { boolean success = vh.weakCompareAndSet(2.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSet float"); float x = (float) vh.get(); - assertEquals(x, 1.0f, "failing weakCompareAndSet float value"); + assertEquals(1.0f, x, "failing weakCompareAndSet float value"); } // Compare set and get @@ -887,27 +885,27 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { vh.set(1.0f); float o = (float) vh.getAndSet(2.0f); - assertEquals(o, 1.0f, "getAndSet float"); + assertEquals(1.0f, o, "getAndSet float"); float x = (float) vh.get(); - assertEquals(x, 2.0f, "getAndSet float value"); + assertEquals(2.0f, x, "getAndSet float value"); } { vh.set(1.0f); float o = (float) vh.getAndSetAcquire(2.0f); - assertEquals(o, 1.0f, "getAndSetAcquire float"); + assertEquals(1.0f, o, "getAndSetAcquire float"); float x = (float) vh.get(); - assertEquals(x, 2.0f, "getAndSetAcquire float value"); + assertEquals(2.0f, x, "getAndSetAcquire float value"); } { vh.set(1.0f); float o = (float) vh.getAndSetRelease(2.0f); - assertEquals(o, 1.0f, "getAndSetRelease float"); + assertEquals(1.0f, o, "getAndSetRelease float"); float x = (float) vh.get(); - assertEquals(x, 2.0f, "getAndSetRelease float value"); + assertEquals(2.0f, x, "getAndSetRelease float value"); } // get and add, add and get @@ -915,27 +913,27 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { vh.set(1.0f); float o = (float) vh.getAndAdd(2.0f); - assertEquals(o, 1.0f, "getAndAdd float"); + assertEquals(1.0f, o, "getAndAdd float"); float x = (float) vh.get(); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAdd float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAdd float value"); } { vh.set(1.0f); float o = (float) vh.getAndAddAcquire(2.0f); - assertEquals(o, 1.0f, "getAndAddAcquire float"); + assertEquals(1.0f, o, "getAndAddAcquire float"); float x = (float) vh.get(); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAddAcquire float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAddAcquire float value"); } { vh.set(1.0f); float o = (float) vh.getAndAddRelease(2.0f); - assertEquals(o, 1.0f, "getAndAddReleasefloat"); + assertEquals(1.0f, o, "getAndAddReleasefloat"); float x = (float) vh.get(); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAddRelease float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAddRelease float value"); } } @@ -989,7 +987,7 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { { vh.set(array, i, 1.0f); float x = (float) vh.get(array, i); - assertEquals(x, 1.0f, "get float value"); + assertEquals(1.0f, x, "get float value"); } @@ -997,21 +995,21 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { { vh.setVolatile(array, i, 2.0f); float x = (float) vh.getVolatile(array, i); - assertEquals(x, 2.0f, "setVolatile float value"); + assertEquals(2.0f, x, "setVolatile float value"); } // Lazy { vh.setRelease(array, i, 1.0f); float x = (float) vh.getAcquire(array, i); - assertEquals(x, 1.0f, "setRelease float value"); + assertEquals(1.0f, x, "setRelease float value"); } // Opaque { vh.setOpaque(array, i, 2.0f); float x = (float) vh.getOpaque(array, i); - assertEquals(x, 2.0f, "setOpaque float value"); + assertEquals(2.0f, x, "setOpaque float value"); } vh.set(array, i, 1.0f); @@ -1021,56 +1019,56 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { boolean r = vh.compareAndSet(array, i, 1.0f, 2.0f); assertEquals(r, true, "success compareAndSet float"); float x = (float) vh.get(array, i); - assertEquals(x, 2.0f, "success compareAndSet float value"); + assertEquals(2.0f, x, "success compareAndSet float value"); } { boolean r = vh.compareAndSet(array, i, 1.0f, 3.0f); assertEquals(r, false, "failing compareAndSet float"); float x = (float) vh.get(array, i); - assertEquals(x, 2.0f, "failing compareAndSet float value"); + assertEquals(2.0f, x, "failing compareAndSet float value"); } { float r = (float) vh.compareAndExchange(array, i, 2.0f, 1.0f); assertEquals(r, 2.0f, "success compareAndExchange float"); float x = (float) vh.get(array, i); - assertEquals(x, 1.0f, "success compareAndExchange float value"); + assertEquals(1.0f, x, "success compareAndExchange float value"); } { float r = (float) vh.compareAndExchange(array, i, 2.0f, 3.0f); assertEquals(r, 1.0f, "failing compareAndExchange float"); float x = (float) vh.get(array, i); - assertEquals(x, 1.0f, "failing compareAndExchange float value"); + assertEquals(1.0f, x, "failing compareAndExchange float value"); } { float r = (float) vh.compareAndExchangeAcquire(array, i, 1.0f, 2.0f); assertEquals(r, 1.0f, "success compareAndExchangeAcquire float"); float x = (float) vh.get(array, i); - assertEquals(x, 2.0f, "success compareAndExchangeAcquire float value"); + assertEquals(2.0f, x, "success compareAndExchangeAcquire float value"); } { float r = (float) vh.compareAndExchangeAcquire(array, i, 1.0f, 3.0f); assertEquals(r, 2.0f, "failing compareAndExchangeAcquire float"); float x = (float) vh.get(array, i); - assertEquals(x, 2.0f, "failing compareAndExchangeAcquire float value"); + assertEquals(2.0f, x, "failing compareAndExchangeAcquire float value"); } { float r = (float) vh.compareAndExchangeRelease(array, i, 2.0f, 1.0f); assertEquals(r, 2.0f, "success compareAndExchangeRelease float"); float x = (float) vh.get(array, i); - assertEquals(x, 1.0f, "success compareAndExchangeRelease float value"); + assertEquals(1.0f, x, "success compareAndExchangeRelease float value"); } { float r = (float) vh.compareAndExchangeRelease(array, i, 2.0f, 3.0f); assertEquals(r, 1.0f, "failing compareAndExchangeRelease float"); float x = (float) vh.get(array, i); - assertEquals(x, 1.0f, "failing compareAndExchangeRelease float value"); + assertEquals(1.0f, x, "failing compareAndExchangeRelease float value"); } { @@ -1081,14 +1079,14 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain float"); float x = (float) vh.get(array, i); - assertEquals(x, 2.0f, "success weakCompareAndSetPlain float value"); + assertEquals(2.0f, x, "success weakCompareAndSetPlain float value"); } { boolean success = vh.weakCompareAndSetPlain(array, i, 1.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetPlain float"); float x = (float) vh.get(array, i); - assertEquals(x, 2.0f, "failing weakCompareAndSetPlain float value"); + assertEquals(2.0f, x, "failing weakCompareAndSetPlain float value"); } { @@ -1099,14 +1097,14 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire float"); float x = (float) vh.get(array, i); - assertEquals(x, 1.0f, "success weakCompareAndSetAcquire float"); + assertEquals(1.0f, x, "success weakCompareAndSetAcquire float"); } { boolean success = vh.weakCompareAndSetAcquire(array, i, 2.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetAcquire float"); float x = (float) vh.get(array, i); - assertEquals(x, 1.0f, "failing weakCompareAndSetAcquire float value"); + assertEquals(1.0f, x, "failing weakCompareAndSetAcquire float value"); } { @@ -1117,14 +1115,14 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease float"); float x = (float) vh.get(array, i); - assertEquals(x, 2.0f, "success weakCompareAndSetRelease float"); + assertEquals(2.0f, x, "success weakCompareAndSetRelease float"); } { boolean success = vh.weakCompareAndSetRelease(array, i, 1.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetRelease float"); float x = (float) vh.get(array, i); - assertEquals(x, 2.0f, "failing weakCompareAndSetRelease float value"); + assertEquals(2.0f, x, "failing weakCompareAndSetRelease float value"); } { @@ -1135,14 +1133,14 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet float"); float x = (float) vh.get(array, i); - assertEquals(x, 1.0f, "success weakCompareAndSet float"); + assertEquals(1.0f, x, "success weakCompareAndSet float"); } { boolean success = vh.weakCompareAndSet(array, i, 2.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSet float"); float x = (float) vh.get(array, i); - assertEquals(x, 1.0f, "failing weakCompareAndSet float value"); + assertEquals(1.0f, x, "failing weakCompareAndSet float value"); } // Compare set and get @@ -1150,27 +1148,27 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { vh.set(array, i, 1.0f); float o = (float) vh.getAndSet(array, i, 2.0f); - assertEquals(o, 1.0f, "getAndSet float"); + assertEquals(1.0f, o, "getAndSet float"); float x = (float) vh.get(array, i); - assertEquals(x, 2.0f, "getAndSet float value"); + assertEquals(2.0f, x, "getAndSet float value"); } { vh.set(array, i, 1.0f); float o = (float) vh.getAndSetAcquire(array, i, 2.0f); - assertEquals(o, 1.0f, "getAndSetAcquire float"); + assertEquals(1.0f, o, "getAndSetAcquire float"); float x = (float) vh.get(array, i); - assertEquals(x, 2.0f, "getAndSetAcquire float value"); + assertEquals(2.0f, x, "getAndSetAcquire float value"); } { vh.set(array, i, 1.0f); float o = (float) vh.getAndSetRelease(array, i, 2.0f); - assertEquals(o, 1.0f, "getAndSetRelease float"); + assertEquals(1.0f, o, "getAndSetRelease float"); float x = (float) vh.get(array, i); - assertEquals(x, 2.0f, "getAndSetRelease float value"); + assertEquals(2.0f, x, "getAndSetRelease float value"); } // get and add, add and get @@ -1178,27 +1176,27 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { vh.set(array, i, 1.0f); float o = (float) vh.getAndAdd(array, i, 2.0f); - assertEquals(o, 1.0f, "getAndAdd float"); + assertEquals(1.0f, o, "getAndAdd float"); float x = (float) vh.get(array, i); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAdd float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAdd float value"); } { vh.set(array, i, 1.0f); float o = (float) vh.getAndAddAcquire(array, i, 2.0f); - assertEquals(o, 1.0f, "getAndAddAcquire float"); + assertEquals(1.0f, o, "getAndAddAcquire float"); float x = (float) vh.get(array, i); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAddAcquire float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAddAcquire float value"); } { vh.set(array, i, 1.0f); float o = (float) vh.getAndAddRelease(array, i, 2.0f); - assertEquals(o, 1.0f, "getAndAddReleasefloat"); + assertEquals(1.0f, o, "getAndAddReleasefloat"); float x = (float) vh.get(array, i); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAddRelease float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAddRelease float value"); } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java index d5dfaa4e1c6..4748d699555 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,28 +23,30 @@ /* * @test - * @run testng/othervm -Diters=10 -Xint VarHandleTestAccessInt + * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessInt * * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds * - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessInt - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessInt - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessInt + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessInt + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessInt + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessInt */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestAccessInt extends VarHandleBaseTest { static final int static_final_v = 0x01234567; @@ -108,7 +110,7 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { return vhs.toArray(new VarHandle[0]); } - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestAccessInt.class, "final_v", int.class); @@ -125,8 +127,6 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(int[].class); } - - @DataProvider public Object[][] varHandlesProvider() throws Exception { List vhs = new ArrayList<>(); vhs.add(vhField); @@ -156,7 +156,8 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("varHandlesProvider") public void testIsAccessModeSupported(VarHandle vh) { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET)); @@ -194,8 +195,6 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE)); } - - @DataProvider public Object[][] typesProvider() throws Exception { List types = new ArrayList<>(); types.add(new Object[] {vhField, Arrays.asList(VarHandleTestAccessInt.class)}); @@ -205,16 +204,16 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { return types.stream().toArray(Object[][]::new); } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), int.class); + assertEquals(int.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - @Test public void testLookupInstanceToStatic() { checkIAE("Lookup of static final field to instance final field", () -> { @@ -241,8 +240,6 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { }); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -284,7 +281,8 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -297,26 +295,26 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { // Plain { int x = (int) vh.get(recv); - assertEquals(x, 0x01234567, "get int value"); + assertEquals(0x01234567, x, "get int value"); } // Volatile { int x = (int) vh.getVolatile(recv); - assertEquals(x, 0x01234567, "getVolatile int value"); + assertEquals(0x01234567, x, "getVolatile int value"); } // Lazy { int x = (int) vh.getAcquire(recv); - assertEquals(x, 0x01234567, "getRelease int value"); + assertEquals(0x01234567, x, "getRelease int value"); } // Opaque { int x = (int) vh.getOpaque(recv); - assertEquals(x, 0x01234567, "getOpaque int value"); + assertEquals(0x01234567, x, "getOpaque int value"); } } @@ -346,26 +344,26 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { // Plain { int x = (int) vh.get(); - assertEquals(x, 0x01234567, "get int value"); + assertEquals(0x01234567, x, "get int value"); } // Volatile { int x = (int) vh.getVolatile(); - assertEquals(x, 0x01234567, "getVolatile int value"); + assertEquals(0x01234567, x, "getVolatile int value"); } // Lazy { int x = (int) vh.getAcquire(); - assertEquals(x, 0x01234567, "getRelease int value"); + assertEquals(0x01234567, x, "getRelease int value"); } // Opaque { int x = (int) vh.getOpaque(); - assertEquals(x, 0x01234567, "getOpaque int value"); + assertEquals(0x01234567, x, "getOpaque int value"); } } @@ -396,7 +394,7 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { { vh.set(recv, 0x01234567); int x = (int) vh.get(recv); - assertEquals(x, 0x01234567, "set int value"); + assertEquals(0x01234567, x, "set int value"); } @@ -404,21 +402,21 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { { vh.setVolatile(recv, 0x89ABCDEF); int x = (int) vh.getVolatile(recv); - assertEquals(x, 0x89ABCDEF, "setVolatile int value"); + assertEquals(0x89ABCDEF, x, "setVolatile int value"); } // Lazy { vh.setRelease(recv, 0x01234567); int x = (int) vh.getAcquire(recv); - assertEquals(x, 0x01234567, "setRelease int value"); + assertEquals(0x01234567, x, "setRelease int value"); } // Opaque { vh.setOpaque(recv, 0x89ABCDEF); int x = (int) vh.getOpaque(recv); - assertEquals(x, 0x89ABCDEF, "setOpaque int value"); + assertEquals(0x89ABCDEF, x, "setOpaque int value"); } vh.set(recv, 0x01234567); @@ -428,56 +426,56 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { boolean r = vh.compareAndSet(recv, 0x01234567, 0x89ABCDEF); assertEquals(r, true, "success compareAndSet int"); int x = (int) vh.get(recv); - assertEquals(x, 0x89ABCDEF, "success compareAndSet int value"); + assertEquals(0x89ABCDEF, x, "success compareAndSet int value"); } { boolean r = vh.compareAndSet(recv, 0x01234567, 0xCAFEBABE); assertEquals(r, false, "failing compareAndSet int"); int x = (int) vh.get(recv); - assertEquals(x, 0x89ABCDEF, "failing compareAndSet int value"); + assertEquals(0x89ABCDEF, x, "failing compareAndSet int value"); } { int r = (int) vh.compareAndExchange(recv, 0x89ABCDEF, 0x01234567); assertEquals(r, 0x89ABCDEF, "success compareAndExchange int"); int x = (int) vh.get(recv); - assertEquals(x, 0x01234567, "success compareAndExchange int value"); + assertEquals(0x01234567, x, "success compareAndExchange int value"); } { int r = (int) vh.compareAndExchange(recv, 0x89ABCDEF, 0xCAFEBABE); assertEquals(r, 0x01234567, "failing compareAndExchange int"); int x = (int) vh.get(recv); - assertEquals(x, 0x01234567, "failing compareAndExchange int value"); + assertEquals(0x01234567, x, "failing compareAndExchange int value"); } { int r = (int) vh.compareAndExchangeAcquire(recv, 0x01234567, 0x89ABCDEF); assertEquals(r, 0x01234567, "success compareAndExchangeAcquire int"); int x = (int) vh.get(recv); - assertEquals(x, 0x89ABCDEF, "success compareAndExchangeAcquire int value"); + assertEquals(0x89ABCDEF, x, "success compareAndExchangeAcquire int value"); } { int r = (int) vh.compareAndExchangeAcquire(recv, 0x01234567, 0xCAFEBABE); assertEquals(r, 0x89ABCDEF, "failing compareAndExchangeAcquire int"); int x = (int) vh.get(recv); - assertEquals(x, 0x89ABCDEF, "failing compareAndExchangeAcquire int value"); + assertEquals(0x89ABCDEF, x, "failing compareAndExchangeAcquire int value"); } { int r = (int) vh.compareAndExchangeRelease(recv, 0x89ABCDEF, 0x01234567); assertEquals(r, 0x89ABCDEF, "success compareAndExchangeRelease int"); int x = (int) vh.get(recv); - assertEquals(x, 0x01234567, "success compareAndExchangeRelease int value"); + assertEquals(0x01234567, x, "success compareAndExchangeRelease int value"); } { int r = (int) vh.compareAndExchangeRelease(recv, 0x89ABCDEF, 0xCAFEBABE); assertEquals(r, 0x01234567, "failing compareAndExchangeRelease int"); int x = (int) vh.get(recv); - assertEquals(x, 0x01234567, "failing compareAndExchangeRelease int value"); + assertEquals(0x01234567, x, "failing compareAndExchangeRelease int value"); } { @@ -488,14 +486,14 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain int"); int x = (int) vh.get(recv); - assertEquals(x, 0x89ABCDEF, "success weakCompareAndSetPlain int value"); + assertEquals(0x89ABCDEF, x, "success weakCompareAndSetPlain int value"); } { boolean success = vh.weakCompareAndSetPlain(recv, 0x01234567, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetPlain int"); int x = (int) vh.get(recv); - assertEquals(x, 0x89ABCDEF, "failing weakCompareAndSetPlain int value"); + assertEquals(0x89ABCDEF, x, "failing weakCompareAndSetPlain int value"); } { @@ -506,14 +504,14 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire int"); int x = (int) vh.get(recv); - assertEquals(x, 0x01234567, "success weakCompareAndSetAcquire int"); + assertEquals(0x01234567, x, "success weakCompareAndSetAcquire int"); } { boolean success = vh.weakCompareAndSetAcquire(recv, 0x89ABCDEF, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetAcquire int"); int x = (int) vh.get(recv); - assertEquals(x, 0x01234567, "failing weakCompareAndSetAcquire int value"); + assertEquals(0x01234567, x, "failing weakCompareAndSetAcquire int value"); } { @@ -524,14 +522,14 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease int"); int x = (int) vh.get(recv); - assertEquals(x, 0x89ABCDEF, "success weakCompareAndSetRelease int"); + assertEquals(0x89ABCDEF, x, "success weakCompareAndSetRelease int"); } { boolean success = vh.weakCompareAndSetRelease(recv, 0x01234567, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetRelease int"); int x = (int) vh.get(recv); - assertEquals(x, 0x89ABCDEF, "failing weakCompareAndSetRelease int value"); + assertEquals(0x89ABCDEF, x, "failing weakCompareAndSetRelease int value"); } { @@ -542,14 +540,14 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet int"); int x = (int) vh.get(recv); - assertEquals(x, 0x01234567, "success weakCompareAndSet int value"); + assertEquals(0x01234567, x, "success weakCompareAndSet int value"); } { boolean success = vh.weakCompareAndSet(recv, 0x89ABCDEF, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSet int"); int x = (int) vh.get(recv); - assertEquals(x, 0x01234567, "failing weakCompareAndSet int value"); + assertEquals(0x01234567, x, "failing weakCompareAndSet int value"); } // Compare set and get @@ -557,27 +555,27 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { vh.set(recv, 0x01234567); int o = (int) vh.getAndSet(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndSet int"); + assertEquals(0x01234567, o, "getAndSet int"); int x = (int) vh.get(recv); - assertEquals(x, 0x89ABCDEF, "getAndSet int value"); + assertEquals(0x89ABCDEF, x, "getAndSet int value"); } { vh.set(recv, 0x01234567); int o = (int) vh.getAndSetAcquire(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndSetAcquire int"); + assertEquals(0x01234567, o, "getAndSetAcquire int"); int x = (int) vh.get(recv); - assertEquals(x, 0x89ABCDEF, "getAndSetAcquire int value"); + assertEquals(0x89ABCDEF, x, "getAndSetAcquire int value"); } { vh.set(recv, 0x01234567); int o = (int) vh.getAndSetRelease(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndSetRelease int"); + assertEquals(0x01234567, o, "getAndSetRelease int"); int x = (int) vh.get(recv); - assertEquals(x, 0x89ABCDEF, "getAndSetRelease int value"); + assertEquals(0x89ABCDEF, x, "getAndSetRelease int value"); } // get and add, add and get @@ -585,27 +583,27 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { vh.set(recv, 0x01234567); int o = (int) vh.getAndAdd(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAdd int"); + assertEquals(0x01234567, o, "getAndAdd int"); int x = (int) vh.get(recv); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAdd int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAdd int value"); } { vh.set(recv, 0x01234567); int o = (int) vh.getAndAddAcquire(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAddAcquire int"); + assertEquals(0x01234567, o, "getAndAddAcquire int"); int x = (int) vh.get(recv); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAddAcquire int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAddAcquire int value"); } { vh.set(recv, 0x01234567); int o = (int) vh.getAndAddRelease(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAddReleaseint"); + assertEquals(0x01234567, o, "getAndAddReleaseint"); int x = (int) vh.get(recv); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAddRelease int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAddRelease int value"); } // get and bitwise or @@ -613,27 +611,27 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { vh.set(recv, 0x01234567); int o = (int) vh.getAndBitwiseOr(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOr int"); + assertEquals(0x01234567, o, "getAndBitwiseOr int"); int x = (int) vh.get(recv); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOr int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOr int value"); } { vh.set(recv, 0x01234567); int o = (int) vh.getAndBitwiseOrAcquire(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOrAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseOrAcquire int"); int x = (int) vh.get(recv); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOrAcquire int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOrAcquire int value"); } { vh.set(recv, 0x01234567); int o = (int) vh.getAndBitwiseOrRelease(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOrRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseOrRelease int"); int x = (int) vh.get(recv); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOrRelease int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOrRelease int value"); } // get and bitwise and @@ -641,27 +639,27 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { vh.set(recv, 0x01234567); int o = (int) vh.getAndBitwiseAnd(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAnd int"); + assertEquals(0x01234567, o, "getAndBitwiseAnd int"); int x = (int) vh.get(recv); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAnd int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAnd int value"); } { vh.set(recv, 0x01234567); int o = (int) vh.getAndBitwiseAndAcquire(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAndAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseAndAcquire int"); int x = (int) vh.get(recv); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAndAcquire int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAndAcquire int value"); } { vh.set(recv, 0x01234567); int o = (int) vh.getAndBitwiseAndRelease(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAndRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseAndRelease int"); int x = (int) vh.get(recv); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAndRelease int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAndRelease int value"); } // get and bitwise xor @@ -669,27 +667,27 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { vh.set(recv, 0x01234567); int o = (int) vh.getAndBitwiseXor(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXor int"); + assertEquals(0x01234567, o, "getAndBitwiseXor int"); int x = (int) vh.get(recv); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXor int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXor int value"); } { vh.set(recv, 0x01234567); int o = (int) vh.getAndBitwiseXorAcquire(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXorAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseXorAcquire int"); int x = (int) vh.get(recv); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXorAcquire int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXorAcquire int value"); } { vh.set(recv, 0x01234567); int o = (int) vh.getAndBitwiseXorRelease(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXorRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseXorRelease int"); int x = (int) vh.get(recv); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXorRelease int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXorRelease int value"); } } @@ -704,7 +702,7 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { { vh.set(0x01234567); int x = (int) vh.get(); - assertEquals(x, 0x01234567, "set int value"); + assertEquals(0x01234567, x, "set int value"); } @@ -712,21 +710,21 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { { vh.setVolatile(0x89ABCDEF); int x = (int) vh.getVolatile(); - assertEquals(x, 0x89ABCDEF, "setVolatile int value"); + assertEquals(0x89ABCDEF, x, "setVolatile int value"); } // Lazy { vh.setRelease(0x01234567); int x = (int) vh.getAcquire(); - assertEquals(x, 0x01234567, "setRelease int value"); + assertEquals(0x01234567, x, "setRelease int value"); } // Opaque { vh.setOpaque(0x89ABCDEF); int x = (int) vh.getOpaque(); - assertEquals(x, 0x89ABCDEF, "setOpaque int value"); + assertEquals(0x89ABCDEF, x, "setOpaque int value"); } vh.set(0x01234567); @@ -736,56 +734,56 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { boolean r = vh.compareAndSet(0x01234567, 0x89ABCDEF); assertEquals(r, true, "success compareAndSet int"); int x = (int) vh.get(); - assertEquals(x, 0x89ABCDEF, "success compareAndSet int value"); + assertEquals(0x89ABCDEF, x, "success compareAndSet int value"); } { boolean r = vh.compareAndSet(0x01234567, 0xCAFEBABE); assertEquals(r, false, "failing compareAndSet int"); int x = (int) vh.get(); - assertEquals(x, 0x89ABCDEF, "failing compareAndSet int value"); + assertEquals(0x89ABCDEF, x, "failing compareAndSet int value"); } { int r = (int) vh.compareAndExchange(0x89ABCDEF, 0x01234567); assertEquals(r, 0x89ABCDEF, "success compareAndExchange int"); int x = (int) vh.get(); - assertEquals(x, 0x01234567, "success compareAndExchange int value"); + assertEquals(0x01234567, x, "success compareAndExchange int value"); } { int r = (int) vh.compareAndExchange(0x89ABCDEF, 0xCAFEBABE); assertEquals(r, 0x01234567, "failing compareAndExchange int"); int x = (int) vh.get(); - assertEquals(x, 0x01234567, "failing compareAndExchange int value"); + assertEquals(0x01234567, x, "failing compareAndExchange int value"); } { int r = (int) vh.compareAndExchangeAcquire(0x01234567, 0x89ABCDEF); assertEquals(r, 0x01234567, "success compareAndExchangeAcquire int"); int x = (int) vh.get(); - assertEquals(x, 0x89ABCDEF, "success compareAndExchangeAcquire int value"); + assertEquals(0x89ABCDEF, x, "success compareAndExchangeAcquire int value"); } { int r = (int) vh.compareAndExchangeAcquire(0x01234567, 0xCAFEBABE); assertEquals(r, 0x89ABCDEF, "failing compareAndExchangeAcquire int"); int x = (int) vh.get(); - assertEquals(x, 0x89ABCDEF, "failing compareAndExchangeAcquire int value"); + assertEquals(0x89ABCDEF, x, "failing compareAndExchangeAcquire int value"); } { int r = (int) vh.compareAndExchangeRelease(0x89ABCDEF, 0x01234567); assertEquals(r, 0x89ABCDEF, "success compareAndExchangeRelease int"); int x = (int) vh.get(); - assertEquals(x, 0x01234567, "success compareAndExchangeRelease int value"); + assertEquals(0x01234567, x, "success compareAndExchangeRelease int value"); } { int r = (int) vh.compareAndExchangeRelease(0x89ABCDEF, 0xCAFEBABE); assertEquals(r, 0x01234567, "failing compareAndExchangeRelease int"); int x = (int) vh.get(); - assertEquals(x, 0x01234567, "failing compareAndExchangeRelease int value"); + assertEquals(0x01234567, x, "failing compareAndExchangeRelease int value"); } { @@ -796,14 +794,14 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain int"); int x = (int) vh.get(); - assertEquals(x, 0x89ABCDEF, "success weakCompareAndSetPlain int value"); + assertEquals(0x89ABCDEF, x, "success weakCompareAndSetPlain int value"); } { boolean success = vh.weakCompareAndSetPlain(0x01234567, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetPlain int"); int x = (int) vh.get(); - assertEquals(x, 0x89ABCDEF, "failing weakCompareAndSetPlain int value"); + assertEquals(0x89ABCDEF, x, "failing weakCompareAndSetPlain int value"); } { @@ -814,14 +812,14 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire int"); int x = (int) vh.get(); - assertEquals(x, 0x01234567, "success weakCompareAndSetAcquire int"); + assertEquals(0x01234567, x, "success weakCompareAndSetAcquire int"); } { boolean success = vh.weakCompareAndSetAcquire(0x89ABCDEF, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetAcquire int"); int x = (int) vh.get(); - assertEquals(x, 0x01234567, "failing weakCompareAndSetAcquire int value"); + assertEquals(0x01234567, x, "failing weakCompareAndSetAcquire int value"); } { @@ -832,14 +830,14 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease int"); int x = (int) vh.get(); - assertEquals(x, 0x89ABCDEF, "success weakCompareAndSetRelease int"); + assertEquals(0x89ABCDEF, x, "success weakCompareAndSetRelease int"); } { boolean success = vh.weakCompareAndSetRelease(0x01234567, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetRelease int"); int x = (int) vh.get(); - assertEquals(x, 0x89ABCDEF, "failing weakCompareAndSetRelease int value"); + assertEquals(0x89ABCDEF, x, "failing weakCompareAndSetRelease int value"); } { @@ -850,14 +848,14 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet int"); int x = (int) vh.get(); - assertEquals(x, 0x01234567, "success weakCompareAndSet int"); + assertEquals(0x01234567, x, "success weakCompareAndSet int"); } { boolean success = vh.weakCompareAndSet(0x89ABCDEF, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSet int"); int x = (int) vh.get(); - assertEquals(x, 0x01234567, "failing weakCompareAndSet int value"); + assertEquals(0x01234567, x, "failing weakCompareAndSet int value"); } // Compare set and get @@ -865,27 +863,27 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { vh.set(0x01234567); int o = (int) vh.getAndSet(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndSet int"); + assertEquals(0x01234567, o, "getAndSet int"); int x = (int) vh.get(); - assertEquals(x, 0x89ABCDEF, "getAndSet int value"); + assertEquals(0x89ABCDEF, x, "getAndSet int value"); } { vh.set(0x01234567); int o = (int) vh.getAndSetAcquire(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndSetAcquire int"); + assertEquals(0x01234567, o, "getAndSetAcquire int"); int x = (int) vh.get(); - assertEquals(x, 0x89ABCDEF, "getAndSetAcquire int value"); + assertEquals(0x89ABCDEF, x, "getAndSetAcquire int value"); } { vh.set(0x01234567); int o = (int) vh.getAndSetRelease(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndSetRelease int"); + assertEquals(0x01234567, o, "getAndSetRelease int"); int x = (int) vh.get(); - assertEquals(x, 0x89ABCDEF, "getAndSetRelease int value"); + assertEquals(0x89ABCDEF, x, "getAndSetRelease int value"); } // get and add, add and get @@ -893,27 +891,27 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { vh.set(0x01234567); int o = (int) vh.getAndAdd(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAdd int"); + assertEquals(0x01234567, o, "getAndAdd int"); int x = (int) vh.get(); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAdd int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAdd int value"); } { vh.set(0x01234567); int o = (int) vh.getAndAddAcquire(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAddAcquire int"); + assertEquals(0x01234567, o, "getAndAddAcquire int"); int x = (int) vh.get(); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAddAcquire int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAddAcquire int value"); } { vh.set(0x01234567); int o = (int) vh.getAndAddRelease(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAddReleaseint"); + assertEquals(0x01234567, o, "getAndAddReleaseint"); int x = (int) vh.get(); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAddRelease int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAddRelease int value"); } // get and bitwise or @@ -921,27 +919,27 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { vh.set(0x01234567); int o = (int) vh.getAndBitwiseOr(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOr int"); + assertEquals(0x01234567, o, "getAndBitwiseOr int"); int x = (int) vh.get(); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOr int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOr int value"); } { vh.set(0x01234567); int o = (int) vh.getAndBitwiseOrAcquire(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOrAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseOrAcquire int"); int x = (int) vh.get(); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOrAcquire int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOrAcquire int value"); } { vh.set(0x01234567); int o = (int) vh.getAndBitwiseOrRelease(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOrRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseOrRelease int"); int x = (int) vh.get(); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOrRelease int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOrRelease int value"); } // get and bitwise and @@ -949,27 +947,27 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { vh.set(0x01234567); int o = (int) vh.getAndBitwiseAnd(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAnd int"); + assertEquals(0x01234567, o, "getAndBitwiseAnd int"); int x = (int) vh.get(); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAnd int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAnd int value"); } { vh.set(0x01234567); int o = (int) vh.getAndBitwiseAndAcquire(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAndAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseAndAcquire int"); int x = (int) vh.get(); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAndAcquire int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAndAcquire int value"); } { vh.set(0x01234567); int o = (int) vh.getAndBitwiseAndRelease(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAndRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseAndRelease int"); int x = (int) vh.get(); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAndRelease int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAndRelease int value"); } // get and bitwise xor @@ -977,27 +975,27 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { vh.set(0x01234567); int o = (int) vh.getAndBitwiseXor(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXor int"); + assertEquals(0x01234567, o, "getAndBitwiseXor int"); int x = (int) vh.get(); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXor int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXor int value"); } { vh.set(0x01234567); int o = (int) vh.getAndBitwiseXorAcquire(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXorAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseXorAcquire int"); int x = (int) vh.get(); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXorAcquire int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXorAcquire int value"); } { vh.set(0x01234567); int o = (int) vh.getAndBitwiseXorRelease(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXorRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseXorRelease int"); int x = (int) vh.get(); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXorRelease int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXorRelease int value"); } } @@ -1015,7 +1013,7 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { { vh.set(array, i, 0x01234567); int x = (int) vh.get(array, i); - assertEquals(x, 0x01234567, "get int value"); + assertEquals(0x01234567, x, "get int value"); } @@ -1023,21 +1021,21 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { { vh.setVolatile(array, i, 0x89ABCDEF); int x = (int) vh.getVolatile(array, i); - assertEquals(x, 0x89ABCDEF, "setVolatile int value"); + assertEquals(0x89ABCDEF, x, "setVolatile int value"); } // Lazy { vh.setRelease(array, i, 0x01234567); int x = (int) vh.getAcquire(array, i); - assertEquals(x, 0x01234567, "setRelease int value"); + assertEquals(0x01234567, x, "setRelease int value"); } // Opaque { vh.setOpaque(array, i, 0x89ABCDEF); int x = (int) vh.getOpaque(array, i); - assertEquals(x, 0x89ABCDEF, "setOpaque int value"); + assertEquals(0x89ABCDEF, x, "setOpaque int value"); } vh.set(array, i, 0x01234567); @@ -1047,56 +1045,56 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { boolean r = vh.compareAndSet(array, i, 0x01234567, 0x89ABCDEF); assertEquals(r, true, "success compareAndSet int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x89ABCDEF, "success compareAndSet int value"); + assertEquals(0x89ABCDEF, x, "success compareAndSet int value"); } { boolean r = vh.compareAndSet(array, i, 0x01234567, 0xCAFEBABE); assertEquals(r, false, "failing compareAndSet int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x89ABCDEF, "failing compareAndSet int value"); + assertEquals(0x89ABCDEF, x, "failing compareAndSet int value"); } { int r = (int) vh.compareAndExchange(array, i, 0x89ABCDEF, 0x01234567); assertEquals(r, 0x89ABCDEF, "success compareAndExchange int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x01234567, "success compareAndExchange int value"); + assertEquals(0x01234567, x, "success compareAndExchange int value"); } { int r = (int) vh.compareAndExchange(array, i, 0x89ABCDEF, 0xCAFEBABE); assertEquals(r, 0x01234567, "failing compareAndExchange int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x01234567, "failing compareAndExchange int value"); + assertEquals(0x01234567, x, "failing compareAndExchange int value"); } { int r = (int) vh.compareAndExchangeAcquire(array, i, 0x01234567, 0x89ABCDEF); assertEquals(r, 0x01234567, "success compareAndExchangeAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x89ABCDEF, "success compareAndExchangeAcquire int value"); + assertEquals(0x89ABCDEF, x, "success compareAndExchangeAcquire int value"); } { int r = (int) vh.compareAndExchangeAcquire(array, i, 0x01234567, 0xCAFEBABE); assertEquals(r, 0x89ABCDEF, "failing compareAndExchangeAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x89ABCDEF, "failing compareAndExchangeAcquire int value"); + assertEquals(0x89ABCDEF, x, "failing compareAndExchangeAcquire int value"); } { int r = (int) vh.compareAndExchangeRelease(array, i, 0x89ABCDEF, 0x01234567); assertEquals(r, 0x89ABCDEF, "success compareAndExchangeRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x01234567, "success compareAndExchangeRelease int value"); + assertEquals(0x01234567, x, "success compareAndExchangeRelease int value"); } { int r = (int) vh.compareAndExchangeRelease(array, i, 0x89ABCDEF, 0xCAFEBABE); assertEquals(r, 0x01234567, "failing compareAndExchangeRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x01234567, "failing compareAndExchangeRelease int value"); + assertEquals(0x01234567, x, "failing compareAndExchangeRelease int value"); } { @@ -1107,14 +1105,14 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x89ABCDEF, "success weakCompareAndSetPlain int value"); + assertEquals(0x89ABCDEF, x, "success weakCompareAndSetPlain int value"); } { boolean success = vh.weakCompareAndSetPlain(array, i, 0x01234567, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetPlain int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x89ABCDEF, "failing weakCompareAndSetPlain int value"); + assertEquals(0x89ABCDEF, x, "failing weakCompareAndSetPlain int value"); } { @@ -1125,14 +1123,14 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x01234567, "success weakCompareAndSetAcquire int"); + assertEquals(0x01234567, x, "success weakCompareAndSetAcquire int"); } { boolean success = vh.weakCompareAndSetAcquire(array, i, 0x89ABCDEF, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x01234567, "failing weakCompareAndSetAcquire int value"); + assertEquals(0x01234567, x, "failing weakCompareAndSetAcquire int value"); } { @@ -1143,14 +1141,14 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x89ABCDEF, "success weakCompareAndSetRelease int"); + assertEquals(0x89ABCDEF, x, "success weakCompareAndSetRelease int"); } { boolean success = vh.weakCompareAndSetRelease(array, i, 0x01234567, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x89ABCDEF, "failing weakCompareAndSetRelease int value"); + assertEquals(0x89ABCDEF, x, "failing weakCompareAndSetRelease int value"); } { @@ -1161,14 +1159,14 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x01234567, "success weakCompareAndSet int"); + assertEquals(0x01234567, x, "success weakCompareAndSet int"); } { boolean success = vh.weakCompareAndSet(array, i, 0x89ABCDEF, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSet int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x01234567, "failing weakCompareAndSet int value"); + assertEquals(0x01234567, x, "failing weakCompareAndSet int value"); } // Compare set and get @@ -1176,27 +1174,27 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { vh.set(array, i, 0x01234567); int o = (int) vh.getAndSet(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndSet int"); + assertEquals(0x01234567, o, "getAndSet int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x89ABCDEF, "getAndSet int value"); + assertEquals(0x89ABCDEF, x, "getAndSet int value"); } { vh.set(array, i, 0x01234567); int o = (int) vh.getAndSetAcquire(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndSetAcquire int"); + assertEquals(0x01234567, o, "getAndSetAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x89ABCDEF, "getAndSetAcquire int value"); + assertEquals(0x89ABCDEF, x, "getAndSetAcquire int value"); } { vh.set(array, i, 0x01234567); int o = (int) vh.getAndSetRelease(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndSetRelease int"); + assertEquals(0x01234567, o, "getAndSetRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, 0x89ABCDEF, "getAndSetRelease int value"); + assertEquals(0x89ABCDEF, x, "getAndSetRelease int value"); } // get and add, add and get @@ -1204,27 +1202,27 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { vh.set(array, i, 0x01234567); int o = (int) vh.getAndAdd(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAdd int"); + assertEquals(0x01234567, o, "getAndAdd int"); int x = (int) vh.get(array, i); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAdd int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAdd int value"); } { vh.set(array, i, 0x01234567); int o = (int) vh.getAndAddAcquire(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAddAcquire int"); + assertEquals(0x01234567, o, "getAndAddAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAddAcquire int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAddAcquire int value"); } { vh.set(array, i, 0x01234567); int o = (int) vh.getAndAddRelease(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAddReleaseint"); + assertEquals(0x01234567, o, "getAndAddReleaseint"); int x = (int) vh.get(array, i); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAddRelease int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAddRelease int value"); } // get and bitwise or @@ -1232,27 +1230,27 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { vh.set(array, i, 0x01234567); int o = (int) vh.getAndBitwiseOr(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOr int"); + assertEquals(0x01234567, o, "getAndBitwiseOr int"); int x = (int) vh.get(array, i); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOr int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOr int value"); } { vh.set(array, i, 0x01234567); int o = (int) vh.getAndBitwiseOrAcquire(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOrAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseOrAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOrAcquire int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOrAcquire int value"); } { vh.set(array, i, 0x01234567); int o = (int) vh.getAndBitwiseOrRelease(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOrRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseOrRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOrRelease int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOrRelease int value"); } // get and bitwise and @@ -1260,27 +1258,27 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { vh.set(array, i, 0x01234567); int o = (int) vh.getAndBitwiseAnd(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAnd int"); + assertEquals(0x01234567, o, "getAndBitwiseAnd int"); int x = (int) vh.get(array, i); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAnd int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAnd int value"); } { vh.set(array, i, 0x01234567); int o = (int) vh.getAndBitwiseAndAcquire(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAndAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseAndAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAndAcquire int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAndAcquire int value"); } { vh.set(array, i, 0x01234567); int o = (int) vh.getAndBitwiseAndRelease(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAndRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseAndRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAndRelease int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAndRelease int value"); } // get and bitwise xor @@ -1288,27 +1286,27 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { vh.set(array, i, 0x01234567); int o = (int) vh.getAndBitwiseXor(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXor int"); + assertEquals(0x01234567, o, "getAndBitwiseXor int"); int x = (int) vh.get(array, i); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXor int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXor int value"); } { vh.set(array, i, 0x01234567); int o = (int) vh.getAndBitwiseXorAcquire(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXorAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseXorAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXorAcquire int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXorAcquire int value"); } { vh.set(array, i, 0x01234567); int o = (int) vh.getAndBitwiseXorRelease(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXorRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseXorRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXorRelease int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXorRelease int value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java index e40256a8bd5..8bf997bb9a6 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,28 +23,30 @@ /* * @test - * @run testng/othervm -Diters=10 -Xint VarHandleTestAccessLong + * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessLong * * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds * - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessLong - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessLong - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessLong + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessLong + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessLong + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessLong */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestAccessLong extends VarHandleBaseTest { static final long static_final_v = 0x0123456789ABCDEFL; @@ -108,7 +110,7 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { return vhs.toArray(new VarHandle[0]); } - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestAccessLong.class, "final_v", long.class); @@ -125,8 +127,6 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(long[].class); } - - @DataProvider public Object[][] varHandlesProvider() throws Exception { List vhs = new ArrayList<>(); vhs.add(vhField); @@ -156,7 +156,8 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("varHandlesProvider") public void testIsAccessModeSupported(VarHandle vh) { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET)); @@ -194,8 +195,6 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE)); } - - @DataProvider public Object[][] typesProvider() throws Exception { List types = new ArrayList<>(); types.add(new Object[] {vhField, Arrays.asList(VarHandleTestAccessLong.class)}); @@ -205,16 +204,16 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { return types.stream().toArray(Object[][]::new); } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), long.class); + assertEquals(long.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - @Test public void testLookupInstanceToStatic() { checkIAE("Lookup of static final field to instance final field", () -> { @@ -241,8 +240,6 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { }); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -284,7 +281,8 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -297,26 +295,26 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { // Plain { long x = (long) vh.get(recv); - assertEquals(x, 0x0123456789ABCDEFL, "get long value"); + assertEquals(0x0123456789ABCDEFL, x, "get long value"); } // Volatile { long x = (long) vh.getVolatile(recv); - assertEquals(x, 0x0123456789ABCDEFL, "getVolatile long value"); + assertEquals(0x0123456789ABCDEFL, x, "getVolatile long value"); } // Lazy { long x = (long) vh.getAcquire(recv); - assertEquals(x, 0x0123456789ABCDEFL, "getRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "getRelease long value"); } // Opaque { long x = (long) vh.getOpaque(recv); - assertEquals(x, 0x0123456789ABCDEFL, "getOpaque long value"); + assertEquals(0x0123456789ABCDEFL, x, "getOpaque long value"); } } @@ -346,26 +344,26 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { // Plain { long x = (long) vh.get(); - assertEquals(x, 0x0123456789ABCDEFL, "get long value"); + assertEquals(0x0123456789ABCDEFL, x, "get long value"); } // Volatile { long x = (long) vh.getVolatile(); - assertEquals(x, 0x0123456789ABCDEFL, "getVolatile long value"); + assertEquals(0x0123456789ABCDEFL, x, "getVolatile long value"); } // Lazy { long x = (long) vh.getAcquire(); - assertEquals(x, 0x0123456789ABCDEFL, "getRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "getRelease long value"); } // Opaque { long x = (long) vh.getOpaque(); - assertEquals(x, 0x0123456789ABCDEFL, "getOpaque long value"); + assertEquals(0x0123456789ABCDEFL, x, "getOpaque long value"); } } @@ -396,7 +394,7 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { { vh.set(recv, 0x0123456789ABCDEFL); long x = (long) vh.get(recv); - assertEquals(x, 0x0123456789ABCDEFL, "set long value"); + assertEquals(0x0123456789ABCDEFL, x, "set long value"); } @@ -404,21 +402,21 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { { vh.setVolatile(recv, 0xCAFEBABECAFEBABEL); long x = (long) vh.getVolatile(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "setVolatile long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "setVolatile long value"); } // Lazy { vh.setRelease(recv, 0x0123456789ABCDEFL); long x = (long) vh.getAcquire(recv); - assertEquals(x, 0x0123456789ABCDEFL, "setRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "setRelease long value"); } // Opaque { vh.setOpaque(recv, 0xCAFEBABECAFEBABEL); long x = (long) vh.getOpaque(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "setOpaque long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "setOpaque long value"); } vh.set(recv, 0x0123456789ABCDEFL); @@ -428,56 +426,56 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { boolean r = vh.compareAndSet(recv, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); assertEquals(r, true, "success compareAndSet long"); long x = (long) vh.get(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success compareAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success compareAndSet long value"); } { boolean r = vh.compareAndSet(recv, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(r, false, "failing compareAndSet long"); long x = (long) vh.get(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing compareAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing compareAndSet long value"); } { long r = (long) vh.compareAndExchange(recv, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "success compareAndExchange long"); long x = (long) vh.get(recv); - assertEquals(x, 0x0123456789ABCDEFL, "success compareAndExchange long value"); + assertEquals(0x0123456789ABCDEFL, x, "success compareAndExchange long value"); } { long r = (long) vh.compareAndExchange(recv, 0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0x0123456789ABCDEFL, "failing compareAndExchange long"); long x = (long) vh.get(recv); - assertEquals(x, 0x0123456789ABCDEFL, "failing compareAndExchange long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing compareAndExchange long value"); } { long r = (long) vh.compareAndExchangeAcquire(recv, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); assertEquals(r, 0x0123456789ABCDEFL, "success compareAndExchangeAcquire long"); long x = (long) vh.get(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success compareAndExchangeAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success compareAndExchangeAcquire long value"); } { long r = (long) vh.compareAndExchangeAcquire(recv, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "failing compareAndExchangeAcquire long"); long x = (long) vh.get(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing compareAndExchangeAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing compareAndExchangeAcquire long value"); } { long r = (long) vh.compareAndExchangeRelease(recv, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "success compareAndExchangeRelease long"); long x = (long) vh.get(recv); - assertEquals(x, 0x0123456789ABCDEFL, "success compareAndExchangeRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "success compareAndExchangeRelease long value"); } { long r = (long) vh.compareAndExchangeRelease(recv, 0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0x0123456789ABCDEFL, "failing compareAndExchangeRelease long"); long x = (long) vh.get(recv); - assertEquals(x, 0x0123456789ABCDEFL, "failing compareAndExchangeRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing compareAndExchangeRelease long value"); } { @@ -488,14 +486,14 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain long"); long x = (long) vh.get(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success weakCompareAndSetPlain long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success weakCompareAndSetPlain long value"); } { boolean success = vh.weakCompareAndSetPlain(recv, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetPlain long"); long x = (long) vh.get(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing weakCompareAndSetPlain long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing weakCompareAndSetPlain long value"); } { @@ -506,14 +504,14 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire long"); long x = (long) vh.get(recv); - assertEquals(x, 0x0123456789ABCDEFL, "success weakCompareAndSetAcquire long"); + assertEquals(0x0123456789ABCDEFL, x, "success weakCompareAndSetAcquire long"); } { boolean success = vh.weakCompareAndSetAcquire(recv, 0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetAcquire long"); long x = (long) vh.get(recv); - assertEquals(x, 0x0123456789ABCDEFL, "failing weakCompareAndSetAcquire long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing weakCompareAndSetAcquire long value"); } { @@ -524,14 +522,14 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease long"); long x = (long) vh.get(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success weakCompareAndSetRelease long"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success weakCompareAndSetRelease long"); } { boolean success = vh.weakCompareAndSetRelease(recv, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetRelease long"); long x = (long) vh.get(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing weakCompareAndSetRelease long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing weakCompareAndSetRelease long value"); } { @@ -542,14 +540,14 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet long"); long x = (long) vh.get(recv); - assertEquals(x, 0x0123456789ABCDEFL, "success weakCompareAndSet long value"); + assertEquals(0x0123456789ABCDEFL, x, "success weakCompareAndSet long value"); } { boolean success = vh.weakCompareAndSet(recv, 0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSet long"); long x = (long) vh.get(recv); - assertEquals(x, 0x0123456789ABCDEFL, "failing weakCompareAndSet long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing weakCompareAndSet long value"); } // Compare set and get @@ -557,27 +555,27 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { vh.set(recv, 0x0123456789ABCDEFL); long o = (long) vh.getAndSet(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndSet long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndSet long"); long x = (long) vh.get(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "getAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSet long value"); } { vh.set(recv, 0x0123456789ABCDEFL); long o = (long) vh.getAndSetAcquire(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndSetAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndSetAcquire long"); long x = (long) vh.get(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "getAndSetAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSetAcquire long value"); } { vh.set(recv, 0x0123456789ABCDEFL); long o = (long) vh.getAndSetRelease(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndSetRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndSetRelease long"); long x = (long) vh.get(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "getAndSetRelease long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSetRelease long value"); } // get and add, add and get @@ -585,27 +583,27 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { vh.set(recv, 0x0123456789ABCDEFL); long o = (long) vh.getAndAdd(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAdd long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAdd long"); long x = (long) vh.get(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAdd long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAdd long value"); } { vh.set(recv, 0x0123456789ABCDEFL); long o = (long) vh.getAndAddAcquire(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAddAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAddAcquire long"); long x = (long) vh.get(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAddAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAddAcquire long value"); } { vh.set(recv, 0x0123456789ABCDEFL); long o = (long) vh.getAndAddRelease(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAddReleaselong"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAddReleaselong"); long x = (long) vh.get(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAddRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAddRelease long value"); } // get and bitwise or @@ -613,27 +611,27 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { vh.set(recv, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseOr(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOr long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOr long"); long x = (long) vh.get(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOr long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOr long value"); } { vh.set(recv, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseOrAcquire(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOrAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOrAcquire long"); long x = (long) vh.get(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOrAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOrAcquire long value"); } { vh.set(recv, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseOrRelease(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOrRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOrRelease long"); long x = (long) vh.get(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOrRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOrRelease long value"); } // get and bitwise and @@ -641,27 +639,27 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { vh.set(recv, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseAnd(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAnd long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAnd long"); long x = (long) vh.get(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAnd long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAnd long value"); } { vh.set(recv, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseAndAcquire(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAndAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAndAcquire long"); long x = (long) vh.get(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAndAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAndAcquire long value"); } { vh.set(recv, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseAndRelease(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAndRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAndRelease long"); long x = (long) vh.get(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAndRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAndRelease long value"); } // get and bitwise xor @@ -669,27 +667,27 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { vh.set(recv, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseXor(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXor long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXor long"); long x = (long) vh.get(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXor long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXor long value"); } { vh.set(recv, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseXorAcquire(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXorAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXorAcquire long"); long x = (long) vh.get(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXorAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXorAcquire long value"); } { vh.set(recv, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseXorRelease(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXorRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXorRelease long"); long x = (long) vh.get(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXorRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXorRelease long value"); } } @@ -704,7 +702,7 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { { vh.set(0x0123456789ABCDEFL); long x = (long) vh.get(); - assertEquals(x, 0x0123456789ABCDEFL, "set long value"); + assertEquals(0x0123456789ABCDEFL, x, "set long value"); } @@ -712,21 +710,21 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { { vh.setVolatile(0xCAFEBABECAFEBABEL); long x = (long) vh.getVolatile(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "setVolatile long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "setVolatile long value"); } // Lazy { vh.setRelease(0x0123456789ABCDEFL); long x = (long) vh.getAcquire(); - assertEquals(x, 0x0123456789ABCDEFL, "setRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "setRelease long value"); } // Opaque { vh.setOpaque(0xCAFEBABECAFEBABEL); long x = (long) vh.getOpaque(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "setOpaque long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "setOpaque long value"); } vh.set(0x0123456789ABCDEFL); @@ -736,56 +734,56 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { boolean r = vh.compareAndSet(0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); assertEquals(r, true, "success compareAndSet long"); long x = (long) vh.get(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success compareAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success compareAndSet long value"); } { boolean r = vh.compareAndSet(0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(r, false, "failing compareAndSet long"); long x = (long) vh.get(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing compareAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing compareAndSet long value"); } { long r = (long) vh.compareAndExchange(0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "success compareAndExchange long"); long x = (long) vh.get(); - assertEquals(x, 0x0123456789ABCDEFL, "success compareAndExchange long value"); + assertEquals(0x0123456789ABCDEFL, x, "success compareAndExchange long value"); } { long r = (long) vh.compareAndExchange(0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0x0123456789ABCDEFL, "failing compareAndExchange long"); long x = (long) vh.get(); - assertEquals(x, 0x0123456789ABCDEFL, "failing compareAndExchange long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing compareAndExchange long value"); } { long r = (long) vh.compareAndExchangeAcquire(0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); assertEquals(r, 0x0123456789ABCDEFL, "success compareAndExchangeAcquire long"); long x = (long) vh.get(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success compareAndExchangeAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success compareAndExchangeAcquire long value"); } { long r = (long) vh.compareAndExchangeAcquire(0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "failing compareAndExchangeAcquire long"); long x = (long) vh.get(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing compareAndExchangeAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing compareAndExchangeAcquire long value"); } { long r = (long) vh.compareAndExchangeRelease(0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "success compareAndExchangeRelease long"); long x = (long) vh.get(); - assertEquals(x, 0x0123456789ABCDEFL, "success compareAndExchangeRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "success compareAndExchangeRelease long value"); } { long r = (long) vh.compareAndExchangeRelease(0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0x0123456789ABCDEFL, "failing compareAndExchangeRelease long"); long x = (long) vh.get(); - assertEquals(x, 0x0123456789ABCDEFL, "failing compareAndExchangeRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing compareAndExchangeRelease long value"); } { @@ -796,14 +794,14 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain long"); long x = (long) vh.get(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success weakCompareAndSetPlain long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success weakCompareAndSetPlain long value"); } { boolean success = vh.weakCompareAndSetPlain(0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetPlain long"); long x = (long) vh.get(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing weakCompareAndSetPlain long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing weakCompareAndSetPlain long value"); } { @@ -814,14 +812,14 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire long"); long x = (long) vh.get(); - assertEquals(x, 0x0123456789ABCDEFL, "success weakCompareAndSetAcquire long"); + assertEquals(0x0123456789ABCDEFL, x, "success weakCompareAndSetAcquire long"); } { boolean success = vh.weakCompareAndSetAcquire(0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetAcquire long"); long x = (long) vh.get(); - assertEquals(x, 0x0123456789ABCDEFL, "failing weakCompareAndSetAcquire long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing weakCompareAndSetAcquire long value"); } { @@ -832,14 +830,14 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease long"); long x = (long) vh.get(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success weakCompareAndSetRelease long"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success weakCompareAndSetRelease long"); } { boolean success = vh.weakCompareAndSetRelease(0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetRelease long"); long x = (long) vh.get(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing weakCompareAndSetRelease long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing weakCompareAndSetRelease long value"); } { @@ -850,14 +848,14 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet long"); long x = (long) vh.get(); - assertEquals(x, 0x0123456789ABCDEFL, "success weakCompareAndSet long"); + assertEquals(0x0123456789ABCDEFL, x, "success weakCompareAndSet long"); } { boolean success = vh.weakCompareAndSet(0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSet long"); long x = (long) vh.get(); - assertEquals(x, 0x0123456789ABCDEFL, "failing weakCompareAndSet long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing weakCompareAndSet long value"); } // Compare set and get @@ -865,27 +863,27 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { vh.set(0x0123456789ABCDEFL); long o = (long) vh.getAndSet(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndSet long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndSet long"); long x = (long) vh.get(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "getAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSet long value"); } { vh.set(0x0123456789ABCDEFL); long o = (long) vh.getAndSetAcquire(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndSetAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndSetAcquire long"); long x = (long) vh.get(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "getAndSetAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSetAcquire long value"); } { vh.set(0x0123456789ABCDEFL); long o = (long) vh.getAndSetRelease(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndSetRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndSetRelease long"); long x = (long) vh.get(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "getAndSetRelease long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSetRelease long value"); } // get and add, add and get @@ -893,27 +891,27 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { vh.set(0x0123456789ABCDEFL); long o = (long) vh.getAndAdd(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAdd long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAdd long"); long x = (long) vh.get(); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAdd long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAdd long value"); } { vh.set(0x0123456789ABCDEFL); long o = (long) vh.getAndAddAcquire(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAddAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAddAcquire long"); long x = (long) vh.get(); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAddAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAddAcquire long value"); } { vh.set(0x0123456789ABCDEFL); long o = (long) vh.getAndAddRelease(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAddReleaselong"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAddReleaselong"); long x = (long) vh.get(); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAddRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAddRelease long value"); } // get and bitwise or @@ -921,27 +919,27 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { vh.set(0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseOr(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOr long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOr long"); long x = (long) vh.get(); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOr long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOr long value"); } { vh.set(0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseOrAcquire(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOrAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOrAcquire long"); long x = (long) vh.get(); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOrAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOrAcquire long value"); } { vh.set(0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseOrRelease(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOrRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOrRelease long"); long x = (long) vh.get(); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOrRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOrRelease long value"); } // get and bitwise and @@ -949,27 +947,27 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { vh.set(0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseAnd(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAnd long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAnd long"); long x = (long) vh.get(); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAnd long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAnd long value"); } { vh.set(0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseAndAcquire(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAndAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAndAcquire long"); long x = (long) vh.get(); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAndAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAndAcquire long value"); } { vh.set(0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseAndRelease(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAndRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAndRelease long"); long x = (long) vh.get(); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAndRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAndRelease long value"); } // get and bitwise xor @@ -977,27 +975,27 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { vh.set(0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseXor(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXor long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXor long"); long x = (long) vh.get(); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXor long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXor long value"); } { vh.set(0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseXorAcquire(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXorAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXorAcquire long"); long x = (long) vh.get(); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXorAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXorAcquire long value"); } { vh.set(0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseXorRelease(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXorRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXorRelease long"); long x = (long) vh.get(); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXorRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXorRelease long value"); } } @@ -1015,7 +1013,7 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { { vh.set(array, i, 0x0123456789ABCDEFL); long x = (long) vh.get(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "get long value"); + assertEquals(0x0123456789ABCDEFL, x, "get long value"); } @@ -1023,21 +1021,21 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { { vh.setVolatile(array, i, 0xCAFEBABECAFEBABEL); long x = (long) vh.getVolatile(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "setVolatile long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "setVolatile long value"); } // Lazy { vh.setRelease(array, i, 0x0123456789ABCDEFL); long x = (long) vh.getAcquire(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "setRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "setRelease long value"); } // Opaque { vh.setOpaque(array, i, 0xCAFEBABECAFEBABEL); long x = (long) vh.getOpaque(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "setOpaque long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "setOpaque long value"); } vh.set(array, i, 0x0123456789ABCDEFL); @@ -1047,56 +1045,56 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { boolean r = vh.compareAndSet(array, i, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); assertEquals(r, true, "success compareAndSet long"); long x = (long) vh.get(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success compareAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success compareAndSet long value"); } { boolean r = vh.compareAndSet(array, i, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(r, false, "failing compareAndSet long"); long x = (long) vh.get(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing compareAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing compareAndSet long value"); } { long r = (long) vh.compareAndExchange(array, i, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "success compareAndExchange long"); long x = (long) vh.get(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "success compareAndExchange long value"); + assertEquals(0x0123456789ABCDEFL, x, "success compareAndExchange long value"); } { long r = (long) vh.compareAndExchange(array, i, 0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0x0123456789ABCDEFL, "failing compareAndExchange long"); long x = (long) vh.get(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "failing compareAndExchange long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing compareAndExchange long value"); } { long r = (long) vh.compareAndExchangeAcquire(array, i, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); assertEquals(r, 0x0123456789ABCDEFL, "success compareAndExchangeAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success compareAndExchangeAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success compareAndExchangeAcquire long value"); } { long r = (long) vh.compareAndExchangeAcquire(array, i, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "failing compareAndExchangeAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing compareAndExchangeAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing compareAndExchangeAcquire long value"); } { long r = (long) vh.compareAndExchangeRelease(array, i, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "success compareAndExchangeRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "success compareAndExchangeRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "success compareAndExchangeRelease long value"); } { long r = (long) vh.compareAndExchangeRelease(array, i, 0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0x0123456789ABCDEFL, "failing compareAndExchangeRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "failing compareAndExchangeRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing compareAndExchangeRelease long value"); } { @@ -1107,14 +1105,14 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain long"); long x = (long) vh.get(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success weakCompareAndSetPlain long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success weakCompareAndSetPlain long value"); } { boolean success = vh.weakCompareAndSetPlain(array, i, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetPlain long"); long x = (long) vh.get(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing weakCompareAndSetPlain long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing weakCompareAndSetPlain long value"); } { @@ -1125,14 +1123,14 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "success weakCompareAndSetAcquire long"); + assertEquals(0x0123456789ABCDEFL, x, "success weakCompareAndSetAcquire long"); } { boolean success = vh.weakCompareAndSetAcquire(array, i, 0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "failing weakCompareAndSetAcquire long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing weakCompareAndSetAcquire long value"); } { @@ -1143,14 +1141,14 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success weakCompareAndSetRelease long"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success weakCompareAndSetRelease long"); } { boolean success = vh.weakCompareAndSetRelease(array, i, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing weakCompareAndSetRelease long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing weakCompareAndSetRelease long value"); } { @@ -1161,14 +1159,14 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet long"); long x = (long) vh.get(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "success weakCompareAndSet long"); + assertEquals(0x0123456789ABCDEFL, x, "success weakCompareAndSet long"); } { boolean success = vh.weakCompareAndSet(array, i, 0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSet long"); long x = (long) vh.get(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "failing weakCompareAndSet long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing weakCompareAndSet long value"); } // Compare set and get @@ -1176,27 +1174,27 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { vh.set(array, i, 0x0123456789ABCDEFL); long o = (long) vh.getAndSet(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndSet long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndSet long"); long x = (long) vh.get(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "getAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSet long value"); } { vh.set(array, i, 0x0123456789ABCDEFL); long o = (long) vh.getAndSetAcquire(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndSetAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndSetAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "getAndSetAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSetAcquire long value"); } { vh.set(array, i, 0x0123456789ABCDEFL); long o = (long) vh.getAndSetRelease(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndSetRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndSetRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "getAndSetRelease long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSetRelease long value"); } // get and add, add and get @@ -1204,27 +1202,27 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { vh.set(array, i, 0x0123456789ABCDEFL); long o = (long) vh.getAndAdd(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAdd long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAdd long"); long x = (long) vh.get(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAdd long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAdd long value"); } { vh.set(array, i, 0x0123456789ABCDEFL); long o = (long) vh.getAndAddAcquire(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAddAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAddAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAddAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAddAcquire long value"); } { vh.set(array, i, 0x0123456789ABCDEFL); long o = (long) vh.getAndAddRelease(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAddReleaselong"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAddReleaselong"); long x = (long) vh.get(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAddRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAddRelease long value"); } // get and bitwise or @@ -1232,27 +1230,27 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { vh.set(array, i, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseOr(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOr long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOr long"); long x = (long) vh.get(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOr long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOr long value"); } { vh.set(array, i, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseOrAcquire(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOrAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOrAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOrAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOrAcquire long value"); } { vh.set(array, i, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseOrRelease(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOrRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOrRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOrRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOrRelease long value"); } // get and bitwise and @@ -1260,27 +1258,27 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { vh.set(array, i, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseAnd(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAnd long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAnd long"); long x = (long) vh.get(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAnd long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAnd long value"); } { vh.set(array, i, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseAndAcquire(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAndAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAndAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAndAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAndAcquire long value"); } { vh.set(array, i, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseAndRelease(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAndRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAndRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAndRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAndRelease long value"); } // get and bitwise xor @@ -1288,27 +1286,27 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { vh.set(array, i, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseXor(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXor long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXor long"); long x = (long) vh.get(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXor long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXor long value"); } { vh.set(array, i, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseXorAcquire(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXorAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXorAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXorAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXorAcquire long value"); } { vh.set(array, i, 0x0123456789ABCDEFL); long o = (long) vh.getAndBitwiseXorRelease(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXorRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXorRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXorRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXorRelease long value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessModeMethodNames.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessModeMethodNames.java index 3365bd923bc..61fc8a53fd0 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessModeMethodNames.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessModeMethodNames.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,32 +23,34 @@ /* * @test - * @run testng VarHandleTestAccessModeMethodNames + * @run junit VarHandleTestAccessModeMethodNames * @modules java.base/java.lang.invoke:open */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.invoke.VarHandle; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.stream.Stream; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestAccessModeMethodNames { - @DataProvider public static Object[][] accessModesProvider() { return Stream.of(VarHandle.AccessMode.values()). map(am -> new Object[]{am}). toArray(Object[][]::new); } - @Test(dataProvider = "accessModesProvider") + @ParameterizedTest + @MethodSource("accessModesProvider") public void testMethodName(VarHandle.AccessMode am) { - assertEquals(am.methodName(), toMethodName(am.name())); + assertEquals(toMethodName(am.name()), am.methodName()); } private static String toMethodName(String name) { @@ -62,9 +64,10 @@ public class VarHandleTestAccessModeMethodNames { } - @Test(dataProvider = "accessModesProvider") + @ParameterizedTest + @MethodSource("accessModesProvider") public void testReturnType(VarHandle.AccessMode am) throws Exception { - assertEquals(getReturnType(am.methodName()), getAccessModeReturnType(am)); + assertEquals(getAccessModeReturnType(am), getReturnType(am.methodName())); } private static Class getReturnType(String name) throws Exception { diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java index b9daf4880a0..552672c7372 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,28 +23,30 @@ /* * @test - * @run testng/othervm -Diters=10 -Xint VarHandleTestAccessShort + * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessShort * * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds * - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessShort - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessShort - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessShort + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessShort + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessShort + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessShort */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestAccessShort extends VarHandleBaseTest { static final short static_final_v = (short)0x0123; @@ -108,7 +110,7 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { return vhs.toArray(new VarHandle[0]); } - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestAccessShort.class, "final_v", short.class); @@ -125,8 +127,6 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(short[].class); } - - @DataProvider public Object[][] varHandlesProvider() throws Exception { List vhs = new ArrayList<>(); vhs.add(vhField); @@ -156,7 +156,8 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("varHandlesProvider") public void testIsAccessModeSupported(VarHandle vh) { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET)); @@ -194,8 +195,6 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE)); } - - @DataProvider public Object[][] typesProvider() throws Exception { List types = new ArrayList<>(); types.add(new Object[] {vhField, Arrays.asList(VarHandleTestAccessShort.class)}); @@ -205,16 +204,16 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { return types.stream().toArray(Object[][]::new); } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), short.class); + assertEquals(short.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - @Test public void testLookupInstanceToStatic() { checkIAE("Lookup of static final field to instance final field", () -> { @@ -241,8 +240,6 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { }); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -284,7 +281,8 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -297,26 +295,26 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { // Plain { short x = (short) vh.get(recv); - assertEquals(x, (short)0x0123, "get short value"); + assertEquals((short)0x0123, x, "get short value"); } // Volatile { short x = (short) vh.getVolatile(recv); - assertEquals(x, (short)0x0123, "getVolatile short value"); + assertEquals((short)0x0123, x, "getVolatile short value"); } // Lazy { short x = (short) vh.getAcquire(recv); - assertEquals(x, (short)0x0123, "getRelease short value"); + assertEquals((short)0x0123, x, "getRelease short value"); } // Opaque { short x = (short) vh.getOpaque(recv); - assertEquals(x, (short)0x0123, "getOpaque short value"); + assertEquals((short)0x0123, x, "getOpaque short value"); } } @@ -346,26 +344,26 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { // Plain { short x = (short) vh.get(); - assertEquals(x, (short)0x0123, "get short value"); + assertEquals((short)0x0123, x, "get short value"); } // Volatile { short x = (short) vh.getVolatile(); - assertEquals(x, (short)0x0123, "getVolatile short value"); + assertEquals((short)0x0123, x, "getVolatile short value"); } // Lazy { short x = (short) vh.getAcquire(); - assertEquals(x, (short)0x0123, "getRelease short value"); + assertEquals((short)0x0123, x, "getRelease short value"); } // Opaque { short x = (short) vh.getOpaque(); - assertEquals(x, (short)0x0123, "getOpaque short value"); + assertEquals((short)0x0123, x, "getOpaque short value"); } } @@ -396,7 +394,7 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { { vh.set(recv, (short)0x0123); short x = (short) vh.get(recv); - assertEquals(x, (short)0x0123, "set short value"); + assertEquals((short)0x0123, x, "set short value"); } @@ -404,21 +402,21 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { { vh.setVolatile(recv, (short)0x4567); short x = (short) vh.getVolatile(recv); - assertEquals(x, (short)0x4567, "setVolatile short value"); + assertEquals((short)0x4567, x, "setVolatile short value"); } // Lazy { vh.setRelease(recv, (short)0x0123); short x = (short) vh.getAcquire(recv); - assertEquals(x, (short)0x0123, "setRelease short value"); + assertEquals((short)0x0123, x, "setRelease short value"); } // Opaque { vh.setOpaque(recv, (short)0x4567); short x = (short) vh.getOpaque(recv); - assertEquals(x, (short)0x4567, "setOpaque short value"); + assertEquals((short)0x4567, x, "setOpaque short value"); } vh.set(recv, (short)0x0123); @@ -428,56 +426,56 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { boolean r = vh.compareAndSet(recv, (short)0x0123, (short)0x4567); assertEquals(r, true, "success compareAndSet short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x4567, "success compareAndSet short value"); + assertEquals((short)0x4567, x, "success compareAndSet short value"); } { boolean r = vh.compareAndSet(recv, (short)0x0123, (short)0x89AB); assertEquals(r, false, "failing compareAndSet short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x4567, "failing compareAndSet short value"); + assertEquals((short)0x4567, x, "failing compareAndSet short value"); } { short r = (short) vh.compareAndExchange(recv, (short)0x4567, (short)0x0123); assertEquals(r, (short)0x4567, "success compareAndExchange short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x0123, "success compareAndExchange short value"); + assertEquals((short)0x0123, x, "success compareAndExchange short value"); } { short r = (short) vh.compareAndExchange(recv, (short)0x4567, (short)0x89AB); assertEquals(r, (short)0x0123, "failing compareAndExchange short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x0123, "failing compareAndExchange short value"); + assertEquals((short)0x0123, x, "failing compareAndExchange short value"); } { short r = (short) vh.compareAndExchangeAcquire(recv, (short)0x0123, (short)0x4567); assertEquals(r, (short)0x0123, "success compareAndExchangeAcquire short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x4567, "success compareAndExchangeAcquire short value"); + assertEquals((short)0x4567, x, "success compareAndExchangeAcquire short value"); } { short r = (short) vh.compareAndExchangeAcquire(recv, (short)0x0123, (short)0x89AB); assertEquals(r, (short)0x4567, "failing compareAndExchangeAcquire short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x4567, "failing compareAndExchangeAcquire short value"); + assertEquals((short)0x4567, x, "failing compareAndExchangeAcquire short value"); } { short r = (short) vh.compareAndExchangeRelease(recv, (short)0x4567, (short)0x0123); assertEquals(r, (short)0x4567, "success compareAndExchangeRelease short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x0123, "success compareAndExchangeRelease short value"); + assertEquals((short)0x0123, x, "success compareAndExchangeRelease short value"); } { short r = (short) vh.compareAndExchangeRelease(recv, (short)0x4567, (short)0x89AB); assertEquals(r, (short)0x0123, "failing compareAndExchangeRelease short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x0123, "failing compareAndExchangeRelease short value"); + assertEquals((short)0x0123, x, "failing compareAndExchangeRelease short value"); } { @@ -488,14 +486,14 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x4567, "success weakCompareAndSetPlain short value"); + assertEquals((short)0x4567, x, "success weakCompareAndSetPlain short value"); } { boolean success = vh.weakCompareAndSetPlain(recv, (short)0x0123, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetPlain short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x4567, "failing weakCompareAndSetPlain short value"); + assertEquals((short)0x4567, x, "failing weakCompareAndSetPlain short value"); } { @@ -506,14 +504,14 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x0123, "success weakCompareAndSetAcquire short"); + assertEquals((short)0x0123, x, "success weakCompareAndSetAcquire short"); } { boolean success = vh.weakCompareAndSetAcquire(recv, (short)0x4567, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetAcquire short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x0123, "failing weakCompareAndSetAcquire short value"); + assertEquals((short)0x0123, x, "failing weakCompareAndSetAcquire short value"); } { @@ -524,14 +522,14 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x4567, "success weakCompareAndSetRelease short"); + assertEquals((short)0x4567, x, "success weakCompareAndSetRelease short"); } { boolean success = vh.weakCompareAndSetRelease(recv, (short)0x0123, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetRelease short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x4567, "failing weakCompareAndSetRelease short value"); + assertEquals((short)0x4567, x, "failing weakCompareAndSetRelease short value"); } { @@ -542,14 +540,14 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x0123, "success weakCompareAndSet short value"); + assertEquals((short)0x0123, x, "success weakCompareAndSet short value"); } { boolean success = vh.weakCompareAndSet(recv, (short)0x4567, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSet short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x0123, "failing weakCompareAndSet short value"); + assertEquals((short)0x0123, x, "failing weakCompareAndSet short value"); } // Compare set and get @@ -557,27 +555,27 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { vh.set(recv, (short)0x0123); short o = (short) vh.getAndSet(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndSet short"); + assertEquals((short)0x0123, o, "getAndSet short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x4567, "getAndSet short value"); + assertEquals((short)0x4567, x, "getAndSet short value"); } { vh.set(recv, (short)0x0123); short o = (short) vh.getAndSetAcquire(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndSetAcquire short"); + assertEquals((short)0x0123, o, "getAndSetAcquire short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x4567, "getAndSetAcquire short value"); + assertEquals((short)0x4567, x, "getAndSetAcquire short value"); } { vh.set(recv, (short)0x0123); short o = (short) vh.getAndSetRelease(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndSetRelease short"); + assertEquals((short)0x0123, o, "getAndSetRelease short"); short x = (short) vh.get(recv); - assertEquals(x, (short)0x4567, "getAndSetRelease short value"); + assertEquals((short)0x4567, x, "getAndSetRelease short value"); } // get and add, add and get @@ -585,27 +583,27 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { vh.set(recv, (short)0x0123); short o = (short) vh.getAndAdd(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndAdd short"); + assertEquals((short)0x0123, o, "getAndAdd short"); short x = (short) vh.get(recv); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAdd short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAdd short value"); } { vh.set(recv, (short)0x0123); short o = (short) vh.getAndAddAcquire(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndAddAcquire short"); + assertEquals((short)0x0123, o, "getAndAddAcquire short"); short x = (short) vh.get(recv); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAddAcquire short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAddAcquire short value"); } { vh.set(recv, (short)0x0123); short o = (short) vh.getAndAddRelease(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndAddReleaseshort"); + assertEquals((short)0x0123, o, "getAndAddReleaseshort"); short x = (short) vh.get(recv); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAddRelease short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAddRelease short value"); } // get and bitwise or @@ -613,27 +611,27 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { vh.set(recv, (short)0x0123); short o = (short) vh.getAndBitwiseOr(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOr short"); + assertEquals((short)0x0123, o, "getAndBitwiseOr short"); short x = (short) vh.get(recv); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOr short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOr short value"); } { vh.set(recv, (short)0x0123); short o = (short) vh.getAndBitwiseOrAcquire(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOrAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseOrAcquire short"); short x = (short) vh.get(recv); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOrAcquire short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOrAcquire short value"); } { vh.set(recv, (short)0x0123); short o = (short) vh.getAndBitwiseOrRelease(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOrRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseOrRelease short"); short x = (short) vh.get(recv); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOrRelease short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOrRelease short value"); } // get and bitwise and @@ -641,27 +639,27 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { vh.set(recv, (short)0x0123); short o = (short) vh.getAndBitwiseAnd(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAnd short"); + assertEquals((short)0x0123, o, "getAndBitwiseAnd short"); short x = (short) vh.get(recv); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAnd short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAnd short value"); } { vh.set(recv, (short)0x0123); short o = (short) vh.getAndBitwiseAndAcquire(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAndAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseAndAcquire short"); short x = (short) vh.get(recv); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAndAcquire short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAndAcquire short value"); } { vh.set(recv, (short)0x0123); short o = (short) vh.getAndBitwiseAndRelease(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAndRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseAndRelease short"); short x = (short) vh.get(recv); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAndRelease short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAndRelease short value"); } // get and bitwise xor @@ -669,27 +667,27 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { vh.set(recv, (short)0x0123); short o = (short) vh.getAndBitwiseXor(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXor short"); + assertEquals((short)0x0123, o, "getAndBitwiseXor short"); short x = (short) vh.get(recv); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXor short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXor short value"); } { vh.set(recv, (short)0x0123); short o = (short) vh.getAndBitwiseXorAcquire(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXorAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseXorAcquire short"); short x = (short) vh.get(recv); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXorAcquire short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXorAcquire short value"); } { vh.set(recv, (short)0x0123); short o = (short) vh.getAndBitwiseXorRelease(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXorRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseXorRelease short"); short x = (short) vh.get(recv); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXorRelease short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXorRelease short value"); } } @@ -704,7 +702,7 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { { vh.set((short)0x0123); short x = (short) vh.get(); - assertEquals(x, (short)0x0123, "set short value"); + assertEquals((short)0x0123, x, "set short value"); } @@ -712,21 +710,21 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { { vh.setVolatile((short)0x4567); short x = (short) vh.getVolatile(); - assertEquals(x, (short)0x4567, "setVolatile short value"); + assertEquals((short)0x4567, x, "setVolatile short value"); } // Lazy { vh.setRelease((short)0x0123); short x = (short) vh.getAcquire(); - assertEquals(x, (short)0x0123, "setRelease short value"); + assertEquals((short)0x0123, x, "setRelease short value"); } // Opaque { vh.setOpaque((short)0x4567); short x = (short) vh.getOpaque(); - assertEquals(x, (short)0x4567, "setOpaque short value"); + assertEquals((short)0x4567, x, "setOpaque short value"); } vh.set((short)0x0123); @@ -736,56 +734,56 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { boolean r = vh.compareAndSet((short)0x0123, (short)0x4567); assertEquals(r, true, "success compareAndSet short"); short x = (short) vh.get(); - assertEquals(x, (short)0x4567, "success compareAndSet short value"); + assertEquals((short)0x4567, x, "success compareAndSet short value"); } { boolean r = vh.compareAndSet((short)0x0123, (short)0x89AB); assertEquals(r, false, "failing compareAndSet short"); short x = (short) vh.get(); - assertEquals(x, (short)0x4567, "failing compareAndSet short value"); + assertEquals((short)0x4567, x, "failing compareAndSet short value"); } { short r = (short) vh.compareAndExchange((short)0x4567, (short)0x0123); assertEquals(r, (short)0x4567, "success compareAndExchange short"); short x = (short) vh.get(); - assertEquals(x, (short)0x0123, "success compareAndExchange short value"); + assertEquals((short)0x0123, x, "success compareAndExchange short value"); } { short r = (short) vh.compareAndExchange((short)0x4567, (short)0x89AB); assertEquals(r, (short)0x0123, "failing compareAndExchange short"); short x = (short) vh.get(); - assertEquals(x, (short)0x0123, "failing compareAndExchange short value"); + assertEquals((short)0x0123, x, "failing compareAndExchange short value"); } { short r = (short) vh.compareAndExchangeAcquire((short)0x0123, (short)0x4567); assertEquals(r, (short)0x0123, "success compareAndExchangeAcquire short"); short x = (short) vh.get(); - assertEquals(x, (short)0x4567, "success compareAndExchangeAcquire short value"); + assertEquals((short)0x4567, x, "success compareAndExchangeAcquire short value"); } { short r = (short) vh.compareAndExchangeAcquire((short)0x0123, (short)0x89AB); assertEquals(r, (short)0x4567, "failing compareAndExchangeAcquire short"); short x = (short) vh.get(); - assertEquals(x, (short)0x4567, "failing compareAndExchangeAcquire short value"); + assertEquals((short)0x4567, x, "failing compareAndExchangeAcquire short value"); } { short r = (short) vh.compareAndExchangeRelease((short)0x4567, (short)0x0123); assertEquals(r, (short)0x4567, "success compareAndExchangeRelease short"); short x = (short) vh.get(); - assertEquals(x, (short)0x0123, "success compareAndExchangeRelease short value"); + assertEquals((short)0x0123, x, "success compareAndExchangeRelease short value"); } { short r = (short) vh.compareAndExchangeRelease((short)0x4567, (short)0x89AB); assertEquals(r, (short)0x0123, "failing compareAndExchangeRelease short"); short x = (short) vh.get(); - assertEquals(x, (short)0x0123, "failing compareAndExchangeRelease short value"); + assertEquals((short)0x0123, x, "failing compareAndExchangeRelease short value"); } { @@ -796,14 +794,14 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain short"); short x = (short) vh.get(); - assertEquals(x, (short)0x4567, "success weakCompareAndSetPlain short value"); + assertEquals((short)0x4567, x, "success weakCompareAndSetPlain short value"); } { boolean success = vh.weakCompareAndSetPlain((short)0x0123, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetPlain short"); short x = (short) vh.get(); - assertEquals(x, (short)0x4567, "failing weakCompareAndSetPlain short value"); + assertEquals((short)0x4567, x, "failing weakCompareAndSetPlain short value"); } { @@ -814,14 +812,14 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire short"); short x = (short) vh.get(); - assertEquals(x, (short)0x0123, "success weakCompareAndSetAcquire short"); + assertEquals((short)0x0123, x, "success weakCompareAndSetAcquire short"); } { boolean success = vh.weakCompareAndSetAcquire((short)0x4567, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetAcquire short"); short x = (short) vh.get(); - assertEquals(x, (short)0x0123, "failing weakCompareAndSetAcquire short value"); + assertEquals((short)0x0123, x, "failing weakCompareAndSetAcquire short value"); } { @@ -832,14 +830,14 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease short"); short x = (short) vh.get(); - assertEquals(x, (short)0x4567, "success weakCompareAndSetRelease short"); + assertEquals((short)0x4567, x, "success weakCompareAndSetRelease short"); } { boolean success = vh.weakCompareAndSetRelease((short)0x0123, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetRelease short"); short x = (short) vh.get(); - assertEquals(x, (short)0x4567, "failing weakCompareAndSetRelease short value"); + assertEquals((short)0x4567, x, "failing weakCompareAndSetRelease short value"); } { @@ -850,14 +848,14 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet short"); short x = (short) vh.get(); - assertEquals(x, (short)0x0123, "success weakCompareAndSet short"); + assertEquals((short)0x0123, x, "success weakCompareAndSet short"); } { boolean success = vh.weakCompareAndSet((short)0x4567, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSet short"); short x = (short) vh.get(); - assertEquals(x, (short)0x0123, "failing weakCompareAndSet short value"); + assertEquals((short)0x0123, x, "failing weakCompareAndSet short value"); } // Compare set and get @@ -865,27 +863,27 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { vh.set((short)0x0123); short o = (short) vh.getAndSet((short)0x4567); - assertEquals(o, (short)0x0123, "getAndSet short"); + assertEquals((short)0x0123, o, "getAndSet short"); short x = (short) vh.get(); - assertEquals(x, (short)0x4567, "getAndSet short value"); + assertEquals((short)0x4567, x, "getAndSet short value"); } { vh.set((short)0x0123); short o = (short) vh.getAndSetAcquire((short)0x4567); - assertEquals(o, (short)0x0123, "getAndSetAcquire short"); + assertEquals((short)0x0123, o, "getAndSetAcquire short"); short x = (short) vh.get(); - assertEquals(x, (short)0x4567, "getAndSetAcquire short value"); + assertEquals((short)0x4567, x, "getAndSetAcquire short value"); } { vh.set((short)0x0123); short o = (short) vh.getAndSetRelease((short)0x4567); - assertEquals(o, (short)0x0123, "getAndSetRelease short"); + assertEquals((short)0x0123, o, "getAndSetRelease short"); short x = (short) vh.get(); - assertEquals(x, (short)0x4567, "getAndSetRelease short value"); + assertEquals((short)0x4567, x, "getAndSetRelease short value"); } // get and add, add and get @@ -893,27 +891,27 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { vh.set((short)0x0123); short o = (short) vh.getAndAdd((short)0x4567); - assertEquals(o, (short)0x0123, "getAndAdd short"); + assertEquals((short)0x0123, o, "getAndAdd short"); short x = (short) vh.get(); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAdd short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAdd short value"); } { vh.set((short)0x0123); short o = (short) vh.getAndAddAcquire((short)0x4567); - assertEquals(o, (short)0x0123, "getAndAddAcquire short"); + assertEquals((short)0x0123, o, "getAndAddAcquire short"); short x = (short) vh.get(); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAddAcquire short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAddAcquire short value"); } { vh.set((short)0x0123); short o = (short) vh.getAndAddRelease((short)0x4567); - assertEquals(o, (short)0x0123, "getAndAddReleaseshort"); + assertEquals((short)0x0123, o, "getAndAddReleaseshort"); short x = (short) vh.get(); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAddRelease short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAddRelease short value"); } // get and bitwise or @@ -921,27 +919,27 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { vh.set((short)0x0123); short o = (short) vh.getAndBitwiseOr((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOr short"); + assertEquals((short)0x0123, o, "getAndBitwiseOr short"); short x = (short) vh.get(); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOr short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOr short value"); } { vh.set((short)0x0123); short o = (short) vh.getAndBitwiseOrAcquire((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOrAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseOrAcquire short"); short x = (short) vh.get(); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOrAcquire short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOrAcquire short value"); } { vh.set((short)0x0123); short o = (short) vh.getAndBitwiseOrRelease((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOrRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseOrRelease short"); short x = (short) vh.get(); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOrRelease short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOrRelease short value"); } // get and bitwise and @@ -949,27 +947,27 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { vh.set((short)0x0123); short o = (short) vh.getAndBitwiseAnd((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAnd short"); + assertEquals((short)0x0123, o, "getAndBitwiseAnd short"); short x = (short) vh.get(); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAnd short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAnd short value"); } { vh.set((short)0x0123); short o = (short) vh.getAndBitwiseAndAcquire((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAndAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseAndAcquire short"); short x = (short) vh.get(); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAndAcquire short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAndAcquire short value"); } { vh.set((short)0x0123); short o = (short) vh.getAndBitwiseAndRelease((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAndRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseAndRelease short"); short x = (short) vh.get(); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAndRelease short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAndRelease short value"); } // get and bitwise xor @@ -977,27 +975,27 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { vh.set((short)0x0123); short o = (short) vh.getAndBitwiseXor((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXor short"); + assertEquals((short)0x0123, o, "getAndBitwiseXor short"); short x = (short) vh.get(); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXor short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXor short value"); } { vh.set((short)0x0123); short o = (short) vh.getAndBitwiseXorAcquire((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXorAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseXorAcquire short"); short x = (short) vh.get(); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXorAcquire short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXorAcquire short value"); } { vh.set((short)0x0123); short o = (short) vh.getAndBitwiseXorRelease((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXorRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseXorRelease short"); short x = (short) vh.get(); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXorRelease short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXorRelease short value"); } } @@ -1015,7 +1013,7 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { { vh.set(array, i, (short)0x0123); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x0123, "get short value"); + assertEquals((short)0x0123, x, "get short value"); } @@ -1023,21 +1021,21 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { { vh.setVolatile(array, i, (short)0x4567); short x = (short) vh.getVolatile(array, i); - assertEquals(x, (short)0x4567, "setVolatile short value"); + assertEquals((short)0x4567, x, "setVolatile short value"); } // Lazy { vh.setRelease(array, i, (short)0x0123); short x = (short) vh.getAcquire(array, i); - assertEquals(x, (short)0x0123, "setRelease short value"); + assertEquals((short)0x0123, x, "setRelease short value"); } // Opaque { vh.setOpaque(array, i, (short)0x4567); short x = (short) vh.getOpaque(array, i); - assertEquals(x, (short)0x4567, "setOpaque short value"); + assertEquals((short)0x4567, x, "setOpaque short value"); } vh.set(array, i, (short)0x0123); @@ -1047,56 +1045,56 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { boolean r = vh.compareAndSet(array, i, (short)0x0123, (short)0x4567); assertEquals(r, true, "success compareAndSet short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x4567, "success compareAndSet short value"); + assertEquals((short)0x4567, x, "success compareAndSet short value"); } { boolean r = vh.compareAndSet(array, i, (short)0x0123, (short)0x89AB); assertEquals(r, false, "failing compareAndSet short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x4567, "failing compareAndSet short value"); + assertEquals((short)0x4567, x, "failing compareAndSet short value"); } { short r = (short) vh.compareAndExchange(array, i, (short)0x4567, (short)0x0123); assertEquals(r, (short)0x4567, "success compareAndExchange short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x0123, "success compareAndExchange short value"); + assertEquals((short)0x0123, x, "success compareAndExchange short value"); } { short r = (short) vh.compareAndExchange(array, i, (short)0x4567, (short)0x89AB); assertEquals(r, (short)0x0123, "failing compareAndExchange short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x0123, "failing compareAndExchange short value"); + assertEquals((short)0x0123, x, "failing compareAndExchange short value"); } { short r = (short) vh.compareAndExchangeAcquire(array, i, (short)0x0123, (short)0x4567); assertEquals(r, (short)0x0123, "success compareAndExchangeAcquire short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x4567, "success compareAndExchangeAcquire short value"); + assertEquals((short)0x4567, x, "success compareAndExchangeAcquire short value"); } { short r = (short) vh.compareAndExchangeAcquire(array, i, (short)0x0123, (short)0x89AB); assertEquals(r, (short)0x4567, "failing compareAndExchangeAcquire short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x4567, "failing compareAndExchangeAcquire short value"); + assertEquals((short)0x4567, x, "failing compareAndExchangeAcquire short value"); } { short r = (short) vh.compareAndExchangeRelease(array, i, (short)0x4567, (short)0x0123); assertEquals(r, (short)0x4567, "success compareAndExchangeRelease short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x0123, "success compareAndExchangeRelease short value"); + assertEquals((short)0x0123, x, "success compareAndExchangeRelease short value"); } { short r = (short) vh.compareAndExchangeRelease(array, i, (short)0x4567, (short)0x89AB); assertEquals(r, (short)0x0123, "failing compareAndExchangeRelease short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x0123, "failing compareAndExchangeRelease short value"); + assertEquals((short)0x0123, x, "failing compareAndExchangeRelease short value"); } { @@ -1107,14 +1105,14 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x4567, "success weakCompareAndSetPlain short value"); + assertEquals((short)0x4567, x, "success weakCompareAndSetPlain short value"); } { boolean success = vh.weakCompareAndSetPlain(array, i, (short)0x0123, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetPlain short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x4567, "failing weakCompareAndSetPlain short value"); + assertEquals((short)0x4567, x, "failing weakCompareAndSetPlain short value"); } { @@ -1125,14 +1123,14 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x0123, "success weakCompareAndSetAcquire short"); + assertEquals((short)0x0123, x, "success weakCompareAndSetAcquire short"); } { boolean success = vh.weakCompareAndSetAcquire(array, i, (short)0x4567, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetAcquire short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x0123, "failing weakCompareAndSetAcquire short value"); + assertEquals((short)0x0123, x, "failing weakCompareAndSetAcquire short value"); } { @@ -1143,14 +1141,14 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x4567, "success weakCompareAndSetRelease short"); + assertEquals((short)0x4567, x, "success weakCompareAndSetRelease short"); } { boolean success = vh.weakCompareAndSetRelease(array, i, (short)0x0123, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetRelease short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x4567, "failing weakCompareAndSetRelease short value"); + assertEquals((short)0x4567, x, "failing weakCompareAndSetRelease short value"); } { @@ -1161,14 +1159,14 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x0123, "success weakCompareAndSet short"); + assertEquals((short)0x0123, x, "success weakCompareAndSet short"); } { boolean success = vh.weakCompareAndSet(array, i, (short)0x4567, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSet short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x0123, "failing weakCompareAndSet short value"); + assertEquals((short)0x0123, x, "failing weakCompareAndSet short value"); } // Compare set and get @@ -1176,27 +1174,27 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { vh.set(array, i, (short)0x0123); short o = (short) vh.getAndSet(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndSet short"); + assertEquals((short)0x0123, o, "getAndSet short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x4567, "getAndSet short value"); + assertEquals((short)0x4567, x, "getAndSet short value"); } { vh.set(array, i, (short)0x0123); short o = (short) vh.getAndSetAcquire(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndSetAcquire short"); + assertEquals((short)0x0123, o, "getAndSetAcquire short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x4567, "getAndSetAcquire short value"); + assertEquals((short)0x4567, x, "getAndSetAcquire short value"); } { vh.set(array, i, (short)0x0123); short o = (short) vh.getAndSetRelease(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndSetRelease short"); + assertEquals((short)0x0123, o, "getAndSetRelease short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)0x4567, "getAndSetRelease short value"); + assertEquals((short)0x4567, x, "getAndSetRelease short value"); } // get and add, add and get @@ -1204,27 +1202,27 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { vh.set(array, i, (short)0x0123); short o = (short) vh.getAndAdd(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndAdd short"); + assertEquals((short)0x0123, o, "getAndAdd short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAdd short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAdd short value"); } { vh.set(array, i, (short)0x0123); short o = (short) vh.getAndAddAcquire(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndAddAcquire short"); + assertEquals((short)0x0123, o, "getAndAddAcquire short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAddAcquire short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAddAcquire short value"); } { vh.set(array, i, (short)0x0123); short o = (short) vh.getAndAddRelease(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndAddReleaseshort"); + assertEquals((short)0x0123, o, "getAndAddReleaseshort"); short x = (short) vh.get(array, i); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAddRelease short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAddRelease short value"); } // get and bitwise or @@ -1232,27 +1230,27 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { vh.set(array, i, (short)0x0123); short o = (short) vh.getAndBitwiseOr(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOr short"); + assertEquals((short)0x0123, o, "getAndBitwiseOr short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOr short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOr short value"); } { vh.set(array, i, (short)0x0123); short o = (short) vh.getAndBitwiseOrAcquire(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOrAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseOrAcquire short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOrAcquire short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOrAcquire short value"); } { vh.set(array, i, (short)0x0123); short o = (short) vh.getAndBitwiseOrRelease(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOrRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseOrRelease short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOrRelease short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOrRelease short value"); } // get and bitwise and @@ -1260,27 +1258,27 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { vh.set(array, i, (short)0x0123); short o = (short) vh.getAndBitwiseAnd(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAnd short"); + assertEquals((short)0x0123, o, "getAndBitwiseAnd short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAnd short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAnd short value"); } { vh.set(array, i, (short)0x0123); short o = (short) vh.getAndBitwiseAndAcquire(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAndAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseAndAcquire short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAndAcquire short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAndAcquire short value"); } { vh.set(array, i, (short)0x0123); short o = (short) vh.getAndBitwiseAndRelease(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAndRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseAndRelease short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAndRelease short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAndRelease short value"); } // get and bitwise xor @@ -1288,27 +1286,27 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { vh.set(array, i, (short)0x0123); short o = (short) vh.getAndBitwiseXor(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXor short"); + assertEquals((short)0x0123, o, "getAndBitwiseXor short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXor short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXor short value"); } { vh.set(array, i, (short)0x0123); short o = (short) vh.getAndBitwiseXorAcquire(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXorAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseXorAcquire short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXorAcquire short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXorAcquire short value"); } { vh.set(array, i, (short)0x0123); short o = (short) vh.getAndBitwiseXorRelease(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXorRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseXorRelease short"); short x = (short) vh.get(array, i); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXorRelease short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXorRelease short value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessString.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessString.java index 8bc30739660..d1a746ba80e 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessString.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,28 +23,30 @@ /* * @test - * @run testng/othervm -Diters=10 -Xint VarHandleTestAccessString + * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessString * * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds * - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessString - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessString - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessString + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessString + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessString + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessString */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestAccessString extends VarHandleBaseTest { static final String static_final_v = "foo"; @@ -109,7 +111,7 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { return vhs.toArray(new VarHandle[0]); } - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestAccessString.class, "final_v", String.class); @@ -127,8 +129,6 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { vhArrayObject = MethodHandles.arrayElementVarHandle(Object[].class); } - - @DataProvider public Object[][] varHandlesProvider() throws Exception { List vhs = new ArrayList<>(); vhs.add(vhField); @@ -158,7 +158,8 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("varHandlesProvider") public void testIsAccessModeSupported(VarHandle vh) { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET)); @@ -196,8 +197,6 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE)); } - - @DataProvider public Object[][] typesProvider() throws Exception { List types = new ArrayList<>(); types.add(new Object[] {vhField, Arrays.asList(VarHandleTestAccessString.class)}); @@ -207,16 +206,16 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { return types.stream().toArray(Object[][]::new); } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), String.class); + assertEquals(String.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - @Test public void testLookupInstanceToStatic() { checkIAE("Lookup of static final field to instance final field", () -> { @@ -243,8 +242,6 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { }); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -291,7 +288,8 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -304,26 +302,26 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { // Plain { String x = (String) vh.get(recv); - assertEquals(x, "foo", "get String value"); + assertEquals("foo", x, "get String value"); } // Volatile { String x = (String) vh.getVolatile(recv); - assertEquals(x, "foo", "getVolatile String value"); + assertEquals("foo", x, "getVolatile String value"); } // Lazy { String x = (String) vh.getAcquire(recv); - assertEquals(x, "foo", "getRelease String value"); + assertEquals("foo", x, "getRelease String value"); } // Opaque { String x = (String) vh.getOpaque(recv); - assertEquals(x, "foo", "getOpaque String value"); + assertEquals("foo", x, "getOpaque String value"); } } @@ -399,26 +397,26 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { // Plain { String x = (String) vh.get(); - assertEquals(x, "foo", "get String value"); + assertEquals("foo", x, "get String value"); } // Volatile { String x = (String) vh.getVolatile(); - assertEquals(x, "foo", "getVolatile String value"); + assertEquals("foo", x, "getVolatile String value"); } // Lazy { String x = (String) vh.getAcquire(); - assertEquals(x, "foo", "getRelease String value"); + assertEquals("foo", x, "getRelease String value"); } // Opaque { String x = (String) vh.getOpaque(); - assertEquals(x, "foo", "getOpaque String value"); + assertEquals("foo", x, "getOpaque String value"); } } @@ -495,7 +493,7 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { { vh.set(recv, "foo"); String x = (String) vh.get(recv); - assertEquals(x, "foo", "set String value"); + assertEquals("foo", x, "set String value"); } @@ -503,21 +501,21 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { { vh.setVolatile(recv, "bar"); String x = (String) vh.getVolatile(recv); - assertEquals(x, "bar", "setVolatile String value"); + assertEquals("bar", x, "setVolatile String value"); } // Lazy { vh.setRelease(recv, "foo"); String x = (String) vh.getAcquire(recv); - assertEquals(x, "foo", "setRelease String value"); + assertEquals("foo", x, "setRelease String value"); } // Opaque { vh.setOpaque(recv, "bar"); String x = (String) vh.getOpaque(recv); - assertEquals(x, "bar", "setOpaque String value"); + assertEquals("bar", x, "setOpaque String value"); } vh.set(recv, "foo"); @@ -527,56 +525,56 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { boolean r = vh.compareAndSet(recv, "foo", "bar"); assertEquals(r, true, "success compareAndSet String"); String x = (String) vh.get(recv); - assertEquals(x, "bar", "success compareAndSet String value"); + assertEquals("bar", x, "success compareAndSet String value"); } { boolean r = vh.compareAndSet(recv, "foo", "baz"); assertEquals(r, false, "failing compareAndSet String"); String x = (String) vh.get(recv); - assertEquals(x, "bar", "failing compareAndSet String value"); + assertEquals("bar", x, "failing compareAndSet String value"); } { String r = (String) vh.compareAndExchange(recv, "bar", "foo"); assertEquals(r, "bar", "success compareAndExchange String"); String x = (String) vh.get(recv); - assertEquals(x, "foo", "success compareAndExchange String value"); + assertEquals("foo", x, "success compareAndExchange String value"); } { String r = (String) vh.compareAndExchange(recv, "bar", "baz"); assertEquals(r, "foo", "failing compareAndExchange String"); String x = (String) vh.get(recv); - assertEquals(x, "foo", "failing compareAndExchange String value"); + assertEquals("foo", x, "failing compareAndExchange String value"); } { String r = (String) vh.compareAndExchangeAcquire(recv, "foo", "bar"); assertEquals(r, "foo", "success compareAndExchangeAcquire String"); String x = (String) vh.get(recv); - assertEquals(x, "bar", "success compareAndExchangeAcquire String value"); + assertEquals("bar", x, "success compareAndExchangeAcquire String value"); } { String r = (String) vh.compareAndExchangeAcquire(recv, "foo", "baz"); assertEquals(r, "bar", "failing compareAndExchangeAcquire String"); String x = (String) vh.get(recv); - assertEquals(x, "bar", "failing compareAndExchangeAcquire String value"); + assertEquals("bar", x, "failing compareAndExchangeAcquire String value"); } { String r = (String) vh.compareAndExchangeRelease(recv, "bar", "foo"); assertEquals(r, "bar", "success compareAndExchangeRelease String"); String x = (String) vh.get(recv); - assertEquals(x, "foo", "success compareAndExchangeRelease String value"); + assertEquals("foo", x, "success compareAndExchangeRelease String value"); } { String r = (String) vh.compareAndExchangeRelease(recv, "bar", "baz"); assertEquals(r, "foo", "failing compareAndExchangeRelease String"); String x = (String) vh.get(recv); - assertEquals(x, "foo", "failing compareAndExchangeRelease String value"); + assertEquals("foo", x, "failing compareAndExchangeRelease String value"); } { @@ -587,14 +585,14 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain String"); String x = (String) vh.get(recv); - assertEquals(x, "bar", "success weakCompareAndSetPlain String value"); + assertEquals("bar", x, "success weakCompareAndSetPlain String value"); } { boolean success = vh.weakCompareAndSetPlain(recv, "foo", "baz"); assertEquals(success, false, "failing weakCompareAndSetPlain String"); String x = (String) vh.get(recv); - assertEquals(x, "bar", "failing weakCompareAndSetPlain String value"); + assertEquals("bar", x, "failing weakCompareAndSetPlain String value"); } { @@ -605,14 +603,14 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire String"); String x = (String) vh.get(recv); - assertEquals(x, "foo", "success weakCompareAndSetAcquire String"); + assertEquals("foo", x, "success weakCompareAndSetAcquire String"); } { boolean success = vh.weakCompareAndSetAcquire(recv, "bar", "baz"); assertEquals(success, false, "failing weakCompareAndSetAcquire String"); String x = (String) vh.get(recv); - assertEquals(x, "foo", "failing weakCompareAndSetAcquire String value"); + assertEquals("foo", x, "failing weakCompareAndSetAcquire String value"); } { @@ -623,14 +621,14 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease String"); String x = (String) vh.get(recv); - assertEquals(x, "bar", "success weakCompareAndSetRelease String"); + assertEquals("bar", x, "success weakCompareAndSetRelease String"); } { boolean success = vh.weakCompareAndSetRelease(recv, "foo", "baz"); assertEquals(success, false, "failing weakCompareAndSetRelease String"); String x = (String) vh.get(recv); - assertEquals(x, "bar", "failing weakCompareAndSetRelease String value"); + assertEquals("bar", x, "failing weakCompareAndSetRelease String value"); } { @@ -641,14 +639,14 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet String"); String x = (String) vh.get(recv); - assertEquals(x, "foo", "success weakCompareAndSet String value"); + assertEquals("foo", x, "success weakCompareAndSet String value"); } { boolean success = vh.weakCompareAndSet(recv, "bar", "baz"); assertEquals(success, false, "failing weakCompareAndSet String"); String x = (String) vh.get(recv); - assertEquals(x, "foo", "failing weakCompareAndSet String value"); + assertEquals("foo", x, "failing weakCompareAndSet String value"); } // Compare set and get @@ -656,27 +654,27 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { vh.set(recv, "foo"); String o = (String) vh.getAndSet(recv, "bar"); - assertEquals(o, "foo", "getAndSet String"); + assertEquals("foo", o, "getAndSet String"); String x = (String) vh.get(recv); - assertEquals(x, "bar", "getAndSet String value"); + assertEquals("bar", x, "getAndSet String value"); } { vh.set(recv, "foo"); String o = (String) vh.getAndSetAcquire(recv, "bar"); - assertEquals(o, "foo", "getAndSetAcquire String"); + assertEquals("foo", o, "getAndSetAcquire String"); String x = (String) vh.get(recv); - assertEquals(x, "bar", "getAndSetAcquire String value"); + assertEquals("bar", x, "getAndSetAcquire String value"); } { vh.set(recv, "foo"); String o = (String) vh.getAndSetRelease(recv, "bar"); - assertEquals(o, "foo", "getAndSetRelease String"); + assertEquals("foo", o, "getAndSetRelease String"); String x = (String) vh.get(recv); - assertEquals(x, "bar", "getAndSetRelease String value"); + assertEquals("bar", x, "getAndSetRelease String value"); } @@ -739,7 +737,7 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { { vh.set("foo"); String x = (String) vh.get(); - assertEquals(x, "foo", "set String value"); + assertEquals("foo", x, "set String value"); } @@ -747,21 +745,21 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { { vh.setVolatile("bar"); String x = (String) vh.getVolatile(); - assertEquals(x, "bar", "setVolatile String value"); + assertEquals("bar", x, "setVolatile String value"); } // Lazy { vh.setRelease("foo"); String x = (String) vh.getAcquire(); - assertEquals(x, "foo", "setRelease String value"); + assertEquals("foo", x, "setRelease String value"); } // Opaque { vh.setOpaque("bar"); String x = (String) vh.getOpaque(); - assertEquals(x, "bar", "setOpaque String value"); + assertEquals("bar", x, "setOpaque String value"); } vh.set("foo"); @@ -771,56 +769,56 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { boolean r = vh.compareAndSet("foo", "bar"); assertEquals(r, true, "success compareAndSet String"); String x = (String) vh.get(); - assertEquals(x, "bar", "success compareAndSet String value"); + assertEquals("bar", x, "success compareAndSet String value"); } { boolean r = vh.compareAndSet("foo", "baz"); assertEquals(r, false, "failing compareAndSet String"); String x = (String) vh.get(); - assertEquals(x, "bar", "failing compareAndSet String value"); + assertEquals("bar", x, "failing compareAndSet String value"); } { String r = (String) vh.compareAndExchange("bar", "foo"); assertEquals(r, "bar", "success compareAndExchange String"); String x = (String) vh.get(); - assertEquals(x, "foo", "success compareAndExchange String value"); + assertEquals("foo", x, "success compareAndExchange String value"); } { String r = (String) vh.compareAndExchange("bar", "baz"); assertEquals(r, "foo", "failing compareAndExchange String"); String x = (String) vh.get(); - assertEquals(x, "foo", "failing compareAndExchange String value"); + assertEquals("foo", x, "failing compareAndExchange String value"); } { String r = (String) vh.compareAndExchangeAcquire("foo", "bar"); assertEquals(r, "foo", "success compareAndExchangeAcquire String"); String x = (String) vh.get(); - assertEquals(x, "bar", "success compareAndExchangeAcquire String value"); + assertEquals("bar", x, "success compareAndExchangeAcquire String value"); } { String r = (String) vh.compareAndExchangeAcquire("foo", "baz"); assertEquals(r, "bar", "failing compareAndExchangeAcquire String"); String x = (String) vh.get(); - assertEquals(x, "bar", "failing compareAndExchangeAcquire String value"); + assertEquals("bar", x, "failing compareAndExchangeAcquire String value"); } { String r = (String) vh.compareAndExchangeRelease("bar", "foo"); assertEquals(r, "bar", "success compareAndExchangeRelease String"); String x = (String) vh.get(); - assertEquals(x, "foo", "success compareAndExchangeRelease String value"); + assertEquals("foo", x, "success compareAndExchangeRelease String value"); } { String r = (String) vh.compareAndExchangeRelease("bar", "baz"); assertEquals(r, "foo", "failing compareAndExchangeRelease String"); String x = (String) vh.get(); - assertEquals(x, "foo", "failing compareAndExchangeRelease String value"); + assertEquals("foo", x, "failing compareAndExchangeRelease String value"); } { @@ -831,14 +829,14 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain String"); String x = (String) vh.get(); - assertEquals(x, "bar", "success weakCompareAndSetPlain String value"); + assertEquals("bar", x, "success weakCompareAndSetPlain String value"); } { boolean success = vh.weakCompareAndSetPlain("foo", "baz"); assertEquals(success, false, "failing weakCompareAndSetPlain String"); String x = (String) vh.get(); - assertEquals(x, "bar", "failing weakCompareAndSetPlain String value"); + assertEquals("bar", x, "failing weakCompareAndSetPlain String value"); } { @@ -849,14 +847,14 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire String"); String x = (String) vh.get(); - assertEquals(x, "foo", "success weakCompareAndSetAcquire String"); + assertEquals("foo", x, "success weakCompareAndSetAcquire String"); } { boolean success = vh.weakCompareAndSetAcquire("bar", "baz"); assertEquals(success, false, "failing weakCompareAndSetAcquire String"); String x = (String) vh.get(); - assertEquals(x, "foo", "failing weakCompareAndSetAcquire String value"); + assertEquals("foo", x, "failing weakCompareAndSetAcquire String value"); } { @@ -867,14 +865,14 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease String"); String x = (String) vh.get(); - assertEquals(x, "bar", "success weakCompareAndSetRelease String"); + assertEquals("bar", x, "success weakCompareAndSetRelease String"); } { boolean success = vh.weakCompareAndSetRelease("foo", "baz"); assertEquals(success, false, "failing weakCompareAndSetRelease String"); String x = (String) vh.get(); - assertEquals(x, "bar", "failing weakCompareAndSetRelease String value"); + assertEquals("bar", x, "failing weakCompareAndSetRelease String value"); } { @@ -885,14 +883,14 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet String"); String x = (String) vh.get(); - assertEquals(x, "foo", "success weakCompareAndSet String"); + assertEquals("foo", x, "success weakCompareAndSet String"); } { boolean success = vh.weakCompareAndSet("bar", "baz"); assertEquals(success, false, "failing weakCompareAndSet String"); String x = (String) vh.get(); - assertEquals(x, "foo", "failing weakCompareAndSet String value"); + assertEquals("foo", x, "failing weakCompareAndSet String value"); } // Compare set and get @@ -900,27 +898,27 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { vh.set("foo"); String o = (String) vh.getAndSet("bar"); - assertEquals(o, "foo", "getAndSet String"); + assertEquals("foo", o, "getAndSet String"); String x = (String) vh.get(); - assertEquals(x, "bar", "getAndSet String value"); + assertEquals("bar", x, "getAndSet String value"); } { vh.set("foo"); String o = (String) vh.getAndSetAcquire("bar"); - assertEquals(o, "foo", "getAndSetAcquire String"); + assertEquals("foo", o, "getAndSetAcquire String"); String x = (String) vh.get(); - assertEquals(x, "bar", "getAndSetAcquire String value"); + assertEquals("bar", x, "getAndSetAcquire String value"); } { vh.set("foo"); String o = (String) vh.getAndSetRelease("bar"); - assertEquals(o, "foo", "getAndSetRelease String"); + assertEquals("foo", o, "getAndSetRelease String"); String x = (String) vh.get(); - assertEquals(x, "bar", "getAndSetRelease String value"); + assertEquals("bar", x, "getAndSetRelease String value"); } @@ -986,7 +984,7 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { { vh.set(array, i, "foo"); String x = (String) vh.get(array, i); - assertEquals(x, "foo", "get String value"); + assertEquals("foo", x, "get String value"); } @@ -994,21 +992,21 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { { vh.setVolatile(array, i, "bar"); String x = (String) vh.getVolatile(array, i); - assertEquals(x, "bar", "setVolatile String value"); + assertEquals("bar", x, "setVolatile String value"); } // Lazy { vh.setRelease(array, i, "foo"); String x = (String) vh.getAcquire(array, i); - assertEquals(x, "foo", "setRelease String value"); + assertEquals("foo", x, "setRelease String value"); } // Opaque { vh.setOpaque(array, i, "bar"); String x = (String) vh.getOpaque(array, i); - assertEquals(x, "bar", "setOpaque String value"); + assertEquals("bar", x, "setOpaque String value"); } vh.set(array, i, "foo"); @@ -1018,56 +1016,56 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { boolean r = vh.compareAndSet(array, i, "foo", "bar"); assertEquals(r, true, "success compareAndSet String"); String x = (String) vh.get(array, i); - assertEquals(x, "bar", "success compareAndSet String value"); + assertEquals("bar", x, "success compareAndSet String value"); } { boolean r = vh.compareAndSet(array, i, "foo", "baz"); assertEquals(r, false, "failing compareAndSet String"); String x = (String) vh.get(array, i); - assertEquals(x, "bar", "failing compareAndSet String value"); + assertEquals("bar", x, "failing compareAndSet String value"); } { String r = (String) vh.compareAndExchange(array, i, "bar", "foo"); assertEquals(r, "bar", "success compareAndExchange String"); String x = (String) vh.get(array, i); - assertEquals(x, "foo", "success compareAndExchange String value"); + assertEquals("foo", x, "success compareAndExchange String value"); } { String r = (String) vh.compareAndExchange(array, i, "bar", "baz"); assertEquals(r, "foo", "failing compareAndExchange String"); String x = (String) vh.get(array, i); - assertEquals(x, "foo", "failing compareAndExchange String value"); + assertEquals("foo", x, "failing compareAndExchange String value"); } { String r = (String) vh.compareAndExchangeAcquire(array, i, "foo", "bar"); assertEquals(r, "foo", "success compareAndExchangeAcquire String"); String x = (String) vh.get(array, i); - assertEquals(x, "bar", "success compareAndExchangeAcquire String value"); + assertEquals("bar", x, "success compareAndExchangeAcquire String value"); } { String r = (String) vh.compareAndExchangeAcquire(array, i, "foo", "baz"); assertEquals(r, "bar", "failing compareAndExchangeAcquire String"); String x = (String) vh.get(array, i); - assertEquals(x, "bar", "failing compareAndExchangeAcquire String value"); + assertEquals("bar", x, "failing compareAndExchangeAcquire String value"); } { String r = (String) vh.compareAndExchangeRelease(array, i, "bar", "foo"); assertEquals(r, "bar", "success compareAndExchangeRelease String"); String x = (String) vh.get(array, i); - assertEquals(x, "foo", "success compareAndExchangeRelease String value"); + assertEquals("foo", x, "success compareAndExchangeRelease String value"); } { String r = (String) vh.compareAndExchangeRelease(array, i, "bar", "baz"); assertEquals(r, "foo", "failing compareAndExchangeRelease String"); String x = (String) vh.get(array, i); - assertEquals(x, "foo", "failing compareAndExchangeRelease String value"); + assertEquals("foo", x, "failing compareAndExchangeRelease String value"); } { @@ -1078,14 +1076,14 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain String"); String x = (String) vh.get(array, i); - assertEquals(x, "bar", "success weakCompareAndSetPlain String value"); + assertEquals("bar", x, "success weakCompareAndSetPlain String value"); } { boolean success = vh.weakCompareAndSetPlain(array, i, "foo", "baz"); assertEquals(success, false, "failing weakCompareAndSetPlain String"); String x = (String) vh.get(array, i); - assertEquals(x, "bar", "failing weakCompareAndSetPlain String value"); + assertEquals("bar", x, "failing weakCompareAndSetPlain String value"); } { @@ -1096,14 +1094,14 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire String"); String x = (String) vh.get(array, i); - assertEquals(x, "foo", "success weakCompareAndSetAcquire String"); + assertEquals("foo", x, "success weakCompareAndSetAcquire String"); } { boolean success = vh.weakCompareAndSetAcquire(array, i, "bar", "baz"); assertEquals(success, false, "failing weakCompareAndSetAcquire String"); String x = (String) vh.get(array, i); - assertEquals(x, "foo", "failing weakCompareAndSetAcquire String value"); + assertEquals("foo", x, "failing weakCompareAndSetAcquire String value"); } { @@ -1114,14 +1112,14 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease String"); String x = (String) vh.get(array, i); - assertEquals(x, "bar", "success weakCompareAndSetRelease String"); + assertEquals("bar", x, "success weakCompareAndSetRelease String"); } { boolean success = vh.weakCompareAndSetRelease(array, i, "foo", "baz"); assertEquals(success, false, "failing weakCompareAndSetRelease String"); String x = (String) vh.get(array, i); - assertEquals(x, "bar", "failing weakCompareAndSetRelease String value"); + assertEquals("bar", x, "failing weakCompareAndSetRelease String value"); } { @@ -1132,14 +1130,14 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet String"); String x = (String) vh.get(array, i); - assertEquals(x, "foo", "success weakCompareAndSet String"); + assertEquals("foo", x, "success weakCompareAndSet String"); } { boolean success = vh.weakCompareAndSet(array, i, "bar", "baz"); assertEquals(success, false, "failing weakCompareAndSet String"); String x = (String) vh.get(array, i); - assertEquals(x, "foo", "failing weakCompareAndSet String value"); + assertEquals("foo", x, "failing weakCompareAndSet String value"); } // Compare set and get @@ -1147,27 +1145,27 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { vh.set(array, i, "foo"); String o = (String) vh.getAndSet(array, i, "bar"); - assertEquals(o, "foo", "getAndSet String"); + assertEquals("foo", o, "getAndSet String"); String x = (String) vh.get(array, i); - assertEquals(x, "bar", "getAndSet String value"); + assertEquals("bar", x, "getAndSet String value"); } { vh.set(array, i, "foo"); String o = (String) vh.getAndSetAcquire(array, i, "bar"); - assertEquals(o, "foo", "getAndSetAcquire String"); + assertEquals("foo", o, "getAndSetAcquire String"); String x = (String) vh.get(array, i); - assertEquals(x, "bar", "getAndSetAcquire String value"); + assertEquals("bar", x, "getAndSetAcquire String value"); } { vh.set(array, i, "foo"); String o = (String) vh.getAndSetRelease(array, i, "bar"); - assertEquals(o, "foo", "getAndSetRelease String"); + assertEquals("foo", o, "getAndSetRelease String"); String x = (String) vh.get(array, i); - assertEquals(x, "bar", "getAndSetRelease String value"); + assertEquals("bar", x, "getAndSetRelease String value"); } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java index 78c13da45a9..26ac4aab893 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,25 +26,25 @@ * @bug 8154556 * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsChar - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsChar - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsChar + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsChar + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsChar + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsChar */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestByteArrayAsChar extends VarHandleBaseByteArrayTest { static final int SIZE = Character.BYTES; @@ -107,7 +107,8 @@ public class VarHandleTestByteArrayAsChar extends VarHandleBaseByteArrayTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("VarHandleBaseByteArrayTest#varHandlesProvider") public void testIsAccessModeSupported(VarHandleSource vhs) { VarHandle vh = vhs.s; @@ -158,17 +159,16 @@ public class VarHandleTestByteArrayAsChar extends VarHandleBaseByteArrayTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE)); } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), char.class); + assertEquals(char.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -230,7 +230,8 @@ public class VarHandleTestByteArrayAsChar extends VarHandleBaseByteArrayTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -239,7 +240,6 @@ public class VarHandleTestByteArrayAsChar extends VarHandleBaseByteArrayTest { } } - static void testArrayNPE(ByteArraySource bs, VarHandleSource vhs) { VarHandle vh = vhs.s; byte[] array = null; @@ -740,7 +740,7 @@ public class VarHandleTestByteArrayAsChar extends VarHandleBaseByteArrayTest { { vh.set(array, i, VALUE_1); char x = (char) vh.get(array, i); - assertEquals(x, VALUE_1, "get char value"); + assertEquals(VALUE_1, x, "get char value"); } } } @@ -759,7 +759,7 @@ public class VarHandleTestByteArrayAsChar extends VarHandleBaseByteArrayTest { { vh.set(array, i, VALUE_1); char x = (char) vh.get(array, i); - assertEquals(x, VALUE_1, "get char value"); + assertEquals(VALUE_1, x, "get char value"); } if (iAligned) { @@ -767,21 +767,21 @@ public class VarHandleTestByteArrayAsChar extends VarHandleBaseByteArrayTest { { vh.setVolatile(array, i, VALUE_2); char x = (char) vh.getVolatile(array, i); - assertEquals(x, VALUE_2, "setVolatile char value"); + assertEquals(VALUE_2, x, "setVolatile char value"); } // Lazy { vh.setRelease(array, i, VALUE_1); char x = (char) vh.getAcquire(array, i); - assertEquals(x, VALUE_1, "setRelease char value"); + assertEquals(VALUE_1, x, "setRelease char value"); } // Opaque { vh.setOpaque(array, i, VALUE_2); char x = (char) vh.getOpaque(array, i); - assertEquals(x, VALUE_2, "setOpaque char value"); + assertEquals(VALUE_2, x, "setOpaque char value"); } @@ -807,26 +807,26 @@ public class VarHandleTestByteArrayAsChar extends VarHandleBaseByteArrayTest { // Plain { char x = (char) vh.get(array, i); - assertEquals(x, v, "get char value"); + assertEquals(v, x, "get char value"); } if (iAligned) { // Volatile { char x = (char) vh.getVolatile(array, i); - assertEquals(x, v, "getVolatile char value"); + assertEquals(v, x, "getVolatile char value"); } // Lazy { char x = (char) vh.getAcquire(array, i); - assertEquals(x, v, "getRelease char value"); + assertEquals(v, x, "getRelease char value"); } // Opaque { char x = (char) vh.getOpaque(array, i); - assertEquals(x, v, "getOpaque char value"); + assertEquals(v, x, "getOpaque char value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java index 331b9073e90..a9e1e603c5d 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,25 +26,25 @@ * @bug 8154556 * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsDouble - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsDouble - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsDouble + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsDouble + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsDouble + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsDouble */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { static final int SIZE = Double.BYTES; @@ -107,7 +107,8 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("VarHandleBaseByteArrayTest#varHandlesProvider") public void testIsAccessModeSupported(VarHandleSource vhs) { VarHandle vh = vhs.s; @@ -172,17 +173,16 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE)); } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), double.class); + assertEquals(double.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -244,7 +244,8 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -253,7 +254,6 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { } } - static void testArrayNPE(ByteArraySource bs, VarHandleSource vhs) { VarHandle vh = vhs.s; byte[] array = null; @@ -883,7 +883,7 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { { vh.set(array, i, VALUE_1); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_1, "get double value"); + assertEquals(VALUE_1, x, "get double value"); } } } @@ -902,7 +902,7 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { { vh.set(array, i, VALUE_1); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_1, "get double value"); + assertEquals(VALUE_1, x, "get double value"); } if (iAligned) { @@ -910,21 +910,21 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { { vh.setVolatile(array, i, VALUE_2); double x = (double) vh.getVolatile(array, i); - assertEquals(x, VALUE_2, "setVolatile double value"); + assertEquals(VALUE_2, x, "setVolatile double value"); } // Lazy { vh.setRelease(array, i, VALUE_1); double x = (double) vh.getAcquire(array, i); - assertEquals(x, VALUE_1, "setRelease double value"); + assertEquals(VALUE_1, x, "setRelease double value"); } // Opaque { vh.setOpaque(array, i, VALUE_2); double x = (double) vh.getOpaque(array, i); - assertEquals(x, VALUE_2, "setOpaque double value"); + assertEquals(VALUE_2, x, "setOpaque double value"); } vh.set(array, i, VALUE_1); @@ -934,56 +934,56 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { boolean r = vh.compareAndSet(array, i, VALUE_1, VALUE_2); assertEquals(r, true, "success compareAndSet double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_2, "success compareAndSet double value"); + assertEquals(VALUE_2, x, "success compareAndSet double value"); } { boolean r = vh.compareAndSet(array, i, VALUE_1, VALUE_3); assertEquals(r, false, "failing compareAndSet double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_2, "failing compareAndSet double value"); + assertEquals(VALUE_2, x, "failing compareAndSet double value"); } { double r = (double) vh.compareAndExchange(array, i, VALUE_2, VALUE_1); assertEquals(r, VALUE_2, "success compareAndExchange double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_1, "success compareAndExchange double value"); + assertEquals(VALUE_1, x, "success compareAndExchange double value"); } { double r = (double) vh.compareAndExchange(array, i, VALUE_2, VALUE_3); assertEquals(r, VALUE_1, "failing compareAndExchange double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_1, "failing compareAndExchange double value"); + assertEquals(VALUE_1, x, "failing compareAndExchange double value"); } { double r = (double) vh.compareAndExchangeAcquire(array, i, VALUE_1, VALUE_2); assertEquals(r, VALUE_1, "success compareAndExchangeAcquire double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_2, "success compareAndExchangeAcquire double value"); + assertEquals(VALUE_2, x, "success compareAndExchangeAcquire double value"); } { double r = (double) vh.compareAndExchangeAcquire(array, i, VALUE_1, VALUE_3); assertEquals(r, VALUE_2, "failing compareAndExchangeAcquire double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_2, "failing compareAndExchangeAcquire double value"); + assertEquals(VALUE_2, x, "failing compareAndExchangeAcquire double value"); } { double r = (double) vh.compareAndExchangeRelease(array, i, VALUE_2, VALUE_1); assertEquals(r, VALUE_2, "success compareAndExchangeRelease double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_1, "success compareAndExchangeRelease double value"); + assertEquals(VALUE_1, x, "success compareAndExchangeRelease double value"); } { double r = (double) vh.compareAndExchangeRelease(array, i, VALUE_2, VALUE_3); assertEquals(r, VALUE_1, "failing compareAndExchangeRelease double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_1, "failing compareAndExchangeRelease double value"); + assertEquals(VALUE_1, x, "failing compareAndExchangeRelease double value"); } { @@ -994,14 +994,14 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSetPlain double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_2, "success weakCompareAndSetPlain double value"); + assertEquals(VALUE_2, x, "success weakCompareAndSetPlain double value"); } { boolean success = vh.weakCompareAndSetPlain(array, i, VALUE_1, VALUE_3); assertEquals(success, false, "failing weakCompareAndSetPlain double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_2, "failing weakCompareAndSetPlain double value"); + assertEquals(VALUE_2, x, "failing weakCompareAndSetPlain double value"); } { @@ -1012,14 +1012,14 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSetAcquire double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_1, "success weakCompareAndSetAcquire double"); + assertEquals(VALUE_1, x, "success weakCompareAndSetAcquire double"); } { boolean success = vh.weakCompareAndSetAcquire(array, i, VALUE_2, VALUE_3); assertEquals(success, false, "failing weakCompareAndSetAcquire double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_1, "failing weakCompareAndSetAcquire double value"); + assertEquals(VALUE_1, x, "failing weakCompareAndSetAcquire double value"); } { @@ -1030,14 +1030,14 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSetRelease double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_2, "success weakCompareAndSetRelease double"); + assertEquals(VALUE_2, x, "success weakCompareAndSetRelease double"); } { boolean success = vh.weakCompareAndSetRelease(array, i, VALUE_1, VALUE_3); assertEquals(success, false, "failing weakCompareAndSetRelease double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_2, "failing weakCompareAndSetRelease double value"); + assertEquals(VALUE_2, x, "failing weakCompareAndSetRelease double value"); } { @@ -1048,14 +1048,14 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSet double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_1, "success weakCompareAndSet double"); + assertEquals(VALUE_1, x, "success weakCompareAndSet double"); } { boolean success = vh.weakCompareAndSet(array, i, VALUE_2, VALUE_3); assertEquals(success, false, "failing weakCompareAndSet double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_1, "failing weakCompareAndSet double value"); + assertEquals(VALUE_1, x, "failing weakCompareAndSet double value"); } // Compare set and get @@ -1063,27 +1063,27 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); double o = (double) vh.getAndSet(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndSet double"); + assertEquals(VALUE_1, o, "getAndSet double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_2, "getAndSet double value"); + assertEquals(VALUE_2, x, "getAndSet double value"); } { vh.set(array, i, VALUE_1); double o = (double) vh.getAndSetAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndSetAcquire double"); + assertEquals(VALUE_1, o, "getAndSetAcquire double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_2, "getAndSetAcquire double value"); + assertEquals(VALUE_2, x, "getAndSetAcquire double value"); } { vh.set(array, i, VALUE_1); double o = (double) vh.getAndSetRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndSetRelease double"); + assertEquals(VALUE_1, o, "getAndSetRelease double"); double x = (double) vh.get(array, i); - assertEquals(x, VALUE_2, "getAndSetRelease double value"); + assertEquals(VALUE_2, x, "getAndSetRelease double value"); } @@ -1109,26 +1109,26 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { // Plain { double x = (double) vh.get(array, i); - assertEquals(x, v, "get double value"); + assertEquals(v, x, "get double value"); } if (iAligned) { // Volatile { double x = (double) vh.getVolatile(array, i); - assertEquals(x, v, "getVolatile double value"); + assertEquals(v, x, "getVolatile double value"); } // Lazy { double x = (double) vh.getAcquire(array, i); - assertEquals(x, v, "getRelease double value"); + assertEquals(v, x, "getRelease double value"); } // Opaque { double x = (double) vh.getOpaque(array, i); - assertEquals(x, v, "getOpaque double value"); + assertEquals(v, x, "getOpaque double value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java index 908d61dd597..486487518e9 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,25 +26,25 @@ * @bug 8154556 * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsFloat - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsFloat - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsFloat + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsFloat + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsFloat + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsFloat */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { static final int SIZE = Float.BYTES; @@ -107,7 +107,8 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("VarHandleBaseByteArrayTest#varHandlesProvider") public void testIsAccessModeSupported(VarHandleSource vhs) { VarHandle vh = vhs.s; @@ -172,17 +173,16 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE)); } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), float.class); + assertEquals(float.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -244,7 +244,8 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -253,7 +254,6 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { } } - static void testArrayNPE(ByteArraySource bs, VarHandleSource vhs) { VarHandle vh = vhs.s; byte[] array = null; @@ -883,7 +883,7 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { { vh.set(array, i, VALUE_1); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_1, "get float value"); + assertEquals(VALUE_1, x, "get float value"); } } } @@ -902,7 +902,7 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { { vh.set(array, i, VALUE_1); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_1, "get float value"); + assertEquals(VALUE_1, x, "get float value"); } if (iAligned) { @@ -910,21 +910,21 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { { vh.setVolatile(array, i, VALUE_2); float x = (float) vh.getVolatile(array, i); - assertEquals(x, VALUE_2, "setVolatile float value"); + assertEquals(VALUE_2, x, "setVolatile float value"); } // Lazy { vh.setRelease(array, i, VALUE_1); float x = (float) vh.getAcquire(array, i); - assertEquals(x, VALUE_1, "setRelease float value"); + assertEquals(VALUE_1, x, "setRelease float value"); } // Opaque { vh.setOpaque(array, i, VALUE_2); float x = (float) vh.getOpaque(array, i); - assertEquals(x, VALUE_2, "setOpaque float value"); + assertEquals(VALUE_2, x, "setOpaque float value"); } vh.set(array, i, VALUE_1); @@ -934,56 +934,56 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { boolean r = vh.compareAndSet(array, i, VALUE_1, VALUE_2); assertEquals(r, true, "success compareAndSet float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_2, "success compareAndSet float value"); + assertEquals(VALUE_2, x, "success compareAndSet float value"); } { boolean r = vh.compareAndSet(array, i, VALUE_1, VALUE_3); assertEquals(r, false, "failing compareAndSet float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_2, "failing compareAndSet float value"); + assertEquals(VALUE_2, x, "failing compareAndSet float value"); } { float r = (float) vh.compareAndExchange(array, i, VALUE_2, VALUE_1); assertEquals(r, VALUE_2, "success compareAndExchange float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_1, "success compareAndExchange float value"); + assertEquals(VALUE_1, x, "success compareAndExchange float value"); } { float r = (float) vh.compareAndExchange(array, i, VALUE_2, VALUE_3); assertEquals(r, VALUE_1, "failing compareAndExchange float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_1, "failing compareAndExchange float value"); + assertEquals(VALUE_1, x, "failing compareAndExchange float value"); } { float r = (float) vh.compareAndExchangeAcquire(array, i, VALUE_1, VALUE_2); assertEquals(r, VALUE_1, "success compareAndExchangeAcquire float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_2, "success compareAndExchangeAcquire float value"); + assertEquals(VALUE_2, x, "success compareAndExchangeAcquire float value"); } { float r = (float) vh.compareAndExchangeAcquire(array, i, VALUE_1, VALUE_3); assertEquals(r, VALUE_2, "failing compareAndExchangeAcquire float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_2, "failing compareAndExchangeAcquire float value"); + assertEquals(VALUE_2, x, "failing compareAndExchangeAcquire float value"); } { float r = (float) vh.compareAndExchangeRelease(array, i, VALUE_2, VALUE_1); assertEquals(r, VALUE_2, "success compareAndExchangeRelease float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_1, "success compareAndExchangeRelease float value"); + assertEquals(VALUE_1, x, "success compareAndExchangeRelease float value"); } { float r = (float) vh.compareAndExchangeRelease(array, i, VALUE_2, VALUE_3); assertEquals(r, VALUE_1, "failing compareAndExchangeRelease float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_1, "failing compareAndExchangeRelease float value"); + assertEquals(VALUE_1, x, "failing compareAndExchangeRelease float value"); } { @@ -994,14 +994,14 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSetPlain float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_2, "success weakCompareAndSetPlain float value"); + assertEquals(VALUE_2, x, "success weakCompareAndSetPlain float value"); } { boolean success = vh.weakCompareAndSetPlain(array, i, VALUE_1, VALUE_3); assertEquals(success, false, "failing weakCompareAndSetPlain float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_2, "failing weakCompareAndSetPlain float value"); + assertEquals(VALUE_2, x, "failing weakCompareAndSetPlain float value"); } { @@ -1012,14 +1012,14 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSetAcquire float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_1, "success weakCompareAndSetAcquire float"); + assertEquals(VALUE_1, x, "success weakCompareAndSetAcquire float"); } { boolean success = vh.weakCompareAndSetAcquire(array, i, VALUE_2, VALUE_3); assertEquals(success, false, "failing weakCompareAndSetAcquire float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_1, "failing weakCompareAndSetAcquire float value"); + assertEquals(VALUE_1, x, "failing weakCompareAndSetAcquire float value"); } { @@ -1030,14 +1030,14 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSetRelease float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_2, "success weakCompareAndSetRelease float"); + assertEquals(VALUE_2, x, "success weakCompareAndSetRelease float"); } { boolean success = vh.weakCompareAndSetRelease(array, i, VALUE_1, VALUE_3); assertEquals(success, false, "failing weakCompareAndSetRelease float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_2, "failing weakCompareAndSetRelease float value"); + assertEquals(VALUE_2, x, "failing weakCompareAndSetRelease float value"); } { @@ -1048,14 +1048,14 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSet float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_1, "success weakCompareAndSet float"); + assertEquals(VALUE_1, x, "success weakCompareAndSet float"); } { boolean success = vh.weakCompareAndSet(array, i, VALUE_2, VALUE_3); assertEquals(success, false, "failing weakCompareAndSet float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_1, "failing weakCompareAndSet float value"); + assertEquals(VALUE_1, x, "failing weakCompareAndSet float value"); } // Compare set and get @@ -1063,27 +1063,27 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); float o = (float) vh.getAndSet(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndSet float"); + assertEquals(VALUE_1, o, "getAndSet float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_2, "getAndSet float value"); + assertEquals(VALUE_2, x, "getAndSet float value"); } { vh.set(array, i, VALUE_1); float o = (float) vh.getAndSetAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndSetAcquire float"); + assertEquals(VALUE_1, o, "getAndSetAcquire float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_2, "getAndSetAcquire float value"); + assertEquals(VALUE_2, x, "getAndSetAcquire float value"); } { vh.set(array, i, VALUE_1); float o = (float) vh.getAndSetRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndSetRelease float"); + assertEquals(VALUE_1, o, "getAndSetRelease float"); float x = (float) vh.get(array, i); - assertEquals(x, VALUE_2, "getAndSetRelease float value"); + assertEquals(VALUE_2, x, "getAndSetRelease float value"); } @@ -1109,26 +1109,26 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { // Plain { float x = (float) vh.get(array, i); - assertEquals(x, v, "get float value"); + assertEquals(v, x, "get float value"); } if (iAligned) { // Volatile { float x = (float) vh.getVolatile(array, i); - assertEquals(x, v, "getVolatile float value"); + assertEquals(v, x, "getVolatile float value"); } // Lazy { float x = (float) vh.getAcquire(array, i); - assertEquals(x, v, "getRelease float value"); + assertEquals(v, x, "getRelease float value"); } // Opaque { float x = (float) vh.getOpaque(array, i); - assertEquals(x, v, "getOpaque float value"); + assertEquals(v, x, "getOpaque float value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java index 791510281c1..ce55c3d5e31 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,25 +26,25 @@ * @bug 8154556 * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsInt - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsInt - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsInt + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsInt + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsInt + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsInt */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { static final int SIZE = Integer.BYTES; @@ -107,7 +107,8 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("VarHandleBaseByteArrayTest#varHandlesProvider") public void testIsAccessModeSupported(VarHandleSource vhs) { VarHandle vh = vhs.s; @@ -190,17 +191,16 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { } } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), int.class); + assertEquals(int.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -262,7 +262,8 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -271,7 +272,6 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { } } - static void testArrayNPE(ByteArraySource bs, VarHandleSource vhs) { VarHandle vh = vhs.s; byte[] array = null; @@ -1039,7 +1039,7 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { { vh.set(array, i, VALUE_1); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1, "get int value"); + assertEquals(VALUE_1, x, "get int value"); } } } @@ -1058,7 +1058,7 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { { vh.set(array, i, VALUE_1); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1, "get int value"); + assertEquals(VALUE_1, x, "get int value"); } if (iAligned) { @@ -1066,21 +1066,21 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { { vh.setVolatile(array, i, VALUE_2); int x = (int) vh.getVolatile(array, i); - assertEquals(x, VALUE_2, "setVolatile int value"); + assertEquals(VALUE_2, x, "setVolatile int value"); } // Lazy { vh.setRelease(array, i, VALUE_1); int x = (int) vh.getAcquire(array, i); - assertEquals(x, VALUE_1, "setRelease int value"); + assertEquals(VALUE_1, x, "setRelease int value"); } // Opaque { vh.setOpaque(array, i, VALUE_2); int x = (int) vh.getOpaque(array, i); - assertEquals(x, VALUE_2, "setOpaque int value"); + assertEquals(VALUE_2, x, "setOpaque int value"); } vh.set(array, i, VALUE_1); @@ -1090,56 +1090,56 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { boolean r = vh.compareAndSet(array, i, VALUE_1, VALUE_2); assertEquals(r, true, "success compareAndSet int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_2, "success compareAndSet int value"); + assertEquals(VALUE_2, x, "success compareAndSet int value"); } { boolean r = vh.compareAndSet(array, i, VALUE_1, VALUE_3); assertEquals(r, false, "failing compareAndSet int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_2, "failing compareAndSet int value"); + assertEquals(VALUE_2, x, "failing compareAndSet int value"); } { int r = (int) vh.compareAndExchange(array, i, VALUE_2, VALUE_1); assertEquals(r, VALUE_2, "success compareAndExchange int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1, "success compareAndExchange int value"); + assertEquals(VALUE_1, x, "success compareAndExchange int value"); } { int r = (int) vh.compareAndExchange(array, i, VALUE_2, VALUE_3); assertEquals(r, VALUE_1, "failing compareAndExchange int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1, "failing compareAndExchange int value"); + assertEquals(VALUE_1, x, "failing compareAndExchange int value"); } { int r = (int) vh.compareAndExchangeAcquire(array, i, VALUE_1, VALUE_2); assertEquals(r, VALUE_1, "success compareAndExchangeAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_2, "success compareAndExchangeAcquire int value"); + assertEquals(VALUE_2, x, "success compareAndExchangeAcquire int value"); } { int r = (int) vh.compareAndExchangeAcquire(array, i, VALUE_1, VALUE_3); assertEquals(r, VALUE_2, "failing compareAndExchangeAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_2, "failing compareAndExchangeAcquire int value"); + assertEquals(VALUE_2, x, "failing compareAndExchangeAcquire int value"); } { int r = (int) vh.compareAndExchangeRelease(array, i, VALUE_2, VALUE_1); assertEquals(r, VALUE_2, "success compareAndExchangeRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1, "success compareAndExchangeRelease int value"); + assertEquals(VALUE_1, x, "success compareAndExchangeRelease int value"); } { int r = (int) vh.compareAndExchangeRelease(array, i, VALUE_2, VALUE_3); assertEquals(r, VALUE_1, "failing compareAndExchangeRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1, "failing compareAndExchangeRelease int value"); + assertEquals(VALUE_1, x, "failing compareAndExchangeRelease int value"); } { @@ -1150,14 +1150,14 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSetPlain int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_2, "success weakCompareAndSetPlain int value"); + assertEquals(VALUE_2, x, "success weakCompareAndSetPlain int value"); } { boolean success = vh.weakCompareAndSetPlain(array, i, VALUE_1, VALUE_3); assertEquals(success, false, "failing weakCompareAndSetPlain int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_2, "failing weakCompareAndSetPlain int value"); + assertEquals(VALUE_2, x, "failing weakCompareAndSetPlain int value"); } { @@ -1168,14 +1168,14 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSetAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1, "success weakCompareAndSetAcquire int"); + assertEquals(VALUE_1, x, "success weakCompareAndSetAcquire int"); } { boolean success = vh.weakCompareAndSetAcquire(array, i, VALUE_2, VALUE_3); assertEquals(success, false, "failing weakCompareAndSetAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1, "failing weakCompareAndSetAcquire int value"); + assertEquals(VALUE_1, x, "failing weakCompareAndSetAcquire int value"); } { @@ -1186,14 +1186,14 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSetRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_2, "success weakCompareAndSetRelease int"); + assertEquals(VALUE_2, x, "success weakCompareAndSetRelease int"); } { boolean success = vh.weakCompareAndSetRelease(array, i, VALUE_1, VALUE_3); assertEquals(success, false, "failing weakCompareAndSetRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_2, "failing weakCompareAndSetRelease int value"); + assertEquals(VALUE_2, x, "failing weakCompareAndSetRelease int value"); } { @@ -1204,14 +1204,14 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSet int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1, "success weakCompareAndSet int"); + assertEquals(VALUE_1, x, "success weakCompareAndSet int"); } { boolean success = vh.weakCompareAndSet(array, i, VALUE_2, VALUE_3); assertEquals(success, false, "failing weakCompareAndSet int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1, "failing weakCompareAndSet int value"); + assertEquals(VALUE_1, x, "failing weakCompareAndSet int value"); } // Compare set and get @@ -1219,27 +1219,27 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); int o = (int) vh.getAndSet(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndSet int"); + assertEquals(VALUE_1, o, "getAndSet int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_2, "getAndSet int value"); + assertEquals(VALUE_2, x, "getAndSet int value"); } { vh.set(array, i, VALUE_1); int o = (int) vh.getAndSetAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndSetAcquire int"); + assertEquals(VALUE_1, o, "getAndSetAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_2, "getAndSetAcquire int value"); + assertEquals(VALUE_2, x, "getAndSetAcquire int value"); } { vh.set(array, i, VALUE_1); int o = (int) vh.getAndSetRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndSetRelease int"); + assertEquals(VALUE_1, o, "getAndSetRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_2, "getAndSetRelease int value"); + assertEquals(VALUE_2, x, "getAndSetRelease int value"); } // get and add, add and get @@ -1247,27 +1247,27 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); int o = (int) vh.getAndAdd(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndAdd int"); + assertEquals(VALUE_1, o, "getAndAdd int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1 + VALUE_2, "getAndAdd int value"); + assertEquals(VALUE_1 + VALUE_2, x, "getAndAdd int value"); } { vh.set(array, i, VALUE_1); int o = (int) vh.getAndAddAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndAddAcquire int"); + assertEquals(VALUE_1, o, "getAndAddAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1 + VALUE_2, "getAndAddAcquire int value"); + assertEquals(VALUE_1 + VALUE_2, x, "getAndAddAcquire int value"); } { vh.set(array, i, VALUE_1); int o = (int) vh.getAndAddRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndAddRelease int"); + assertEquals(VALUE_1, o, "getAndAddRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1 + VALUE_2, "getAndAddRelease int value"); + assertEquals(VALUE_1 + VALUE_2, x, "getAndAddRelease int value"); } // get and bitwise or @@ -1275,27 +1275,27 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); int o = (int) vh.getAndBitwiseOr(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseOr int"); + assertEquals(VALUE_1, o, "getAndBitwiseOr int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1 | VALUE_2, "getAndBitwiseOr int value"); + assertEquals(VALUE_1 | VALUE_2, x, "getAndBitwiseOr int value"); } { vh.set(array, i, VALUE_1); int o = (int) vh.getAndBitwiseOrAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseOrAcquire int"); + assertEquals(VALUE_1, o, "getAndBitwiseOrAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1 | VALUE_2, "getAndBitwiseOrAcquire int value"); + assertEquals(VALUE_1 | VALUE_2, x, "getAndBitwiseOrAcquire int value"); } { vh.set(array, i, VALUE_1); int o = (int) vh.getAndBitwiseOrRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseOrRelease int"); + assertEquals(VALUE_1, o, "getAndBitwiseOrRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1 | VALUE_2, "getAndBitwiseOrRelease int value"); + assertEquals(VALUE_1 | VALUE_2, x, "getAndBitwiseOrRelease int value"); } // get and bitwise and @@ -1303,27 +1303,27 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); int o = (int) vh.getAndBitwiseAnd(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseAnd int"); + assertEquals(VALUE_1, o, "getAndBitwiseAnd int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1 & VALUE_2, "getAndBitwiseAnd int value"); + assertEquals(VALUE_1 & VALUE_2, x, "getAndBitwiseAnd int value"); } { vh.set(array, i, VALUE_1); int o = (int) vh.getAndBitwiseAndAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseAndAcquire int"); + assertEquals(VALUE_1, o, "getAndBitwiseAndAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1 & VALUE_2, "getAndBitwiseAndAcquire int value"); + assertEquals(VALUE_1 & VALUE_2, x, "getAndBitwiseAndAcquire int value"); } { vh.set(array, i, VALUE_1); int o = (int) vh.getAndBitwiseAndRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseAndRelease int"); + assertEquals(VALUE_1, o, "getAndBitwiseAndRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1 & VALUE_2, "getAndBitwiseAndRelease int value"); + assertEquals(VALUE_1 & VALUE_2, x, "getAndBitwiseAndRelease int value"); } // get and bitwise xor @@ -1331,27 +1331,27 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); int o = (int) vh.getAndBitwiseXor(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseXor int"); + assertEquals(VALUE_1, o, "getAndBitwiseXor int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1 ^ VALUE_2, "getAndBitwiseXor int value"); + assertEquals(VALUE_1 ^ VALUE_2, x, "getAndBitwiseXor int value"); } { vh.set(array, i, VALUE_1); int o = (int) vh.getAndBitwiseXorAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseXorAcquire int"); + assertEquals(VALUE_1, o, "getAndBitwiseXorAcquire int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1 ^ VALUE_2, "getAndBitwiseXorAcquire int value"); + assertEquals(VALUE_1 ^ VALUE_2, x, "getAndBitwiseXorAcquire int value"); } { vh.set(array, i, VALUE_1); int o = (int) vh.getAndBitwiseXorRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseXorRelease int"); + assertEquals(VALUE_1, o, "getAndBitwiseXorRelease int"); int x = (int) vh.get(array, i); - assertEquals(x, VALUE_1 ^ VALUE_2, "getAndBitwiseXorRelease int value"); + assertEquals(VALUE_1 ^ VALUE_2, x, "getAndBitwiseXorRelease int value"); } } } @@ -1375,26 +1375,26 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { // Plain { int x = (int) vh.get(array, i); - assertEquals(x, v, "get int value"); + assertEquals(v, x, "get int value"); } if (iAligned) { // Volatile { int x = (int) vh.getVolatile(array, i); - assertEquals(x, v, "getVolatile int value"); + assertEquals(v, x, "getVolatile int value"); } // Lazy { int x = (int) vh.getAcquire(array, i); - assertEquals(x, v, "getRelease int value"); + assertEquals(v, x, "getRelease int value"); } // Opaque { int x = (int) vh.getOpaque(array, i); - assertEquals(x, v, "getOpaque int value"); + assertEquals(v, x, "getOpaque int value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java index 4188a51a559..763703b6079 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,25 +26,25 @@ * @bug 8154556 * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsLong - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsLong - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsLong + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsLong + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsLong + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsLong */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { static final int SIZE = Long.BYTES; @@ -107,7 +107,8 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("VarHandleBaseByteArrayTest#varHandlesProvider") public void testIsAccessModeSupported(VarHandleSource vhs) { VarHandle vh = vhs.s; @@ -190,17 +191,16 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { } } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), long.class); + assertEquals(long.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -262,7 +262,8 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -271,7 +272,6 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { } } - static void testArrayNPE(ByteArraySource bs, VarHandleSource vhs) { VarHandle vh = vhs.s; byte[] array = null; @@ -1039,7 +1039,7 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { { vh.set(array, i, VALUE_1); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1, "get long value"); + assertEquals(VALUE_1, x, "get long value"); } } } @@ -1058,7 +1058,7 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { { vh.set(array, i, VALUE_1); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1, "get long value"); + assertEquals(VALUE_1, x, "get long value"); } if (iAligned) { @@ -1066,21 +1066,21 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { { vh.setVolatile(array, i, VALUE_2); long x = (long) vh.getVolatile(array, i); - assertEquals(x, VALUE_2, "setVolatile long value"); + assertEquals(VALUE_2, x, "setVolatile long value"); } // Lazy { vh.setRelease(array, i, VALUE_1); long x = (long) vh.getAcquire(array, i); - assertEquals(x, VALUE_1, "setRelease long value"); + assertEquals(VALUE_1, x, "setRelease long value"); } // Opaque { vh.setOpaque(array, i, VALUE_2); long x = (long) vh.getOpaque(array, i); - assertEquals(x, VALUE_2, "setOpaque long value"); + assertEquals(VALUE_2, x, "setOpaque long value"); } vh.set(array, i, VALUE_1); @@ -1090,56 +1090,56 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { boolean r = vh.compareAndSet(array, i, VALUE_1, VALUE_2); assertEquals(r, true, "success compareAndSet long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_2, "success compareAndSet long value"); + assertEquals(VALUE_2, x, "success compareAndSet long value"); } { boolean r = vh.compareAndSet(array, i, VALUE_1, VALUE_3); assertEquals(r, false, "failing compareAndSet long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_2, "failing compareAndSet long value"); + assertEquals(VALUE_2, x, "failing compareAndSet long value"); } { long r = (long) vh.compareAndExchange(array, i, VALUE_2, VALUE_1); assertEquals(r, VALUE_2, "success compareAndExchange long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1, "success compareAndExchange long value"); + assertEquals(VALUE_1, x, "success compareAndExchange long value"); } { long r = (long) vh.compareAndExchange(array, i, VALUE_2, VALUE_3); assertEquals(r, VALUE_1, "failing compareAndExchange long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1, "failing compareAndExchange long value"); + assertEquals(VALUE_1, x, "failing compareAndExchange long value"); } { long r = (long) vh.compareAndExchangeAcquire(array, i, VALUE_1, VALUE_2); assertEquals(r, VALUE_1, "success compareAndExchangeAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_2, "success compareAndExchangeAcquire long value"); + assertEquals(VALUE_2, x, "success compareAndExchangeAcquire long value"); } { long r = (long) vh.compareAndExchangeAcquire(array, i, VALUE_1, VALUE_3); assertEquals(r, VALUE_2, "failing compareAndExchangeAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_2, "failing compareAndExchangeAcquire long value"); + assertEquals(VALUE_2, x, "failing compareAndExchangeAcquire long value"); } { long r = (long) vh.compareAndExchangeRelease(array, i, VALUE_2, VALUE_1); assertEquals(r, VALUE_2, "success compareAndExchangeRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1, "success compareAndExchangeRelease long value"); + assertEquals(VALUE_1, x, "success compareAndExchangeRelease long value"); } { long r = (long) vh.compareAndExchangeRelease(array, i, VALUE_2, VALUE_3); assertEquals(r, VALUE_1, "failing compareAndExchangeRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1, "failing compareAndExchangeRelease long value"); + assertEquals(VALUE_1, x, "failing compareAndExchangeRelease long value"); } { @@ -1150,14 +1150,14 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSetPlain long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_2, "success weakCompareAndSetPlain long value"); + assertEquals(VALUE_2, x, "success weakCompareAndSetPlain long value"); } { boolean success = vh.weakCompareAndSetPlain(array, i, VALUE_1, VALUE_3); assertEquals(success, false, "failing weakCompareAndSetPlain long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_2, "failing weakCompareAndSetPlain long value"); + assertEquals(VALUE_2, x, "failing weakCompareAndSetPlain long value"); } { @@ -1168,14 +1168,14 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSetAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1, "success weakCompareAndSetAcquire long"); + assertEquals(VALUE_1, x, "success weakCompareAndSetAcquire long"); } { boolean success = vh.weakCompareAndSetAcquire(array, i, VALUE_2, VALUE_3); assertEquals(success, false, "failing weakCompareAndSetAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1, "failing weakCompareAndSetAcquire long value"); + assertEquals(VALUE_1, x, "failing weakCompareAndSetAcquire long value"); } { @@ -1186,14 +1186,14 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSetRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_2, "success weakCompareAndSetRelease long"); + assertEquals(VALUE_2, x, "success weakCompareAndSetRelease long"); } { boolean success = vh.weakCompareAndSetRelease(array, i, VALUE_1, VALUE_3); assertEquals(success, false, "failing weakCompareAndSetRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_2, "failing weakCompareAndSetRelease long value"); + assertEquals(VALUE_2, x, "failing weakCompareAndSetRelease long value"); } { @@ -1204,14 +1204,14 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSet long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1, "success weakCompareAndSet long"); + assertEquals(VALUE_1, x, "success weakCompareAndSet long"); } { boolean success = vh.weakCompareAndSet(array, i, VALUE_2, VALUE_3); assertEquals(success, false, "failing weakCompareAndSet long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1, "failing weakCompareAndSet long value"); + assertEquals(VALUE_1, x, "failing weakCompareAndSet long value"); } // Compare set and get @@ -1219,27 +1219,27 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); long o = (long) vh.getAndSet(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndSet long"); + assertEquals(VALUE_1, o, "getAndSet long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_2, "getAndSet long value"); + assertEquals(VALUE_2, x, "getAndSet long value"); } { vh.set(array, i, VALUE_1); long o = (long) vh.getAndSetAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndSetAcquire long"); + assertEquals(VALUE_1, o, "getAndSetAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_2, "getAndSetAcquire long value"); + assertEquals(VALUE_2, x, "getAndSetAcquire long value"); } { vh.set(array, i, VALUE_1); long o = (long) vh.getAndSetRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndSetRelease long"); + assertEquals(VALUE_1, o, "getAndSetRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_2, "getAndSetRelease long value"); + assertEquals(VALUE_2, x, "getAndSetRelease long value"); } // get and add, add and get @@ -1247,27 +1247,27 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); long o = (long) vh.getAndAdd(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndAdd long"); + assertEquals(VALUE_1, o, "getAndAdd long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1 + VALUE_2, "getAndAdd long value"); + assertEquals(VALUE_1 + VALUE_2, x, "getAndAdd long value"); } { vh.set(array, i, VALUE_1); long o = (long) vh.getAndAddAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndAddAcquire long"); + assertEquals(VALUE_1, o, "getAndAddAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1 + VALUE_2, "getAndAddAcquire long value"); + assertEquals(VALUE_1 + VALUE_2, x, "getAndAddAcquire long value"); } { vh.set(array, i, VALUE_1); long o = (long) vh.getAndAddRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndAddRelease long"); + assertEquals(VALUE_1, o, "getAndAddRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1 + VALUE_2, "getAndAddRelease long value"); + assertEquals(VALUE_1 + VALUE_2, x, "getAndAddRelease long value"); } // get and bitwise or @@ -1275,27 +1275,27 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); long o = (long) vh.getAndBitwiseOr(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseOr long"); + assertEquals(VALUE_1, o, "getAndBitwiseOr long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1 | VALUE_2, "getAndBitwiseOr long value"); + assertEquals(VALUE_1 | VALUE_2, x, "getAndBitwiseOr long value"); } { vh.set(array, i, VALUE_1); long o = (long) vh.getAndBitwiseOrAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseOrAcquire long"); + assertEquals(VALUE_1, o, "getAndBitwiseOrAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1 | VALUE_2, "getAndBitwiseOrAcquire long value"); + assertEquals(VALUE_1 | VALUE_2, x, "getAndBitwiseOrAcquire long value"); } { vh.set(array, i, VALUE_1); long o = (long) vh.getAndBitwiseOrRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseOrRelease long"); + assertEquals(VALUE_1, o, "getAndBitwiseOrRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1 | VALUE_2, "getAndBitwiseOrRelease long value"); + assertEquals(VALUE_1 | VALUE_2, x, "getAndBitwiseOrRelease long value"); } // get and bitwise and @@ -1303,27 +1303,27 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); long o = (long) vh.getAndBitwiseAnd(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseAnd long"); + assertEquals(VALUE_1, o, "getAndBitwiseAnd long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1 & VALUE_2, "getAndBitwiseAnd long value"); + assertEquals(VALUE_1 & VALUE_2, x, "getAndBitwiseAnd long value"); } { vh.set(array, i, VALUE_1); long o = (long) vh.getAndBitwiseAndAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseAndAcquire long"); + assertEquals(VALUE_1, o, "getAndBitwiseAndAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1 & VALUE_2, "getAndBitwiseAndAcquire long value"); + assertEquals(VALUE_1 & VALUE_2, x, "getAndBitwiseAndAcquire long value"); } { vh.set(array, i, VALUE_1); long o = (long) vh.getAndBitwiseAndRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseAndRelease long"); + assertEquals(VALUE_1, o, "getAndBitwiseAndRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1 & VALUE_2, "getAndBitwiseAndRelease long value"); + assertEquals(VALUE_1 & VALUE_2, x, "getAndBitwiseAndRelease long value"); } // get and bitwise xor @@ -1331,27 +1331,27 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); long o = (long) vh.getAndBitwiseXor(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseXor long"); + assertEquals(VALUE_1, o, "getAndBitwiseXor long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1 ^ VALUE_2, "getAndBitwiseXor long value"); + assertEquals(VALUE_1 ^ VALUE_2, x, "getAndBitwiseXor long value"); } { vh.set(array, i, VALUE_1); long o = (long) vh.getAndBitwiseXorAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseXorAcquire long"); + assertEquals(VALUE_1, o, "getAndBitwiseXorAcquire long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1 ^ VALUE_2, "getAndBitwiseXorAcquire long value"); + assertEquals(VALUE_1 ^ VALUE_2, x, "getAndBitwiseXorAcquire long value"); } { vh.set(array, i, VALUE_1); long o = (long) vh.getAndBitwiseXorRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseXorRelease long"); + assertEquals(VALUE_1, o, "getAndBitwiseXorRelease long"); long x = (long) vh.get(array, i); - assertEquals(x, VALUE_1 ^ VALUE_2, "getAndBitwiseXorRelease long value"); + assertEquals(VALUE_1 ^ VALUE_2, x, "getAndBitwiseXorRelease long value"); } } } @@ -1375,26 +1375,26 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { // Plain { long x = (long) vh.get(array, i); - assertEquals(x, v, "get long value"); + assertEquals(v, x, "get long value"); } if (iAligned) { // Volatile { long x = (long) vh.getVolatile(array, i); - assertEquals(x, v, "getVolatile long value"); + assertEquals(v, x, "getVolatile long value"); } // Lazy { long x = (long) vh.getAcquire(array, i); - assertEquals(x, v, "getRelease long value"); + assertEquals(v, x, "getRelease long value"); } // Opaque { long x = (long) vh.getOpaque(array, i); - assertEquals(x, v, "getOpaque long value"); + assertEquals(v, x, "getOpaque long value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java index 1ecfef0476e..7a3bc069c22 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,25 +26,25 @@ * @bug 8154556 * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsShort - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsShort - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsShort + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsShort + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsShort + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsShort */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestByteArrayAsShort extends VarHandleBaseByteArrayTest { static final int SIZE = Short.BYTES; @@ -107,7 +107,8 @@ public class VarHandleTestByteArrayAsShort extends VarHandleBaseByteArrayTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("VarHandleBaseByteArrayTest#varHandlesProvider") public void testIsAccessModeSupported(VarHandleSource vhs) { VarHandle vh = vhs.s; @@ -158,17 +159,16 @@ public class VarHandleTestByteArrayAsShort extends VarHandleBaseByteArrayTest { assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE)); } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), short.class); + assertEquals(short.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -230,7 +230,8 @@ public class VarHandleTestByteArrayAsShort extends VarHandleBaseByteArrayTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -239,7 +240,6 @@ public class VarHandleTestByteArrayAsShort extends VarHandleBaseByteArrayTest { } } - static void testArrayNPE(ByteArraySource bs, VarHandleSource vhs) { VarHandle vh = vhs.s; byte[] array = null; @@ -740,7 +740,7 @@ public class VarHandleTestByteArrayAsShort extends VarHandleBaseByteArrayTest { { vh.set(array, i, VALUE_1); short x = (short) vh.get(array, i); - assertEquals(x, VALUE_1, "get short value"); + assertEquals(VALUE_1, x, "get short value"); } } } @@ -759,7 +759,7 @@ public class VarHandleTestByteArrayAsShort extends VarHandleBaseByteArrayTest { { vh.set(array, i, VALUE_1); short x = (short) vh.get(array, i); - assertEquals(x, VALUE_1, "get short value"); + assertEquals(VALUE_1, x, "get short value"); } if (iAligned) { @@ -767,21 +767,21 @@ public class VarHandleTestByteArrayAsShort extends VarHandleBaseByteArrayTest { { vh.setVolatile(array, i, VALUE_2); short x = (short) vh.getVolatile(array, i); - assertEquals(x, VALUE_2, "setVolatile short value"); + assertEquals(VALUE_2, x, "setVolatile short value"); } // Lazy { vh.setRelease(array, i, VALUE_1); short x = (short) vh.getAcquire(array, i); - assertEquals(x, VALUE_1, "setRelease short value"); + assertEquals(VALUE_1, x, "setRelease short value"); } // Opaque { vh.setOpaque(array, i, VALUE_2); short x = (short) vh.getOpaque(array, i); - assertEquals(x, VALUE_2, "setOpaque short value"); + assertEquals(VALUE_2, x, "setOpaque short value"); } @@ -807,26 +807,26 @@ public class VarHandleTestByteArrayAsShort extends VarHandleBaseByteArrayTest { // Plain { short x = (short) vh.get(array, i); - assertEquals(x, v, "get short value"); + assertEquals(v, x, "get short value"); } if (iAligned) { // Volatile { short x = (short) vh.getVolatile(array, i); - assertEquals(x, v, "getVolatile short value"); + assertEquals(v, x, "getVolatile short value"); } // Lazy { short x = (short) vh.getAcquire(array, i); - assertEquals(x, v, "getRelease short value"); + assertEquals(v, x, "getRelease short value"); } // Opaque { short x = (short) vh.getOpaque(array, i); - assertEquals(x, v, "getOpaque short value"); + assertEquals(v, x, "getOpaque short value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestExact.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestExact.java index fc706815bce..9960e08a0c7 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestExact.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestExact.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,20 +26,20 @@ * @modules java.base/jdk.internal.access.foreign * @modules java.base/jdk.internal.foreign.layout * - * @run testng/othervm -Xverify:all + * @run junit/othervm -Xverify:all * -Djdk.internal.foreign.SHOULD_ADAPT_HANDLES=false * VarHandleTestExact - * @run testng/othervm -Xverify:all + * @run junit/othervm -Xverify:all * -Djdk.internal.foreign.SHOULD_ADAPT_HANDLES=false * -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true * -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true * VarHandleTestExact - * @run testng/othervm -Xverify:all + * @run junit/othervm -Xverify:all * -Djdk.internal.foreign.SHOULD_ADAPT_HANDLES=false * -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false * -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false * VarHandleTestExact - * @run testng/othervm -Xverify:all + * @run junit/othervm -Xverify:all * -Djdk.internal.foreign.SHOULD_ADAPT_HANDLES=false * -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false * -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true @@ -50,9 +50,6 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import jdk.internal.foreign.layout.ValueLayouts; -import org.testng.SkipException; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; @@ -64,8 +61,13 @@ import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestExact { private static class Widget { @@ -90,12 +92,13 @@ public class VarHandleTestExact { final Long aLongField_RO = 1234L; } - @Test(dataProvider = "dataObjectAccess") + @ParameterizedTest + @MethodSource("dataObjectAccess") public void testExactSet(String fieldBaseName, Class fieldType, boolean ro, Object testValue, SetX setter, GetX getter, SetStaticX staticSetter, GetStaticX staticGetter) throws NoSuchFieldException, IllegalAccessException { - if (ro) throw new SkipException("Can not test setter with read only field"); + Assumptions.assumeFalse(ro, "Can not test setter with read only field"); VarHandle vh = MethodHandles.lookup().findVarHandle(Widget.class, fieldBaseName + "_RW", fieldType); Widget w = new Widget(); @@ -105,7 +108,8 @@ public class VarHandleTestExact { ".*\\Qhandle's method type (Widget," + fieldType.getSimpleName() + ")void \\E.*"); } - @Test(dataProvider = "dataObjectAccess") + @ParameterizedTest + @MethodSource("dataObjectAccess") public void testExactGet(String fieldBaseName, Class fieldType, boolean ro, Object testValue, SetX setter, GetX getter, SetStaticX staticSetter, GetStaticX staticGetter) @@ -119,12 +123,13 @@ public class VarHandleTestExact { ".*\\Qhandle's method type (Widget)" + fieldType.getSimpleName() + " \\E.*"); } - @Test(dataProvider = "dataObjectAccess") + @ParameterizedTest + @MethodSource("dataObjectAccess") public void testExactSetStatic(String fieldBaseName, Class fieldType, boolean ro, Object testValue, SetX setter, GetX getter, SetStaticX staticSetter, GetStaticX staticGetter) throws NoSuchFieldException, IllegalAccessException { - if (ro) throw new SkipException("Can not test setter with read only field"); + Assumptions.assumeFalse(ro, "Can not test setter with read only field"); VarHandle vh = MethodHandles.lookup().findStaticVarHandle(Widget.class, fieldBaseName + "_SRW", fieldType); doTest(vh, @@ -133,7 +138,8 @@ public class VarHandleTestExact { ".*\\Qhandle's method type (" + fieldType.getSimpleName() + ")void \\E.*"); } - @Test(dataProvider = "dataObjectAccess") + @ParameterizedTest + @MethodSource("dataObjectAccess") public void testExactGetStatic(String fieldBaseName, Class fieldType, boolean ro, Object testValue, SetX setter, GetX getter, SetStaticX staticSetter, GetStaticX staticGetter) @@ -146,7 +152,8 @@ public class VarHandleTestExact { ".*\\Qhandle's method type ()" + fieldType.getSimpleName() + " \\E.*"); } - @Test(dataProvider = "dataSetArray") + @ParameterizedTest + @MethodSource("dataSetArray") public void testExactArraySet(Class arrayClass, Object testValue, SetArrayX setter) { VarHandle vh = MethodHandles.arrayElementVarHandle(arrayClass); Object arr = Array.newInstance(arrayClass.componentType(), 1); @@ -157,7 +164,8 @@ public class VarHandleTestExact { ".*\\Qhandle's method type (" + arrayClass.getSimpleName() + ",int," + arrayClass.componentType().getSimpleName() + ")void \\E.*"); } - @Test(dataProvider = "dataSetBuffer") + @ParameterizedTest + @MethodSource("dataSetBuffer") public void testExactBufferSet(Class arrayClass, Object testValue, SetBufferX setter) { VarHandle vh = MethodHandles.byteBufferViewVarHandle(arrayClass, ByteOrder.nativeOrder()); ByteBuffer buff = ByteBuffer.allocateDirect(8); @@ -168,7 +176,8 @@ public class VarHandleTestExact { ".*\\Qhandle's method type (ByteBuffer,int," + arrayClass.componentType().getSimpleName() + ")void \\E.*"); } - @Test(dataProvider = "dataSetMemorySegment") + @ParameterizedTest + @MethodSource("dataSetMemorySegment") public void testExactSegmentSet(Class carrier, Object testValue, SetSegmentX setter) { VarHandle vh = ValueLayouts.valueLayout(carrier, ByteOrder.nativeOrder()).varHandle(); try (Arena arena = Arena.ofConfined()) { @@ -265,7 +274,6 @@ public class VarHandleTestExact { cases.add(new Object[] { carrier, testValue, setter }); } - @DataProvider public static Object[][] dataObjectAccess() { List cases = new ArrayList<>(); @@ -334,7 +342,6 @@ public class VarHandleTestExact { return cases.toArray(Object[][]::new); } - @DataProvider public static Object[][] dataSetArray() { List cases = new ArrayList<>(); @@ -355,7 +362,6 @@ public class VarHandleTestExact { return cases.toArray(Object[][]::new); } - @DataProvider public static Object[][] dataSetBuffer() { List cases = new ArrayList<>(); @@ -373,7 +379,6 @@ public class VarHandleTestExact { return cases.toArray(Object[][]::new); } - @DataProvider public static Object[][] dataSetMemorySegment() { List cases = new ArrayList<>(); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessBoolean.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessBoolean.java index 14d5c05d3b8..6540693a906 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessBoolean.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessBoolean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,22 @@ * @test * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessBoolean + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessBoolean */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { static final boolean static_final_v = true; @@ -60,7 +60,7 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodHandleAccessBoolean.class, "final_v", boolean.class); @@ -77,8 +77,6 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(boolean[].class); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -111,7 +109,8 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -120,13 +119,12 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { } } - static void testInstanceField(VarHandleTestMethodHandleAccessBoolean recv, Handles hs) throws Throwable { // Plain { hs.get(TestAccessMode.SET).invokeExact(recv, true); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, true, "set boolean value"); + assertEquals(true, x, "set boolean value"); } @@ -134,21 +132,21 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(recv, false); boolean x = (boolean) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(recv); - assertEquals(x, false, "setVolatile boolean value"); + assertEquals(false, x, "setVolatile boolean value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(recv, true); boolean x = (boolean) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(recv); - assertEquals(x, true, "setRelease boolean value"); + assertEquals(true, x, "setRelease boolean value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(recv, false); boolean x = (boolean) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(recv); - assertEquals(x, false, "setOpaque boolean value"); + assertEquals(false, x, "setOpaque boolean value"); } hs.get(TestAccessMode.SET).invokeExact(recv, true); @@ -158,56 +156,56 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, true, false); assertEquals(r, true, "success compareAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, false, "success compareAndSet boolean value"); + assertEquals(false, x, "success compareAndSet boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, true, false); assertEquals(r, false, "failing compareAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, false, "failing compareAndSet boolean value"); + assertEquals(false, x, "failing compareAndSet boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, false, true); assertEquals(r, false, "success compareAndExchange boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, true, "success compareAndExchange boolean value"); + assertEquals(true, x, "success compareAndExchange boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, false, false); assertEquals(r, true, "failing compareAndExchange boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, true, "failing compareAndExchange boolean value"); + assertEquals(true, x, "failing compareAndExchange boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, true, false); assertEquals(r, true, "success compareAndExchangeAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, false, "success compareAndExchangeAcquire boolean value"); + assertEquals(false, x, "success compareAndExchangeAcquire boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, true, false); assertEquals(r, false, "failing compareAndExchangeAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, false, "failing compareAndExchangeAcquire boolean value"); + assertEquals(false, x, "failing compareAndExchangeAcquire boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, false, true); assertEquals(r, false, "success compareAndExchangeRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, true, "success compareAndExchangeRelease boolean value"); + assertEquals(true, x, "success compareAndExchangeRelease boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, false, false); assertEquals(r, true, "failing compareAndExchangeRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, true, "failing compareAndExchangeRelease boolean value"); + assertEquals(true, x, "failing compareAndExchangeRelease boolean value"); } { @@ -219,14 +217,14 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, false, "success weakCompareAndSetPlain boolean value"); + assertEquals(false, x, "success weakCompareAndSetPlain boolean value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, true, false); assertEquals(success, false, "failing weakCompareAndSetPlain boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, false, "failing weakCompareAndSetPlain boolean value"); + assertEquals(false, x, "failing weakCompareAndSetPlain boolean value"); } { @@ -238,14 +236,14 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, true, "success weakCompareAndSetAcquire boolean"); + assertEquals(true, x, "success weakCompareAndSetAcquire boolean"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, false, false); assertEquals(success, false, "failing weakCompareAndSetAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, true, "failing weakCompareAndSetAcquire boolean value"); + assertEquals(true, x, "failing weakCompareAndSetAcquire boolean value"); } { @@ -257,14 +255,14 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, false, "success weakCompareAndSetRelease boolean"); + assertEquals(false, x, "success weakCompareAndSetRelease boolean"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, true, false); assertEquals(success, false, "failing weakCompareAndSetRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, false, "failing weakCompareAndSetRelease boolean value"); + assertEquals(false, x, "failing weakCompareAndSetRelease boolean value"); } { @@ -276,22 +274,22 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, true, "success weakCompareAndSet boolean"); + assertEquals(true, x, "success weakCompareAndSet boolean"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, false, false); assertEquals(success, false, "failing weakCompareAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, true, "failing weakCompareAndSet boolean value"); + assertEquals(true, x, "failing weakCompareAndSet boolean value"); } // Compare set and get { boolean o = (boolean) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, false); - assertEquals(o, true, "getAndSet boolean"); + assertEquals(true, o, "getAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, false, "getAndSet boolean value"); + assertEquals(false, x, "getAndSet boolean value"); } @@ -300,27 +298,27 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(recv, false); - assertEquals(o, true, "getAndBitwiseOr boolean"); + assertEquals(true, o, "getAndBitwiseOr boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOr boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOr boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(recv, false); - assertEquals(o, true, "getAndBitwiseOrAcquire boolean"); + assertEquals(true, o, "getAndBitwiseOrAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOrAcquire boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOrAcquire boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(recv, false); - assertEquals(o, true, "getAndBitwiseOrRelease boolean"); + assertEquals(true, o, "getAndBitwiseOrRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOrRelease boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOrRelease boolean value"); } // get and bitwise and @@ -328,27 +326,27 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(recv, false); - assertEquals(o, true, "getAndBitwiseAnd boolean"); + assertEquals(true, o, "getAndBitwiseAnd boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAnd boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAnd boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(recv, false); - assertEquals(o, true, "getAndBitwiseAndAcquire boolean"); + assertEquals(true, o, "getAndBitwiseAndAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAndAcquire boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAndAcquire boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(recv, false); - assertEquals(o, true, "getAndBitwiseAndRelease boolean"); + assertEquals(true, o, "getAndBitwiseAndRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAndRelease boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAndRelease boolean value"); } // get and bitwise xor @@ -356,27 +354,27 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(recv, false); - assertEquals(o, true, "getAndBitwiseXor boolean"); + assertEquals(true, o, "getAndBitwiseXor boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXor boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXor boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(recv, false); - assertEquals(o, true, "getAndBitwiseXorAcquire boolean"); + assertEquals(true, o, "getAndBitwiseXorAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXorAcquire boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXorAcquire boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(recv, false); - assertEquals(o, true, "getAndBitwiseXorRelease boolean"); + assertEquals(true, o, "getAndBitwiseXorRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXorRelease boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXorRelease boolean value"); } } @@ -396,7 +394,7 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact(true); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, true, "set boolean value"); + assertEquals(true, x, "set boolean value"); } @@ -404,21 +402,21 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(false); boolean x = (boolean) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(); - assertEquals(x, false, "setVolatile boolean value"); + assertEquals(false, x, "setVolatile boolean value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(true); boolean x = (boolean) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(); - assertEquals(x, true, "setRelease boolean value"); + assertEquals(true, x, "setRelease boolean value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(false); boolean x = (boolean) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(); - assertEquals(x, false, "setOpaque boolean value"); + assertEquals(false, x, "setOpaque boolean value"); } hs.get(TestAccessMode.SET).invokeExact(true); @@ -428,56 +426,56 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(true, false); assertEquals(r, true, "success compareAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, false, "success compareAndSet boolean value"); + assertEquals(false, x, "success compareAndSet boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(true, false); assertEquals(r, false, "failing compareAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, false, "failing compareAndSet boolean value"); + assertEquals(false, x, "failing compareAndSet boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(false, true); assertEquals(r, false, "success compareAndExchange boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, true, "success compareAndExchange boolean value"); + assertEquals(true, x, "success compareAndExchange boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(false, false); assertEquals(r, true, "failing compareAndExchange boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, true, "failing compareAndExchange boolean value"); + assertEquals(true, x, "failing compareAndExchange boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(true, false); assertEquals(r, true, "success compareAndExchangeAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, false, "success compareAndExchangeAcquire boolean value"); + assertEquals(false, x, "success compareAndExchangeAcquire boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(true, false); assertEquals(r, false, "failing compareAndExchangeAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, false, "failing compareAndExchangeAcquire boolean value"); + assertEquals(false, x, "failing compareAndExchangeAcquire boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(false, true); assertEquals(r, false, "success compareAndExchangeRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, true, "success compareAndExchangeRelease boolean value"); + assertEquals(true, x, "success compareAndExchangeRelease boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(false, false); assertEquals(r, true, "failing compareAndExchangeRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, true, "failing compareAndExchangeRelease boolean value"); + assertEquals(true, x, "failing compareAndExchangeRelease boolean value"); } { @@ -489,14 +487,14 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, false, "success weakCompareAndSetPlain boolean value"); + assertEquals(false, x, "success weakCompareAndSetPlain boolean value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(true, false); assertEquals(success, false, "failing weakCompareAndSetPlain boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, false, "failing weakCompareAndSetPlain boolean value"); + assertEquals(false, x, "failing weakCompareAndSetPlain boolean value"); } { @@ -508,7 +506,7 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, true, "success weakCompareAndSetAcquire boolean"); + assertEquals(true, x, "success weakCompareAndSetAcquire boolean"); } { @@ -516,7 +514,7 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { boolean success = (boolean) mh.invokeExact(false, false); assertEquals(success, false, "failing weakCompareAndSetAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, true, "failing weakCompareAndSetAcquire boolean value"); + assertEquals(true, x, "failing weakCompareAndSetAcquire boolean value"); } { @@ -528,14 +526,14 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, false, "success weakCompareAndSetRelease boolean"); + assertEquals(false, x, "success weakCompareAndSetRelease boolean"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(true, false); assertEquals(success, false, "failing weakCompareAndSetRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, false, "failing weakCompareAndSetRelease boolean value"); + assertEquals(false, x, "failing weakCompareAndSetRelease boolean value"); } { @@ -547,14 +545,14 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, true, "success weakCompareAndSet boolean"); + assertEquals(true, x, "success weakCompareAndSet boolean"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(false, false); assertEquals(success, false, "failing weakCompareAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, true, "failing weakCompareAndSetRe boolean value"); + assertEquals(true, x, "failing weakCompareAndSetRe boolean value"); } // Compare set and get @@ -562,9 +560,9 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_SET).invokeExact(false); - assertEquals(o, true, "getAndSet boolean"); + assertEquals(true, o, "getAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, false, "getAndSet boolean value"); + assertEquals(false, x, "getAndSet boolean value"); } // Compare set and get @@ -572,9 +570,9 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(false); - assertEquals(o, true, "getAndSetAcquire boolean"); + assertEquals(true, o, "getAndSetAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, false, "getAndSetAcquire boolean value"); + assertEquals(false, x, "getAndSetAcquire boolean value"); } // Compare set and get @@ -582,9 +580,9 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(false); - assertEquals(o, true, "getAndSetRelease boolean"); + assertEquals(true, o, "getAndSetRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, false, "getAndSetRelease boolean value"); + assertEquals(false, x, "getAndSetRelease boolean value"); } @@ -593,27 +591,27 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(false); - assertEquals(o, true, "getAndBitwiseOr boolean"); + assertEquals(true, o, "getAndBitwiseOr boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOr boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOr boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(false); - assertEquals(o, true, "getAndBitwiseOrAcquire boolean"); + assertEquals(true, o, "getAndBitwiseOrAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOrAcquire boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOrAcquire boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(false); - assertEquals(o, true, "getAndBitwiseOrRelease boolean"); + assertEquals(true, o, "getAndBitwiseOrRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOrRelease boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOrRelease boolean value"); } // get and bitwise and @@ -621,27 +619,27 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(false); - assertEquals(o, true, "getAndBitwiseAnd boolean"); + assertEquals(true, o, "getAndBitwiseAnd boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAnd boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAnd boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(false); - assertEquals(o, true, "getAndBitwiseAndAcquire boolean"); + assertEquals(true, o, "getAndBitwiseAndAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAndAcquire boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAndAcquire boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(false); - assertEquals(o, true, "getAndBitwiseAndRelease boolean"); + assertEquals(true, o, "getAndBitwiseAndRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAndRelease boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAndRelease boolean value"); } // get and bitwise xor @@ -649,27 +647,27 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(false); - assertEquals(o, true, "getAndBitwiseXor boolean"); + assertEquals(true, o, "getAndBitwiseXor boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXor boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXor boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(false); - assertEquals(o, true, "getAndBitwiseXorAcquire boolean"); + assertEquals(true, o, "getAndBitwiseXorAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXorAcquire boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXorAcquire boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(false); - assertEquals(o, true, "getAndBitwiseXorRelease boolean"); + assertEquals(true, o, "getAndBitwiseXorRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXorRelease boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXorRelease boolean value"); } } @@ -692,7 +690,7 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact(array, i, true); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, true, "get boolean value"); + assertEquals(true, x, "get boolean value"); } @@ -700,21 +698,21 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(array, i, false); boolean x = (boolean) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(array, i); - assertEquals(x, false, "setVolatile boolean value"); + assertEquals(false, x, "setVolatile boolean value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(array, i, true); boolean x = (boolean) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(array, i); - assertEquals(x, true, "setRelease boolean value"); + assertEquals(true, x, "setRelease boolean value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(array, i, false); boolean x = (boolean) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(array, i); - assertEquals(x, false, "setOpaque boolean value"); + assertEquals(false, x, "setOpaque boolean value"); } hs.get(TestAccessMode.SET).invokeExact(array, i, true); @@ -724,56 +722,56 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, true, false); assertEquals(r, true, "success compareAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, false, "success compareAndSet boolean value"); + assertEquals(false, x, "success compareAndSet boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, true, false); assertEquals(r, false, "failing compareAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, false, "failing compareAndSet boolean value"); + assertEquals(false, x, "failing compareAndSet boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, false, true); assertEquals(r, false, "success compareAndExchange boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, true, "success compareAndExchange boolean value"); + assertEquals(true, x, "success compareAndExchange boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, false, false); assertEquals(r, true, "failing compareAndExchange boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, true, "failing compareAndExchange boolean value"); + assertEquals(true, x, "failing compareAndExchange boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, true, false); assertEquals(r, true, "success compareAndExchangeAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, false, "success compareAndExchangeAcquire boolean value"); + assertEquals(false, x, "success compareAndExchangeAcquire boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, true, false); assertEquals(r, false, "failing compareAndExchangeAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, false, "failing compareAndExchangeAcquire boolean value"); + assertEquals(false, x, "failing compareAndExchangeAcquire boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, false, true); assertEquals(r, false, "success compareAndExchangeRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, true, "success compareAndExchangeRelease boolean value"); + assertEquals(true, x, "success compareAndExchangeRelease boolean value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, false, false); assertEquals(r, true, "failing compareAndExchangeRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, true, "failing compareAndExchangeRelease boolean value"); + assertEquals(true, x, "failing compareAndExchangeRelease boolean value"); } { @@ -785,14 +783,14 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, false, "success weakCompareAndSetPlain boolean value"); + assertEquals(false, x, "success weakCompareAndSetPlain boolean value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, true, false); assertEquals(success, false, "failing weakCompareAndSetPlain boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, false, "failing weakCompareAndSetPlain boolean value"); + assertEquals(false, x, "failing weakCompareAndSetPlain boolean value"); } { @@ -804,14 +802,14 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, true, "success weakCompareAndSetAcquire boolean"); + assertEquals(true, x, "success weakCompareAndSetAcquire boolean"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, false, false); assertEquals(success, false, "failing weakCompareAndSetAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, true, "failing weakCompareAndSetAcquire boolean value"); + assertEquals(true, x, "failing weakCompareAndSetAcquire boolean value"); } { @@ -823,14 +821,14 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, false, "success weakCompareAndSetRelease boolean"); + assertEquals(false, x, "success weakCompareAndSetRelease boolean"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, true, false); assertEquals(success, false, "failing weakCompareAndSetAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, false, "failing weakCompareAndSetAcquire boolean value"); + assertEquals(false, x, "failing weakCompareAndSetAcquire boolean value"); } { @@ -842,14 +840,14 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, true, "success weakCompareAndSet boolean"); + assertEquals(true, x, "success weakCompareAndSet boolean"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, false, false); assertEquals(success, false, "failing weakCompareAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, true, "failing weakCompareAndSet boolean value"); + assertEquals(true, x, "failing weakCompareAndSet boolean value"); } // Compare set and get @@ -857,27 +855,27 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, false); - assertEquals(o, true, "getAndSet boolean"); + assertEquals(true, o, "getAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, false, "getAndSet boolean value"); + assertEquals(false, x, "getAndSet boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(array, i, false); - assertEquals(o, true, "getAndSetAcquire boolean"); + assertEquals(true, o, "getAndSetAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, false, "getAndSetAcquire boolean value"); + assertEquals(false, x, "getAndSetAcquire boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(array, i, false); - assertEquals(o, true, "getAndSetRelease boolean"); + assertEquals(true, o, "getAndSetRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, false, "getAndSetRelease boolean value"); + assertEquals(false, x, "getAndSetRelease boolean value"); } @@ -886,27 +884,27 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(array, i, false); - assertEquals(o, true, "getAndBitwiseOr boolean"); + assertEquals(true, o, "getAndBitwiseOr boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOr boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOr boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(array, i, false); - assertEquals(o, true, "getAndBitwiseOrAcquire boolean"); + assertEquals(true, o, "getAndBitwiseOrAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOrAcquire boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOrAcquire boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(array, i, false); - assertEquals(o, true, "getAndBitwiseOrRelease boolean"); + assertEquals(true, o, "getAndBitwiseOrRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (boolean)(true | false), "getAndBitwiseOrRelease boolean value"); + assertEquals((boolean)(true | false), x, "getAndBitwiseOrRelease boolean value"); } // get and bitwise and @@ -914,27 +912,27 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(array, i, false); - assertEquals(o, true, "getAndBitwiseAnd boolean"); + assertEquals(true, o, "getAndBitwiseAnd boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAnd boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAnd boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(array, i, false); - assertEquals(o, true, "getAndBitwiseAndAcquire boolean"); + assertEquals(true, o, "getAndBitwiseAndAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAndAcquire boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAndAcquire boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(array, i, false); - assertEquals(o, true, "getAndBitwiseAndRelease boolean"); + assertEquals(true, o, "getAndBitwiseAndRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (boolean)(true & false), "getAndBitwiseAndRelease boolean value"); + assertEquals((boolean)(true & false), x, "getAndBitwiseAndRelease boolean value"); } // get and bitwise xor @@ -942,27 +940,27 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(array, i, false); - assertEquals(o, true, "getAndBitwiseXor boolean"); + assertEquals(true, o, "getAndBitwiseXor boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXor boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXor boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(array, i, false); - assertEquals(o, true, "getAndBitwiseXorAcquire boolean"); + assertEquals(true, o, "getAndBitwiseXorAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXorAcquire boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXorAcquire boolean value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, true); boolean o = (boolean) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(array, i, false); - assertEquals(o, true, "getAndBitwiseXorRelease boolean"); + assertEquals(true, o, "getAndBitwiseXorRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (boolean)(true ^ false), "getAndBitwiseXorRelease boolean value"); + assertEquals((boolean)(true ^ false), x, "getAndBitwiseXorRelease boolean value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessByte.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessByte.java index 5b3eafba63b..6f7f54a57f5 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessByte.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessByte.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,22 @@ * @test * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessByte + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessByte */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { static final byte static_final_v = (byte)0x01; @@ -60,7 +60,7 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodHandleAccessByte.class, "final_v", byte.class); @@ -77,8 +77,6 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(byte[].class); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -111,7 +109,8 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -120,13 +119,12 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { } } - static void testInstanceField(VarHandleTestMethodHandleAccessByte recv, Handles hs) throws Throwable { // Plain { hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x01, "set byte value"); + assertEquals((byte)0x01, x, "set byte value"); } @@ -134,21 +132,21 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(recv, (byte)0x23); byte x = (byte) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(recv); - assertEquals(x, (byte)0x23, "setVolatile byte value"); + assertEquals((byte)0x23, x, "setVolatile byte value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(recv, (byte)0x01); byte x = (byte) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(recv); - assertEquals(x, (byte)0x01, "setRelease byte value"); + assertEquals((byte)0x01, x, "setRelease byte value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(recv, (byte)0x23); byte x = (byte) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(recv); - assertEquals(x, (byte)0x23, "setOpaque byte value"); + assertEquals((byte)0x23, x, "setOpaque byte value"); } hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); @@ -158,56 +156,56 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, (byte)0x01, (byte)0x23); assertEquals(r, true, "success compareAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x23, "success compareAndSet byte value"); + assertEquals((byte)0x23, x, "success compareAndSet byte value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, (byte)0x01, (byte)0x45); assertEquals(r, false, "failing compareAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x23, "failing compareAndSet byte value"); + assertEquals((byte)0x23, x, "failing compareAndSet byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, (byte)0x23, (byte)0x01); assertEquals(r, (byte)0x23, "success compareAndExchange byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x01, "success compareAndExchange byte value"); + assertEquals((byte)0x01, x, "success compareAndExchange byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, (byte)0x23, (byte)0x45); assertEquals(r, (byte)0x01, "failing compareAndExchange byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x01, "failing compareAndExchange byte value"); + assertEquals((byte)0x01, x, "failing compareAndExchange byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, (byte)0x01, (byte)0x23); assertEquals(r, (byte)0x01, "success compareAndExchangeAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x23, "success compareAndExchangeAcquire byte value"); + assertEquals((byte)0x23, x, "success compareAndExchangeAcquire byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, (byte)0x01, (byte)0x45); assertEquals(r, (byte)0x23, "failing compareAndExchangeAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x23, "failing compareAndExchangeAcquire byte value"); + assertEquals((byte)0x23, x, "failing compareAndExchangeAcquire byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, (byte)0x23, (byte)0x01); assertEquals(r, (byte)0x23, "success compareAndExchangeRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x01, "success compareAndExchangeRelease byte value"); + assertEquals((byte)0x01, x, "success compareAndExchangeRelease byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, (byte)0x23, (byte)0x45); assertEquals(r, (byte)0x01, "failing compareAndExchangeRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x01, "failing compareAndExchangeRelease byte value"); + assertEquals((byte)0x01, x, "failing compareAndExchangeRelease byte value"); } { @@ -219,14 +217,14 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x23, "success weakCompareAndSetPlain byte value"); + assertEquals((byte)0x23, x, "success weakCompareAndSetPlain byte value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, (byte)0x01, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetPlain byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x23, "failing weakCompareAndSetPlain byte value"); + assertEquals((byte)0x23, x, "failing weakCompareAndSetPlain byte value"); } { @@ -238,14 +236,14 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x01, "success weakCompareAndSetAcquire byte"); + assertEquals((byte)0x01, x, "success weakCompareAndSetAcquire byte"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, (byte)0x23, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x01, "failing weakCompareAndSetAcquire byte value"); + assertEquals((byte)0x01, x, "failing weakCompareAndSetAcquire byte value"); } { @@ -257,14 +255,14 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x23, "success weakCompareAndSetRelease byte"); + assertEquals((byte)0x23, x, "success weakCompareAndSetRelease byte"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, (byte)0x01, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x23, "failing weakCompareAndSetRelease byte value"); + assertEquals((byte)0x23, x, "failing weakCompareAndSetRelease byte value"); } { @@ -276,22 +274,22 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x01, "success weakCompareAndSet byte"); + assertEquals((byte)0x01, x, "success weakCompareAndSet byte"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, (byte)0x23, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x01, "failing weakCompareAndSet byte value"); + assertEquals((byte)0x01, x, "failing weakCompareAndSet byte value"); } // Compare set and get { byte o = (byte) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndSet byte"); + assertEquals((byte)0x01, o, "getAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)0x23, "getAndSet byte value"); + assertEquals((byte)0x23, x, "getAndSet byte value"); } // get and add, add and get @@ -299,27 +297,27 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndAdd byte"); + assertEquals((byte)0x01, o, "getAndAdd byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAdd byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAdd byte value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndAddAcquire byte"); + assertEquals((byte)0x01, o, "getAndAddAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAddAcquire byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAddAcquire byte value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndAddRelease byte"); + assertEquals((byte)0x01, o, "getAndAddRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAddRelease byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAddRelease byte value"); } // get and bitwise or @@ -327,27 +325,27 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOr byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOr byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOr byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOr byte value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOrAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOrAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOrAcquire byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOrAcquire byte value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOrRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOrRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOrRelease byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOrRelease byte value"); } // get and bitwise and @@ -355,27 +353,27 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAnd byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAnd byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAnd byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAnd byte value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAndAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAndAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAndAcquire byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAndAcquire byte value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAndRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAndRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAndRelease byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAndRelease byte value"); } // get and bitwise xor @@ -383,27 +381,27 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXor byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXor byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXor byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXor byte value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXorAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXorAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXorAcquire byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXorAcquire byte value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(recv, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXorRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXorRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXorRelease byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXorRelease byte value"); } } @@ -418,7 +416,7 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x01, "set byte value"); + assertEquals((byte)0x01, x, "set byte value"); } @@ -426,21 +424,21 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact((byte)0x23); byte x = (byte) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(); - assertEquals(x, (byte)0x23, "setVolatile byte value"); + assertEquals((byte)0x23, x, "setVolatile byte value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact((byte)0x01); byte x = (byte) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(); - assertEquals(x, (byte)0x01, "setRelease byte value"); + assertEquals((byte)0x01, x, "setRelease byte value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact((byte)0x23); byte x = (byte) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(); - assertEquals(x, (byte)0x23, "setOpaque byte value"); + assertEquals((byte)0x23, x, "setOpaque byte value"); } hs.get(TestAccessMode.SET).invokeExact((byte)0x01); @@ -450,56 +448,56 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact((byte)0x01, (byte)0x23); assertEquals(r, true, "success compareAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x23, "success compareAndSet byte value"); + assertEquals((byte)0x23, x, "success compareAndSet byte value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact((byte)0x01, (byte)0x45); assertEquals(r, false, "failing compareAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x23, "failing compareAndSet byte value"); + assertEquals((byte)0x23, x, "failing compareAndSet byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact((byte)0x23, (byte)0x01); assertEquals(r, (byte)0x23, "success compareAndExchange byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x01, "success compareAndExchange byte value"); + assertEquals((byte)0x01, x, "success compareAndExchange byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact((byte)0x23, (byte)0x45); assertEquals(r, (byte)0x01, "failing compareAndExchange byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x01, "failing compareAndExchange byte value"); + assertEquals((byte)0x01, x, "failing compareAndExchange byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact((byte)0x01, (byte)0x23); assertEquals(r, (byte)0x01, "success compareAndExchangeAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x23, "success compareAndExchangeAcquire byte value"); + assertEquals((byte)0x23, x, "success compareAndExchangeAcquire byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact((byte)0x01, (byte)0x45); assertEquals(r, (byte)0x23, "failing compareAndExchangeAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x23, "failing compareAndExchangeAcquire byte value"); + assertEquals((byte)0x23, x, "failing compareAndExchangeAcquire byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact((byte)0x23, (byte)0x01); assertEquals(r, (byte)0x23, "success compareAndExchangeRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x01, "success compareAndExchangeRelease byte value"); + assertEquals((byte)0x01, x, "success compareAndExchangeRelease byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact((byte)0x23, (byte)0x45); assertEquals(r, (byte)0x01, "failing compareAndExchangeRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x01, "failing compareAndExchangeRelease byte value"); + assertEquals((byte)0x01, x, "failing compareAndExchangeRelease byte value"); } { @@ -511,14 +509,14 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x23, "success weakCompareAndSetPlain byte value"); + assertEquals((byte)0x23, x, "success weakCompareAndSetPlain byte value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact((byte)0x01, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetPlain byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x23, "failing weakCompareAndSetPlain byte value"); + assertEquals((byte)0x23, x, "failing weakCompareAndSetPlain byte value"); } { @@ -530,7 +528,7 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x01, "success weakCompareAndSetAcquire byte"); + assertEquals((byte)0x01, x, "success weakCompareAndSetAcquire byte"); } { @@ -538,7 +536,7 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { boolean success = (boolean) mh.invokeExact((byte)0x23, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x01, "failing weakCompareAndSetAcquire byte value"); + assertEquals((byte)0x01, x, "failing weakCompareAndSetAcquire byte value"); } { @@ -550,14 +548,14 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x23, "success weakCompareAndSetRelease byte"); + assertEquals((byte)0x23, x, "success weakCompareAndSetRelease byte"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact((byte)0x01, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x23, "failing weakCompareAndSetRelease byte value"); + assertEquals((byte)0x23, x, "failing weakCompareAndSetRelease byte value"); } { @@ -569,14 +567,14 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x01, "success weakCompareAndSet byte"); + assertEquals((byte)0x01, x, "success weakCompareAndSet byte"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact((byte)0x23, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x01, "failing weakCompareAndSetRe byte value"); + assertEquals((byte)0x01, x, "failing weakCompareAndSetRe byte value"); } // Compare set and get @@ -584,9 +582,9 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_SET).invokeExact((byte)0x23); - assertEquals(o, (byte)0x01, "getAndSet byte"); + assertEquals((byte)0x01, o, "getAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x23, "getAndSet byte value"); + assertEquals((byte)0x23, x, "getAndSet byte value"); } // Compare set and get @@ -594,9 +592,9 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact((byte)0x23); - assertEquals(o, (byte)0x01, "getAndSetAcquire byte"); + assertEquals((byte)0x01, o, "getAndSetAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x23, "getAndSetAcquire byte value"); + assertEquals((byte)0x23, x, "getAndSetAcquire byte value"); } // Compare set and get @@ -604,9 +602,9 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact((byte)0x23); - assertEquals(o, (byte)0x01, "getAndSetRelease byte"); + assertEquals((byte)0x01, o, "getAndSetRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)0x23, "getAndSetRelease byte value"); + assertEquals((byte)0x23, x, "getAndSetRelease byte value"); } // get and add, add and get @@ -614,27 +612,27 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_ADD).invokeExact((byte)0x23); - assertEquals(o, (byte)0x01, "getAndAdd byte"); + assertEquals((byte)0x01, o, "getAndAdd byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAdd byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAdd byte value"); } { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact((byte)0x23); - assertEquals(o, (byte)0x01, "getAndAddAcquire byte"); + assertEquals((byte)0x01, o, "getAndAddAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAddAcquire byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAddAcquire byte value"); } { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact((byte)0x23); - assertEquals(o, (byte)0x01, "getAndAddRelease byte"); + assertEquals((byte)0x01, o, "getAndAddRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAddRelease byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAddRelease byte value"); } // get and bitwise or @@ -642,27 +640,27 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOr byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOr byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOr byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOr byte value"); } { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOrAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOrAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOrAcquire byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOrAcquire byte value"); } { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOrRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOrRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOrRelease byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOrRelease byte value"); } // get and bitwise and @@ -670,27 +668,27 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAnd byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAnd byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAnd byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAnd byte value"); } { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAndAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAndAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAndAcquire byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAndAcquire byte value"); } { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAndRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAndRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAndRelease byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAndRelease byte value"); } // get and bitwise xor @@ -698,27 +696,27 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXor byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXor byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXor byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXor byte value"); } { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXorAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXorAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXorAcquire byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXorAcquire byte value"); } { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact((byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXorRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXorRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXorRelease byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXorRelease byte value"); } } @@ -736,7 +734,7 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x01, "get byte value"); + assertEquals((byte)0x01, x, "get byte value"); } @@ -744,21 +742,21 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(array, i, (byte)0x23); byte x = (byte) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(array, i); - assertEquals(x, (byte)0x23, "setVolatile byte value"); + assertEquals((byte)0x23, x, "setVolatile byte value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(array, i, (byte)0x01); byte x = (byte) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(array, i); - assertEquals(x, (byte)0x01, "setRelease byte value"); + assertEquals((byte)0x01, x, "setRelease byte value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(array, i, (byte)0x23); byte x = (byte) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(array, i); - assertEquals(x, (byte)0x23, "setOpaque byte value"); + assertEquals((byte)0x23, x, "setOpaque byte value"); } hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); @@ -768,56 +766,56 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, (byte)0x01, (byte)0x23); assertEquals(r, true, "success compareAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x23, "success compareAndSet byte value"); + assertEquals((byte)0x23, x, "success compareAndSet byte value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, (byte)0x01, (byte)0x45); assertEquals(r, false, "failing compareAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x23, "failing compareAndSet byte value"); + assertEquals((byte)0x23, x, "failing compareAndSet byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, (byte)0x23, (byte)0x01); assertEquals(r, (byte)0x23, "success compareAndExchange byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x01, "success compareAndExchange byte value"); + assertEquals((byte)0x01, x, "success compareAndExchange byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, (byte)0x23, (byte)0x45); assertEquals(r, (byte)0x01, "failing compareAndExchange byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x01, "failing compareAndExchange byte value"); + assertEquals((byte)0x01, x, "failing compareAndExchange byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, (byte)0x01, (byte)0x23); assertEquals(r, (byte)0x01, "success compareAndExchangeAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x23, "success compareAndExchangeAcquire byte value"); + assertEquals((byte)0x23, x, "success compareAndExchangeAcquire byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, (byte)0x01, (byte)0x45); assertEquals(r, (byte)0x23, "failing compareAndExchangeAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x23, "failing compareAndExchangeAcquire byte value"); + assertEquals((byte)0x23, x, "failing compareAndExchangeAcquire byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, (byte)0x23, (byte)0x01); assertEquals(r, (byte)0x23, "success compareAndExchangeRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x01, "success compareAndExchangeRelease byte value"); + assertEquals((byte)0x01, x, "success compareAndExchangeRelease byte value"); } { byte r = (byte) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, (byte)0x23, (byte)0x45); assertEquals(r, (byte)0x01, "failing compareAndExchangeRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x01, "failing compareAndExchangeRelease byte value"); + assertEquals((byte)0x01, x, "failing compareAndExchangeRelease byte value"); } { @@ -829,14 +827,14 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x23, "success weakCompareAndSetPlain byte value"); + assertEquals((byte)0x23, x, "success weakCompareAndSetPlain byte value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, (byte)0x01, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetPlain byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x23, "failing weakCompareAndSetPlain byte value"); + assertEquals((byte)0x23, x, "failing weakCompareAndSetPlain byte value"); } { @@ -848,14 +846,14 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x01, "success weakCompareAndSetAcquire byte"); + assertEquals((byte)0x01, x, "success weakCompareAndSetAcquire byte"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, (byte)0x23, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x01, "failing weakCompareAndSetAcquire byte value"); + assertEquals((byte)0x01, x, "failing weakCompareAndSetAcquire byte value"); } { @@ -867,14 +865,14 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x23, "success weakCompareAndSetRelease byte"); + assertEquals((byte)0x23, x, "success weakCompareAndSetRelease byte"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, (byte)0x01, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x23, "failing weakCompareAndSetAcquire byte value"); + assertEquals((byte)0x23, x, "failing weakCompareAndSetAcquire byte value"); } { @@ -886,14 +884,14 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x01, "success weakCompareAndSet byte"); + assertEquals((byte)0x01, x, "success weakCompareAndSet byte"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, (byte)0x23, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x01, "failing weakCompareAndSet byte value"); + assertEquals((byte)0x01, x, "failing weakCompareAndSet byte value"); } // Compare set and get @@ -901,27 +899,27 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndSet byte"); + assertEquals((byte)0x01, o, "getAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x23, "getAndSet byte value"); + assertEquals((byte)0x23, x, "getAndSet byte value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndSetAcquire byte"); + assertEquals((byte)0x01, o, "getAndSetAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x23, "getAndSetAcquire byte value"); + assertEquals((byte)0x23, x, "getAndSetAcquire byte value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndSetRelease byte"); + assertEquals((byte)0x01, o, "getAndSetRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)0x23, "getAndSetRelease byte value"); + assertEquals((byte)0x23, x, "getAndSetRelease byte value"); } // get and add, add and get @@ -929,27 +927,27 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndAdd byte"); + assertEquals((byte)0x01, o, "getAndAdd byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAdd byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAdd byte value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndAddAcquire byte"); + assertEquals((byte)0x01, o, "getAndAddAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAddAcquire byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAddAcquire byte value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndAddRelease byte"); + assertEquals((byte)0x01, o, "getAndAddRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)((byte)0x01 + (byte)0x23), "getAndAddRelease byte value"); + assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAddRelease byte value"); } // get and bitwise or @@ -957,27 +955,27 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOr byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOr byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOr byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOr byte value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOrAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOrAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOrAcquire byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOrAcquire byte value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseOrRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseOrRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)((byte)0x01 | (byte)0x23), "getAndBitwiseOrRelease byte value"); + assertEquals((byte)((byte)0x01 | (byte)0x23), x, "getAndBitwiseOrRelease byte value"); } // get and bitwise and @@ -985,27 +983,27 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAnd byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAnd byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAnd byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAnd byte value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAndAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAndAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAndAcquire byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAndAcquire byte value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseAndRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseAndRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)((byte)0x01 & (byte)0x23), "getAndBitwiseAndRelease byte value"); + assertEquals((byte)((byte)0x01 & (byte)0x23), x, "getAndBitwiseAndRelease byte value"); } // get and bitwise xor @@ -1013,27 +1011,27 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXor byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXor byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXor byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXor byte value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXorAcquire byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXorAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXorAcquire byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXorAcquire byte value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (byte)0x01); byte o = (byte) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(array, i, (byte)0x23); - assertEquals(o, (byte)0x01, "getAndBitwiseXorRelease byte"); + assertEquals((byte)0x01, o, "getAndBitwiseXorRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (byte)((byte)0x01 ^ (byte)0x23), "getAndBitwiseXorRelease byte value"); + assertEquals((byte)((byte)0x01 ^ (byte)0x23), x, "getAndBitwiseXorRelease byte value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessChar.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessChar.java index d191b507366..3e31ee282ff 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessChar.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessChar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,22 @@ * @test * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessChar + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessChar */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { static final char static_final_v = '\u0123'; @@ -60,7 +60,7 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodHandleAccessChar.class, "final_v", char.class); @@ -77,8 +77,6 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(char[].class); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -111,7 +109,8 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -120,13 +119,12 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { } } - static void testInstanceField(VarHandleTestMethodHandleAccessChar recv, Handles hs) throws Throwable { // Plain { hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u0123', "set char value"); + assertEquals('\u0123', x, "set char value"); } @@ -134,21 +132,21 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(recv, '\u4567'); char x = (char) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(recv); - assertEquals(x, '\u4567', "setVolatile char value"); + assertEquals('\u4567', x, "setVolatile char value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(recv, '\u0123'); char x = (char) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(recv); - assertEquals(x, '\u0123', "setRelease char value"); + assertEquals('\u0123', x, "setRelease char value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(recv, '\u4567'); char x = (char) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(recv); - assertEquals(x, '\u4567', "setOpaque char value"); + assertEquals('\u4567', x, "setOpaque char value"); } hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); @@ -158,56 +156,56 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, '\u0123', '\u4567'); assertEquals(r, true, "success compareAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u4567', "success compareAndSet char value"); + assertEquals('\u4567', x, "success compareAndSet char value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, '\u0123', '\u89AB'); assertEquals(r, false, "failing compareAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u4567', "failing compareAndSet char value"); + assertEquals('\u4567', x, "failing compareAndSet char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, '\u4567', '\u0123'); assertEquals(r, '\u4567', "success compareAndExchange char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u0123', "success compareAndExchange char value"); + assertEquals('\u0123', x, "success compareAndExchange char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, '\u4567', '\u89AB'); assertEquals(r, '\u0123', "failing compareAndExchange char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u0123', "failing compareAndExchange char value"); + assertEquals('\u0123', x, "failing compareAndExchange char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, '\u0123', '\u4567'); assertEquals(r, '\u0123', "success compareAndExchangeAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u4567', "success compareAndExchangeAcquire char value"); + assertEquals('\u4567', x, "success compareAndExchangeAcquire char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, '\u0123', '\u89AB'); assertEquals(r, '\u4567', "failing compareAndExchangeAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u4567', "failing compareAndExchangeAcquire char value"); + assertEquals('\u4567', x, "failing compareAndExchangeAcquire char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, '\u4567', '\u0123'); assertEquals(r, '\u4567', "success compareAndExchangeRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u0123', "success compareAndExchangeRelease char value"); + assertEquals('\u0123', x, "success compareAndExchangeRelease char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, '\u4567', '\u89AB'); assertEquals(r, '\u0123', "failing compareAndExchangeRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u0123', "failing compareAndExchangeRelease char value"); + assertEquals('\u0123', x, "failing compareAndExchangeRelease char value"); } { @@ -219,14 +217,14 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u4567', "success weakCompareAndSetPlain char value"); + assertEquals('\u4567', x, "success weakCompareAndSetPlain char value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, '\u0123', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetPlain char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u4567', "failing weakCompareAndSetPlain char value"); + assertEquals('\u4567', x, "failing weakCompareAndSetPlain char value"); } { @@ -238,14 +236,14 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u0123', "success weakCompareAndSetAcquire char"); + assertEquals('\u0123', x, "success weakCompareAndSetAcquire char"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, '\u4567', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u0123', "failing weakCompareAndSetAcquire char value"); + assertEquals('\u0123', x, "failing weakCompareAndSetAcquire char value"); } { @@ -257,14 +255,14 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u4567', "success weakCompareAndSetRelease char"); + assertEquals('\u4567', x, "success weakCompareAndSetRelease char"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, '\u0123', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u4567', "failing weakCompareAndSetRelease char value"); + assertEquals('\u4567', x, "failing weakCompareAndSetRelease char value"); } { @@ -276,22 +274,22 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u0123', "success weakCompareAndSet char"); + assertEquals('\u0123', x, "success weakCompareAndSet char"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, '\u4567', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u0123', "failing weakCompareAndSet char value"); + assertEquals('\u0123', x, "failing weakCompareAndSet char value"); } // Compare set and get { char o = (char) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndSet char"); + assertEquals('\u0123', o, "getAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, '\u4567', "getAndSet char value"); + assertEquals('\u4567', x, "getAndSet char value"); } // get and add, add and get @@ -299,27 +297,27 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndAdd char"); + assertEquals('\u0123', o, "getAndAdd char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAdd char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAdd char value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndAddAcquire char"); + assertEquals('\u0123', o, "getAndAddAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAddAcquire char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAddAcquire char value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndAddRelease char"); + assertEquals('\u0123', o, "getAndAddRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAddRelease char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAddRelease char value"); } // get and bitwise or @@ -327,27 +325,27 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOr char"); + assertEquals('\u0123', o, "getAndBitwiseOr char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOr char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOr char value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOrAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseOrAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOrAcquire char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOrAcquire char value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOrRelease char"); + assertEquals('\u0123', o, "getAndBitwiseOrRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOrRelease char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOrRelease char value"); } // get and bitwise and @@ -355,27 +353,27 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAnd char"); + assertEquals('\u0123', o, "getAndBitwiseAnd char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAnd char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAnd char value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAndAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseAndAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAndAcquire char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAndAcquire char value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAndRelease char"); + assertEquals('\u0123', o, "getAndBitwiseAndRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAndRelease char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAndRelease char value"); } // get and bitwise xor @@ -383,27 +381,27 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXor char"); + assertEquals('\u0123', o, "getAndBitwiseXor char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXor char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXor char value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXorAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseXorAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXorAcquire char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXorAcquire char value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(recv, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXorRelease char"); + assertEquals('\u0123', o, "getAndBitwiseXorRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXorRelease char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXorRelease char value"); } } @@ -418,7 +416,7 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact('\u0123'); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u0123', "set char value"); + assertEquals('\u0123', x, "set char value"); } @@ -426,21 +424,21 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact('\u4567'); char x = (char) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(); - assertEquals(x, '\u4567', "setVolatile char value"); + assertEquals('\u4567', x, "setVolatile char value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact('\u0123'); char x = (char) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(); - assertEquals(x, '\u0123', "setRelease char value"); + assertEquals('\u0123', x, "setRelease char value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact('\u4567'); char x = (char) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(); - assertEquals(x, '\u4567', "setOpaque char value"); + assertEquals('\u4567', x, "setOpaque char value"); } hs.get(TestAccessMode.SET).invokeExact('\u0123'); @@ -450,56 +448,56 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact('\u0123', '\u4567'); assertEquals(r, true, "success compareAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u4567', "success compareAndSet char value"); + assertEquals('\u4567', x, "success compareAndSet char value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact('\u0123', '\u89AB'); assertEquals(r, false, "failing compareAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u4567', "failing compareAndSet char value"); + assertEquals('\u4567', x, "failing compareAndSet char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact('\u4567', '\u0123'); assertEquals(r, '\u4567', "success compareAndExchange char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u0123', "success compareAndExchange char value"); + assertEquals('\u0123', x, "success compareAndExchange char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact('\u4567', '\u89AB'); assertEquals(r, '\u0123', "failing compareAndExchange char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u0123', "failing compareAndExchange char value"); + assertEquals('\u0123', x, "failing compareAndExchange char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact('\u0123', '\u4567'); assertEquals(r, '\u0123', "success compareAndExchangeAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u4567', "success compareAndExchangeAcquire char value"); + assertEquals('\u4567', x, "success compareAndExchangeAcquire char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact('\u0123', '\u89AB'); assertEquals(r, '\u4567', "failing compareAndExchangeAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u4567', "failing compareAndExchangeAcquire char value"); + assertEquals('\u4567', x, "failing compareAndExchangeAcquire char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact('\u4567', '\u0123'); assertEquals(r, '\u4567', "success compareAndExchangeRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u0123', "success compareAndExchangeRelease char value"); + assertEquals('\u0123', x, "success compareAndExchangeRelease char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact('\u4567', '\u89AB'); assertEquals(r, '\u0123', "failing compareAndExchangeRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u0123', "failing compareAndExchangeRelease char value"); + assertEquals('\u0123', x, "failing compareAndExchangeRelease char value"); } { @@ -511,14 +509,14 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u4567', "success weakCompareAndSetPlain char value"); + assertEquals('\u4567', x, "success weakCompareAndSetPlain char value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact('\u0123', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetPlain char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u4567', "failing weakCompareAndSetPlain char value"); + assertEquals('\u4567', x, "failing weakCompareAndSetPlain char value"); } { @@ -530,7 +528,7 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u0123', "success weakCompareAndSetAcquire char"); + assertEquals('\u0123', x, "success weakCompareAndSetAcquire char"); } { @@ -538,7 +536,7 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { boolean success = (boolean) mh.invokeExact('\u4567', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u0123', "failing weakCompareAndSetAcquire char value"); + assertEquals('\u0123', x, "failing weakCompareAndSetAcquire char value"); } { @@ -550,14 +548,14 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u4567', "success weakCompareAndSetRelease char"); + assertEquals('\u4567', x, "success weakCompareAndSetRelease char"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact('\u0123', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u4567', "failing weakCompareAndSetRelease char value"); + assertEquals('\u4567', x, "failing weakCompareAndSetRelease char value"); } { @@ -569,14 +567,14 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u0123', "success weakCompareAndSet char"); + assertEquals('\u0123', x, "success weakCompareAndSet char"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact('\u4567', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u0123', "failing weakCompareAndSetRe char value"); + assertEquals('\u0123', x, "failing weakCompareAndSetRe char value"); } // Compare set and get @@ -584,9 +582,9 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact('\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_SET).invokeExact('\u4567'); - assertEquals(o, '\u0123', "getAndSet char"); + assertEquals('\u0123', o, "getAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u4567', "getAndSet char value"); + assertEquals('\u4567', x, "getAndSet char value"); } // Compare set and get @@ -594,9 +592,9 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact('\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact('\u4567'); - assertEquals(o, '\u0123', "getAndSetAcquire char"); + assertEquals('\u0123', o, "getAndSetAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u4567', "getAndSetAcquire char value"); + assertEquals('\u4567', x, "getAndSetAcquire char value"); } // Compare set and get @@ -604,9 +602,9 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact('\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact('\u4567'); - assertEquals(o, '\u0123', "getAndSetRelease char"); + assertEquals('\u0123', o, "getAndSetRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, '\u4567', "getAndSetRelease char value"); + assertEquals('\u4567', x, "getAndSetRelease char value"); } // get and add, add and get @@ -614,27 +612,27 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact('\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_ADD).invokeExact('\u4567'); - assertEquals(o, '\u0123', "getAndAdd char"); + assertEquals('\u0123', o, "getAndAdd char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAdd char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAdd char value"); } { hs.get(TestAccessMode.SET).invokeExact('\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact('\u4567'); - assertEquals(o, '\u0123', "getAndAddAcquire char"); + assertEquals('\u0123', o, "getAndAddAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAddAcquire char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAddAcquire char value"); } { hs.get(TestAccessMode.SET).invokeExact('\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact('\u4567'); - assertEquals(o, '\u0123', "getAndAddRelease char"); + assertEquals('\u0123', o, "getAndAddRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAddRelease char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAddRelease char value"); } // get and bitwise or @@ -642,27 +640,27 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact('\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOr char"); + assertEquals('\u0123', o, "getAndBitwiseOr char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOr char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOr char value"); } { hs.get(TestAccessMode.SET).invokeExact('\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOrAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseOrAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOrAcquire char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOrAcquire char value"); } { hs.get(TestAccessMode.SET).invokeExact('\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOrRelease char"); + assertEquals('\u0123', o, "getAndBitwiseOrRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOrRelease char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOrRelease char value"); } // get and bitwise and @@ -670,27 +668,27 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact('\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAnd char"); + assertEquals('\u0123', o, "getAndBitwiseAnd char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAnd char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAnd char value"); } { hs.get(TestAccessMode.SET).invokeExact('\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAndAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseAndAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAndAcquire char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAndAcquire char value"); } { hs.get(TestAccessMode.SET).invokeExact('\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAndRelease char"); + assertEquals('\u0123', o, "getAndBitwiseAndRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAndRelease char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAndRelease char value"); } // get and bitwise xor @@ -698,27 +696,27 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact('\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXor char"); + assertEquals('\u0123', o, "getAndBitwiseXor char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXor char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXor char value"); } { hs.get(TestAccessMode.SET).invokeExact('\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXorAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseXorAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXorAcquire char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXorAcquire char value"); } { hs.get(TestAccessMode.SET).invokeExact('\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact('\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXorRelease char"); + assertEquals('\u0123', o, "getAndBitwiseXorRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXorRelease char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXorRelease char value"); } } @@ -736,7 +734,7 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u0123', "get char value"); + assertEquals('\u0123', x, "get char value"); } @@ -744,21 +742,21 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(array, i, '\u4567'); char x = (char) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(array, i); - assertEquals(x, '\u4567', "setVolatile char value"); + assertEquals('\u4567', x, "setVolatile char value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(array, i, '\u0123'); char x = (char) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(array, i); - assertEquals(x, '\u0123', "setRelease char value"); + assertEquals('\u0123', x, "setRelease char value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(array, i, '\u4567'); char x = (char) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(array, i); - assertEquals(x, '\u4567', "setOpaque char value"); + assertEquals('\u4567', x, "setOpaque char value"); } hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); @@ -768,56 +766,56 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, '\u0123', '\u4567'); assertEquals(r, true, "success compareAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u4567', "success compareAndSet char value"); + assertEquals('\u4567', x, "success compareAndSet char value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, '\u0123', '\u89AB'); assertEquals(r, false, "failing compareAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u4567', "failing compareAndSet char value"); + assertEquals('\u4567', x, "failing compareAndSet char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, '\u4567', '\u0123'); assertEquals(r, '\u4567', "success compareAndExchange char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u0123', "success compareAndExchange char value"); + assertEquals('\u0123', x, "success compareAndExchange char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, '\u4567', '\u89AB'); assertEquals(r, '\u0123', "failing compareAndExchange char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u0123', "failing compareAndExchange char value"); + assertEquals('\u0123', x, "failing compareAndExchange char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, '\u0123', '\u4567'); assertEquals(r, '\u0123', "success compareAndExchangeAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u4567', "success compareAndExchangeAcquire char value"); + assertEquals('\u4567', x, "success compareAndExchangeAcquire char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, '\u0123', '\u89AB'); assertEquals(r, '\u4567', "failing compareAndExchangeAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u4567', "failing compareAndExchangeAcquire char value"); + assertEquals('\u4567', x, "failing compareAndExchangeAcquire char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, '\u4567', '\u0123'); assertEquals(r, '\u4567', "success compareAndExchangeRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u0123', "success compareAndExchangeRelease char value"); + assertEquals('\u0123', x, "success compareAndExchangeRelease char value"); } { char r = (char) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, '\u4567', '\u89AB'); assertEquals(r, '\u0123', "failing compareAndExchangeRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u0123', "failing compareAndExchangeRelease char value"); + assertEquals('\u0123', x, "failing compareAndExchangeRelease char value"); } { @@ -829,14 +827,14 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u4567', "success weakCompareAndSetPlain char value"); + assertEquals('\u4567', x, "success weakCompareAndSetPlain char value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, '\u0123', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetPlain char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u4567', "failing weakCompareAndSetPlain char value"); + assertEquals('\u4567', x, "failing weakCompareAndSetPlain char value"); } { @@ -848,14 +846,14 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u0123', "success weakCompareAndSetAcquire char"); + assertEquals('\u0123', x, "success weakCompareAndSetAcquire char"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, '\u4567', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u0123', "failing weakCompareAndSetAcquire char value"); + assertEquals('\u0123', x, "failing weakCompareAndSetAcquire char value"); } { @@ -867,14 +865,14 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u4567', "success weakCompareAndSetRelease char"); + assertEquals('\u4567', x, "success weakCompareAndSetRelease char"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, '\u0123', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u4567', "failing weakCompareAndSetAcquire char value"); + assertEquals('\u4567', x, "failing weakCompareAndSetAcquire char value"); } { @@ -886,14 +884,14 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u0123', "success weakCompareAndSet char"); + assertEquals('\u0123', x, "success weakCompareAndSet char"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, '\u4567', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u0123', "failing weakCompareAndSet char value"); + assertEquals('\u0123', x, "failing weakCompareAndSet char value"); } // Compare set and get @@ -901,27 +899,27 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndSet char"); + assertEquals('\u0123', o, "getAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u4567', "getAndSet char value"); + assertEquals('\u4567', x, "getAndSet char value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndSetAcquire char"); + assertEquals('\u0123', o, "getAndSetAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u4567', "getAndSetAcquire char value"); + assertEquals('\u4567', x, "getAndSetAcquire char value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndSetRelease char"); + assertEquals('\u0123', o, "getAndSetRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, '\u4567', "getAndSetRelease char value"); + assertEquals('\u4567', x, "getAndSetRelease char value"); } // get and add, add and get @@ -929,27 +927,27 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndAdd char"); + assertEquals('\u0123', o, "getAndAdd char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAdd char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAdd char value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndAddAcquire char"); + assertEquals('\u0123', o, "getAndAddAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAddAcquire char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAddAcquire char value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndAddRelease char"); + assertEquals('\u0123', o, "getAndAddRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (char)('\u0123' + '\u4567'), "getAndAddRelease char value"); + assertEquals((char)('\u0123' + '\u4567'), x, "getAndAddRelease char value"); } // get and bitwise or @@ -957,27 +955,27 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOr char"); + assertEquals('\u0123', o, "getAndBitwiseOr char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOr char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOr char value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOrAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseOrAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOrAcquire char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOrAcquire char value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseOrRelease char"); + assertEquals('\u0123', o, "getAndBitwiseOrRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (char)('\u0123' | '\u4567'), "getAndBitwiseOrRelease char value"); + assertEquals((char)('\u0123' | '\u4567'), x, "getAndBitwiseOrRelease char value"); } // get and bitwise and @@ -985,27 +983,27 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAnd char"); + assertEquals('\u0123', o, "getAndBitwiseAnd char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAnd char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAnd char value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAndAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseAndAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAndAcquire char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAndAcquire char value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseAndRelease char"); + assertEquals('\u0123', o, "getAndBitwiseAndRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (char)('\u0123' & '\u4567'), "getAndBitwiseAndRelease char value"); + assertEquals((char)('\u0123' & '\u4567'), x, "getAndBitwiseAndRelease char value"); } // get and bitwise xor @@ -1013,27 +1011,27 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXor char"); + assertEquals('\u0123', o, "getAndBitwiseXor char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXor char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXor char value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXorAcquire char"); + assertEquals('\u0123', o, "getAndBitwiseXorAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXorAcquire char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXorAcquire char value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, '\u0123'); char o = (char) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(array, i, '\u4567'); - assertEquals(o, '\u0123', "getAndBitwiseXorRelease char"); + assertEquals('\u0123', o, "getAndBitwiseXorRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (char)('\u0123' ^ '\u4567'), "getAndBitwiseXorRelease char value"); + assertEquals((char)('\u0123' ^ '\u4567'), x, "getAndBitwiseXorRelease char value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessDouble.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessDouble.java index fe0455d2375..056d45478ed 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessDouble.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessDouble.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,22 @@ * @test * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessDouble + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessDouble */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { static final double static_final_v = 1.0d; @@ -60,7 +60,7 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodHandleAccessDouble.class, "final_v", double.class); @@ -77,8 +77,6 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(double[].class); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -111,7 +109,8 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -120,13 +119,12 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { } } - static void testInstanceField(VarHandleTestMethodHandleAccessDouble recv, Handles hs) throws Throwable { // Plain { hs.get(TestAccessMode.SET).invokeExact(recv, 1.0d); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0d, "set double value"); + assertEquals(1.0d, x, "set double value"); } @@ -134,21 +132,21 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(recv, 2.0d); double x = (double) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(recv); - assertEquals(x, 2.0d, "setVolatile double value"); + assertEquals(2.0d, x, "setVolatile double value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(recv, 1.0d); double x = (double) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(recv); - assertEquals(x, 1.0d, "setRelease double value"); + assertEquals(1.0d, x, "setRelease double value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(recv, 2.0d); double x = (double) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(recv); - assertEquals(x, 2.0d, "setOpaque double value"); + assertEquals(2.0d, x, "setOpaque double value"); } hs.get(TestAccessMode.SET).invokeExact(recv, 1.0d); @@ -158,56 +156,56 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, 1.0d, 2.0d); assertEquals(r, true, "success compareAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0d, "success compareAndSet double value"); + assertEquals(2.0d, x, "success compareAndSet double value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, 1.0d, 3.0d); assertEquals(r, false, "failing compareAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0d, "failing compareAndSet double value"); + assertEquals(2.0d, x, "failing compareAndSet double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, 2.0d, 1.0d); assertEquals(r, 2.0d, "success compareAndExchange double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0d, "success compareAndExchange double value"); + assertEquals(1.0d, x, "success compareAndExchange double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, 2.0d, 3.0d); assertEquals(r, 1.0d, "failing compareAndExchange double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0d, "failing compareAndExchange double value"); + assertEquals(1.0d, x, "failing compareAndExchange double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, 1.0d, 2.0d); assertEquals(r, 1.0d, "success compareAndExchangeAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0d, "success compareAndExchangeAcquire double value"); + assertEquals(2.0d, x, "success compareAndExchangeAcquire double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, 1.0d, 3.0d); assertEquals(r, 2.0d, "failing compareAndExchangeAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0d, "failing compareAndExchangeAcquire double value"); + assertEquals(2.0d, x, "failing compareAndExchangeAcquire double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, 2.0d, 1.0d); assertEquals(r, 2.0d, "success compareAndExchangeRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0d, "success compareAndExchangeRelease double value"); + assertEquals(1.0d, x, "success compareAndExchangeRelease double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, 2.0d, 3.0d); assertEquals(r, 1.0d, "failing compareAndExchangeRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0d, "failing compareAndExchangeRelease double value"); + assertEquals(1.0d, x, "failing compareAndExchangeRelease double value"); } { @@ -219,14 +217,14 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0d, "success weakCompareAndSetPlain double value"); + assertEquals(2.0d, x, "success weakCompareAndSetPlain double value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, 1.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetPlain double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0d, "failing weakCompareAndSetPlain double value"); + assertEquals(2.0d, x, "failing weakCompareAndSetPlain double value"); } { @@ -238,14 +236,14 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0d, "success weakCompareAndSetAcquire double"); + assertEquals(1.0d, x, "success weakCompareAndSetAcquire double"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, 2.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0d, "failing weakCompareAndSetAcquire double value"); + assertEquals(1.0d, x, "failing weakCompareAndSetAcquire double value"); } { @@ -257,14 +255,14 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0d, "success weakCompareAndSetRelease double"); + assertEquals(2.0d, x, "success weakCompareAndSetRelease double"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, 1.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0d, "failing weakCompareAndSetRelease double value"); + assertEquals(2.0d, x, "failing weakCompareAndSetRelease double value"); } { @@ -276,22 +274,22 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0d, "success weakCompareAndSet double"); + assertEquals(1.0d, x, "success weakCompareAndSet double"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, 2.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0d, "failing weakCompareAndSet double value"); + assertEquals(1.0d, x, "failing weakCompareAndSet double value"); } // Compare set and get { double o = (double) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, 2.0d); - assertEquals(o, 1.0d, "getAndSet double"); + assertEquals(1.0d, o, "getAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0d, "getAndSet double value"); + assertEquals(2.0d, x, "getAndSet double value"); } // get and add, add and get @@ -299,27 +297,27 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, 1.0d); double o = (double) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(recv, 2.0d); - assertEquals(o, 1.0d, "getAndAdd double"); + assertEquals(1.0d, o, "getAndAdd double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAdd double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAdd double value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 1.0d); double o = (double) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(recv, 2.0d); - assertEquals(o, 1.0d, "getAndAddAcquire double"); + assertEquals(1.0d, o, "getAndAddAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAddAcquire double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAddAcquire double value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 1.0d); double o = (double) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(recv, 2.0d); - assertEquals(o, 1.0d, "getAndAddRelease double"); + assertEquals(1.0d, o, "getAndAddRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAddRelease double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAddRelease double value"); } } @@ -340,7 +338,7 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact(1.0d); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0d, "set double value"); + assertEquals(1.0d, x, "set double value"); } @@ -348,21 +346,21 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(2.0d); double x = (double) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(); - assertEquals(x, 2.0d, "setVolatile double value"); + assertEquals(2.0d, x, "setVolatile double value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(1.0d); double x = (double) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(); - assertEquals(x, 1.0d, "setRelease double value"); + assertEquals(1.0d, x, "setRelease double value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(2.0d); double x = (double) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(); - assertEquals(x, 2.0d, "setOpaque double value"); + assertEquals(2.0d, x, "setOpaque double value"); } hs.get(TestAccessMode.SET).invokeExact(1.0d); @@ -372,56 +370,56 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(1.0d, 2.0d); assertEquals(r, true, "success compareAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0d, "success compareAndSet double value"); + assertEquals(2.0d, x, "success compareAndSet double value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(1.0d, 3.0d); assertEquals(r, false, "failing compareAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0d, "failing compareAndSet double value"); + assertEquals(2.0d, x, "failing compareAndSet double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(2.0d, 1.0d); assertEquals(r, 2.0d, "success compareAndExchange double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0d, "success compareAndExchange double value"); + assertEquals(1.0d, x, "success compareAndExchange double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(2.0d, 3.0d); assertEquals(r, 1.0d, "failing compareAndExchange double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0d, "failing compareAndExchange double value"); + assertEquals(1.0d, x, "failing compareAndExchange double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(1.0d, 2.0d); assertEquals(r, 1.0d, "success compareAndExchangeAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0d, "success compareAndExchangeAcquire double value"); + assertEquals(2.0d, x, "success compareAndExchangeAcquire double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(1.0d, 3.0d); assertEquals(r, 2.0d, "failing compareAndExchangeAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0d, "failing compareAndExchangeAcquire double value"); + assertEquals(2.0d, x, "failing compareAndExchangeAcquire double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(2.0d, 1.0d); assertEquals(r, 2.0d, "success compareAndExchangeRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0d, "success compareAndExchangeRelease double value"); + assertEquals(1.0d, x, "success compareAndExchangeRelease double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(2.0d, 3.0d); assertEquals(r, 1.0d, "failing compareAndExchangeRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0d, "failing compareAndExchangeRelease double value"); + assertEquals(1.0d, x, "failing compareAndExchangeRelease double value"); } { @@ -433,14 +431,14 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0d, "success weakCompareAndSetPlain double value"); + assertEquals(2.0d, x, "success weakCompareAndSetPlain double value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(1.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetPlain double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0d, "failing weakCompareAndSetPlain double value"); + assertEquals(2.0d, x, "failing weakCompareAndSetPlain double value"); } { @@ -452,7 +450,7 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0d, "success weakCompareAndSetAcquire double"); + assertEquals(1.0d, x, "success weakCompareAndSetAcquire double"); } { @@ -460,7 +458,7 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { boolean success = (boolean) mh.invokeExact(2.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0d, "failing weakCompareAndSetAcquire double value"); + assertEquals(1.0d, x, "failing weakCompareAndSetAcquire double value"); } { @@ -472,14 +470,14 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0d, "success weakCompareAndSetRelease double"); + assertEquals(2.0d, x, "success weakCompareAndSetRelease double"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(1.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0d, "failing weakCompareAndSetRelease double value"); + assertEquals(2.0d, x, "failing weakCompareAndSetRelease double value"); } { @@ -491,14 +489,14 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0d, "success weakCompareAndSet double"); + assertEquals(1.0d, x, "success weakCompareAndSet double"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(2.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0d, "failing weakCompareAndSetRe double value"); + assertEquals(1.0d, x, "failing weakCompareAndSetRe double value"); } // Compare set and get @@ -506,9 +504,9 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(1.0d); double o = (double) hs.get(TestAccessMode.GET_AND_SET).invokeExact(2.0d); - assertEquals(o, 1.0d, "getAndSet double"); + assertEquals(1.0d, o, "getAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0d, "getAndSet double value"); + assertEquals(2.0d, x, "getAndSet double value"); } // Compare set and get @@ -516,9 +514,9 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(1.0d); double o = (double) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(2.0d); - assertEquals(o, 1.0d, "getAndSetAcquire double"); + assertEquals(1.0d, o, "getAndSetAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0d, "getAndSetAcquire double value"); + assertEquals(2.0d, x, "getAndSetAcquire double value"); } // Compare set and get @@ -526,9 +524,9 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(1.0d); double o = (double) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(2.0d); - assertEquals(o, 1.0d, "getAndSetRelease double"); + assertEquals(1.0d, o, "getAndSetRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0d, "getAndSetRelease double value"); + assertEquals(2.0d, x, "getAndSetRelease double value"); } // get and add, add and get @@ -536,27 +534,27 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(1.0d); double o = (double) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(2.0d); - assertEquals(o, 1.0d, "getAndAdd double"); + assertEquals(1.0d, o, "getAndAdd double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAdd double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAdd double value"); } { hs.get(TestAccessMode.SET).invokeExact(1.0d); double o = (double) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(2.0d); - assertEquals(o, 1.0d, "getAndAddAcquire double"); + assertEquals(1.0d, o, "getAndAddAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAddAcquire double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAddAcquire double value"); } { hs.get(TestAccessMode.SET).invokeExact(1.0d); double o = (double) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(2.0d); - assertEquals(o, 1.0d, "getAndAddRelease double"); + assertEquals(1.0d, o, "getAndAddRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAddRelease double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAddRelease double value"); } } @@ -580,7 +578,7 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact(array, i, 1.0d); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0d, "get double value"); + assertEquals(1.0d, x, "get double value"); } @@ -588,21 +586,21 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(array, i, 2.0d); double x = (double) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(array, i); - assertEquals(x, 2.0d, "setVolatile double value"); + assertEquals(2.0d, x, "setVolatile double value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(array, i, 1.0d); double x = (double) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(array, i); - assertEquals(x, 1.0d, "setRelease double value"); + assertEquals(1.0d, x, "setRelease double value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(array, i, 2.0d); double x = (double) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(array, i); - assertEquals(x, 2.0d, "setOpaque double value"); + assertEquals(2.0d, x, "setOpaque double value"); } hs.get(TestAccessMode.SET).invokeExact(array, i, 1.0d); @@ -612,56 +610,56 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, 1.0d, 2.0d); assertEquals(r, true, "success compareAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0d, "success compareAndSet double value"); + assertEquals(2.0d, x, "success compareAndSet double value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, 1.0d, 3.0d); assertEquals(r, false, "failing compareAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0d, "failing compareAndSet double value"); + assertEquals(2.0d, x, "failing compareAndSet double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, 2.0d, 1.0d); assertEquals(r, 2.0d, "success compareAndExchange double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0d, "success compareAndExchange double value"); + assertEquals(1.0d, x, "success compareAndExchange double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, 2.0d, 3.0d); assertEquals(r, 1.0d, "failing compareAndExchange double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0d, "failing compareAndExchange double value"); + assertEquals(1.0d, x, "failing compareAndExchange double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, 1.0d, 2.0d); assertEquals(r, 1.0d, "success compareAndExchangeAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0d, "success compareAndExchangeAcquire double value"); + assertEquals(2.0d, x, "success compareAndExchangeAcquire double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, 1.0d, 3.0d); assertEquals(r, 2.0d, "failing compareAndExchangeAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0d, "failing compareAndExchangeAcquire double value"); + assertEquals(2.0d, x, "failing compareAndExchangeAcquire double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, 2.0d, 1.0d); assertEquals(r, 2.0d, "success compareAndExchangeRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0d, "success compareAndExchangeRelease double value"); + assertEquals(1.0d, x, "success compareAndExchangeRelease double value"); } { double r = (double) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, 2.0d, 3.0d); assertEquals(r, 1.0d, "failing compareAndExchangeRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0d, "failing compareAndExchangeRelease double value"); + assertEquals(1.0d, x, "failing compareAndExchangeRelease double value"); } { @@ -673,14 +671,14 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0d, "success weakCompareAndSetPlain double value"); + assertEquals(2.0d, x, "success weakCompareAndSetPlain double value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, 1.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetPlain double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0d, "failing weakCompareAndSetPlain double value"); + assertEquals(2.0d, x, "failing weakCompareAndSetPlain double value"); } { @@ -692,14 +690,14 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0d, "success weakCompareAndSetAcquire double"); + assertEquals(1.0d, x, "success weakCompareAndSetAcquire double"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, 2.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0d, "failing weakCompareAndSetAcquire double value"); + assertEquals(1.0d, x, "failing weakCompareAndSetAcquire double value"); } { @@ -711,14 +709,14 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0d, "success weakCompareAndSetRelease double"); + assertEquals(2.0d, x, "success weakCompareAndSetRelease double"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, 1.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0d, "failing weakCompareAndSetAcquire double value"); + assertEquals(2.0d, x, "failing weakCompareAndSetAcquire double value"); } { @@ -730,14 +728,14 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0d, "success weakCompareAndSet double"); + assertEquals(1.0d, x, "success weakCompareAndSet double"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, 2.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0d, "failing weakCompareAndSet double value"); + assertEquals(1.0d, x, "failing weakCompareAndSet double value"); } // Compare set and get @@ -745,27 +743,27 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, 1.0d); double o = (double) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, 2.0d); - assertEquals(o, 1.0d, "getAndSet double"); + assertEquals(1.0d, o, "getAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0d, "getAndSet double value"); + assertEquals(2.0d, x, "getAndSet double value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 1.0d); double o = (double) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(array, i, 2.0d); - assertEquals(o, 1.0d, "getAndSetAcquire double"); + assertEquals(1.0d, o, "getAndSetAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0d, "getAndSetAcquire double value"); + assertEquals(2.0d, x, "getAndSetAcquire double value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 1.0d); double o = (double) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(array, i, 2.0d); - assertEquals(o, 1.0d, "getAndSetRelease double"); + assertEquals(1.0d, o, "getAndSetRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0d, "getAndSetRelease double value"); + assertEquals(2.0d, x, "getAndSetRelease double value"); } // get and add, add and get @@ -773,27 +771,27 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, 1.0d); double o = (double) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(array, i, 2.0d); - assertEquals(o, 1.0d, "getAndAdd double"); + assertEquals(1.0d, o, "getAndAdd double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAdd double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAdd double value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 1.0d); double o = (double) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(array, i, 2.0d); - assertEquals(o, 1.0d, "getAndAddAcquire double"); + assertEquals(1.0d, o, "getAndAddAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAddAcquire double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAddAcquire double value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 1.0d); double o = (double) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(array, i, 2.0d); - assertEquals(o, 1.0d, "getAndAddRelease double"); + assertEquals(1.0d, o, "getAndAddRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (double)(1.0d + 2.0d), "getAndAddRelease double value"); + assertEquals((double)(1.0d + 2.0d), x, "getAndAddRelease double value"); } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessFloat.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessFloat.java index 256e4723eec..98eb72301cb 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessFloat.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessFloat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,22 @@ * @test * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessFloat + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessFloat */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { static final float static_final_v = 1.0f; @@ -60,7 +60,7 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodHandleAccessFloat.class, "final_v", float.class); @@ -77,8 +77,6 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(float[].class); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -111,7 +109,8 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -120,13 +119,12 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { } } - static void testInstanceField(VarHandleTestMethodHandleAccessFloat recv, Handles hs) throws Throwable { // Plain { hs.get(TestAccessMode.SET).invokeExact(recv, 1.0f); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0f, "set float value"); + assertEquals(1.0f, x, "set float value"); } @@ -134,21 +132,21 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(recv, 2.0f); float x = (float) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(recv); - assertEquals(x, 2.0f, "setVolatile float value"); + assertEquals(2.0f, x, "setVolatile float value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(recv, 1.0f); float x = (float) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(recv); - assertEquals(x, 1.0f, "setRelease float value"); + assertEquals(1.0f, x, "setRelease float value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(recv, 2.0f); float x = (float) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(recv); - assertEquals(x, 2.0f, "setOpaque float value"); + assertEquals(2.0f, x, "setOpaque float value"); } hs.get(TestAccessMode.SET).invokeExact(recv, 1.0f); @@ -158,56 +156,56 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, 1.0f, 2.0f); assertEquals(r, true, "success compareAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0f, "success compareAndSet float value"); + assertEquals(2.0f, x, "success compareAndSet float value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, 1.0f, 3.0f); assertEquals(r, false, "failing compareAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0f, "failing compareAndSet float value"); + assertEquals(2.0f, x, "failing compareAndSet float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, 2.0f, 1.0f); assertEquals(r, 2.0f, "success compareAndExchange float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0f, "success compareAndExchange float value"); + assertEquals(1.0f, x, "success compareAndExchange float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, 2.0f, 3.0f); assertEquals(r, 1.0f, "failing compareAndExchange float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0f, "failing compareAndExchange float value"); + assertEquals(1.0f, x, "failing compareAndExchange float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, 1.0f, 2.0f); assertEquals(r, 1.0f, "success compareAndExchangeAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0f, "success compareAndExchangeAcquire float value"); + assertEquals(2.0f, x, "success compareAndExchangeAcquire float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, 1.0f, 3.0f); assertEquals(r, 2.0f, "failing compareAndExchangeAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0f, "failing compareAndExchangeAcquire float value"); + assertEquals(2.0f, x, "failing compareAndExchangeAcquire float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, 2.0f, 1.0f); assertEquals(r, 2.0f, "success compareAndExchangeRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0f, "success compareAndExchangeRelease float value"); + assertEquals(1.0f, x, "success compareAndExchangeRelease float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, 2.0f, 3.0f); assertEquals(r, 1.0f, "failing compareAndExchangeRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0f, "failing compareAndExchangeRelease float value"); + assertEquals(1.0f, x, "failing compareAndExchangeRelease float value"); } { @@ -219,14 +217,14 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0f, "success weakCompareAndSetPlain float value"); + assertEquals(2.0f, x, "success weakCompareAndSetPlain float value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, 1.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetPlain float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0f, "failing weakCompareAndSetPlain float value"); + assertEquals(2.0f, x, "failing weakCompareAndSetPlain float value"); } { @@ -238,14 +236,14 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0f, "success weakCompareAndSetAcquire float"); + assertEquals(1.0f, x, "success weakCompareAndSetAcquire float"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, 2.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0f, "failing weakCompareAndSetAcquire float value"); + assertEquals(1.0f, x, "failing weakCompareAndSetAcquire float value"); } { @@ -257,14 +255,14 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0f, "success weakCompareAndSetRelease float"); + assertEquals(2.0f, x, "success weakCompareAndSetRelease float"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, 1.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0f, "failing weakCompareAndSetRelease float value"); + assertEquals(2.0f, x, "failing weakCompareAndSetRelease float value"); } { @@ -276,22 +274,22 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0f, "success weakCompareAndSet float"); + assertEquals(1.0f, x, "success weakCompareAndSet float"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, 2.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 1.0f, "failing weakCompareAndSet float value"); + assertEquals(1.0f, x, "failing weakCompareAndSet float value"); } // Compare set and get { float o = (float) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, 2.0f); - assertEquals(o, 1.0f, "getAndSet float"); + assertEquals(1.0f, o, "getAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 2.0f, "getAndSet float value"); + assertEquals(2.0f, x, "getAndSet float value"); } // get and add, add and get @@ -299,27 +297,27 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, 1.0f); float o = (float) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(recv, 2.0f); - assertEquals(o, 1.0f, "getAndAdd float"); + assertEquals(1.0f, o, "getAndAdd float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAdd float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAdd float value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 1.0f); float o = (float) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(recv, 2.0f); - assertEquals(o, 1.0f, "getAndAddAcquire float"); + assertEquals(1.0f, o, "getAndAddAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAddAcquire float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAddAcquire float value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 1.0f); float o = (float) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(recv, 2.0f); - assertEquals(o, 1.0f, "getAndAddRelease float"); + assertEquals(1.0f, o, "getAndAddRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAddRelease float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAddRelease float value"); } } @@ -340,7 +338,7 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact(1.0f); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0f, "set float value"); + assertEquals(1.0f, x, "set float value"); } @@ -348,21 +346,21 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(2.0f); float x = (float) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(); - assertEquals(x, 2.0f, "setVolatile float value"); + assertEquals(2.0f, x, "setVolatile float value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(1.0f); float x = (float) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(); - assertEquals(x, 1.0f, "setRelease float value"); + assertEquals(1.0f, x, "setRelease float value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(2.0f); float x = (float) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(); - assertEquals(x, 2.0f, "setOpaque float value"); + assertEquals(2.0f, x, "setOpaque float value"); } hs.get(TestAccessMode.SET).invokeExact(1.0f); @@ -372,56 +370,56 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(1.0f, 2.0f); assertEquals(r, true, "success compareAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0f, "success compareAndSet float value"); + assertEquals(2.0f, x, "success compareAndSet float value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(1.0f, 3.0f); assertEquals(r, false, "failing compareAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0f, "failing compareAndSet float value"); + assertEquals(2.0f, x, "failing compareAndSet float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(2.0f, 1.0f); assertEquals(r, 2.0f, "success compareAndExchange float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0f, "success compareAndExchange float value"); + assertEquals(1.0f, x, "success compareAndExchange float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(2.0f, 3.0f); assertEquals(r, 1.0f, "failing compareAndExchange float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0f, "failing compareAndExchange float value"); + assertEquals(1.0f, x, "failing compareAndExchange float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(1.0f, 2.0f); assertEquals(r, 1.0f, "success compareAndExchangeAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0f, "success compareAndExchangeAcquire float value"); + assertEquals(2.0f, x, "success compareAndExchangeAcquire float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(1.0f, 3.0f); assertEquals(r, 2.0f, "failing compareAndExchangeAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0f, "failing compareAndExchangeAcquire float value"); + assertEquals(2.0f, x, "failing compareAndExchangeAcquire float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(2.0f, 1.0f); assertEquals(r, 2.0f, "success compareAndExchangeRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0f, "success compareAndExchangeRelease float value"); + assertEquals(1.0f, x, "success compareAndExchangeRelease float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(2.0f, 3.0f); assertEquals(r, 1.0f, "failing compareAndExchangeRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0f, "failing compareAndExchangeRelease float value"); + assertEquals(1.0f, x, "failing compareAndExchangeRelease float value"); } { @@ -433,14 +431,14 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0f, "success weakCompareAndSetPlain float value"); + assertEquals(2.0f, x, "success weakCompareAndSetPlain float value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(1.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetPlain float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0f, "failing weakCompareAndSetPlain float value"); + assertEquals(2.0f, x, "failing weakCompareAndSetPlain float value"); } { @@ -452,7 +450,7 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0f, "success weakCompareAndSetAcquire float"); + assertEquals(1.0f, x, "success weakCompareAndSetAcquire float"); } { @@ -460,7 +458,7 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { boolean success = (boolean) mh.invokeExact(2.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0f, "failing weakCompareAndSetAcquire float value"); + assertEquals(1.0f, x, "failing weakCompareAndSetAcquire float value"); } { @@ -472,14 +470,14 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0f, "success weakCompareAndSetRelease float"); + assertEquals(2.0f, x, "success weakCompareAndSetRelease float"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(1.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0f, "failing weakCompareAndSetRelease float value"); + assertEquals(2.0f, x, "failing weakCompareAndSetRelease float value"); } { @@ -491,14 +489,14 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0f, "success weakCompareAndSet float"); + assertEquals(1.0f, x, "success weakCompareAndSet float"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(2.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 1.0f, "failing weakCompareAndSetRe float value"); + assertEquals(1.0f, x, "failing weakCompareAndSetRe float value"); } // Compare set and get @@ -506,9 +504,9 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(1.0f); float o = (float) hs.get(TestAccessMode.GET_AND_SET).invokeExact(2.0f); - assertEquals(o, 1.0f, "getAndSet float"); + assertEquals(1.0f, o, "getAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0f, "getAndSet float value"); + assertEquals(2.0f, x, "getAndSet float value"); } // Compare set and get @@ -516,9 +514,9 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(1.0f); float o = (float) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(2.0f); - assertEquals(o, 1.0f, "getAndSetAcquire float"); + assertEquals(1.0f, o, "getAndSetAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0f, "getAndSetAcquire float value"); + assertEquals(2.0f, x, "getAndSetAcquire float value"); } // Compare set and get @@ -526,9 +524,9 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(1.0f); float o = (float) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(2.0f); - assertEquals(o, 1.0f, "getAndSetRelease float"); + assertEquals(1.0f, o, "getAndSetRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 2.0f, "getAndSetRelease float value"); + assertEquals(2.0f, x, "getAndSetRelease float value"); } // get and add, add and get @@ -536,27 +534,27 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(1.0f); float o = (float) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(2.0f); - assertEquals(o, 1.0f, "getAndAdd float"); + assertEquals(1.0f, o, "getAndAdd float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAdd float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAdd float value"); } { hs.get(TestAccessMode.SET).invokeExact(1.0f); float o = (float) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(2.0f); - assertEquals(o, 1.0f, "getAndAddAcquire float"); + assertEquals(1.0f, o, "getAndAddAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAddAcquire float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAddAcquire float value"); } { hs.get(TestAccessMode.SET).invokeExact(1.0f); float o = (float) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(2.0f); - assertEquals(o, 1.0f, "getAndAddRelease float"); + assertEquals(1.0f, o, "getAndAddRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAddRelease float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAddRelease float value"); } } @@ -580,7 +578,7 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact(array, i, 1.0f); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0f, "get float value"); + assertEquals(1.0f, x, "get float value"); } @@ -588,21 +586,21 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(array, i, 2.0f); float x = (float) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(array, i); - assertEquals(x, 2.0f, "setVolatile float value"); + assertEquals(2.0f, x, "setVolatile float value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(array, i, 1.0f); float x = (float) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(array, i); - assertEquals(x, 1.0f, "setRelease float value"); + assertEquals(1.0f, x, "setRelease float value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(array, i, 2.0f); float x = (float) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(array, i); - assertEquals(x, 2.0f, "setOpaque float value"); + assertEquals(2.0f, x, "setOpaque float value"); } hs.get(TestAccessMode.SET).invokeExact(array, i, 1.0f); @@ -612,56 +610,56 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, 1.0f, 2.0f); assertEquals(r, true, "success compareAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0f, "success compareAndSet float value"); + assertEquals(2.0f, x, "success compareAndSet float value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, 1.0f, 3.0f); assertEquals(r, false, "failing compareAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0f, "failing compareAndSet float value"); + assertEquals(2.0f, x, "failing compareAndSet float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, 2.0f, 1.0f); assertEquals(r, 2.0f, "success compareAndExchange float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0f, "success compareAndExchange float value"); + assertEquals(1.0f, x, "success compareAndExchange float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, 2.0f, 3.0f); assertEquals(r, 1.0f, "failing compareAndExchange float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0f, "failing compareAndExchange float value"); + assertEquals(1.0f, x, "failing compareAndExchange float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, 1.0f, 2.0f); assertEquals(r, 1.0f, "success compareAndExchangeAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0f, "success compareAndExchangeAcquire float value"); + assertEquals(2.0f, x, "success compareAndExchangeAcquire float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, 1.0f, 3.0f); assertEquals(r, 2.0f, "failing compareAndExchangeAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0f, "failing compareAndExchangeAcquire float value"); + assertEquals(2.0f, x, "failing compareAndExchangeAcquire float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, 2.0f, 1.0f); assertEquals(r, 2.0f, "success compareAndExchangeRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0f, "success compareAndExchangeRelease float value"); + assertEquals(1.0f, x, "success compareAndExchangeRelease float value"); } { float r = (float) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, 2.0f, 3.0f); assertEquals(r, 1.0f, "failing compareAndExchangeRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0f, "failing compareAndExchangeRelease float value"); + assertEquals(1.0f, x, "failing compareAndExchangeRelease float value"); } { @@ -673,14 +671,14 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0f, "success weakCompareAndSetPlain float value"); + assertEquals(2.0f, x, "success weakCompareAndSetPlain float value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, 1.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetPlain float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0f, "failing weakCompareAndSetPlain float value"); + assertEquals(2.0f, x, "failing weakCompareAndSetPlain float value"); } { @@ -692,14 +690,14 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0f, "success weakCompareAndSetAcquire float"); + assertEquals(1.0f, x, "success weakCompareAndSetAcquire float"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, 2.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0f, "failing weakCompareAndSetAcquire float value"); + assertEquals(1.0f, x, "failing weakCompareAndSetAcquire float value"); } { @@ -711,14 +709,14 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0f, "success weakCompareAndSetRelease float"); + assertEquals(2.0f, x, "success weakCompareAndSetRelease float"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, 1.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0f, "failing weakCompareAndSetAcquire float value"); + assertEquals(2.0f, x, "failing weakCompareAndSetAcquire float value"); } { @@ -730,14 +728,14 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0f, "success weakCompareAndSet float"); + assertEquals(1.0f, x, "success weakCompareAndSet float"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, 2.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 1.0f, "failing weakCompareAndSet float value"); + assertEquals(1.0f, x, "failing weakCompareAndSet float value"); } // Compare set and get @@ -745,27 +743,27 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, 1.0f); float o = (float) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, 2.0f); - assertEquals(o, 1.0f, "getAndSet float"); + assertEquals(1.0f, o, "getAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0f, "getAndSet float value"); + assertEquals(2.0f, x, "getAndSet float value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 1.0f); float o = (float) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(array, i, 2.0f); - assertEquals(o, 1.0f, "getAndSetAcquire float"); + assertEquals(1.0f, o, "getAndSetAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0f, "getAndSetAcquire float value"); + assertEquals(2.0f, x, "getAndSetAcquire float value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 1.0f); float o = (float) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(array, i, 2.0f); - assertEquals(o, 1.0f, "getAndSetRelease float"); + assertEquals(1.0f, o, "getAndSetRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 2.0f, "getAndSetRelease float value"); + assertEquals(2.0f, x, "getAndSetRelease float value"); } // get and add, add and get @@ -773,27 +771,27 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, 1.0f); float o = (float) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(array, i, 2.0f); - assertEquals(o, 1.0f, "getAndAdd float"); + assertEquals(1.0f, o, "getAndAdd float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAdd float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAdd float value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 1.0f); float o = (float) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(array, i, 2.0f); - assertEquals(o, 1.0f, "getAndAddAcquire float"); + assertEquals(1.0f, o, "getAndAddAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAddAcquire float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAddAcquire float value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 1.0f); float o = (float) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(array, i, 2.0f); - assertEquals(o, 1.0f, "getAndAddRelease float"); + assertEquals(1.0f, o, "getAndAddRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (float)(1.0f + 2.0f), "getAndAddRelease float value"); + assertEquals((float)(1.0f + 2.0f), x, "getAndAddRelease float value"); } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java index d8558e0b070..920d8453bab 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,22 @@ * @test * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessInt + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessInt */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { static final int static_final_v = 0x01234567; @@ -60,7 +60,7 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodHandleAccessInt.class, "final_v", int.class); @@ -77,8 +77,6 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(int[].class); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -111,7 +109,8 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -120,13 +119,12 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { } } - static void testInstanceField(VarHandleTestMethodHandleAccessInt recv, Handles hs) throws Throwable { // Plain { hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x01234567, "set int value"); + assertEquals(0x01234567, x, "set int value"); } @@ -134,21 +132,21 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(recv, 0x89ABCDEF); int x = (int) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(recv); - assertEquals(x, 0x89ABCDEF, "setVolatile int value"); + assertEquals(0x89ABCDEF, x, "setVolatile int value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(recv, 0x01234567); int x = (int) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(recv); - assertEquals(x, 0x01234567, "setRelease int value"); + assertEquals(0x01234567, x, "setRelease int value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(recv, 0x89ABCDEF); int x = (int) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(recv); - assertEquals(x, 0x89ABCDEF, "setOpaque int value"); + assertEquals(0x89ABCDEF, x, "setOpaque int value"); } hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); @@ -158,56 +156,56 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, 0x01234567, 0x89ABCDEF); assertEquals(r, true, "success compareAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x89ABCDEF, "success compareAndSet int value"); + assertEquals(0x89ABCDEF, x, "success compareAndSet int value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, 0x01234567, 0xCAFEBABE); assertEquals(r, false, "failing compareAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x89ABCDEF, "failing compareAndSet int value"); + assertEquals(0x89ABCDEF, x, "failing compareAndSet int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, 0x89ABCDEF, 0x01234567); assertEquals(r, 0x89ABCDEF, "success compareAndExchange int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x01234567, "success compareAndExchange int value"); + assertEquals(0x01234567, x, "success compareAndExchange int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, 0x89ABCDEF, 0xCAFEBABE); assertEquals(r, 0x01234567, "failing compareAndExchange int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x01234567, "failing compareAndExchange int value"); + assertEquals(0x01234567, x, "failing compareAndExchange int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, 0x01234567, 0x89ABCDEF); assertEquals(r, 0x01234567, "success compareAndExchangeAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x89ABCDEF, "success compareAndExchangeAcquire int value"); + assertEquals(0x89ABCDEF, x, "success compareAndExchangeAcquire int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, 0x01234567, 0xCAFEBABE); assertEquals(r, 0x89ABCDEF, "failing compareAndExchangeAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x89ABCDEF, "failing compareAndExchangeAcquire int value"); + assertEquals(0x89ABCDEF, x, "failing compareAndExchangeAcquire int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, 0x89ABCDEF, 0x01234567); assertEquals(r, 0x89ABCDEF, "success compareAndExchangeRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x01234567, "success compareAndExchangeRelease int value"); + assertEquals(0x01234567, x, "success compareAndExchangeRelease int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, 0x89ABCDEF, 0xCAFEBABE); assertEquals(r, 0x01234567, "failing compareAndExchangeRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x01234567, "failing compareAndExchangeRelease int value"); + assertEquals(0x01234567, x, "failing compareAndExchangeRelease int value"); } { @@ -219,14 +217,14 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x89ABCDEF, "success weakCompareAndSetPlain int value"); + assertEquals(0x89ABCDEF, x, "success weakCompareAndSetPlain int value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, 0x01234567, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetPlain int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x89ABCDEF, "failing weakCompareAndSetPlain int value"); + assertEquals(0x89ABCDEF, x, "failing weakCompareAndSetPlain int value"); } { @@ -238,14 +236,14 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x01234567, "success weakCompareAndSetAcquire int"); + assertEquals(0x01234567, x, "success weakCompareAndSetAcquire int"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, 0x89ABCDEF, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x01234567, "failing weakCompareAndSetAcquire int value"); + assertEquals(0x01234567, x, "failing weakCompareAndSetAcquire int value"); } { @@ -257,14 +255,14 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x89ABCDEF, "success weakCompareAndSetRelease int"); + assertEquals(0x89ABCDEF, x, "success weakCompareAndSetRelease int"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, 0x01234567, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x89ABCDEF, "failing weakCompareAndSetRelease int value"); + assertEquals(0x89ABCDEF, x, "failing weakCompareAndSetRelease int value"); } { @@ -276,22 +274,22 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x01234567, "success weakCompareAndSet int"); + assertEquals(0x01234567, x, "success weakCompareAndSet int"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, 0x89ABCDEF, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x01234567, "failing weakCompareAndSet int value"); + assertEquals(0x01234567, x, "failing weakCompareAndSet int value"); } // Compare set and get { int o = (int) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndSet int"); + assertEquals(0x01234567, o, "getAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x89ABCDEF, "getAndSet int value"); + assertEquals(0x89ABCDEF, x, "getAndSet int value"); } // get and add, add and get @@ -299,27 +297,27 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAdd int"); + assertEquals(0x01234567, o, "getAndAdd int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAdd int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAdd int value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAddAcquire int"); + assertEquals(0x01234567, o, "getAndAddAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAddAcquire int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAddAcquire int value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAddRelease int"); + assertEquals(0x01234567, o, "getAndAddRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAddRelease int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAddRelease int value"); } // get and bitwise or @@ -327,27 +325,27 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOr int"); + assertEquals(0x01234567, o, "getAndBitwiseOr int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOr int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOr int value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOrAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseOrAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOrAcquire int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOrAcquire int value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOrRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseOrRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOrRelease int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOrRelease int value"); } // get and bitwise and @@ -355,27 +353,27 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAnd int"); + assertEquals(0x01234567, o, "getAndBitwiseAnd int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAnd int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAnd int value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAndAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseAndAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAndAcquire int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAndAcquire int value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAndRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseAndRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAndRelease int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAndRelease int value"); } // get and bitwise xor @@ -383,27 +381,27 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXor int"); + assertEquals(0x01234567, o, "getAndBitwiseXor int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXor int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXor int value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXorAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseXorAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXorAcquire int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXorAcquire int value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(recv, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXorRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseXorRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXorRelease int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXorRelease int value"); } } @@ -418,7 +416,7 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact(0x01234567); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x01234567, "set int value"); + assertEquals(0x01234567, x, "set int value"); } @@ -426,21 +424,21 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(0x89ABCDEF); int x = (int) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(); - assertEquals(x, 0x89ABCDEF, "setVolatile int value"); + assertEquals(0x89ABCDEF, x, "setVolatile int value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(0x01234567); int x = (int) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(); - assertEquals(x, 0x01234567, "setRelease int value"); + assertEquals(0x01234567, x, "setRelease int value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(0x89ABCDEF); int x = (int) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(); - assertEquals(x, 0x89ABCDEF, "setOpaque int value"); + assertEquals(0x89ABCDEF, x, "setOpaque int value"); } hs.get(TestAccessMode.SET).invokeExact(0x01234567); @@ -450,56 +448,56 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(0x01234567, 0x89ABCDEF); assertEquals(r, true, "success compareAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x89ABCDEF, "success compareAndSet int value"); + assertEquals(0x89ABCDEF, x, "success compareAndSet int value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(0x01234567, 0xCAFEBABE); assertEquals(r, false, "failing compareAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x89ABCDEF, "failing compareAndSet int value"); + assertEquals(0x89ABCDEF, x, "failing compareAndSet int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(0x89ABCDEF, 0x01234567); assertEquals(r, 0x89ABCDEF, "success compareAndExchange int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x01234567, "success compareAndExchange int value"); + assertEquals(0x01234567, x, "success compareAndExchange int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(0x89ABCDEF, 0xCAFEBABE); assertEquals(r, 0x01234567, "failing compareAndExchange int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x01234567, "failing compareAndExchange int value"); + assertEquals(0x01234567, x, "failing compareAndExchange int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(0x01234567, 0x89ABCDEF); assertEquals(r, 0x01234567, "success compareAndExchangeAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x89ABCDEF, "success compareAndExchangeAcquire int value"); + assertEquals(0x89ABCDEF, x, "success compareAndExchangeAcquire int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(0x01234567, 0xCAFEBABE); assertEquals(r, 0x89ABCDEF, "failing compareAndExchangeAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x89ABCDEF, "failing compareAndExchangeAcquire int value"); + assertEquals(0x89ABCDEF, x, "failing compareAndExchangeAcquire int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(0x89ABCDEF, 0x01234567); assertEquals(r, 0x89ABCDEF, "success compareAndExchangeRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x01234567, "success compareAndExchangeRelease int value"); + assertEquals(0x01234567, x, "success compareAndExchangeRelease int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(0x89ABCDEF, 0xCAFEBABE); assertEquals(r, 0x01234567, "failing compareAndExchangeRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x01234567, "failing compareAndExchangeRelease int value"); + assertEquals(0x01234567, x, "failing compareAndExchangeRelease int value"); } { @@ -511,14 +509,14 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x89ABCDEF, "success weakCompareAndSetPlain int value"); + assertEquals(0x89ABCDEF, x, "success weakCompareAndSetPlain int value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(0x01234567, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetPlain int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x89ABCDEF, "failing weakCompareAndSetPlain int value"); + assertEquals(0x89ABCDEF, x, "failing weakCompareAndSetPlain int value"); } { @@ -530,7 +528,7 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x01234567, "success weakCompareAndSetAcquire int"); + assertEquals(0x01234567, x, "success weakCompareAndSetAcquire int"); } { @@ -538,7 +536,7 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { boolean success = (boolean) mh.invokeExact(0x89ABCDEF, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x01234567, "failing weakCompareAndSetAcquire int value"); + assertEquals(0x01234567, x, "failing weakCompareAndSetAcquire int value"); } { @@ -550,14 +548,14 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x89ABCDEF, "success weakCompareAndSetRelease int"); + assertEquals(0x89ABCDEF, x, "success weakCompareAndSetRelease int"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(0x01234567, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x89ABCDEF, "failing weakCompareAndSetRelease int value"); + assertEquals(0x89ABCDEF, x, "failing weakCompareAndSetRelease int value"); } { @@ -569,14 +567,14 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x01234567, "success weakCompareAndSet int"); + assertEquals(0x01234567, x, "success weakCompareAndSet int"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(0x89ABCDEF, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x01234567, "failing weakCompareAndSetRe int value"); + assertEquals(0x01234567, x, "failing weakCompareAndSetRe int value"); } // Compare set and get @@ -584,9 +582,9 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_SET).invokeExact(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndSet int"); + assertEquals(0x01234567, o, "getAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x89ABCDEF, "getAndSet int value"); + assertEquals(0x89ABCDEF, x, "getAndSet int value"); } // Compare set and get @@ -594,9 +592,9 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndSetAcquire int"); + assertEquals(0x01234567, o, "getAndSetAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x89ABCDEF, "getAndSetAcquire int value"); + assertEquals(0x89ABCDEF, x, "getAndSetAcquire int value"); } // Compare set and get @@ -604,9 +602,9 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndSetRelease int"); + assertEquals(0x01234567, o, "getAndSetRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x89ABCDEF, "getAndSetRelease int value"); + assertEquals(0x89ABCDEF, x, "getAndSetRelease int value"); } // get and add, add and get @@ -614,27 +612,27 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAdd int"); + assertEquals(0x01234567, o, "getAndAdd int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAdd int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAdd int value"); } { hs.get(TestAccessMode.SET).invokeExact(0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAddAcquire int"); + assertEquals(0x01234567, o, "getAndAddAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAddAcquire int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAddAcquire int value"); } { hs.get(TestAccessMode.SET).invokeExact(0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAddRelease int"); + assertEquals(0x01234567, o, "getAndAddRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAddRelease int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAddRelease int value"); } // get and bitwise or @@ -642,27 +640,27 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOr int"); + assertEquals(0x01234567, o, "getAndBitwiseOr int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOr int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOr int value"); } { hs.get(TestAccessMode.SET).invokeExact(0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOrAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseOrAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOrAcquire int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOrAcquire int value"); } { hs.get(TestAccessMode.SET).invokeExact(0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOrRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseOrRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOrRelease int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOrRelease int value"); } // get and bitwise and @@ -670,27 +668,27 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAnd int"); + assertEquals(0x01234567, o, "getAndBitwiseAnd int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAnd int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAnd int value"); } { hs.get(TestAccessMode.SET).invokeExact(0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAndAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseAndAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAndAcquire int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAndAcquire int value"); } { hs.get(TestAccessMode.SET).invokeExact(0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAndRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseAndRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAndRelease int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAndRelease int value"); } // get and bitwise xor @@ -698,27 +696,27 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXor int"); + assertEquals(0x01234567, o, "getAndBitwiseXor int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXor int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXor int value"); } { hs.get(TestAccessMode.SET).invokeExact(0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXorAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseXorAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXorAcquire int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXorAcquire int value"); } { hs.get(TestAccessMode.SET).invokeExact(0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXorRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseXorRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXorRelease int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXorRelease int value"); } } @@ -736,7 +734,7 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x01234567, "get int value"); + assertEquals(0x01234567, x, "get int value"); } @@ -744,21 +742,21 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(array, i, 0x89ABCDEF); int x = (int) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(array, i); - assertEquals(x, 0x89ABCDEF, "setVolatile int value"); + assertEquals(0x89ABCDEF, x, "setVolatile int value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(array, i, 0x01234567); int x = (int) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(array, i); - assertEquals(x, 0x01234567, "setRelease int value"); + assertEquals(0x01234567, x, "setRelease int value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(array, i, 0x89ABCDEF); int x = (int) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(array, i); - assertEquals(x, 0x89ABCDEF, "setOpaque int value"); + assertEquals(0x89ABCDEF, x, "setOpaque int value"); } hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); @@ -768,56 +766,56 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, 0x01234567, 0x89ABCDEF); assertEquals(r, true, "success compareAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x89ABCDEF, "success compareAndSet int value"); + assertEquals(0x89ABCDEF, x, "success compareAndSet int value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, 0x01234567, 0xCAFEBABE); assertEquals(r, false, "failing compareAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x89ABCDEF, "failing compareAndSet int value"); + assertEquals(0x89ABCDEF, x, "failing compareAndSet int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, 0x89ABCDEF, 0x01234567); assertEquals(r, 0x89ABCDEF, "success compareAndExchange int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x01234567, "success compareAndExchange int value"); + assertEquals(0x01234567, x, "success compareAndExchange int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, 0x89ABCDEF, 0xCAFEBABE); assertEquals(r, 0x01234567, "failing compareAndExchange int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x01234567, "failing compareAndExchange int value"); + assertEquals(0x01234567, x, "failing compareAndExchange int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, 0x01234567, 0x89ABCDEF); assertEquals(r, 0x01234567, "success compareAndExchangeAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x89ABCDEF, "success compareAndExchangeAcquire int value"); + assertEquals(0x89ABCDEF, x, "success compareAndExchangeAcquire int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, 0x01234567, 0xCAFEBABE); assertEquals(r, 0x89ABCDEF, "failing compareAndExchangeAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x89ABCDEF, "failing compareAndExchangeAcquire int value"); + assertEquals(0x89ABCDEF, x, "failing compareAndExchangeAcquire int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, 0x89ABCDEF, 0x01234567); assertEquals(r, 0x89ABCDEF, "success compareAndExchangeRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x01234567, "success compareAndExchangeRelease int value"); + assertEquals(0x01234567, x, "success compareAndExchangeRelease int value"); } { int r = (int) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, 0x89ABCDEF, 0xCAFEBABE); assertEquals(r, 0x01234567, "failing compareAndExchangeRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x01234567, "failing compareAndExchangeRelease int value"); + assertEquals(0x01234567, x, "failing compareAndExchangeRelease int value"); } { @@ -829,14 +827,14 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x89ABCDEF, "success weakCompareAndSetPlain int value"); + assertEquals(0x89ABCDEF, x, "success weakCompareAndSetPlain int value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, 0x01234567, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetPlain int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x89ABCDEF, "failing weakCompareAndSetPlain int value"); + assertEquals(0x89ABCDEF, x, "failing weakCompareAndSetPlain int value"); } { @@ -848,14 +846,14 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x01234567, "success weakCompareAndSetAcquire int"); + assertEquals(0x01234567, x, "success weakCompareAndSetAcquire int"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, 0x89ABCDEF, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x01234567, "failing weakCompareAndSetAcquire int value"); + assertEquals(0x01234567, x, "failing weakCompareAndSetAcquire int value"); } { @@ -867,14 +865,14 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x89ABCDEF, "success weakCompareAndSetRelease int"); + assertEquals(0x89ABCDEF, x, "success weakCompareAndSetRelease int"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, 0x01234567, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x89ABCDEF, "failing weakCompareAndSetAcquire int value"); + assertEquals(0x89ABCDEF, x, "failing weakCompareAndSetAcquire int value"); } { @@ -886,14 +884,14 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x01234567, "success weakCompareAndSet int"); + assertEquals(0x01234567, x, "success weakCompareAndSet int"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, 0x89ABCDEF, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x01234567, "failing weakCompareAndSet int value"); + assertEquals(0x01234567, x, "failing weakCompareAndSet int value"); } // Compare set and get @@ -901,27 +899,27 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndSet int"); + assertEquals(0x01234567, o, "getAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x89ABCDEF, "getAndSet int value"); + assertEquals(0x89ABCDEF, x, "getAndSet int value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndSetAcquire int"); + assertEquals(0x01234567, o, "getAndSetAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x89ABCDEF, "getAndSetAcquire int value"); + assertEquals(0x89ABCDEF, x, "getAndSetAcquire int value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndSetRelease int"); + assertEquals(0x01234567, o, "getAndSetRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x89ABCDEF, "getAndSetRelease int value"); + assertEquals(0x89ABCDEF, x, "getAndSetRelease int value"); } // get and add, add and get @@ -929,27 +927,27 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAdd int"); + assertEquals(0x01234567, o, "getAndAdd int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAdd int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAdd int value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAddAcquire int"); + assertEquals(0x01234567, o, "getAndAddAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAddAcquire int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAddAcquire int value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndAddRelease int"); + assertEquals(0x01234567, o, "getAndAddRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (int)(0x01234567 + 0x89ABCDEF), "getAndAddRelease int value"); + assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAddRelease int value"); } // get and bitwise or @@ -957,27 +955,27 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOr int"); + assertEquals(0x01234567, o, "getAndBitwiseOr int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOr int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOr int value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOrAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseOrAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOrAcquire int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOrAcquire int value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseOrRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseOrRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (int)(0x01234567 | 0x89ABCDEF), "getAndBitwiseOrRelease int value"); + assertEquals((int)(0x01234567 | 0x89ABCDEF), x, "getAndBitwiseOrRelease int value"); } // get and bitwise and @@ -985,27 +983,27 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAnd int"); + assertEquals(0x01234567, o, "getAndBitwiseAnd int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAnd int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAnd int value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAndAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseAndAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAndAcquire int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAndAcquire int value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseAndRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseAndRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (int)(0x01234567 & 0x89ABCDEF), "getAndBitwiseAndRelease int value"); + assertEquals((int)(0x01234567 & 0x89ABCDEF), x, "getAndBitwiseAndRelease int value"); } // get and bitwise xor @@ -1013,27 +1011,27 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXor int"); + assertEquals(0x01234567, o, "getAndBitwiseXor int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXor int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXor int value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXorAcquire int"); + assertEquals(0x01234567, o, "getAndBitwiseXorAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXorAcquire int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXorAcquire int value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x01234567); int o = (int) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(array, i, 0x89ABCDEF); - assertEquals(o, 0x01234567, "getAndBitwiseXorRelease int"); + assertEquals(0x01234567, o, "getAndBitwiseXorRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (int)(0x01234567 ^ 0x89ABCDEF), "getAndBitwiseXorRelease int value"); + assertEquals((int)(0x01234567 ^ 0x89ABCDEF), x, "getAndBitwiseXorRelease int value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java index 0e73063395d..90f6dd12c47 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,22 @@ * @test * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessLong + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessLong */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { static final long static_final_v = 0x0123456789ABCDEFL; @@ -60,7 +60,7 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodHandleAccessLong.class, "final_v", long.class); @@ -77,8 +77,6 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(long[].class); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -111,7 +109,8 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -120,13 +119,12 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { } } - static void testInstanceField(VarHandleTestMethodHandleAccessLong recv, Handles hs) throws Throwable { // Plain { hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x0123456789ABCDEFL, "set long value"); + assertEquals(0x0123456789ABCDEFL, x, "set long value"); } @@ -134,21 +132,21 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(recv, 0xCAFEBABECAFEBABEL); long x = (long) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "setVolatile long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "setVolatile long value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(recv, 0x0123456789ABCDEFL); long x = (long) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(recv); - assertEquals(x, 0x0123456789ABCDEFL, "setRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "setRelease long value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(recv, 0xCAFEBABECAFEBABEL); long x = (long) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "setOpaque long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "setOpaque long value"); } hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); @@ -158,56 +156,56 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); assertEquals(r, true, "success compareAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success compareAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success compareAndSet long value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(r, false, "failing compareAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing compareAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing compareAndSet long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "success compareAndExchange long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x0123456789ABCDEFL, "success compareAndExchange long value"); + assertEquals(0x0123456789ABCDEFL, x, "success compareAndExchange long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, 0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0x0123456789ABCDEFL, "failing compareAndExchange long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x0123456789ABCDEFL, "failing compareAndExchange long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing compareAndExchange long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); assertEquals(r, 0x0123456789ABCDEFL, "success compareAndExchangeAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success compareAndExchangeAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success compareAndExchangeAcquire long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "failing compareAndExchangeAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing compareAndExchangeAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing compareAndExchangeAcquire long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "success compareAndExchangeRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x0123456789ABCDEFL, "success compareAndExchangeRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "success compareAndExchangeRelease long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, 0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0x0123456789ABCDEFL, "failing compareAndExchangeRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x0123456789ABCDEFL, "failing compareAndExchangeRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing compareAndExchangeRelease long value"); } { @@ -219,14 +217,14 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success weakCompareAndSetPlain long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success weakCompareAndSetPlain long value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetPlain long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing weakCompareAndSetPlain long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing weakCompareAndSetPlain long value"); } { @@ -238,14 +236,14 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x0123456789ABCDEFL, "success weakCompareAndSetAcquire long"); + assertEquals(0x0123456789ABCDEFL, x, "success weakCompareAndSetAcquire long"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, 0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x0123456789ABCDEFL, "failing weakCompareAndSetAcquire long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing weakCompareAndSetAcquire long value"); } { @@ -257,14 +255,14 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success weakCompareAndSetRelease long"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success weakCompareAndSetRelease long"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing weakCompareAndSetRelease long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing weakCompareAndSetRelease long value"); } { @@ -276,22 +274,22 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x0123456789ABCDEFL, "success weakCompareAndSet long"); + assertEquals(0x0123456789ABCDEFL, x, "success weakCompareAndSet long"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, 0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0x0123456789ABCDEFL, "failing weakCompareAndSet long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing weakCompareAndSet long value"); } // Compare set and get { long o = (long) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndSet long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, 0xCAFEBABECAFEBABEL, "getAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSet long value"); } // get and add, add and get @@ -299,27 +297,27 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAdd long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAdd long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAdd long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAdd long value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAddAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAddAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAddAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAddAcquire long value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAddRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAddRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAddRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAddRelease long value"); } // get and bitwise or @@ -327,27 +325,27 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOr long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOr long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOr long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOr long value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOrAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOrAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOrAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOrAcquire long value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOrRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOrRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOrRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOrRelease long value"); } // get and bitwise and @@ -355,27 +353,27 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAnd long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAnd long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAnd long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAnd long value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAndAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAndAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAndAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAndAcquire long value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAndRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAndRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAndRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAndRelease long value"); } // get and bitwise xor @@ -383,27 +381,27 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXor long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXor long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXor long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXor long value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXorAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXorAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXorAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXorAcquire long value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(recv, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXorRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXorRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXorRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXorRelease long value"); } } @@ -418,7 +416,7 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x0123456789ABCDEFL, "set long value"); + assertEquals(0x0123456789ABCDEFL, x, "set long value"); } @@ -426,21 +424,21 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(0xCAFEBABECAFEBABEL); long x = (long) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "setVolatile long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "setVolatile long value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(0x0123456789ABCDEFL); long x = (long) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(); - assertEquals(x, 0x0123456789ABCDEFL, "setRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "setRelease long value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(0xCAFEBABECAFEBABEL); long x = (long) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "setOpaque long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "setOpaque long value"); } hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); @@ -450,56 +448,56 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); assertEquals(r, true, "success compareAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success compareAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success compareAndSet long value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(r, false, "failing compareAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing compareAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing compareAndSet long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "success compareAndExchange long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x0123456789ABCDEFL, "success compareAndExchange long value"); + assertEquals(0x0123456789ABCDEFL, x, "success compareAndExchange long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0x0123456789ABCDEFL, "failing compareAndExchange long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x0123456789ABCDEFL, "failing compareAndExchange long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing compareAndExchange long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); assertEquals(r, 0x0123456789ABCDEFL, "success compareAndExchangeAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success compareAndExchangeAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success compareAndExchangeAcquire long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "failing compareAndExchangeAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing compareAndExchangeAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing compareAndExchangeAcquire long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "success compareAndExchangeRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x0123456789ABCDEFL, "success compareAndExchangeRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "success compareAndExchangeRelease long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0x0123456789ABCDEFL, "failing compareAndExchangeRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x0123456789ABCDEFL, "failing compareAndExchangeRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing compareAndExchangeRelease long value"); } { @@ -511,14 +509,14 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success weakCompareAndSetPlain long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success weakCompareAndSetPlain long value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetPlain long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing weakCompareAndSetPlain long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing weakCompareAndSetPlain long value"); } { @@ -530,7 +528,7 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x0123456789ABCDEFL, "success weakCompareAndSetAcquire long"); + assertEquals(0x0123456789ABCDEFL, x, "success weakCompareAndSetAcquire long"); } { @@ -538,7 +536,7 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { boolean success = (boolean) mh.invokeExact(0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x0123456789ABCDEFL, "failing weakCompareAndSetAcquire long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing weakCompareAndSetAcquire long value"); } { @@ -550,14 +548,14 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success weakCompareAndSetRelease long"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success weakCompareAndSetRelease long"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing weakCompareAndSetRelease long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing weakCompareAndSetRelease long value"); } { @@ -569,14 +567,14 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x0123456789ABCDEFL, "success weakCompareAndSet long"); + assertEquals(0x0123456789ABCDEFL, x, "success weakCompareAndSet long"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0x0123456789ABCDEFL, "failing weakCompareAndSetRe long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing weakCompareAndSetRe long value"); } // Compare set and get @@ -584,9 +582,9 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_SET).invokeExact(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndSet long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "getAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSet long value"); } // Compare set and get @@ -594,9 +592,9 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndSetAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndSetAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "getAndSetAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSetAcquire long value"); } // Compare set and get @@ -604,9 +602,9 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndSetRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndSetRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, 0xCAFEBABECAFEBABEL, "getAndSetRelease long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSetRelease long value"); } // get and add, add and get @@ -614,27 +612,27 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAdd long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAdd long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAdd long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAdd long value"); } { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAddAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAddAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAddAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAddAcquire long value"); } { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAddRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAddRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAddRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAddRelease long value"); } // get and bitwise or @@ -642,27 +640,27 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOr long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOr long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOr long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOr long value"); } { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOrAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOrAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOrAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOrAcquire long value"); } { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOrRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOrRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOrRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOrRelease long value"); } // get and bitwise and @@ -670,27 +668,27 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAnd long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAnd long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAnd long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAnd long value"); } { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAndAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAndAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAndAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAndAcquire long value"); } { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAndRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAndRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAndRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAndRelease long value"); } // get and bitwise xor @@ -698,27 +696,27 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXor long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXor long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXor long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXor long value"); } { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXorAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXorAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXorAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXorAcquire long value"); } { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXorRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXorRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXorRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXorRelease long value"); } } @@ -736,7 +734,7 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "get long value"); + assertEquals(0x0123456789ABCDEFL, x, "get long value"); } @@ -744,21 +742,21 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(array, i, 0xCAFEBABECAFEBABEL); long x = (long) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "setVolatile long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "setVolatile long value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(array, i, 0x0123456789ABCDEFL); long x = (long) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "setRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "setRelease long value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(array, i, 0xCAFEBABECAFEBABEL); long x = (long) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "setOpaque long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "setOpaque long value"); } hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); @@ -768,56 +766,56 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); assertEquals(r, true, "success compareAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success compareAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success compareAndSet long value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(r, false, "failing compareAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing compareAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing compareAndSet long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "success compareAndExchange long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "success compareAndExchange long value"); + assertEquals(0x0123456789ABCDEFL, x, "success compareAndExchange long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, 0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0x0123456789ABCDEFL, "failing compareAndExchange long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "failing compareAndExchange long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing compareAndExchange long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); assertEquals(r, 0x0123456789ABCDEFL, "success compareAndExchangeAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success compareAndExchangeAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success compareAndExchangeAcquire long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "failing compareAndExchangeAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing compareAndExchangeAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing compareAndExchangeAcquire long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); assertEquals(r, 0xCAFEBABECAFEBABEL, "success compareAndExchangeRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "success compareAndExchangeRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "success compareAndExchangeRelease long value"); } { long r = (long) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, 0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(r, 0x0123456789ABCDEFL, "failing compareAndExchangeRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "failing compareAndExchangeRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing compareAndExchangeRelease long value"); } { @@ -829,14 +827,14 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success weakCompareAndSetPlain long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success weakCompareAndSetPlain long value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetPlain long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing weakCompareAndSetPlain long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing weakCompareAndSetPlain long value"); } { @@ -848,14 +846,14 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "success weakCompareAndSetAcquire long"); + assertEquals(0x0123456789ABCDEFL, x, "success weakCompareAndSetAcquire long"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, 0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "failing weakCompareAndSetAcquire long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing weakCompareAndSetAcquire long value"); } { @@ -867,14 +865,14 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "success weakCompareAndSetRelease long"); + assertEquals(0xCAFEBABECAFEBABEL, x, "success weakCompareAndSetRelease long"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "failing weakCompareAndSetAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing weakCompareAndSetAcquire long value"); } { @@ -886,14 +884,14 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "success weakCompareAndSet long"); + assertEquals(0x0123456789ABCDEFL, x, "success weakCompareAndSet long"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, 0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0x0123456789ABCDEFL, "failing weakCompareAndSet long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing weakCompareAndSet long value"); } // Compare set and get @@ -901,27 +899,27 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndSet long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "getAndSet long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSet long value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndSetAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndSetAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "getAndSetAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSetAcquire long value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndSetRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndSetRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, 0xCAFEBABECAFEBABEL, "getAndSetRelease long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSetRelease long value"); } // get and add, add and get @@ -929,27 +927,27 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAdd long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAdd long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAdd long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAdd long value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAddAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAddAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAddAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAddAcquire long value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndAddRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAddRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), "getAndAddRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAddRelease long value"); } // get and bitwise or @@ -957,27 +955,27 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOr long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOr long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOr long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOr long value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOrAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOrAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOrAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOrAcquire long value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseOrRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseOrRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), "getAndBitwiseOrRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL | 0xCAFEBABECAFEBABEL), x, "getAndBitwiseOrRelease long value"); } // get and bitwise and @@ -985,27 +983,27 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAnd long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAnd long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAnd long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAnd long value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAndAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAndAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAndAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAndAcquire long value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseAndRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseAndRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), "getAndBitwiseAndRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL & 0xCAFEBABECAFEBABEL), x, "getAndBitwiseAndRelease long value"); } // get and bitwise xor @@ -1013,27 +1011,27 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXor long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXor long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXor long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXor long value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXorAcquire long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXorAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXorAcquire long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXorAcquire long value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, 0x0123456789ABCDEFL); long o = (long) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(o, 0x0123456789ABCDEFL, "getAndBitwiseXorRelease long"); + assertEquals(0x0123456789ABCDEFL, o, "getAndBitwiseXorRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), "getAndBitwiseXorRelease long value"); + assertEquals((long)(0x0123456789ABCDEFL ^ 0xCAFEBABECAFEBABEL), x, "getAndBitwiseXorRelease long value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessShort.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessShort.java index 8fb23d7dc55..d8f548fe2d6 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessShort.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessShort.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,22 @@ * @test * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessShort + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessShort */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { static final short static_final_v = (short)0x0123; @@ -60,7 +60,7 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodHandleAccessShort.class, "final_v", short.class); @@ -77,8 +77,6 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(short[].class); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -111,7 +109,8 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -120,13 +119,12 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { } } - static void testInstanceField(VarHandleTestMethodHandleAccessShort recv, Handles hs) throws Throwable { // Plain { hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x0123, "set short value"); + assertEquals((short)0x0123, x, "set short value"); } @@ -134,21 +132,21 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(recv, (short)0x4567); short x = (short) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(recv); - assertEquals(x, (short)0x4567, "setVolatile short value"); + assertEquals((short)0x4567, x, "setVolatile short value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(recv, (short)0x0123); short x = (short) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(recv); - assertEquals(x, (short)0x0123, "setRelease short value"); + assertEquals((short)0x0123, x, "setRelease short value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(recv, (short)0x4567); short x = (short) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(recv); - assertEquals(x, (short)0x4567, "setOpaque short value"); + assertEquals((short)0x4567, x, "setOpaque short value"); } hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); @@ -158,56 +156,56 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, (short)0x0123, (short)0x4567); assertEquals(r, true, "success compareAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x4567, "success compareAndSet short value"); + assertEquals((short)0x4567, x, "success compareAndSet short value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, (short)0x0123, (short)0x89AB); assertEquals(r, false, "failing compareAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x4567, "failing compareAndSet short value"); + assertEquals((short)0x4567, x, "failing compareAndSet short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, (short)0x4567, (short)0x0123); assertEquals(r, (short)0x4567, "success compareAndExchange short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x0123, "success compareAndExchange short value"); + assertEquals((short)0x0123, x, "success compareAndExchange short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, (short)0x4567, (short)0x89AB); assertEquals(r, (short)0x0123, "failing compareAndExchange short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x0123, "failing compareAndExchange short value"); + assertEquals((short)0x0123, x, "failing compareAndExchange short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, (short)0x0123, (short)0x4567); assertEquals(r, (short)0x0123, "success compareAndExchangeAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x4567, "success compareAndExchangeAcquire short value"); + assertEquals((short)0x4567, x, "success compareAndExchangeAcquire short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, (short)0x0123, (short)0x89AB); assertEquals(r, (short)0x4567, "failing compareAndExchangeAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x4567, "failing compareAndExchangeAcquire short value"); + assertEquals((short)0x4567, x, "failing compareAndExchangeAcquire short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, (short)0x4567, (short)0x0123); assertEquals(r, (short)0x4567, "success compareAndExchangeRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x0123, "success compareAndExchangeRelease short value"); + assertEquals((short)0x0123, x, "success compareAndExchangeRelease short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, (short)0x4567, (short)0x89AB); assertEquals(r, (short)0x0123, "failing compareAndExchangeRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x0123, "failing compareAndExchangeRelease short value"); + assertEquals((short)0x0123, x, "failing compareAndExchangeRelease short value"); } { @@ -219,14 +217,14 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x4567, "success weakCompareAndSetPlain short value"); + assertEquals((short)0x4567, x, "success weakCompareAndSetPlain short value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, (short)0x0123, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetPlain short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x4567, "failing weakCompareAndSetPlain short value"); + assertEquals((short)0x4567, x, "failing weakCompareAndSetPlain short value"); } { @@ -238,14 +236,14 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x0123, "success weakCompareAndSetAcquire short"); + assertEquals((short)0x0123, x, "success weakCompareAndSetAcquire short"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, (short)0x4567, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x0123, "failing weakCompareAndSetAcquire short value"); + assertEquals((short)0x0123, x, "failing weakCompareAndSetAcquire short value"); } { @@ -257,14 +255,14 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x4567, "success weakCompareAndSetRelease short"); + assertEquals((short)0x4567, x, "success weakCompareAndSetRelease short"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, (short)0x0123, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x4567, "failing weakCompareAndSetRelease short value"); + assertEquals((short)0x4567, x, "failing weakCompareAndSetRelease short value"); } { @@ -276,22 +274,22 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x0123, "success weakCompareAndSet short"); + assertEquals((short)0x0123, x, "success weakCompareAndSet short"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, (short)0x4567, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x0123, "failing weakCompareAndSet short value"); + assertEquals((short)0x0123, x, "failing weakCompareAndSet short value"); } // Compare set and get { short o = (short) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndSet short"); + assertEquals((short)0x0123, o, "getAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)0x4567, "getAndSet short value"); + assertEquals((short)0x4567, x, "getAndSet short value"); } // get and add, add and get @@ -299,27 +297,27 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndAdd short"); + assertEquals((short)0x0123, o, "getAndAdd short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAdd short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAdd short value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndAddAcquire short"); + assertEquals((short)0x0123, o, "getAndAddAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAddAcquire short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAddAcquire short value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndAddRelease short"); + assertEquals((short)0x0123, o, "getAndAddRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAddRelease short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAddRelease short value"); } // get and bitwise or @@ -327,27 +325,27 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOr short"); + assertEquals((short)0x0123, o, "getAndBitwiseOr short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOr short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOr short value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOrAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseOrAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOrAcquire short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOrAcquire short value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOrRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseOrRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOrRelease short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOrRelease short value"); } // get and bitwise and @@ -355,27 +353,27 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAnd short"); + assertEquals((short)0x0123, o, "getAndBitwiseAnd short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAnd short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAnd short value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAndAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseAndAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAndAcquire short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAndAcquire short value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAndRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseAndRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAndRelease short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAndRelease short value"); } // get and bitwise xor @@ -383,27 +381,27 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXor short"); + assertEquals((short)0x0123, o, "getAndBitwiseXor short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXor short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXor short value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXorAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseXorAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXorAcquire short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXorAcquire short value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(recv, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXorRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseXorRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXorRelease short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXorRelease short value"); } } @@ -418,7 +416,7 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x0123, "set short value"); + assertEquals((short)0x0123, x, "set short value"); } @@ -426,21 +424,21 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact((short)0x4567); short x = (short) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(); - assertEquals(x, (short)0x4567, "setVolatile short value"); + assertEquals((short)0x4567, x, "setVolatile short value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact((short)0x0123); short x = (short) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(); - assertEquals(x, (short)0x0123, "setRelease short value"); + assertEquals((short)0x0123, x, "setRelease short value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact((short)0x4567); short x = (short) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(); - assertEquals(x, (short)0x4567, "setOpaque short value"); + assertEquals((short)0x4567, x, "setOpaque short value"); } hs.get(TestAccessMode.SET).invokeExact((short)0x0123); @@ -450,56 +448,56 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact((short)0x0123, (short)0x4567); assertEquals(r, true, "success compareAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x4567, "success compareAndSet short value"); + assertEquals((short)0x4567, x, "success compareAndSet short value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact((short)0x0123, (short)0x89AB); assertEquals(r, false, "failing compareAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x4567, "failing compareAndSet short value"); + assertEquals((short)0x4567, x, "failing compareAndSet short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact((short)0x4567, (short)0x0123); assertEquals(r, (short)0x4567, "success compareAndExchange short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x0123, "success compareAndExchange short value"); + assertEquals((short)0x0123, x, "success compareAndExchange short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact((short)0x4567, (short)0x89AB); assertEquals(r, (short)0x0123, "failing compareAndExchange short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x0123, "failing compareAndExchange short value"); + assertEquals((short)0x0123, x, "failing compareAndExchange short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact((short)0x0123, (short)0x4567); assertEquals(r, (short)0x0123, "success compareAndExchangeAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x4567, "success compareAndExchangeAcquire short value"); + assertEquals((short)0x4567, x, "success compareAndExchangeAcquire short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact((short)0x0123, (short)0x89AB); assertEquals(r, (short)0x4567, "failing compareAndExchangeAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x4567, "failing compareAndExchangeAcquire short value"); + assertEquals((short)0x4567, x, "failing compareAndExchangeAcquire short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact((short)0x4567, (short)0x0123); assertEquals(r, (short)0x4567, "success compareAndExchangeRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x0123, "success compareAndExchangeRelease short value"); + assertEquals((short)0x0123, x, "success compareAndExchangeRelease short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact((short)0x4567, (short)0x89AB); assertEquals(r, (short)0x0123, "failing compareAndExchangeRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x0123, "failing compareAndExchangeRelease short value"); + assertEquals((short)0x0123, x, "failing compareAndExchangeRelease short value"); } { @@ -511,14 +509,14 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x4567, "success weakCompareAndSetPlain short value"); + assertEquals((short)0x4567, x, "success weakCompareAndSetPlain short value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact((short)0x0123, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetPlain short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x4567, "failing weakCompareAndSetPlain short value"); + assertEquals((short)0x4567, x, "failing weakCompareAndSetPlain short value"); } { @@ -530,7 +528,7 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x0123, "success weakCompareAndSetAcquire short"); + assertEquals((short)0x0123, x, "success weakCompareAndSetAcquire short"); } { @@ -538,7 +536,7 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { boolean success = (boolean) mh.invokeExact((short)0x4567, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x0123, "failing weakCompareAndSetAcquire short value"); + assertEquals((short)0x0123, x, "failing weakCompareAndSetAcquire short value"); } { @@ -550,14 +548,14 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x4567, "success weakCompareAndSetRelease short"); + assertEquals((short)0x4567, x, "success weakCompareAndSetRelease short"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact((short)0x0123, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x4567, "failing weakCompareAndSetRelease short value"); + assertEquals((short)0x4567, x, "failing weakCompareAndSetRelease short value"); } { @@ -569,14 +567,14 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x0123, "success weakCompareAndSet short"); + assertEquals((short)0x0123, x, "success weakCompareAndSet short"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact((short)0x4567, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x0123, "failing weakCompareAndSetRe short value"); + assertEquals((short)0x0123, x, "failing weakCompareAndSetRe short value"); } // Compare set and get @@ -584,9 +582,9 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_SET).invokeExact((short)0x4567); - assertEquals(o, (short)0x0123, "getAndSet short"); + assertEquals((short)0x0123, o, "getAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x4567, "getAndSet short value"); + assertEquals((short)0x4567, x, "getAndSet short value"); } // Compare set and get @@ -594,9 +592,9 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact((short)0x4567); - assertEquals(o, (short)0x0123, "getAndSetAcquire short"); + assertEquals((short)0x0123, o, "getAndSetAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x4567, "getAndSetAcquire short value"); + assertEquals((short)0x4567, x, "getAndSetAcquire short value"); } // Compare set and get @@ -604,9 +602,9 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact((short)0x4567); - assertEquals(o, (short)0x0123, "getAndSetRelease short"); + assertEquals((short)0x0123, o, "getAndSetRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)0x4567, "getAndSetRelease short value"); + assertEquals((short)0x4567, x, "getAndSetRelease short value"); } // get and add, add and get @@ -614,27 +612,27 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_ADD).invokeExact((short)0x4567); - assertEquals(o, (short)0x0123, "getAndAdd short"); + assertEquals((short)0x0123, o, "getAndAdd short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAdd short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAdd short value"); } { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact((short)0x4567); - assertEquals(o, (short)0x0123, "getAndAddAcquire short"); + assertEquals((short)0x0123, o, "getAndAddAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAddAcquire short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAddAcquire short value"); } { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact((short)0x4567); - assertEquals(o, (short)0x0123, "getAndAddRelease short"); + assertEquals((short)0x0123, o, "getAndAddRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAddRelease short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAddRelease short value"); } // get and bitwise or @@ -642,27 +640,27 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOr short"); + assertEquals((short)0x0123, o, "getAndBitwiseOr short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOr short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOr short value"); } { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOrAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseOrAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOrAcquire short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOrAcquire short value"); } { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOrRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseOrRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOrRelease short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOrRelease short value"); } // get and bitwise and @@ -670,27 +668,27 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAnd short"); + assertEquals((short)0x0123, o, "getAndBitwiseAnd short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAnd short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAnd short value"); } { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAndAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseAndAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAndAcquire short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAndAcquire short value"); } { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAndRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseAndRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAndRelease short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAndRelease short value"); } // get and bitwise xor @@ -698,27 +696,27 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXor short"); + assertEquals((short)0x0123, o, "getAndBitwiseXor short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXor short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXor short value"); } { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXorAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseXorAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXorAcquire short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXorAcquire short value"); } { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact((short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXorRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseXorRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXorRelease short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXorRelease short value"); } } @@ -736,7 +734,7 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x0123, "get short value"); + assertEquals((short)0x0123, x, "get short value"); } @@ -744,21 +742,21 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(array, i, (short)0x4567); short x = (short) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(array, i); - assertEquals(x, (short)0x4567, "setVolatile short value"); + assertEquals((short)0x4567, x, "setVolatile short value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(array, i, (short)0x0123); short x = (short) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(array, i); - assertEquals(x, (short)0x0123, "setRelease short value"); + assertEquals((short)0x0123, x, "setRelease short value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(array, i, (short)0x4567); short x = (short) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(array, i); - assertEquals(x, (short)0x4567, "setOpaque short value"); + assertEquals((short)0x4567, x, "setOpaque short value"); } hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); @@ -768,56 +766,56 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, (short)0x0123, (short)0x4567); assertEquals(r, true, "success compareAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x4567, "success compareAndSet short value"); + assertEquals((short)0x4567, x, "success compareAndSet short value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, (short)0x0123, (short)0x89AB); assertEquals(r, false, "failing compareAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x4567, "failing compareAndSet short value"); + assertEquals((short)0x4567, x, "failing compareAndSet short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, (short)0x4567, (short)0x0123); assertEquals(r, (short)0x4567, "success compareAndExchange short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x0123, "success compareAndExchange short value"); + assertEquals((short)0x0123, x, "success compareAndExchange short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, (short)0x4567, (short)0x89AB); assertEquals(r, (short)0x0123, "failing compareAndExchange short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x0123, "failing compareAndExchange short value"); + assertEquals((short)0x0123, x, "failing compareAndExchange short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, (short)0x0123, (short)0x4567); assertEquals(r, (short)0x0123, "success compareAndExchangeAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x4567, "success compareAndExchangeAcquire short value"); + assertEquals((short)0x4567, x, "success compareAndExchangeAcquire short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, (short)0x0123, (short)0x89AB); assertEquals(r, (short)0x4567, "failing compareAndExchangeAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x4567, "failing compareAndExchangeAcquire short value"); + assertEquals((short)0x4567, x, "failing compareAndExchangeAcquire short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, (short)0x4567, (short)0x0123); assertEquals(r, (short)0x4567, "success compareAndExchangeRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x0123, "success compareAndExchangeRelease short value"); + assertEquals((short)0x0123, x, "success compareAndExchangeRelease short value"); } { short r = (short) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, (short)0x4567, (short)0x89AB); assertEquals(r, (short)0x0123, "failing compareAndExchangeRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x0123, "failing compareAndExchangeRelease short value"); + assertEquals((short)0x0123, x, "failing compareAndExchangeRelease short value"); } { @@ -829,14 +827,14 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x4567, "success weakCompareAndSetPlain short value"); + assertEquals((short)0x4567, x, "success weakCompareAndSetPlain short value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, (short)0x0123, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetPlain short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x4567, "failing weakCompareAndSetPlain short value"); + assertEquals((short)0x4567, x, "failing weakCompareAndSetPlain short value"); } { @@ -848,14 +846,14 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x0123, "success weakCompareAndSetAcquire short"); + assertEquals((short)0x0123, x, "success weakCompareAndSetAcquire short"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, (short)0x4567, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x0123, "failing weakCompareAndSetAcquire short value"); + assertEquals((short)0x0123, x, "failing weakCompareAndSetAcquire short value"); } { @@ -867,14 +865,14 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x4567, "success weakCompareAndSetRelease short"); + assertEquals((short)0x4567, x, "success weakCompareAndSetRelease short"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, (short)0x0123, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x4567, "failing weakCompareAndSetAcquire short value"); + assertEquals((short)0x4567, x, "failing weakCompareAndSetAcquire short value"); } { @@ -886,14 +884,14 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x0123, "success weakCompareAndSet short"); + assertEquals((short)0x0123, x, "success weakCompareAndSet short"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, (short)0x4567, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x0123, "failing weakCompareAndSet short value"); + assertEquals((short)0x0123, x, "failing weakCompareAndSet short value"); } // Compare set and get @@ -901,27 +899,27 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndSet short"); + assertEquals((short)0x0123, o, "getAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x4567, "getAndSet short value"); + assertEquals((short)0x4567, x, "getAndSet short value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndSetAcquire short"); + assertEquals((short)0x0123, o, "getAndSetAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x4567, "getAndSetAcquire short value"); + assertEquals((short)0x4567, x, "getAndSetAcquire short value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndSetRelease short"); + assertEquals((short)0x0123, o, "getAndSetRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)0x4567, "getAndSetRelease short value"); + assertEquals((short)0x4567, x, "getAndSetRelease short value"); } // get and add, add and get @@ -929,27 +927,27 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndAdd short"); + assertEquals((short)0x0123, o, "getAndAdd short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAdd short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAdd short value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndAddAcquire short"); + assertEquals((short)0x0123, o, "getAndAddAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAddAcquire short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAddAcquire short value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndAddRelease short"); + assertEquals((short)0x0123, o, "getAndAddRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)((short)0x0123 + (short)0x4567), "getAndAddRelease short value"); + assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAddRelease short value"); } // get and bitwise or @@ -957,27 +955,27 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOr short"); + assertEquals((short)0x0123, o, "getAndBitwiseOr short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOr short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOr short value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOrAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseOrAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOrAcquire short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOrAcquire short value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseOrRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseOrRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)((short)0x0123 | (short)0x4567), "getAndBitwiseOrRelease short value"); + assertEquals((short)((short)0x0123 | (short)0x4567), x, "getAndBitwiseOrRelease short value"); } // get and bitwise and @@ -985,27 +983,27 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAnd short"); + assertEquals((short)0x0123, o, "getAndBitwiseAnd short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAnd short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAnd short value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAndAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseAndAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAndAcquire short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAndAcquire short value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseAndRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseAndRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)((short)0x0123 & (short)0x4567), "getAndBitwiseAndRelease short value"); + assertEquals((short)((short)0x0123 & (short)0x4567), x, "getAndBitwiseAndRelease short value"); } // get and bitwise xor @@ -1013,27 +1011,27 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXor short"); + assertEquals((short)0x0123, o, "getAndBitwiseXor short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXor short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXor short value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXorAcquire short"); + assertEquals((short)0x0123, o, "getAndBitwiseXorAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXorAcquire short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXorAcquire short value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, (short)0x0123); short o = (short) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(array, i, (short)0x4567); - assertEquals(o, (short)0x0123, "getAndBitwiseXorRelease short"); + assertEquals((short)0x0123, o, "getAndBitwiseXorRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, (short)((short)0x0123 ^ (short)0x4567), "getAndBitwiseXorRelease short value"); + assertEquals((short)((short)0x0123 ^ (short)0x4567), x, "getAndBitwiseXorRelease short value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java index 8ccede760c9..35723f63d27 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,22 @@ * @test * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessString + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessString */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { static final String static_final_v = "foo"; @@ -60,7 +60,7 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodHandleAccessString.class, "final_v", String.class); @@ -77,8 +77,6 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(String[].class); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -111,7 +109,8 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -120,13 +119,12 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { } } - static void testInstanceField(VarHandleTestMethodHandleAccessString recv, Handles hs) throws Throwable { // Plain { hs.get(TestAccessMode.SET).invokeExact(recv, "foo"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "foo", "set String value"); + assertEquals("foo", x, "set String value"); } @@ -134,21 +132,21 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(recv, "bar"); String x = (String) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(recv); - assertEquals(x, "bar", "setVolatile String value"); + assertEquals("bar", x, "setVolatile String value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(recv, "foo"); String x = (String) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(recv); - assertEquals(x, "foo", "setRelease String value"); + assertEquals("foo", x, "setRelease String value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(recv, "bar"); String x = (String) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(recv); - assertEquals(x, "bar", "setOpaque String value"); + assertEquals("bar", x, "setOpaque String value"); } hs.get(TestAccessMode.SET).invokeExact(recv, "foo"); @@ -158,56 +156,56 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, "foo", "bar"); assertEquals(r, true, "success compareAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "bar", "success compareAndSet String value"); + assertEquals("bar", x, "success compareAndSet String value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, "foo", "baz"); assertEquals(r, false, "failing compareAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "bar", "failing compareAndSet String value"); + assertEquals("bar", x, "failing compareAndSet String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, "bar", "foo"); assertEquals(r, "bar", "success compareAndExchange String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "foo", "success compareAndExchange String value"); + assertEquals("foo", x, "success compareAndExchange String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, "bar", "baz"); assertEquals(r, "foo", "failing compareAndExchange String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "foo", "failing compareAndExchange String value"); + assertEquals("foo", x, "failing compareAndExchange String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, "foo", "bar"); assertEquals(r, "foo", "success compareAndExchangeAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "bar", "success compareAndExchangeAcquire String value"); + assertEquals("bar", x, "success compareAndExchangeAcquire String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, "foo", "baz"); assertEquals(r, "bar", "failing compareAndExchangeAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "bar", "failing compareAndExchangeAcquire String value"); + assertEquals("bar", x, "failing compareAndExchangeAcquire String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, "bar", "foo"); assertEquals(r, "bar", "success compareAndExchangeRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "foo", "success compareAndExchangeRelease String value"); + assertEquals("foo", x, "success compareAndExchangeRelease String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, "bar", "baz"); assertEquals(r, "foo", "failing compareAndExchangeRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "foo", "failing compareAndExchangeRelease String value"); + assertEquals("foo", x, "failing compareAndExchangeRelease String value"); } { @@ -219,14 +217,14 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "bar", "success weakCompareAndSetPlain String value"); + assertEquals("bar", x, "success weakCompareAndSetPlain String value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, "foo", "baz"); assertEquals(success, false, "failing weakCompareAndSetPlain String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "bar", "failing weakCompareAndSetPlain String value"); + assertEquals("bar", x, "failing weakCompareAndSetPlain String value"); } { @@ -238,14 +236,14 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "foo", "success weakCompareAndSetAcquire String"); + assertEquals("foo", x, "success weakCompareAndSetAcquire String"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, "bar", "baz"); assertEquals(success, false, "failing weakCompareAndSetAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "foo", "failing weakCompareAndSetAcquire String value"); + assertEquals("foo", x, "failing weakCompareAndSetAcquire String value"); } { @@ -257,14 +255,14 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "bar", "success weakCompareAndSetRelease String"); + assertEquals("bar", x, "success weakCompareAndSetRelease String"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, "foo", "baz"); assertEquals(success, false, "failing weakCompareAndSetRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "bar", "failing weakCompareAndSetRelease String value"); + assertEquals("bar", x, "failing weakCompareAndSetRelease String value"); } { @@ -276,22 +274,22 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "foo", "success weakCompareAndSet String"); + assertEquals("foo", x, "success weakCompareAndSet String"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, "bar", "baz"); assertEquals(success, false, "failing weakCompareAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "foo", "failing weakCompareAndSet String value"); + assertEquals("foo", x, "failing weakCompareAndSet String value"); } // Compare set and get { String o = (String) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, "bar"); - assertEquals(o, "foo", "getAndSet String"); + assertEquals("foo", o, "getAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, "bar", "getAndSet String value"); + assertEquals("bar", x, "getAndSet String value"); } @@ -318,7 +316,7 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact("foo"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "foo", "set String value"); + assertEquals("foo", x, "set String value"); } @@ -326,21 +324,21 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact("bar"); String x = (String) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(); - assertEquals(x, "bar", "setVolatile String value"); + assertEquals("bar", x, "setVolatile String value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact("foo"); String x = (String) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(); - assertEquals(x, "foo", "setRelease String value"); + assertEquals("foo", x, "setRelease String value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact("bar"); String x = (String) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(); - assertEquals(x, "bar", "setOpaque String value"); + assertEquals("bar", x, "setOpaque String value"); } hs.get(TestAccessMode.SET).invokeExact("foo"); @@ -350,56 +348,56 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact("foo", "bar"); assertEquals(r, true, "success compareAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "bar", "success compareAndSet String value"); + assertEquals("bar", x, "success compareAndSet String value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact("foo", "baz"); assertEquals(r, false, "failing compareAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "bar", "failing compareAndSet String value"); + assertEquals("bar", x, "failing compareAndSet String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact("bar", "foo"); assertEquals(r, "bar", "success compareAndExchange String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "foo", "success compareAndExchange String value"); + assertEquals("foo", x, "success compareAndExchange String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact("bar", "baz"); assertEquals(r, "foo", "failing compareAndExchange String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "foo", "failing compareAndExchange String value"); + assertEquals("foo", x, "failing compareAndExchange String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact("foo", "bar"); assertEquals(r, "foo", "success compareAndExchangeAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "bar", "success compareAndExchangeAcquire String value"); + assertEquals("bar", x, "success compareAndExchangeAcquire String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact("foo", "baz"); assertEquals(r, "bar", "failing compareAndExchangeAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "bar", "failing compareAndExchangeAcquire String value"); + assertEquals("bar", x, "failing compareAndExchangeAcquire String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact("bar", "foo"); assertEquals(r, "bar", "success compareAndExchangeRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "foo", "success compareAndExchangeRelease String value"); + assertEquals("foo", x, "success compareAndExchangeRelease String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact("bar", "baz"); assertEquals(r, "foo", "failing compareAndExchangeRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "foo", "failing compareAndExchangeRelease String value"); + assertEquals("foo", x, "failing compareAndExchangeRelease String value"); } { @@ -411,14 +409,14 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "bar", "success weakCompareAndSetPlain String value"); + assertEquals("bar", x, "success weakCompareAndSetPlain String value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact("foo", "baz"); assertEquals(success, false, "failing weakCompareAndSetPlain String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "bar", "failing weakCompareAndSetPlain String value"); + assertEquals("bar", x, "failing weakCompareAndSetPlain String value"); } { @@ -430,7 +428,7 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "foo", "success weakCompareAndSetAcquire String"); + assertEquals("foo", x, "success weakCompareAndSetAcquire String"); } { @@ -438,7 +436,7 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { boolean success = (boolean) mh.invokeExact("bar", "baz"); assertEquals(success, false, "failing weakCompareAndSetAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "foo", "failing weakCompareAndSetAcquire String value"); + assertEquals("foo", x, "failing weakCompareAndSetAcquire String value"); } { @@ -450,14 +448,14 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "bar", "success weakCompareAndSetRelease String"); + assertEquals("bar", x, "success weakCompareAndSetRelease String"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact("foo", "baz"); assertEquals(success, false, "failing weakCompareAndSetRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "bar", "failing weakCompareAndSetRelease String value"); + assertEquals("bar", x, "failing weakCompareAndSetRelease String value"); } { @@ -469,14 +467,14 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "foo", "success weakCompareAndSet String"); + assertEquals("foo", x, "success weakCompareAndSet String"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact("bar", "baz"); assertEquals(success, false, "failing weakCompareAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "foo", "failing weakCompareAndSetRe String value"); + assertEquals("foo", x, "failing weakCompareAndSetRe String value"); } // Compare set and get @@ -484,9 +482,9 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact("foo"); String o = (String) hs.get(TestAccessMode.GET_AND_SET).invokeExact("bar"); - assertEquals(o, "foo", "getAndSet String"); + assertEquals("foo", o, "getAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "bar", "getAndSet String value"); + assertEquals("bar", x, "getAndSet String value"); } // Compare set and get @@ -494,9 +492,9 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact("foo"); String o = (String) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact("bar"); - assertEquals(o, "foo", "getAndSetAcquire String"); + assertEquals("foo", o, "getAndSetAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "bar", "getAndSetAcquire String value"); + assertEquals("bar", x, "getAndSetAcquire String value"); } // Compare set and get @@ -504,9 +502,9 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact("foo"); String o = (String) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact("bar"); - assertEquals(o, "foo", "getAndSetRelease String"); + assertEquals("foo", o, "getAndSetRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, "bar", "getAndSetRelease String value"); + assertEquals("bar", x, "getAndSetRelease String value"); } @@ -536,7 +534,7 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact(array, i, "foo"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "foo", "get String value"); + assertEquals("foo", x, "get String value"); } @@ -544,21 +542,21 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(array, i, "bar"); String x = (String) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(array, i); - assertEquals(x, "bar", "setVolatile String value"); + assertEquals("bar", x, "setVolatile String value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(array, i, "foo"); String x = (String) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(array, i); - assertEquals(x, "foo", "setRelease String value"); + assertEquals("foo", x, "setRelease String value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(array, i, "bar"); String x = (String) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(array, i); - assertEquals(x, "bar", "setOpaque String value"); + assertEquals("bar", x, "setOpaque String value"); } hs.get(TestAccessMode.SET).invokeExact(array, i, "foo"); @@ -568,56 +566,56 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, "foo", "bar"); assertEquals(r, true, "success compareAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "bar", "success compareAndSet String value"); + assertEquals("bar", x, "success compareAndSet String value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, "foo", "baz"); assertEquals(r, false, "failing compareAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "bar", "failing compareAndSet String value"); + assertEquals("bar", x, "failing compareAndSet String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, "bar", "foo"); assertEquals(r, "bar", "success compareAndExchange String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "foo", "success compareAndExchange String value"); + assertEquals("foo", x, "success compareAndExchange String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, "bar", "baz"); assertEquals(r, "foo", "failing compareAndExchange String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "foo", "failing compareAndExchange String value"); + assertEquals("foo", x, "failing compareAndExchange String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, "foo", "bar"); assertEquals(r, "foo", "success compareAndExchangeAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "bar", "success compareAndExchangeAcquire String value"); + assertEquals("bar", x, "success compareAndExchangeAcquire String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, "foo", "baz"); assertEquals(r, "bar", "failing compareAndExchangeAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "bar", "failing compareAndExchangeAcquire String value"); + assertEquals("bar", x, "failing compareAndExchangeAcquire String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, "bar", "foo"); assertEquals(r, "bar", "success compareAndExchangeRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "foo", "success compareAndExchangeRelease String value"); + assertEquals("foo", x, "success compareAndExchangeRelease String value"); } { String r = (String) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, "bar", "baz"); assertEquals(r, "foo", "failing compareAndExchangeRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "foo", "failing compareAndExchangeRelease String value"); + assertEquals("foo", x, "failing compareAndExchangeRelease String value"); } { @@ -629,14 +627,14 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "bar", "success weakCompareAndSetPlain String value"); + assertEquals("bar", x, "success weakCompareAndSetPlain String value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, "foo", "baz"); assertEquals(success, false, "failing weakCompareAndSetPlain String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "bar", "failing weakCompareAndSetPlain String value"); + assertEquals("bar", x, "failing weakCompareAndSetPlain String value"); } { @@ -648,14 +646,14 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "foo", "success weakCompareAndSetAcquire String"); + assertEquals("foo", x, "success weakCompareAndSetAcquire String"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, "bar", "baz"); assertEquals(success, false, "failing weakCompareAndSetAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "foo", "failing weakCompareAndSetAcquire String value"); + assertEquals("foo", x, "failing weakCompareAndSetAcquire String value"); } { @@ -667,14 +665,14 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "bar", "success weakCompareAndSetRelease String"); + assertEquals("bar", x, "success weakCompareAndSetRelease String"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, "foo", "baz"); assertEquals(success, false, "failing weakCompareAndSetAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "bar", "failing weakCompareAndSetAcquire String value"); + assertEquals("bar", x, "failing weakCompareAndSetAcquire String value"); } { @@ -686,14 +684,14 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "foo", "success weakCompareAndSet String"); + assertEquals("foo", x, "success weakCompareAndSet String"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, "bar", "baz"); assertEquals(success, false, "failing weakCompareAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "foo", "failing weakCompareAndSet String value"); + assertEquals("foo", x, "failing weakCompareAndSet String value"); } // Compare set and get @@ -701,27 +699,27 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, "foo"); String o = (String) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, "bar"); - assertEquals(o, "foo", "getAndSet String"); + assertEquals("foo", o, "getAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "bar", "getAndSet String value"); + assertEquals("bar", x, "getAndSet String value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, "foo"); String o = (String) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(array, i, "bar"); - assertEquals(o, "foo", "getAndSetAcquire String"); + assertEquals("foo", o, "getAndSetAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "bar", "getAndSetAcquire String value"); + assertEquals("bar", x, "getAndSetAcquire String value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, "foo"); String o = (String) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(array, i, "bar"); - assertEquals(o, "foo", "getAndSetRelease String"); + assertEquals("foo", o, "getAndSetRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, "bar", "getAndSetRelease String value"); + assertEquals("bar", x, "getAndSetRelease String value"); } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeBoolean.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeBoolean.java index eb6327d4c55..b10466a1fc7 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeBoolean.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeBoolean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,26 +24,26 @@ /* * @test * @bug 8156486 - * @run testng/othervm VarHandleTestMethodTypeBoolean - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeBoolean - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeBoolean - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeBoolean + * @run junit/othervm VarHandleTestMethodTypeBoolean + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeBoolean + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeBoolean + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeBoolean */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; - import static java.lang.invoke.MethodType.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodTypeBoolean extends VarHandleBaseTest { static final boolean static_final_v = true; @@ -63,7 +63,7 @@ public class VarHandleTestMethodTypeBoolean extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodTypeBoolean.class, "final_v", boolean.class); @@ -80,7 +80,6 @@ public class VarHandleTestMethodTypeBoolean extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(boolean[].class); } - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -115,7 +114,8 @@ public class VarHandleTestMethodTypeBoolean extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -124,7 +124,6 @@ public class VarHandleTestMethodTypeBoolean extends VarHandleBaseTest { } } - static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv, VarHandle vh) throws Throwable { // Get // Incorrect argument types diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeByte.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeByte.java index 08b834699af..ce8686ebd74 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeByte.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeByte.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,26 +24,26 @@ /* * @test * @bug 8156486 - * @run testng/othervm VarHandleTestMethodTypeByte - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeByte - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeByte - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeByte + * @run junit/othervm VarHandleTestMethodTypeByte + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeByte + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeByte + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeByte */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; - import static java.lang.invoke.MethodType.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodTypeByte extends VarHandleBaseTest { static final byte static_final_v = (byte)0x01; @@ -63,7 +63,7 @@ public class VarHandleTestMethodTypeByte extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodTypeByte.class, "final_v", byte.class); @@ -80,7 +80,6 @@ public class VarHandleTestMethodTypeByte extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(byte[].class); } - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -115,7 +114,8 @@ public class VarHandleTestMethodTypeByte extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -124,7 +124,6 @@ public class VarHandleTestMethodTypeByte extends VarHandleBaseTest { } } - static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, VarHandle vh) throws Throwable { // Get // Incorrect argument types diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeChar.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeChar.java index 25aa62825b7..d89af7f212c 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeChar.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeChar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,26 +24,26 @@ /* * @test * @bug 8156486 - * @run testng/othervm VarHandleTestMethodTypeChar - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeChar - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeChar - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeChar + * @run junit/othervm VarHandleTestMethodTypeChar + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeChar + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeChar + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeChar */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; - import static java.lang.invoke.MethodType.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodTypeChar extends VarHandleBaseTest { static final char static_final_v = '\u0123'; @@ -63,7 +63,7 @@ public class VarHandleTestMethodTypeChar extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodTypeChar.class, "final_v", char.class); @@ -80,7 +80,6 @@ public class VarHandleTestMethodTypeChar extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(char[].class); } - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -115,7 +114,8 @@ public class VarHandleTestMethodTypeChar extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -124,7 +124,6 @@ public class VarHandleTestMethodTypeChar extends VarHandleBaseTest { } } - static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, VarHandle vh) throws Throwable { // Get // Incorrect argument types diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeDouble.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeDouble.java index c3f8d22435b..0363a996ceb 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeDouble.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeDouble.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,26 +24,26 @@ /* * @test * @bug 8156486 - * @run testng/othervm VarHandleTestMethodTypeDouble - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeDouble - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeDouble - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeDouble + * @run junit/othervm VarHandleTestMethodTypeDouble + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeDouble + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeDouble + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeDouble */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; - import static java.lang.invoke.MethodType.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodTypeDouble extends VarHandleBaseTest { static final double static_final_v = 1.0d; @@ -63,7 +63,7 @@ public class VarHandleTestMethodTypeDouble extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodTypeDouble.class, "final_v", double.class); @@ -80,7 +80,6 @@ public class VarHandleTestMethodTypeDouble extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(double[].class); } - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -115,7 +114,8 @@ public class VarHandleTestMethodTypeDouble extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -124,7 +124,6 @@ public class VarHandleTestMethodTypeDouble extends VarHandleBaseTest { } } - static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeDouble recv, VarHandle vh) throws Throwable { // Get // Incorrect argument types diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeFloat.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeFloat.java index 0d05270b3ac..c8b965e41df 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeFloat.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeFloat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,26 +24,26 @@ /* * @test * @bug 8156486 - * @run testng/othervm VarHandleTestMethodTypeFloat - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeFloat - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeFloat - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeFloat + * @run junit/othervm VarHandleTestMethodTypeFloat + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeFloat + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeFloat + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeFloat */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; - import static java.lang.invoke.MethodType.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodTypeFloat extends VarHandleBaseTest { static final float static_final_v = 1.0f; @@ -63,7 +63,7 @@ public class VarHandleTestMethodTypeFloat extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodTypeFloat.class, "final_v", float.class); @@ -80,7 +80,6 @@ public class VarHandleTestMethodTypeFloat extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(float[].class); } - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -115,7 +114,8 @@ public class VarHandleTestMethodTypeFloat extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -124,7 +124,6 @@ public class VarHandleTestMethodTypeFloat extends VarHandleBaseTest { } } - static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeFloat recv, VarHandle vh) throws Throwable { // Get // Incorrect argument types diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java index a431c0a889e..e09427c55c7 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,26 +24,26 @@ /* * @test * @bug 8156486 - * @run testng/othervm VarHandleTestMethodTypeInt - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeInt - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeInt - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeInt + * @run junit/othervm VarHandleTestMethodTypeInt + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeInt + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeInt + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeInt */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; - import static java.lang.invoke.MethodType.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodTypeInt extends VarHandleBaseTest { static final int static_final_v = 0x01234567; @@ -63,7 +63,7 @@ public class VarHandleTestMethodTypeInt extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodTypeInt.class, "final_v", int.class); @@ -80,7 +80,6 @@ public class VarHandleTestMethodTypeInt extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(int[].class); } - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -115,7 +114,8 @@ public class VarHandleTestMethodTypeInt extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -124,7 +124,6 @@ public class VarHandleTestMethodTypeInt extends VarHandleBaseTest { } } - static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, VarHandle vh) throws Throwable { // Get // Incorrect argument types diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java index 53b9257d700..5944e935877 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,26 +24,26 @@ /* * @test * @bug 8156486 - * @run testng/othervm VarHandleTestMethodTypeLong - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeLong - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeLong - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeLong + * @run junit/othervm VarHandleTestMethodTypeLong + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeLong + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeLong + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeLong */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; - import static java.lang.invoke.MethodType.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodTypeLong extends VarHandleBaseTest { static final long static_final_v = 0x0123456789ABCDEFL; @@ -63,7 +63,7 @@ public class VarHandleTestMethodTypeLong extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodTypeLong.class, "final_v", long.class); @@ -80,7 +80,6 @@ public class VarHandleTestMethodTypeLong extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(long[].class); } - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -115,7 +114,8 @@ public class VarHandleTestMethodTypeLong extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -124,7 +124,6 @@ public class VarHandleTestMethodTypeLong extends VarHandleBaseTest { } } - static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, VarHandle vh) throws Throwable { // Get // Incorrect argument types diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeShort.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeShort.java index 10dd5832c9b..fdb30ee88aa 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeShort.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeShort.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,26 +24,26 @@ /* * @test * @bug 8156486 - * @run testng/othervm VarHandleTestMethodTypeShort - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeShort - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeShort - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeShort + * @run junit/othervm VarHandleTestMethodTypeShort + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeShort + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeShort + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeShort */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; - import static java.lang.invoke.MethodType.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodTypeShort extends VarHandleBaseTest { static final short static_final_v = (short)0x0123; @@ -63,7 +63,7 @@ public class VarHandleTestMethodTypeShort extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodTypeShort.class, "final_v", short.class); @@ -80,7 +80,6 @@ public class VarHandleTestMethodTypeShort extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(short[].class); } - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -115,7 +114,8 @@ public class VarHandleTestMethodTypeShort extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -124,7 +124,6 @@ public class VarHandleTestMethodTypeShort extends VarHandleBaseTest { } } - static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, VarHandle vh) throws Throwable { // Get // Incorrect argument types diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java index d823a21d69f..2a5284ca36e 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,26 +24,26 @@ /* * @test * @bug 8156486 - * @run testng/othervm VarHandleTestMethodTypeString - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeString - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeString - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeString + * @run junit/othervm VarHandleTestMethodTypeString + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeString + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeString + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeString */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; - import static java.lang.invoke.MethodType.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodTypeString extends VarHandleBaseTest { static final String static_final_v = "foo"; @@ -63,7 +63,7 @@ public class VarHandleTestMethodTypeString extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodTypeString.class, "final_v", String.class); @@ -80,7 +80,6 @@ public class VarHandleTestMethodTypeString extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle(String[].class); } - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -115,7 +114,8 @@ public class VarHandleTestMethodTypeString extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -124,7 +124,6 @@ public class VarHandleTestMethodTypeString extends VarHandleBaseTest { } } - static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeString recv, VarHandle vh) throws Throwable { // Get // Incorrect argument types diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java index b20e18d263e..2c22fd5595b 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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,11 +23,9 @@ /* * @test - * @run testng VarHandleTestReflection + * @run junit VarHandleTestReflection */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandleInfo; @@ -36,11 +34,16 @@ import java.lang.invoke.VarHandle; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.stream.Stream; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestReflection extends VarHandleBaseTest { String string; - @DataProvider public static Object[][] accessModesProvider() { return Stream.of(VarHandle.AccessMode.values()). map(am -> new Object[]{am}). @@ -52,17 +55,19 @@ public class VarHandleTestReflection extends VarHandleBaseTest { findVarHandle(VarHandleTestReflection.class, "string", String.class); } - @Test(dataProvider = "accessModesProvider", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("accessModesProvider") public void methodInvocationArgumentMismatch(VarHandle.AccessMode accessMode) throws Exception { VarHandle v = handle(); // Try a reflective invoke using a Method, with no arguments Method vhm = VarHandle.class.getMethod(accessMode.methodName(), Object[].class); - vhm.invoke(v, new Object[]{}); + assertThrows(IllegalArgumentException.class, () -> vhm.invoke(v, new Object[]{})); } - @Test(dataProvider = "accessModesProvider") + @ParameterizedTest + @MethodSource("accessModesProvider") public void methodInvocationMatchingArguments(VarHandle.AccessMode accessMode) throws Exception { VarHandle v = handle(); @@ -70,17 +75,15 @@ public class VarHandleTestReflection extends VarHandleBaseTest { Method vhm = VarHandle.class.getMethod(accessMode.methodName(), Object[].class); Object arg = new Object[0]; - try { - vhm.invoke(v, arg); - } catch (InvocationTargetException e) { - if (!(e.getCause() instanceof UnsupportedOperationException)) { - throw new RuntimeException("expected UnsupportedOperationException but got: " - + e.getCause().getClass().getName(), e); - } + var e = assertThrows(InvocationTargetException.class, () -> vhm.invoke(v, arg)); + if (!(e.getCause() instanceof UnsupportedOperationException)) { + throw new RuntimeException("expected UnsupportedOperationException but got: " + + e.getCause().getClass().getName(), e); } } - @Test(dataProvider = "accessModesProvider", expectedExceptions = UnsupportedOperationException.class) + @ParameterizedTest + @MethodSource("accessModesProvider") public void methodHandleInvoke(VarHandle.AccessMode accessMode) throws Throwable { VarHandle v = handle(); @@ -90,10 +93,13 @@ public class VarHandleTestReflection extends VarHandleBaseTest { VarHandle.class.getMethod(accessMode.methodName(), Object[].class)); // Use invoke to avoid WrongMethodTypeException for // non-signature-polymorphic return types - Object o = (Object) mh.invoke(v, new Object[]{}); + assertThrows(UnsupportedOperationException.class, () -> { + Object o = (Object) mh.invoke(v, new Object[]{}); + }); } - @Test(dataProvider = "accessModesProvider", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("accessModesProvider") public void methodInvocationFromMethodInfo(VarHandle.AccessMode accessMode) throws Exception { VarHandle v = handle(); @@ -104,10 +110,13 @@ public class VarHandleTestReflection extends VarHandleBaseTest { VarHandle.class.getMethod(accessMode.methodName(), Object[].class)); MethodHandleInfo info = MethodHandles.lookup().revealDirect(mh); Method im = info.reflectAs(Method.class, MethodHandles.lookup()); - im.invoke(v, new Object[]{}); + assertThrows(IllegalArgumentException.class, () -> { + im.invoke(v, new Object[]{}); + }); } - @Test(dataProvider = "accessModesProvider", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("accessModesProvider") public void reflectAsFromVarHandleInvoker(VarHandle.AccessMode accessMode) throws Exception { VarHandle v = handle(); @@ -116,10 +125,11 @@ public class VarHandleTestReflection extends VarHandleBaseTest { MethodHandleInfo info = MethodHandles.lookup().revealDirect(mh); - info.reflectAs(Method.class, MethodHandles.lookup()); + assertThrows(IllegalArgumentException.class, () -> info.reflectAs(Method.class, MethodHandles.lookup())); } - @Test(dataProvider = "accessModesProvider", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("accessModesProvider") public void reflectAsFromFindVirtual(VarHandle.AccessMode accessMode) throws Exception { VarHandle v = handle(); @@ -128,6 +138,6 @@ public class VarHandleTestReflection extends VarHandleBaseTest { MethodHandleInfo info = MethodHandles.lookup().revealDirect(mh); - info.reflectAs(Method.class, MethodHandles.lookup()); + assertThrows(IllegalArgumentException.class, () -> info.reflectAs(Method.class, MethodHandles.lookup())); } } diff --git a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template index f3c90c5e8cc..b18dbb6e1b0 100644 --- a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template +++ b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,28 +23,30 @@ /* * @test - * @run testng/othervm -Diters=10 -Xint VarHandleTestAccess$Type$ + * @run junit/othervm -Diters=10 -Xint VarHandleTestAccess$Type$ * * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds * - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccess$Type$ - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccess$Type$ - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccess$Type$ + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccess$Type$ + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccess$Type$ + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccess$Type$ */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { static final $type$ static_final_v = $value1$; @@ -115,7 +117,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { return vhs.toArray(new VarHandle[0]); } - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestAccess$Type$.class, "final_v", $type$.class); @@ -135,8 +137,6 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { #end[String] } - - @DataProvider public Object[][] varHandlesProvider() throws Exception { List vhs = new ArrayList<>(); vhs.add(vhField); @@ -166,7 +166,8 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("varHandlesProvider") public void testIsAccessModeSupported(VarHandle vh) { assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET)); assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET)); @@ -236,8 +237,6 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { #end[Bitwise] } - - @DataProvider public Object[][] typesProvider() throws Exception { List types = new ArrayList<>(); types.add(new Object[] {vhField, Arrays.asList(VarHandleTestAccess$Type$.class)}); @@ -247,16 +246,16 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { return types.stream().toArray(Object[][]::new); } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), $type$.class); + assertEquals($type$.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - @Test public void testLookupInstanceToStatic() { checkIAE("Lookup of static final field to instance final field", () -> { @@ -283,8 +282,6 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { }); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -335,7 +332,8 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -348,26 +346,26 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { // Plain { $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value1$, "get $type$ value"); + assertEquals($value1$, x, "get $type$ value"); } // Volatile { $type$ x = ($type$) vh.getVolatile(recv); - assertEquals(x, $value1$, "getVolatile $type$ value"); + assertEquals($value1$, x, "getVolatile $type$ value"); } // Lazy { $type$ x = ($type$) vh.getAcquire(recv); - assertEquals(x, $value1$, "getRelease $type$ value"); + assertEquals($value1$, x, "getRelease $type$ value"); } // Opaque { $type$ x = ($type$) vh.getOpaque(recv); - assertEquals(x, $value1$, "getOpaque $type$ value"); + assertEquals($value1$, x, "getOpaque $type$ value"); } } @@ -492,26 +490,26 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { // Plain { $type$ x = ($type$) vh.get(); - assertEquals(x, $value1$, "get $type$ value"); + assertEquals($value1$, x, "get $type$ value"); } // Volatile { $type$ x = ($type$) vh.getVolatile(); - assertEquals(x, $value1$, "getVolatile $type$ value"); + assertEquals($value1$, x, "getVolatile $type$ value"); } // Lazy { $type$ x = ($type$) vh.getAcquire(); - assertEquals(x, $value1$, "getRelease $type$ value"); + assertEquals($value1$, x, "getRelease $type$ value"); } // Opaque { $type$ x = ($type$) vh.getOpaque(); - assertEquals(x, $value1$, "getOpaque $type$ value"); + assertEquals($value1$, x, "getOpaque $type$ value"); } } @@ -637,7 +635,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { { vh.set(recv, $value1$); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value1$, "set $type$ value"); + assertEquals($value1$, x, "set $type$ value"); } @@ -645,21 +643,21 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { { vh.setVolatile(recv, $value2$); $type$ x = ($type$) vh.getVolatile(recv); - assertEquals(x, $value2$, "setVolatile $type$ value"); + assertEquals($value2$, x, "setVolatile $type$ value"); } // Lazy { vh.setRelease(recv, $value1$); $type$ x = ($type$) vh.getAcquire(recv); - assertEquals(x, $value1$, "setRelease $type$ value"); + assertEquals($value1$, x, "setRelease $type$ value"); } // Opaque { vh.setOpaque(recv, $value2$); $type$ x = ($type$) vh.getOpaque(recv); - assertEquals(x, $value2$, "setOpaque $type$ value"); + assertEquals($value2$, x, "setOpaque $type$ value"); } #if[CAS] @@ -670,56 +668,56 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean r = vh.compareAndSet(recv, $value1$, $value2$); assertEquals(r, true, "success compareAndSet $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value2$, "success compareAndSet $type$ value"); + assertEquals($value2$, x, "success compareAndSet $type$ value"); } { boolean r = vh.compareAndSet(recv, $value1$, $value3$); assertEquals(r, false, "failing compareAndSet $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value2$, "failing compareAndSet $type$ value"); + assertEquals($value2$, x, "failing compareAndSet $type$ value"); } { $type$ r = ($type$) vh.compareAndExchange(recv, $value2$, $value1$); assertEquals(r, $value2$, "success compareAndExchange $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value1$, "success compareAndExchange $type$ value"); + assertEquals($value1$, x, "success compareAndExchange $type$ value"); } { $type$ r = ($type$) vh.compareAndExchange(recv, $value2$, $value3$); assertEquals(r, $value1$, "failing compareAndExchange $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value1$, "failing compareAndExchange $type$ value"); + assertEquals($value1$, x, "failing compareAndExchange $type$ value"); } { $type$ r = ($type$) vh.compareAndExchangeAcquire(recv, $value1$, $value2$); assertEquals(r, $value1$, "success compareAndExchangeAcquire $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value2$, "success compareAndExchangeAcquire $type$ value"); + assertEquals($value2$, x, "success compareAndExchangeAcquire $type$ value"); } { $type$ r = ($type$) vh.compareAndExchangeAcquire(recv, $value1$, $value3$); assertEquals(r, $value2$, "failing compareAndExchangeAcquire $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value2$, "failing compareAndExchangeAcquire $type$ value"); + assertEquals($value2$, x, "failing compareAndExchangeAcquire $type$ value"); } { $type$ r = ($type$) vh.compareAndExchangeRelease(recv, $value2$, $value1$); assertEquals(r, $value2$, "success compareAndExchangeRelease $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value1$, "success compareAndExchangeRelease $type$ value"); + assertEquals($value1$, x, "success compareAndExchangeRelease $type$ value"); } { $type$ r = ($type$) vh.compareAndExchangeRelease(recv, $value2$, $value3$); assertEquals(r, $value1$, "failing compareAndExchangeRelease $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value1$, "failing compareAndExchangeRelease $type$ value"); + assertEquals($value1$, x, "failing compareAndExchangeRelease $type$ value"); } { @@ -730,14 +728,14 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value2$, "success weakCompareAndSetPlain $type$ value"); + assertEquals($value2$, x, "success weakCompareAndSetPlain $type$ value"); } { boolean success = vh.weakCompareAndSetPlain(recv, $value1$, $value3$); assertEquals(success, false, "failing weakCompareAndSetPlain $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value2$, "failing weakCompareAndSetPlain $type$ value"); + assertEquals($value2$, x, "failing weakCompareAndSetPlain $type$ value"); } { @@ -748,14 +746,14 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value1$, "success weakCompareAndSetAcquire $type$"); + assertEquals($value1$, x, "success weakCompareAndSetAcquire $type$"); } { boolean success = vh.weakCompareAndSetAcquire(recv, $value2$, $value3$); assertEquals(success, false, "failing weakCompareAndSetAcquire $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value1$, "failing weakCompareAndSetAcquire $type$ value"); + assertEquals($value1$, x, "failing weakCompareAndSetAcquire $type$ value"); } { @@ -766,14 +764,14 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value2$, "success weakCompareAndSetRelease $type$"); + assertEquals($value2$, x, "success weakCompareAndSetRelease $type$"); } { boolean success = vh.weakCompareAndSetRelease(recv, $value1$, $value3$); assertEquals(success, false, "failing weakCompareAndSetRelease $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value2$, "failing weakCompareAndSetRelease $type$ value"); + assertEquals($value2$, x, "failing weakCompareAndSetRelease $type$ value"); } { @@ -784,14 +782,14 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value1$, "success weakCompareAndSet $type$ value"); + assertEquals($value1$, x, "success weakCompareAndSet $type$ value"); } { boolean success = vh.weakCompareAndSet(recv, $value2$, $value3$); assertEquals(success, false, "failing weakCompareAndSet $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value1$, "failing weakCompareAndSet $type$ value"); + assertEquals($value1$, x, "failing weakCompareAndSet $type$ value"); } // Compare set and get @@ -799,27 +797,27 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set(recv, $value1$); $type$ o = ($type$) vh.getAndSet(recv, $value2$); - assertEquals(o, $value1$, "getAndSet $type$"); + assertEquals($value1$, o, "getAndSet $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value2$, "getAndSet $type$ value"); + assertEquals($value2$, x, "getAndSet $type$ value"); } { vh.set(recv, $value1$); $type$ o = ($type$) vh.getAndSetAcquire(recv, $value2$); - assertEquals(o, $value1$, "getAndSetAcquire $type$"); + assertEquals($value1$, o, "getAndSetAcquire $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value2$, "getAndSetAcquire $type$ value"); + assertEquals($value2$, x, "getAndSetAcquire $type$ value"); } { vh.set(recv, $value1$); $type$ o = ($type$) vh.getAndSetRelease(recv, $value2$); - assertEquals(o, $value1$, "getAndSetRelease $type$"); + assertEquals($value1$, o, "getAndSetRelease $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, $value2$, "getAndSetRelease $type$ value"); + assertEquals($value2$, x, "getAndSetRelease $type$ value"); } #end[CAS] @@ -829,27 +827,27 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set(recv, $value1$); $type$ o = ($type$) vh.getAndAdd(recv, $value2$); - assertEquals(o, $value1$, "getAndAdd $type$"); + assertEquals($value1$, o, "getAndAdd $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAdd $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAdd $type$ value"); } { vh.set(recv, $value1$); $type$ o = ($type$) vh.getAndAddAcquire(recv, $value2$); - assertEquals(o, $value1$, "getAndAddAcquire $type$"); + assertEquals($value1$, o, "getAndAddAcquire $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAddAcquire $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAddAcquire $type$ value"); } { vh.set(recv, $value1$); $type$ o = ($type$) vh.getAndAddRelease(recv, $value2$); - assertEquals(o, $value1$, "getAndAddRelease$type$"); + assertEquals($value1$, o, "getAndAddRelease$type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAddRelease $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAddRelease $type$ value"); } #end[AtomicAdd] @@ -859,27 +857,27 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set(recv, $value1$); $type$ o = ($type$) vh.getAndBitwiseOr(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseOr $type$"); + assertEquals($value1$, o, "getAndBitwiseOr $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOr $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOr $type$ value"); } { vh.set(recv, $value1$); $type$ o = ($type$) vh.getAndBitwiseOrAcquire(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseOrAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseOrAcquire $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOrAcquire $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOrAcquire $type$ value"); } { vh.set(recv, $value1$); $type$ o = ($type$) vh.getAndBitwiseOrRelease(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseOrRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseOrRelease $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOrRelease $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOrRelease $type$ value"); } // get and bitwise and @@ -887,27 +885,27 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set(recv, $value1$); $type$ o = ($type$) vh.getAndBitwiseAnd(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseAnd $type$"); + assertEquals($value1$, o, "getAndBitwiseAnd $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAnd $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAnd $type$ value"); } { vh.set(recv, $value1$); $type$ o = ($type$) vh.getAndBitwiseAndAcquire(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseAndAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseAndAcquire $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAndAcquire $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAndAcquire $type$ value"); } { vh.set(recv, $value1$); $type$ o = ($type$) vh.getAndBitwiseAndRelease(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseAndRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseAndRelease $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAndRelease $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAndRelease $type$ value"); } // get and bitwise xor @@ -915,27 +913,27 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set(recv, $value1$); $type$ o = ($type$) vh.getAndBitwiseXor(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseXor $type$"); + assertEquals($value1$, o, "getAndBitwiseXor $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXor $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXor $type$ value"); } { vh.set(recv, $value1$); $type$ o = ($type$) vh.getAndBitwiseXorAcquire(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseXorAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseXorAcquire $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXorAcquire $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXorAcquire $type$ value"); } { vh.set(recv, $value1$); $type$ o = ($type$) vh.getAndBitwiseXorRelease(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseXorRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseXorRelease $type$"); $type$ x = ($type$) vh.get(recv); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXorRelease $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXorRelease $type$ value"); } #end[Bitwise] } @@ -1046,7 +1044,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { { vh.set($value1$); $type$ x = ($type$) vh.get(); - assertEquals(x, $value1$, "set $type$ value"); + assertEquals($value1$, x, "set $type$ value"); } @@ -1054,21 +1052,21 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { { vh.setVolatile($value2$); $type$ x = ($type$) vh.getVolatile(); - assertEquals(x, $value2$, "setVolatile $type$ value"); + assertEquals($value2$, x, "setVolatile $type$ value"); } // Lazy { vh.setRelease($value1$); $type$ x = ($type$) vh.getAcquire(); - assertEquals(x, $value1$, "setRelease $type$ value"); + assertEquals($value1$, x, "setRelease $type$ value"); } // Opaque { vh.setOpaque($value2$); $type$ x = ($type$) vh.getOpaque(); - assertEquals(x, $value2$, "setOpaque $type$ value"); + assertEquals($value2$, x, "setOpaque $type$ value"); } #if[CAS] @@ -1079,56 +1077,56 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean r = vh.compareAndSet($value1$, $value2$); assertEquals(r, true, "success compareAndSet $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value2$, "success compareAndSet $type$ value"); + assertEquals($value2$, x, "success compareAndSet $type$ value"); } { boolean r = vh.compareAndSet($value1$, $value3$); assertEquals(r, false, "failing compareAndSet $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value2$, "failing compareAndSet $type$ value"); + assertEquals($value2$, x, "failing compareAndSet $type$ value"); } { $type$ r = ($type$) vh.compareAndExchange($value2$, $value1$); assertEquals(r, $value2$, "success compareAndExchange $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value1$, "success compareAndExchange $type$ value"); + assertEquals($value1$, x, "success compareAndExchange $type$ value"); } { $type$ r = ($type$) vh.compareAndExchange($value2$, $value3$); assertEquals(r, $value1$, "failing compareAndExchange $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value1$, "failing compareAndExchange $type$ value"); + assertEquals($value1$, x, "failing compareAndExchange $type$ value"); } { $type$ r = ($type$) vh.compareAndExchangeAcquire($value1$, $value2$); assertEquals(r, $value1$, "success compareAndExchangeAcquire $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value2$, "success compareAndExchangeAcquire $type$ value"); + assertEquals($value2$, x, "success compareAndExchangeAcquire $type$ value"); } { $type$ r = ($type$) vh.compareAndExchangeAcquire($value1$, $value3$); assertEquals(r, $value2$, "failing compareAndExchangeAcquire $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value2$, "failing compareAndExchangeAcquire $type$ value"); + assertEquals($value2$, x, "failing compareAndExchangeAcquire $type$ value"); } { $type$ r = ($type$) vh.compareAndExchangeRelease($value2$, $value1$); assertEquals(r, $value2$, "success compareAndExchangeRelease $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value1$, "success compareAndExchangeRelease $type$ value"); + assertEquals($value1$, x, "success compareAndExchangeRelease $type$ value"); } { $type$ r = ($type$) vh.compareAndExchangeRelease($value2$, $value3$); assertEquals(r, $value1$, "failing compareAndExchangeRelease $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value1$, "failing compareAndExchangeRelease $type$ value"); + assertEquals($value1$, x, "failing compareAndExchangeRelease $type$ value"); } { @@ -1139,14 +1137,14 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value2$, "success weakCompareAndSetPlain $type$ value"); + assertEquals($value2$, x, "success weakCompareAndSetPlain $type$ value"); } { boolean success = vh.weakCompareAndSetPlain($value1$, $value3$); assertEquals(success, false, "failing weakCompareAndSetPlain $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value2$, "failing weakCompareAndSetPlain $type$ value"); + assertEquals($value2$, x, "failing weakCompareAndSetPlain $type$ value"); } { @@ -1157,14 +1155,14 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value1$, "success weakCompareAndSetAcquire $type$"); + assertEquals($value1$, x, "success weakCompareAndSetAcquire $type$"); } { boolean success = vh.weakCompareAndSetAcquire($value2$, $value3$); assertEquals(success, false, "failing weakCompareAndSetAcquire $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value1$, "failing weakCompareAndSetAcquire $type$ value"); + assertEquals($value1$, x, "failing weakCompareAndSetAcquire $type$ value"); } { @@ -1175,14 +1173,14 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value2$, "success weakCompareAndSetRelease $type$"); + assertEquals($value2$, x, "success weakCompareAndSetRelease $type$"); } { boolean success = vh.weakCompareAndSetRelease($value1$, $value3$); assertEquals(success, false, "failing weakCompareAndSetRelease $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value2$, "failing weakCompareAndSetRelease $type$ value"); + assertEquals($value2$, x, "failing weakCompareAndSetRelease $type$ value"); } { @@ -1193,14 +1191,14 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value1$, "success weakCompareAndSet $type$"); + assertEquals($value1$, x, "success weakCompareAndSet $type$"); } { boolean success = vh.weakCompareAndSet($value2$, $value3$); assertEquals(success, false, "failing weakCompareAndSet $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value1$, "failing weakCompareAndSet $type$ value"); + assertEquals($value1$, x, "failing weakCompareAndSet $type$ value"); } // Compare set and get @@ -1208,27 +1206,27 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set($value1$); $type$ o = ($type$) vh.getAndSet($value2$); - assertEquals(o, $value1$, "getAndSet $type$"); + assertEquals($value1$, o, "getAndSet $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value2$, "getAndSet $type$ value"); + assertEquals($value2$, x, "getAndSet $type$ value"); } { vh.set($value1$); $type$ o = ($type$) vh.getAndSetAcquire($value2$); - assertEquals(o, $value1$, "getAndSetAcquire $type$"); + assertEquals($value1$, o, "getAndSetAcquire $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value2$, "getAndSetAcquire $type$ value"); + assertEquals($value2$, x, "getAndSetAcquire $type$ value"); } { vh.set($value1$); $type$ o = ($type$) vh.getAndSetRelease($value2$); - assertEquals(o, $value1$, "getAndSetRelease $type$"); + assertEquals($value1$, o, "getAndSetRelease $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, $value2$, "getAndSetRelease $type$ value"); + assertEquals($value2$, x, "getAndSetRelease $type$ value"); } #end[CAS] @@ -1238,27 +1236,27 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set($value1$); $type$ o = ($type$) vh.getAndAdd($value2$); - assertEquals(o, $value1$, "getAndAdd $type$"); + assertEquals($value1$, o, "getAndAdd $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAdd $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAdd $type$ value"); } { vh.set($value1$); $type$ o = ($type$) vh.getAndAddAcquire($value2$); - assertEquals(o, $value1$, "getAndAddAcquire $type$"); + assertEquals($value1$, o, "getAndAddAcquire $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAddAcquire $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAddAcquire $type$ value"); } { vh.set($value1$); $type$ o = ($type$) vh.getAndAddRelease($value2$); - assertEquals(o, $value1$, "getAndAddRelease$type$"); + assertEquals($value1$, o, "getAndAddRelease$type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAddRelease $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAddRelease $type$ value"); } #end[AtomicAdd] @@ -1268,27 +1266,27 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set($value1$); $type$ o = ($type$) vh.getAndBitwiseOr($value2$); - assertEquals(o, $value1$, "getAndBitwiseOr $type$"); + assertEquals($value1$, o, "getAndBitwiseOr $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOr $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOr $type$ value"); } { vh.set($value1$); $type$ o = ($type$) vh.getAndBitwiseOrAcquire($value2$); - assertEquals(o, $value1$, "getAndBitwiseOrAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseOrAcquire $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOrAcquire $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOrAcquire $type$ value"); } { vh.set($value1$); $type$ o = ($type$) vh.getAndBitwiseOrRelease($value2$); - assertEquals(o, $value1$, "getAndBitwiseOrRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseOrRelease $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOrRelease $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOrRelease $type$ value"); } // get and bitwise and @@ -1296,27 +1294,27 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set($value1$); $type$ o = ($type$) vh.getAndBitwiseAnd($value2$); - assertEquals(o, $value1$, "getAndBitwiseAnd $type$"); + assertEquals($value1$, o, "getAndBitwiseAnd $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAnd $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAnd $type$ value"); } { vh.set($value1$); $type$ o = ($type$) vh.getAndBitwiseAndAcquire($value2$); - assertEquals(o, $value1$, "getAndBitwiseAndAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseAndAcquire $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAndAcquire $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAndAcquire $type$ value"); } { vh.set($value1$); $type$ o = ($type$) vh.getAndBitwiseAndRelease($value2$); - assertEquals(o, $value1$, "getAndBitwiseAndRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseAndRelease $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAndRelease $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAndRelease $type$ value"); } // get and bitwise xor @@ -1324,27 +1322,27 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set($value1$); $type$ o = ($type$) vh.getAndBitwiseXor($value2$); - assertEquals(o, $value1$, "getAndBitwiseXor $type$"); + assertEquals($value1$, o, "getAndBitwiseXor $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXor $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXor $type$ value"); } { vh.set($value1$); $type$ o = ($type$) vh.getAndBitwiseXorAcquire($value2$); - assertEquals(o, $value1$, "getAndBitwiseXorAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseXorAcquire $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXorAcquire $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXorAcquire $type$ value"); } { vh.set($value1$); $type$ o = ($type$) vh.getAndBitwiseXorRelease($value2$); - assertEquals(o, $value1$, "getAndBitwiseXorRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseXorRelease $type$"); $type$ x = ($type$) vh.get(); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXorRelease $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXorRelease $type$ value"); } #end[Bitwise] } @@ -1458,7 +1456,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { { vh.set(array, i, $value1$); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value1$, "get $type$ value"); + assertEquals($value1$, x, "get $type$ value"); } @@ -1466,21 +1464,21 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { { vh.setVolatile(array, i, $value2$); $type$ x = ($type$) vh.getVolatile(array, i); - assertEquals(x, $value2$, "setVolatile $type$ value"); + assertEquals($value2$, x, "setVolatile $type$ value"); } // Lazy { vh.setRelease(array, i, $value1$); $type$ x = ($type$) vh.getAcquire(array, i); - assertEquals(x, $value1$, "setRelease $type$ value"); + assertEquals($value1$, x, "setRelease $type$ value"); } // Opaque { vh.setOpaque(array, i, $value2$); $type$ x = ($type$) vh.getOpaque(array, i); - assertEquals(x, $value2$, "setOpaque $type$ value"); + assertEquals($value2$, x, "setOpaque $type$ value"); } #if[CAS] @@ -1491,56 +1489,56 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean r = vh.compareAndSet(array, i, $value1$, $value2$); assertEquals(r, true, "success compareAndSet $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value2$, "success compareAndSet $type$ value"); + assertEquals($value2$, x, "success compareAndSet $type$ value"); } { boolean r = vh.compareAndSet(array, i, $value1$, $value3$); assertEquals(r, false, "failing compareAndSet $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value2$, "failing compareAndSet $type$ value"); + assertEquals($value2$, x, "failing compareAndSet $type$ value"); } { $type$ r = ($type$) vh.compareAndExchange(array, i, $value2$, $value1$); assertEquals(r, $value2$, "success compareAndExchange $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value1$, "success compareAndExchange $type$ value"); + assertEquals($value1$, x, "success compareAndExchange $type$ value"); } { $type$ r = ($type$) vh.compareAndExchange(array, i, $value2$, $value3$); assertEquals(r, $value1$, "failing compareAndExchange $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value1$, "failing compareAndExchange $type$ value"); + assertEquals($value1$, x, "failing compareAndExchange $type$ value"); } { $type$ r = ($type$) vh.compareAndExchangeAcquire(array, i, $value1$, $value2$); assertEquals(r, $value1$, "success compareAndExchangeAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value2$, "success compareAndExchangeAcquire $type$ value"); + assertEquals($value2$, x, "success compareAndExchangeAcquire $type$ value"); } { $type$ r = ($type$) vh.compareAndExchangeAcquire(array, i, $value1$, $value3$); assertEquals(r, $value2$, "failing compareAndExchangeAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value2$, "failing compareAndExchangeAcquire $type$ value"); + assertEquals($value2$, x, "failing compareAndExchangeAcquire $type$ value"); } { $type$ r = ($type$) vh.compareAndExchangeRelease(array, i, $value2$, $value1$); assertEquals(r, $value2$, "success compareAndExchangeRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value1$, "success compareAndExchangeRelease $type$ value"); + assertEquals($value1$, x, "success compareAndExchangeRelease $type$ value"); } { $type$ r = ($type$) vh.compareAndExchangeRelease(array, i, $value2$, $value3$); assertEquals(r, $value1$, "failing compareAndExchangeRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value1$, "failing compareAndExchangeRelease $type$ value"); + assertEquals($value1$, x, "failing compareAndExchangeRelease $type$ value"); } { @@ -1551,14 +1549,14 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value2$, "success weakCompareAndSetPlain $type$ value"); + assertEquals($value2$, x, "success weakCompareAndSetPlain $type$ value"); } { boolean success = vh.weakCompareAndSetPlain(array, i, $value1$, $value3$); assertEquals(success, false, "failing weakCompareAndSetPlain $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value2$, "failing weakCompareAndSetPlain $type$ value"); + assertEquals($value2$, x, "failing weakCompareAndSetPlain $type$ value"); } { @@ -1569,14 +1567,14 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value1$, "success weakCompareAndSetAcquire $type$"); + assertEquals($value1$, x, "success weakCompareAndSetAcquire $type$"); } { boolean success = vh.weakCompareAndSetAcquire(array, i, $value2$, $value3$); assertEquals(success, false, "failing weakCompareAndSetAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value1$, "failing weakCompareAndSetAcquire $type$ value"); + assertEquals($value1$, x, "failing weakCompareAndSetAcquire $type$ value"); } { @@ -1587,14 +1585,14 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value2$, "success weakCompareAndSetRelease $type$"); + assertEquals($value2$, x, "success weakCompareAndSetRelease $type$"); } { boolean success = vh.weakCompareAndSetRelease(array, i, $value1$, $value3$); assertEquals(success, false, "failing weakCompareAndSetRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value2$, "failing weakCompareAndSetRelease $type$ value"); + assertEquals($value2$, x, "failing weakCompareAndSetRelease $type$ value"); } { @@ -1605,14 +1603,14 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value1$, "success weakCompareAndSet $type$"); + assertEquals($value1$, x, "success weakCompareAndSet $type$"); } { boolean success = vh.weakCompareAndSet(array, i, $value2$, $value3$); assertEquals(success, false, "failing weakCompareAndSet $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value1$, "failing weakCompareAndSet $type$ value"); + assertEquals($value1$, x, "failing weakCompareAndSet $type$ value"); } // Compare set and get @@ -1620,27 +1618,27 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set(array, i, $value1$); $type$ o = ($type$) vh.getAndSet(array, i, $value2$); - assertEquals(o, $value1$, "getAndSet $type$"); + assertEquals($value1$, o, "getAndSet $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value2$, "getAndSet $type$ value"); + assertEquals($value2$, x, "getAndSet $type$ value"); } { vh.set(array, i, $value1$); $type$ o = ($type$) vh.getAndSetAcquire(array, i, $value2$); - assertEquals(o, $value1$, "getAndSetAcquire $type$"); + assertEquals($value1$, o, "getAndSetAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value2$, "getAndSetAcquire $type$ value"); + assertEquals($value2$, x, "getAndSetAcquire $type$ value"); } { vh.set(array, i, $value1$); $type$ o = ($type$) vh.getAndSetRelease(array, i, $value2$); - assertEquals(o, $value1$, "getAndSetRelease $type$"); + assertEquals($value1$, o, "getAndSetRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, $value2$, "getAndSetRelease $type$ value"); + assertEquals($value2$, x, "getAndSetRelease $type$ value"); } #end[CAS] @@ -1650,27 +1648,27 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set(array, i, $value1$); $type$ o = ($type$) vh.getAndAdd(array, i, $value2$); - assertEquals(o, $value1$, "getAndAdd $type$"); + assertEquals($value1$, o, "getAndAdd $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAdd $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAdd $type$ value"); } { vh.set(array, i, $value1$); $type$ o = ($type$) vh.getAndAddAcquire(array, i, $value2$); - assertEquals(o, $value1$, "getAndAddAcquire $type$"); + assertEquals($value1$, o, "getAndAddAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAddAcquire $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAddAcquire $type$ value"); } { vh.set(array, i, $value1$); $type$ o = ($type$) vh.getAndAddRelease(array, i, $value2$); - assertEquals(o, $value1$, "getAndAddRelease$type$"); + assertEquals($value1$, o, "getAndAddRelease$type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAddRelease $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAddRelease $type$ value"); } #end[AtomicAdd] @@ -1680,27 +1678,27 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set(array, i, $value1$); $type$ o = ($type$) vh.getAndBitwiseOr(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseOr $type$"); + assertEquals($value1$, o, "getAndBitwiseOr $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOr $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOr $type$ value"); } { vh.set(array, i, $value1$); $type$ o = ($type$) vh.getAndBitwiseOrAcquire(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseOrAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseOrAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOrAcquire $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOrAcquire $type$ value"); } { vh.set(array, i, $value1$); $type$ o = ($type$) vh.getAndBitwiseOrRelease(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseOrRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseOrRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOrRelease $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOrRelease $type$ value"); } // get and bitwise and @@ -1708,27 +1706,27 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set(array, i, $value1$); $type$ o = ($type$) vh.getAndBitwiseAnd(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseAnd $type$"); + assertEquals($value1$, o, "getAndBitwiseAnd $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAnd $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAnd $type$ value"); } { vh.set(array, i, $value1$); $type$ o = ($type$) vh.getAndBitwiseAndAcquire(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseAndAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseAndAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAndAcquire $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAndAcquire $type$ value"); } { vh.set(array, i, $value1$); $type$ o = ($type$) vh.getAndBitwiseAndRelease(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseAndRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseAndRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAndRelease $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAndRelease $type$ value"); } // get and bitwise xor @@ -1736,27 +1734,27 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set(array, i, $value1$); $type$ o = ($type$) vh.getAndBitwiseXor(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseXor $type$"); + assertEquals($value1$, o, "getAndBitwiseXor $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXor $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXor $type$ value"); } { vh.set(array, i, $value1$); $type$ o = ($type$) vh.getAndBitwiseXorAcquire(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseXorAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseXorAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXorAcquire $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXorAcquire $type$ value"); } { vh.set(array, i, $value1$); $type$ o = ($type$) vh.getAndBitwiseXorRelease(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseXorRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseXorRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXorRelease $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXorRelease $type$ value"); } #end[Bitwise] } diff --git a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template index c21709d6d37..9a40bfb2780 100644 --- a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template +++ b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,25 +26,25 @@ * @bug 8154556 * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAs$Type$ - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAs$Type$ - * @run testng/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAs$Type$ + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAs$Type$ + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAs$Type$ + * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAs$Type$ */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { static final int SIZE = $BoxType$.BYTES; @@ -111,7 +111,8 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { } } - @Test(dataProvider = "varHandlesProvider") + @ParameterizedTest + @MethodSource("VarHandleBaseByteArrayTest#varHandlesProvider") public void testIsAccessModeSupported(VarHandleSource vhs) { VarHandle vh = vhs.s; @@ -206,17 +207,16 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { #end[Bitwise] } - @Test(dataProvider = "typesProvider") + @ParameterizedTest + @MethodSource("typesProvider") public void testTypes(VarHandle vh, List> pts) { - assertEquals(vh.varType(), $type$.class); + assertEquals($type$.class, vh.varType()); - assertEquals(vh.coordinateTypes(), pts); + assertEquals(pts, vh.coordinateTypes()); testTypes(vh); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -278,7 +278,8 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -287,7 +288,6 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { } } - static void testArrayNPE(ByteArraySource bs, VarHandleSource vhs) { VarHandle vh = vhs.s; byte[] array = null; @@ -1272,7 +1272,7 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { { vh.set(array, i, VALUE_1); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1, "get $type$ value"); + assertEquals(VALUE_1, x, "get $type$ value"); } } } @@ -1291,7 +1291,7 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { { vh.set(array, i, VALUE_1); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1, "get $type$ value"); + assertEquals(VALUE_1, x, "get $type$ value"); } if (iAligned) { @@ -1299,21 +1299,21 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { { vh.setVolatile(array, i, VALUE_2); $type$ x = ($type$) vh.getVolatile(array, i); - assertEquals(x, VALUE_2, "setVolatile $type$ value"); + assertEquals(VALUE_2, x, "setVolatile $type$ value"); } // Lazy { vh.setRelease(array, i, VALUE_1); $type$ x = ($type$) vh.getAcquire(array, i); - assertEquals(x, VALUE_1, "setRelease $type$ value"); + assertEquals(VALUE_1, x, "setRelease $type$ value"); } // Opaque { vh.setOpaque(array, i, VALUE_2); $type$ x = ($type$) vh.getOpaque(array, i); - assertEquals(x, VALUE_2, "setOpaque $type$ value"); + assertEquals(VALUE_2, x, "setOpaque $type$ value"); } #if[CAS] @@ -1324,56 +1324,56 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean r = vh.compareAndSet(array, i, VALUE_1, VALUE_2); assertEquals(r, true, "success compareAndSet $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_2, "success compareAndSet $type$ value"); + assertEquals(VALUE_2, x, "success compareAndSet $type$ value"); } { boolean r = vh.compareAndSet(array, i, VALUE_1, VALUE_3); assertEquals(r, false, "failing compareAndSet $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_2, "failing compareAndSet $type$ value"); + assertEquals(VALUE_2, x, "failing compareAndSet $type$ value"); } { $type$ r = ($type$) vh.compareAndExchange(array, i, VALUE_2, VALUE_1); assertEquals(r, VALUE_2, "success compareAndExchange $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1, "success compareAndExchange $type$ value"); + assertEquals(VALUE_1, x, "success compareAndExchange $type$ value"); } { $type$ r = ($type$) vh.compareAndExchange(array, i, VALUE_2, VALUE_3); assertEquals(r, VALUE_1, "failing compareAndExchange $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1, "failing compareAndExchange $type$ value"); + assertEquals(VALUE_1, x, "failing compareAndExchange $type$ value"); } { $type$ r = ($type$) vh.compareAndExchangeAcquire(array, i, VALUE_1, VALUE_2); assertEquals(r, VALUE_1, "success compareAndExchangeAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_2, "success compareAndExchangeAcquire $type$ value"); + assertEquals(VALUE_2, x, "success compareAndExchangeAcquire $type$ value"); } { $type$ r = ($type$) vh.compareAndExchangeAcquire(array, i, VALUE_1, VALUE_3); assertEquals(r, VALUE_2, "failing compareAndExchangeAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_2, "failing compareAndExchangeAcquire $type$ value"); + assertEquals(VALUE_2, x, "failing compareAndExchangeAcquire $type$ value"); } { $type$ r = ($type$) vh.compareAndExchangeRelease(array, i, VALUE_2, VALUE_1); assertEquals(r, VALUE_2, "success compareAndExchangeRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1, "success compareAndExchangeRelease $type$ value"); + assertEquals(VALUE_1, x, "success compareAndExchangeRelease $type$ value"); } { $type$ r = ($type$) vh.compareAndExchangeRelease(array, i, VALUE_2, VALUE_3); assertEquals(r, VALUE_1, "failing compareAndExchangeRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1, "failing compareAndExchangeRelease $type$ value"); + assertEquals(VALUE_1, x, "failing compareAndExchangeRelease $type$ value"); } { @@ -1384,14 +1384,14 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSetPlain $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_2, "success weakCompareAndSetPlain $type$ value"); + assertEquals(VALUE_2, x, "success weakCompareAndSetPlain $type$ value"); } { boolean success = vh.weakCompareAndSetPlain(array, i, VALUE_1, VALUE_3); assertEquals(success, false, "failing weakCompareAndSetPlain $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_2, "failing weakCompareAndSetPlain $type$ value"); + assertEquals(VALUE_2, x, "failing weakCompareAndSetPlain $type$ value"); } { @@ -1402,14 +1402,14 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSetAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1, "success weakCompareAndSetAcquire $type$"); + assertEquals(VALUE_1, x, "success weakCompareAndSetAcquire $type$"); } { boolean success = vh.weakCompareAndSetAcquire(array, i, VALUE_2, VALUE_3); assertEquals(success, false, "failing weakCompareAndSetAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1, "failing weakCompareAndSetAcquire $type$ value"); + assertEquals(VALUE_1, x, "failing weakCompareAndSetAcquire $type$ value"); } { @@ -1420,14 +1420,14 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSetRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_2, "success weakCompareAndSetRelease $type$"); + assertEquals(VALUE_2, x, "success weakCompareAndSetRelease $type$"); } { boolean success = vh.weakCompareAndSetRelease(array, i, VALUE_1, VALUE_3); assertEquals(success, false, "failing weakCompareAndSetRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_2, "failing weakCompareAndSetRelease $type$ value"); + assertEquals(VALUE_2, x, "failing weakCompareAndSetRelease $type$ value"); } { @@ -1438,14 +1438,14 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { } assertEquals(success, true, "success weakCompareAndSet $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1, "success weakCompareAndSet $type$"); + assertEquals(VALUE_1, x, "success weakCompareAndSet $type$"); } { boolean success = vh.weakCompareAndSet(array, i, VALUE_2, VALUE_3); assertEquals(success, false, "failing weakCompareAndSet $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1, "failing weakCompareAndSet $type$ value"); + assertEquals(VALUE_1, x, "failing weakCompareAndSet $type$ value"); } // Compare set and get @@ -1453,27 +1453,27 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); $type$ o = ($type$) vh.getAndSet(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndSet $type$"); + assertEquals(VALUE_1, o, "getAndSet $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_2, "getAndSet $type$ value"); + assertEquals(VALUE_2, x, "getAndSet $type$ value"); } { vh.set(array, i, VALUE_1); $type$ o = ($type$) vh.getAndSetAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndSetAcquire $type$"); + assertEquals(VALUE_1, o, "getAndSetAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_2, "getAndSetAcquire $type$ value"); + assertEquals(VALUE_2, x, "getAndSetAcquire $type$ value"); } { vh.set(array, i, VALUE_1); $type$ o = ($type$) vh.getAndSetRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndSetRelease $type$"); + assertEquals(VALUE_1, o, "getAndSetRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_2, "getAndSetRelease $type$ value"); + assertEquals(VALUE_2, x, "getAndSetRelease $type$ value"); } #end[CAS] @@ -1483,27 +1483,27 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); $type$ o = ($type$) vh.getAndAdd(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndAdd $type$"); + assertEquals(VALUE_1, o, "getAndAdd $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1 + VALUE_2, "getAndAdd $type$ value"); + assertEquals(VALUE_1 + VALUE_2, x, "getAndAdd $type$ value"); } { vh.set(array, i, VALUE_1); $type$ o = ($type$) vh.getAndAddAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndAddAcquire $type$"); + assertEquals(VALUE_1, o, "getAndAddAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1 + VALUE_2, "getAndAddAcquire $type$ value"); + assertEquals(VALUE_1 + VALUE_2, x, "getAndAddAcquire $type$ value"); } { vh.set(array, i, VALUE_1); $type$ o = ($type$) vh.getAndAddRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndAddRelease $type$"); + assertEquals(VALUE_1, o, "getAndAddRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1 + VALUE_2, "getAndAddRelease $type$ value"); + assertEquals(VALUE_1 + VALUE_2, x, "getAndAddRelease $type$ value"); } #end[AtomicAdd] @@ -1513,27 +1513,27 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); $type$ o = ($type$) vh.getAndBitwiseOr(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseOr $type$"); + assertEquals(VALUE_1, o, "getAndBitwiseOr $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1 | VALUE_2, "getAndBitwiseOr $type$ value"); + assertEquals(VALUE_1 | VALUE_2, x, "getAndBitwiseOr $type$ value"); } { vh.set(array, i, VALUE_1); $type$ o = ($type$) vh.getAndBitwiseOrAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseOrAcquire $type$"); + assertEquals(VALUE_1, o, "getAndBitwiseOrAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1 | VALUE_2, "getAndBitwiseOrAcquire $type$ value"); + assertEquals(VALUE_1 | VALUE_2, x, "getAndBitwiseOrAcquire $type$ value"); } { vh.set(array, i, VALUE_1); $type$ o = ($type$) vh.getAndBitwiseOrRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseOrRelease $type$"); + assertEquals(VALUE_1, o, "getAndBitwiseOrRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1 | VALUE_2, "getAndBitwiseOrRelease $type$ value"); + assertEquals(VALUE_1 | VALUE_2, x, "getAndBitwiseOrRelease $type$ value"); } // get and bitwise and @@ -1541,27 +1541,27 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); $type$ o = ($type$) vh.getAndBitwiseAnd(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseAnd $type$"); + assertEquals(VALUE_1, o, "getAndBitwiseAnd $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1 & VALUE_2, "getAndBitwiseAnd $type$ value"); + assertEquals(VALUE_1 & VALUE_2, x, "getAndBitwiseAnd $type$ value"); } { vh.set(array, i, VALUE_1); $type$ o = ($type$) vh.getAndBitwiseAndAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseAndAcquire $type$"); + assertEquals(VALUE_1, o, "getAndBitwiseAndAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1 & VALUE_2, "getAndBitwiseAndAcquire $type$ value"); + assertEquals(VALUE_1 & VALUE_2, x, "getAndBitwiseAndAcquire $type$ value"); } { vh.set(array, i, VALUE_1); $type$ o = ($type$) vh.getAndBitwiseAndRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseAndRelease $type$"); + assertEquals(VALUE_1, o, "getAndBitwiseAndRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1 & VALUE_2, "getAndBitwiseAndRelease $type$ value"); + assertEquals(VALUE_1 & VALUE_2, x, "getAndBitwiseAndRelease $type$ value"); } // get and bitwise xor @@ -1569,27 +1569,27 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { vh.set(array, i, VALUE_1); $type$ o = ($type$) vh.getAndBitwiseXor(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseXor $type$"); + assertEquals(VALUE_1, o, "getAndBitwiseXor $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1 ^ VALUE_2, "getAndBitwiseXor $type$ value"); + assertEquals(VALUE_1 ^ VALUE_2, x, "getAndBitwiseXor $type$ value"); } { vh.set(array, i, VALUE_1); $type$ o = ($type$) vh.getAndBitwiseXorAcquire(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseXorAcquire $type$"); + assertEquals(VALUE_1, o, "getAndBitwiseXorAcquire $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1 ^ VALUE_2, "getAndBitwiseXorAcquire $type$ value"); + assertEquals(VALUE_1 ^ VALUE_2, x, "getAndBitwiseXorAcquire $type$ value"); } { vh.set(array, i, VALUE_1); $type$ o = ($type$) vh.getAndBitwiseXorRelease(array, i, VALUE_2); - assertEquals(o, VALUE_1, "getAndBitwiseXorRelease $type$"); + assertEquals(VALUE_1, o, "getAndBitwiseXorRelease $type$"); $type$ x = ($type$) vh.get(array, i); - assertEquals(x, VALUE_1 ^ VALUE_2, "getAndBitwiseXorRelease $type$ value"); + assertEquals(VALUE_1 ^ VALUE_2, x, "getAndBitwiseXorRelease $type$ value"); } #end[Bitwise] } @@ -1614,26 +1614,26 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { // Plain { $type$ x = ($type$) vh.get(array, i); - assertEquals(x, v, "get $type$ value"); + assertEquals(v, x, "get $type$ value"); } if (iAligned) { // Volatile { $type$ x = ($type$) vh.getVolatile(array, i); - assertEquals(x, v, "getVolatile $type$ value"); + assertEquals(v, x, "getVolatile $type$ value"); } // Lazy { $type$ x = ($type$) vh.getAcquire(array, i); - assertEquals(x, v, "getRelease $type$ value"); + assertEquals(v, x, "getRelease $type$ value"); } // Opaque { $type$ x = ($type$) vh.getOpaque(array, i); - assertEquals(x, v, "getOpaque $type$ value"); + assertEquals(v, x, "getOpaque $type$ value"); } } } diff --git a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template index 4a9fa7c4fe8..a347b232d7e 100644 --- a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template +++ b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,22 @@ * @test * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds - * @run testng/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccess$Type$ + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccess$Type$ */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { static final $type$ static_final_v = $value1$; @@ -60,7 +60,7 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodHandleAccess$Type$.class, "final_v", $type$.class); @@ -77,8 +77,6 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle($type$[].class); } - - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -111,7 +109,8 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -120,13 +119,12 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } } - static void testInstanceField(VarHandleTestMethodHandleAccess$Type$ recv, Handles hs) throws Throwable { // Plain { hs.get(TestAccessMode.SET).invokeExact(recv, $value1$); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value1$, "set $type$ value"); + assertEquals($value1$, x, "set $type$ value"); } @@ -134,21 +132,21 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(recv, $value2$); $type$ x = ($type$) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(recv); - assertEquals(x, $value2$, "setVolatile $type$ value"); + assertEquals($value2$, x, "setVolatile $type$ value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(recv, $value1$); $type$ x = ($type$) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(recv); - assertEquals(x, $value1$, "setRelease $type$ value"); + assertEquals($value1$, x, "setRelease $type$ value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(recv, $value2$); $type$ x = ($type$) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(recv); - assertEquals(x, $value2$, "setOpaque $type$ value"); + assertEquals($value2$, x, "setOpaque $type$ value"); } #if[CAS] @@ -159,56 +157,56 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, $value1$, $value2$); assertEquals(r, true, "success compareAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value2$, "success compareAndSet $type$ value"); + assertEquals($value2$, x, "success compareAndSet $type$ value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, $value1$, $value3$); assertEquals(r, false, "failing compareAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value2$, "failing compareAndSet $type$ value"); + assertEquals($value2$, x, "failing compareAndSet $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, $value2$, $value1$); assertEquals(r, $value2$, "success compareAndExchange $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value1$, "success compareAndExchange $type$ value"); + assertEquals($value1$, x, "success compareAndExchange $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, $value2$, $value3$); assertEquals(r, $value1$, "failing compareAndExchange $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value1$, "failing compareAndExchange $type$ value"); + assertEquals($value1$, x, "failing compareAndExchange $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, $value1$, $value2$); assertEquals(r, $value1$, "success compareAndExchangeAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value2$, "success compareAndExchangeAcquire $type$ value"); + assertEquals($value2$, x, "success compareAndExchangeAcquire $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, $value1$, $value3$); assertEquals(r, $value2$, "failing compareAndExchangeAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value2$, "failing compareAndExchangeAcquire $type$ value"); + assertEquals($value2$, x, "failing compareAndExchangeAcquire $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, $value2$, $value1$); assertEquals(r, $value2$, "success compareAndExchangeRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value1$, "success compareAndExchangeRelease $type$ value"); + assertEquals($value1$, x, "success compareAndExchangeRelease $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, $value2$, $value3$); assertEquals(r, $value1$, "failing compareAndExchangeRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value1$, "failing compareAndExchangeRelease $type$ value"); + assertEquals($value1$, x, "failing compareAndExchangeRelease $type$ value"); } { @@ -220,14 +218,14 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value2$, "success weakCompareAndSetPlain $type$ value"); + assertEquals($value2$, x, "success weakCompareAndSetPlain $type$ value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, $value1$, $value3$); assertEquals(success, false, "failing weakCompareAndSetPlain $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value2$, "failing weakCompareAndSetPlain $type$ value"); + assertEquals($value2$, x, "failing weakCompareAndSetPlain $type$ value"); } { @@ -239,14 +237,14 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value1$, "success weakCompareAndSetAcquire $type$"); + assertEquals($value1$, x, "success weakCompareAndSetAcquire $type$"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, $value2$, $value3$); assertEquals(success, false, "failing weakCompareAndSetAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value1$, "failing weakCompareAndSetAcquire $type$ value"); + assertEquals($value1$, x, "failing weakCompareAndSetAcquire $type$ value"); } { @@ -258,14 +256,14 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value2$, "success weakCompareAndSetRelease $type$"); + assertEquals($value2$, x, "success weakCompareAndSetRelease $type$"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, $value1$, $value3$); assertEquals(success, false, "failing weakCompareAndSetRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value2$, "failing weakCompareAndSetRelease $type$ value"); + assertEquals($value2$, x, "failing weakCompareAndSetRelease $type$ value"); } { @@ -277,22 +275,22 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value1$, "success weakCompareAndSet $type$"); + assertEquals($value1$, x, "success weakCompareAndSet $type$"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, $value2$, $value3$); assertEquals(success, false, "failing weakCompareAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value1$, "failing weakCompareAndSet $type$ value"); + assertEquals($value1$, x, "failing weakCompareAndSet $type$ value"); } // Compare set and get { $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, $value2$); - assertEquals(o, $value1$, "getAndSet $type$"); + assertEquals($value1$, o, "getAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, $value2$, "getAndSet $type$ value"); + assertEquals($value2$, x, "getAndSet $type$ value"); } #end[CAS] @@ -302,27 +300,27 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(recv, $value2$); - assertEquals(o, $value1$, "getAndAdd $type$"); + assertEquals($value1$, o, "getAndAdd $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAdd $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAdd $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(recv, $value2$); - assertEquals(o, $value1$, "getAndAddAcquire $type$"); + assertEquals($value1$, o, "getAndAddAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAddAcquire $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAddAcquire $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(recv, $value2$); - assertEquals(o, $value1$, "getAndAddRelease $type$"); + assertEquals($value1$, o, "getAndAddRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAddRelease $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAddRelease $type$ value"); } #end[AtomicAdd] @@ -332,27 +330,27 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseOr $type$"); + assertEquals($value1$, o, "getAndBitwiseOr $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOr $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOr $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseOrAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseOrAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOrAcquire $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOrAcquire $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseOrRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseOrRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOrRelease $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOrRelease $type$ value"); } // get and bitwise and @@ -360,27 +358,27 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseAnd $type$"); + assertEquals($value1$, o, "getAndBitwiseAnd $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAnd $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAnd $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseAndAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseAndAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAndAcquire $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAndAcquire $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseAndRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseAndRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAndRelease $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAndRelease $type$ value"); } // get and bitwise xor @@ -388,27 +386,27 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(recv, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseXor $type$"); + assertEquals($value1$, o, "getAndBitwiseXor $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXor $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXor $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseXorAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseXorAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXorAcquire $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXorAcquire $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(recv, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(recv, $value2$); - assertEquals(o, $value1$, "getAndBitwiseXorRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseXorRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXorRelease $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXorRelease $type$ value"); } #end[Bitwise] } @@ -457,7 +455,7 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact($value1$); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value1$, "set $type$ value"); + assertEquals($value1$, x, "set $type$ value"); } @@ -465,21 +463,21 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact($value2$); $type$ x = ($type$) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(); - assertEquals(x, $value2$, "setVolatile $type$ value"); + assertEquals($value2$, x, "setVolatile $type$ value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact($value1$); $type$ x = ($type$) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(); - assertEquals(x, $value1$, "setRelease $type$ value"); + assertEquals($value1$, x, "setRelease $type$ value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact($value2$); $type$ x = ($type$) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(); - assertEquals(x, $value2$, "setOpaque $type$ value"); + assertEquals($value2$, x, "setOpaque $type$ value"); } #if[CAS] @@ -490,56 +488,56 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact($value1$, $value2$); assertEquals(r, true, "success compareAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value2$, "success compareAndSet $type$ value"); + assertEquals($value2$, x, "success compareAndSet $type$ value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact($value1$, $value3$); assertEquals(r, false, "failing compareAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value2$, "failing compareAndSet $type$ value"); + assertEquals($value2$, x, "failing compareAndSet $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact($value2$, $value1$); assertEquals(r, $value2$, "success compareAndExchange $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value1$, "success compareAndExchange $type$ value"); + assertEquals($value1$, x, "success compareAndExchange $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact($value2$, $value3$); assertEquals(r, $value1$, "failing compareAndExchange $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value1$, "failing compareAndExchange $type$ value"); + assertEquals($value1$, x, "failing compareAndExchange $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact($value1$, $value2$); assertEquals(r, $value1$, "success compareAndExchangeAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value2$, "success compareAndExchangeAcquire $type$ value"); + assertEquals($value2$, x, "success compareAndExchangeAcquire $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact($value1$, $value3$); assertEquals(r, $value2$, "failing compareAndExchangeAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value2$, "failing compareAndExchangeAcquire $type$ value"); + assertEquals($value2$, x, "failing compareAndExchangeAcquire $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact($value2$, $value1$); assertEquals(r, $value2$, "success compareAndExchangeRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value1$, "success compareAndExchangeRelease $type$ value"); + assertEquals($value1$, x, "success compareAndExchangeRelease $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact($value2$, $value3$); assertEquals(r, $value1$, "failing compareAndExchangeRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value1$, "failing compareAndExchangeRelease $type$ value"); + assertEquals($value1$, x, "failing compareAndExchangeRelease $type$ value"); } { @@ -551,14 +549,14 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value2$, "success weakCompareAndSetPlain $type$ value"); + assertEquals($value2$, x, "success weakCompareAndSetPlain $type$ value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact($value1$, $value3$); assertEquals(success, false, "failing weakCompareAndSetPlain $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value2$, "failing weakCompareAndSetPlain $type$ value"); + assertEquals($value2$, x, "failing weakCompareAndSetPlain $type$ value"); } { @@ -570,7 +568,7 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value1$, "success weakCompareAndSetAcquire $type$"); + assertEquals($value1$, x, "success weakCompareAndSetAcquire $type$"); } { @@ -578,7 +576,7 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { boolean success = (boolean) mh.invokeExact($value2$, $value3$); assertEquals(success, false, "failing weakCompareAndSetAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value1$, "failing weakCompareAndSetAcquire $type$ value"); + assertEquals($value1$, x, "failing weakCompareAndSetAcquire $type$ value"); } { @@ -590,14 +588,14 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value2$, "success weakCompareAndSetRelease $type$"); + assertEquals($value2$, x, "success weakCompareAndSetRelease $type$"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact($value1$, $value3$); assertEquals(success, false, "failing weakCompareAndSetRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value2$, "failing weakCompareAndSetRelease $type$ value"); + assertEquals($value2$, x, "failing weakCompareAndSetRelease $type$ value"); } { @@ -609,14 +607,14 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value1$, "success weakCompareAndSet $type$"); + assertEquals($value1$, x, "success weakCompareAndSet $type$"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact($value2$, $value3$); assertEquals(success, false, "failing weakCompareAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value1$, "failing weakCompareAndSetRe $type$ value"); + assertEquals($value1$, x, "failing weakCompareAndSetRe $type$ value"); } // Compare set and get @@ -624,9 +622,9 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact($value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET).invokeExact($value2$); - assertEquals(o, $value1$, "getAndSet $type$"); + assertEquals($value1$, o, "getAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value2$, "getAndSet $type$ value"); + assertEquals($value2$, x, "getAndSet $type$ value"); } // Compare set and get @@ -634,9 +632,9 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact($value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact($value2$); - assertEquals(o, $value1$, "getAndSetAcquire $type$"); + assertEquals($value1$, o, "getAndSetAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value2$, "getAndSetAcquire $type$ value"); + assertEquals($value2$, x, "getAndSetAcquire $type$ value"); } // Compare set and get @@ -644,9 +642,9 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact($value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact($value2$); - assertEquals(o, $value1$, "getAndSetRelease $type$"); + assertEquals($value1$, o, "getAndSetRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, $value2$, "getAndSetRelease $type$ value"); + assertEquals($value2$, x, "getAndSetRelease $type$ value"); } #end[CAS] @@ -656,27 +654,27 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact($value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_ADD).invokeExact($value2$); - assertEquals(o, $value1$, "getAndAdd $type$"); + assertEquals($value1$, o, "getAndAdd $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAdd $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAdd $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact($value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact($value2$); - assertEquals(o, $value1$, "getAndAddAcquire $type$"); + assertEquals($value1$, o, "getAndAddAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAddAcquire $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAddAcquire $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact($value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact($value2$); - assertEquals(o, $value1$, "getAndAddRelease $type$"); + assertEquals($value1$, o, "getAndAddRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAddRelease $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAddRelease $type$ value"); } #end[AtomicAdd] @@ -686,27 +684,27 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact($value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact($value2$); - assertEquals(o, $value1$, "getAndBitwiseOr $type$"); + assertEquals($value1$, o, "getAndBitwiseOr $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOr $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOr $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact($value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact($value2$); - assertEquals(o, $value1$, "getAndBitwiseOrAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseOrAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOrAcquire $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOrAcquire $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact($value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact($value2$); - assertEquals(o, $value1$, "getAndBitwiseOrRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseOrRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOrRelease $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOrRelease $type$ value"); } // get and bitwise and @@ -714,27 +712,27 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact($value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact($value2$); - assertEquals(o, $value1$, "getAndBitwiseAnd $type$"); + assertEquals($value1$, o, "getAndBitwiseAnd $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAnd $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAnd $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact($value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact($value2$); - assertEquals(o, $value1$, "getAndBitwiseAndAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseAndAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAndAcquire $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAndAcquire $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact($value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact($value2$); - assertEquals(o, $value1$, "getAndBitwiseAndRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseAndRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAndRelease $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAndRelease $type$ value"); } // get and bitwise xor @@ -742,27 +740,27 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact($value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact($value2$); - assertEquals(o, $value1$, "getAndBitwiseXor $type$"); + assertEquals($value1$, o, "getAndBitwiseXor $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXor $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXor $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact($value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact($value2$); - assertEquals(o, $value1$, "getAndBitwiseXorAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseXorAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXorAcquire $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXorAcquire $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact($value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact($value2$); - assertEquals(o, $value1$, "getAndBitwiseXorRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseXorRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXorRelease $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXorRelease $type$ value"); } #end[Bitwise] } @@ -814,7 +812,7 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { { hs.get(TestAccessMode.SET).invokeExact(array, i, $value1$); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value1$, "get $type$ value"); + assertEquals($value1$, x, "get $type$ value"); } @@ -822,21 +820,21 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { { hs.get(TestAccessMode.SET_VOLATILE).invokeExact(array, i, $value2$); $type$ x = ($type$) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(array, i); - assertEquals(x, $value2$, "setVolatile $type$ value"); + assertEquals($value2$, x, "setVolatile $type$ value"); } // Lazy { hs.get(TestAccessMode.SET_RELEASE).invokeExact(array, i, $value1$); $type$ x = ($type$) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(array, i); - assertEquals(x, $value1$, "setRelease $type$ value"); + assertEquals($value1$, x, "setRelease $type$ value"); } // Opaque { hs.get(TestAccessMode.SET_OPAQUE).invokeExact(array, i, $value2$); $type$ x = ($type$) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(array, i); - assertEquals(x, $value2$, "setOpaque $type$ value"); + assertEquals($value2$, x, "setOpaque $type$ value"); } #if[CAS] @@ -847,56 +845,56 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, $value1$, $value2$); assertEquals(r, true, "success compareAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value2$, "success compareAndSet $type$ value"); + assertEquals($value2$, x, "success compareAndSet $type$ value"); } { boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, $value1$, $value3$); assertEquals(r, false, "failing compareAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value2$, "failing compareAndSet $type$ value"); + assertEquals($value2$, x, "failing compareAndSet $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, $value2$, $value1$); assertEquals(r, $value2$, "success compareAndExchange $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value1$, "success compareAndExchange $type$ value"); + assertEquals($value1$, x, "success compareAndExchange $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, $value2$, $value3$); assertEquals(r, $value1$, "failing compareAndExchange $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value1$, "failing compareAndExchange $type$ value"); + assertEquals($value1$, x, "failing compareAndExchange $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, $value1$, $value2$); assertEquals(r, $value1$, "success compareAndExchangeAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value2$, "success compareAndExchangeAcquire $type$ value"); + assertEquals($value2$, x, "success compareAndExchangeAcquire $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, $value1$, $value3$); assertEquals(r, $value2$, "failing compareAndExchangeAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value2$, "failing compareAndExchangeAcquire $type$ value"); + assertEquals($value2$, x, "failing compareAndExchangeAcquire $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, $value2$, $value1$); assertEquals(r, $value2$, "success compareAndExchangeRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value1$, "success compareAndExchangeRelease $type$ value"); + assertEquals($value1$, x, "success compareAndExchangeRelease $type$ value"); } { $type$ r = ($type$) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, $value2$, $value3$); assertEquals(r, $value1$, "failing compareAndExchangeRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value1$, "failing compareAndExchangeRelease $type$ value"); + assertEquals($value1$, x, "failing compareAndExchangeRelease $type$ value"); } { @@ -908,14 +906,14 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetPlain $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value2$, "success weakCompareAndSetPlain $type$ value"); + assertEquals($value2$, x, "success weakCompareAndSetPlain $type$ value"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, $value1$, $value3$); assertEquals(success, false, "failing weakCompareAndSetPlain $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value2$, "failing weakCompareAndSetPlain $type$ value"); + assertEquals($value2$, x, "failing weakCompareAndSetPlain $type$ value"); } { @@ -927,14 +925,14 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value1$, "success weakCompareAndSetAcquire $type$"); + assertEquals($value1$, x, "success weakCompareAndSetAcquire $type$"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, $value2$, $value3$); assertEquals(success, false, "failing weakCompareAndSetAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value1$, "failing weakCompareAndSetAcquire $type$ value"); + assertEquals($value1$, x, "failing weakCompareAndSetAcquire $type$ value"); } { @@ -946,14 +944,14 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSetRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value2$, "success weakCompareAndSetRelease $type$"); + assertEquals($value2$, x, "success weakCompareAndSetRelease $type$"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, $value1$, $value3$); assertEquals(success, false, "failing weakCompareAndSetAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value2$, "failing weakCompareAndSetAcquire $type$ value"); + assertEquals($value2$, x, "failing weakCompareAndSetAcquire $type$ value"); } { @@ -965,14 +963,14 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } assertEquals(success, true, "success weakCompareAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value1$, "success weakCompareAndSet $type$"); + assertEquals($value1$, x, "success weakCompareAndSet $type$"); } { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, $value2$, $value3$); assertEquals(success, false, "failing weakCompareAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value1$, "failing weakCompareAndSet $type$ value"); + assertEquals($value1$, x, "failing weakCompareAndSet $type$ value"); } // Compare set and get @@ -980,27 +978,27 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, $value2$); - assertEquals(o, $value1$, "getAndSet $type$"); + assertEquals($value1$, o, "getAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value2$, "getAndSet $type$ value"); + assertEquals($value2$, x, "getAndSet $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(array, i, $value2$); - assertEquals(o, $value1$, "getAndSetAcquire $type$"); + assertEquals($value1$, o, "getAndSetAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value2$, "getAndSetAcquire $type$ value"); + assertEquals($value2$, x, "getAndSetAcquire $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(array, i, $value2$); - assertEquals(o, $value1$, "getAndSetRelease $type$"); + assertEquals($value1$, o, "getAndSetRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, $value2$, "getAndSetRelease $type$ value"); + assertEquals($value2$, x, "getAndSetRelease $type$ value"); } #end[CAS] @@ -1010,27 +1008,27 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_ADD).invokeExact(array, i, $value2$); - assertEquals(o, $value1$, "getAndAdd $type$"); + assertEquals($value1$, o, "getAndAdd $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAdd $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAdd $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_ADD_ACQUIRE).invokeExact(array, i, $value2$); - assertEquals(o, $value1$, "getAndAddAcquire $type$"); + assertEquals($value1$, o, "getAndAddAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAddAcquire $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAddAcquire $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_ADD_RELEASE).invokeExact(array, i, $value2$); - assertEquals(o, $value1$, "getAndAddRelease $type$"); + assertEquals($value1$, o, "getAndAddRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, ($type$)($value1$ + $value2$), "getAndAddRelease $type$ value"); + assertEquals(($type$)($value1$ + $value2$), x, "getAndAddRelease $type$ value"); } #end[AtomicAdd] @@ -1040,27 +1038,27 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_OR).invokeExact(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseOr $type$"); + assertEquals($value1$, o, "getAndBitwiseOr $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOr $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOr $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_OR_ACQUIRE).invokeExact(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseOrAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseOrAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOrAcquire $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOrAcquire $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_OR_RELEASE).invokeExact(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseOrRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseOrRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, ($type$)($value1$ | $value2$), "getAndBitwiseOrRelease $type$ value"); + assertEquals(($type$)($value1$ | $value2$), x, "getAndBitwiseOrRelease $type$ value"); } // get and bitwise and @@ -1068,27 +1066,27 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_AND).invokeExact(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseAnd $type$"); + assertEquals($value1$, o, "getAndBitwiseAnd $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAnd $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAnd $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_AND_ACQUIRE).invokeExact(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseAndAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseAndAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAndAcquire $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAndAcquire $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_AND_RELEASE).invokeExact(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseAndRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseAndRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, ($type$)($value1$ & $value2$), "getAndBitwiseAndRelease $type$ value"); + assertEquals(($type$)($value1$ & $value2$), x, "getAndBitwiseAndRelease $type$ value"); } // get and bitwise xor @@ -1096,27 +1094,27 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { hs.get(TestAccessMode.SET).invokeExact(array, i, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_XOR).invokeExact(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseXor $type$"); + assertEquals($value1$, o, "getAndBitwiseXor $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXor $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXor $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_ACQUIRE).invokeExact(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseXorAcquire $type$"); + assertEquals($value1$, o, "getAndBitwiseXorAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXorAcquire $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXorAcquire $type$ value"); } { hs.get(TestAccessMode.SET).invokeExact(array, i, $value1$); $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_BITWISE_XOR_RELEASE).invokeExact(array, i, $value2$); - assertEquals(o, $value1$, "getAndBitwiseXorRelease $type$"); + assertEquals($value1$, o, "getAndBitwiseXorRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(x, ($type$)($value1$ ^ $value2$), "getAndBitwiseXorRelease $type$ value"); + assertEquals(($type$)($value1$ ^ $value2$), x, "getAndBitwiseXorRelease $type$ value"); } #end[Bitwise] } diff --git a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template index 85ecf9bb95c..77531cc309f 100644 --- a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template +++ b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,26 +24,26 @@ /* * @test * @bug 8156486 - * @run testng/othervm VarHandleTestMethodType$Type$ - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodType$Type$ - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodType$Type$ - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodType$Type$ + * @run junit/othervm VarHandleTestMethodType$Type$ + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodType$Type$ + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodType$Type$ + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodType$Type$ */ -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.testng.Assert.*; - import static java.lang.invoke.MethodType.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { static final $type$ static_final_v = $value1$; @@ -63,7 +63,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { VarHandle vhArray; - @BeforeClass + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( VarHandleTestMethodType$Type$.class, "final_v", $type$.class); @@ -80,7 +80,6 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { vhArray = MethodHandles.arrayElementVarHandle($type$[].class); } - @DataProvider public Object[][] accessTestCaseProvider() throws Exception { List> cases = new ArrayList<>(); @@ -115,7 +114,8 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); } - @Test(dataProvider = "accessTestCaseProvider") + @ParameterizedTest + @MethodSource("accessTestCaseProvider") public void testAccess(String desc, AccessTestCase atc) throws Throwable { T t = atc.get(); int iters = atc.requiresLoop() ? ITERS : 1; @@ -124,7 +124,6 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { } } - static void testInstanceFieldWrongMethodType(VarHandleTestMethodType$Type$ recv, VarHandle vh) throws Throwable { // Get // Incorrect argument types diff --git a/test/jdk/java/lang/invoke/VarHandles/accessibility/TestFieldLookupAccessibility.java b/test/jdk/java/lang/invoke/VarHandles/accessibility/TestFieldLookupAccessibility.java index 343b15a1caf..11cd6ec233c 100644 --- a/test/jdk/java/lang/invoke/VarHandles/accessibility/TestFieldLookupAccessibility.java +++ b/test/jdk/java/lang/invoke/VarHandles/accessibility/TestFieldLookupAccessibility.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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,14 +27,11 @@ * @compile TestFieldLookupAccessibility.java * pkg/A.java pkg/B_extends_A.java pkg/C.java * pkg/subpkg/B_extends_A.java pkg/subpkg/C.java - * @run testng/othervm --enable-final-field-mutation=ALL-UNNAMED -DwriteAccess=true TestFieldLookupAccessibility - * @run testng/othervm --illegal-final-field-mutation=deny -DwriteAccess=false TestFieldLookupAccessibility + * @run junit/othervm --enable-final-field-mutation=ALL-UNNAMED -DwriteAccess=true TestFieldLookupAccessibility + * @run junit/othervm --illegal-final-field-mutation=deny -DwriteAccess=false TestFieldLookupAccessibility */ -import static org.testng.Assert.*; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.*; import pkg.B_extends_A; import java.lang.invoke.MethodHandles; @@ -48,11 +45,14 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class TestFieldLookupAccessibility { static boolean writeAccess; - @BeforeClass + @BeforeAll static void setup() { String s = System.getProperty("writeAccess"); assertNotNull(s); @@ -188,8 +188,7 @@ public class TestFieldLookupAccessibility { } } - @DataProvider - public Object[][] lookupProvider() throws Exception { + public static Object[][] lookupProvider() throws Exception { Stream> baseCases = Stream.of( // Look up from same package List.of(pkg.A.class, pkg.A.lookup(), pkg.A.inaccessibleFields()), @@ -215,7 +214,8 @@ public class TestFieldLookupAccessibility { return pl.toArray(); } - @Test(dataProvider = "lookupProvider") + @ParameterizedTest + @MethodSource("lookupProvider") public void test(FieldLookup fl, Class src, MethodHandles.Lookup l, Set inaccessibleFields) { // Add to the expected failures all inaccessible fields due to accessibility modifiers Set expected = fl.inaccessibleFields(inaccessibleFields); @@ -240,10 +240,10 @@ public class TestFieldLookupAccessibility { collect(Collectors.toSet()); if (!actualFieldNames.equals(expected)) { if (actualFieldNames.isEmpty()) { - assertEquals(actualFieldNames, expected, "No accessibility failures:"); + assertEquals(expected, actualFieldNames, "No accessibility failures:"); } else { - assertEquals(actualFieldNames, expected, "Accessibility failures differ:"); + assertEquals(expected, actualFieldNames, "Accessibility failures differ:"); } } else { diff --git a/test/jdk/java/lang/invoke/WrongMethodTypeTest.java b/test/jdk/java/lang/invoke/WrongMethodTypeTest.java index be0c59e0d77..32cbfc545ce 100644 --- a/test/jdk/java/lang/invoke/WrongMethodTypeTest.java +++ b/test/jdk/java/lang/invoke/WrongMethodTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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,8 +21,9 @@ * questions. */ -/* @test 8299183 - * @run testng WrongMethodTypeTest +/* @test + * @bug 8299183 + * @run junit WrongMethodTypeTest */ import java.lang.invoke.MethodHandle; @@ -33,9 +34,10 @@ import java.lang.invoke.WrongMethodTypeException; import static java.lang.invoke.MethodType.methodType; -import static org.testng.AssertJUnit.*; +import org.junit.jupiter.api.Test; -import org.testng.annotations.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class WrongMethodTypeTest { static final Lookup LOOKUP = MethodHandles.lookup(); @@ -43,13 +45,11 @@ public class WrongMethodTypeTest { @Test public void checkExactType() throws Throwable { String expectedMessage = "handle's method type (int)int but found ()boolean"; - try { - MethodHandle mh = LOOKUP.findStatic(WrongMethodTypeTest.class, "m", methodType(int.class, int.class)); + MethodHandle mh = LOOKUP.findStatic(WrongMethodTypeTest.class, "m", methodType(int.class, int.class)); + var ex = assertThrows(WrongMethodTypeException.class, () -> { boolean b = (boolean)mh.invokeExact(); - fail("Expected WrongMethodTypeException"); - } catch (WrongMethodTypeException ex) { - assertEquals(expectedMessage, ex.getMessage()); - } + }); + assertEquals(expectedMessage, ex.getMessage()); } @Test @@ -57,11 +57,10 @@ public class WrongMethodTypeTest { String expectedMessage = "handle's method type ()int but found ()Void"; VarHandle vh = LOOKUP.findStaticVarHandle(WrongMethodTypeTest.class, "x", int.class) .withInvokeExactBehavior(); - try { + var ex = assertThrows(WrongMethodTypeException.class, () -> { Void o = (Void) vh.get(); - } catch (WrongMethodTypeException ex) { - assertEquals(expectedMessage, ex.getMessage()); - } + }); + assertEquals(expectedMessage, ex.getMessage()); } @Test @@ -69,11 +68,10 @@ public class WrongMethodTypeTest { String expectedMessage = "handle's method type (WrongMethodTypeTest)boolean but found (WrongMethodTypeTest)int"; VarHandle vh = LOOKUP.findVarHandle(WrongMethodTypeTest.class, "y", boolean.class) .withInvokeExactBehavior(); - try { + var ex = assertThrows(WrongMethodTypeException.class, () -> { int o = (int) vh.get(new WrongMethodTypeTest()); - } catch (WrongMethodTypeException ex) { - assertEquals(expectedMessage, ex.getMessage()); - } + }); + assertEquals(expectedMessage, ex.getMessage()); } static int m(int x) { diff --git a/test/jdk/java/lang/invoke/accessClassAndFindClass/TestAccessClass.java b/test/jdk/java/lang/invoke/accessClassAndFindClass/TestAccessClass.java index 083a357a430..23893655c0a 100644 --- a/test/jdk/java/lang/invoke/accessClassAndFindClass/TestAccessClass.java +++ b/test/jdk/java/lang/invoke/accessClassAndFindClass/TestAccessClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* @test * @bug 8150782 8207027 8266269 * @compile TestAccessClass.java TestCls.java p/Foo.java q/Bar.java - * @run testng/othervm -ea -esa test.java.lang.invoke.TestAccessClass + * @run junit/othervm -ea -esa test.java.lang.invoke.TestAccessClass */ package test.java.lang.invoke; @@ -36,9 +36,11 @@ import q.Bar; import static java.lang.invoke.MethodHandles.*; -import static org.testng.AssertJUnit.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -import org.testng.annotations.*; +import static org.junit.jupiter.api.Assertions.*; public class TestAccessClass { @@ -68,17 +70,19 @@ public class TestAccessClass { assertEquals(Class1[].class, aClass); } - @DataProvider - Object[][] illegalAccessAccess() { + static Object[][] illegalAccessAccess() { return new Object[][] { {publicLookup(), Class1.class}, {publicLookup(), TestCls.getPrivateSIC()} }; } - @Test(dataProvider = "illegalAccessAccess", expectedExceptions = {IllegalAccessException.class}) + @ParameterizedTest + @MethodSource("illegalAccessAccess") public void illegalAccessExceptionTest(Lookup lookup, Class klass) throws IllegalAccessException { - lookup.accessClass(klass); + assertThrows(IllegalAccessException.class, () -> { + lookup.accessClass(klass); + }); } @Test @@ -98,8 +102,8 @@ public class TestAccessClass { mh.invoke(null); } - @Test(expectedExceptions = {NullPointerException.class}) + @Test public void illegalArgument() throws IllegalAccessException { - lookup().accessClass(null); + assertThrows(NullPointerException.class, () -> lookup().accessClass(null)); } } diff --git a/test/jdk/java/lang/invoke/accessClassAndFindClass/TestFindClass.java b/test/jdk/java/lang/invoke/accessClassAndFindClass/TestFindClass.java index 54674729fe3..94ec3c54b4f 100644 --- a/test/jdk/java/lang/invoke/accessClassAndFindClass/TestFindClass.java +++ b/test/jdk/java/lang/invoke/accessClassAndFindClass/TestFindClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* @test * @bug 8150782 8207027 8266269 * @compile TestFindClass.java TestCls.java p/Foo.java q/Bar.java - * @run testng/othervm -ea -esa test.java.lang.invoke.TestFindClass + * @run junit/othervm -ea -esa test.java.lang.invoke.TestFindClass */ package test.java.lang.invoke; @@ -34,9 +34,11 @@ import q.Bar; import static java.lang.invoke.MethodHandles.*; -import static org.testng.AssertJUnit.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -import org.testng.annotations.*; +import static org.junit.jupiter.api.Assertions.*; public class TestFindClass { @@ -68,13 +70,12 @@ public class TestFindClass { assertEquals(Class1[].class, aClass); } - @Test(expectedExceptions = {ClassNotFoundException.class}) + @Test public void classNotFoundExceptionTest() throws IllegalAccessException, ClassNotFoundException { - lookup().findClass(PACKAGE_PREFIX + "TestFindClass$NonExistent"); + assertThrows(ClassNotFoundException.class, () -> lookup().findClass(PACKAGE_PREFIX + "TestFindClass$NonExistent")); } - @DataProvider - Object[][] illegalAccessFind() { + static Object[][] illegalAccessFind() { return new Object[][] { {publicLookup(), PACKAGE_PREFIX + "TestFindClass$Class1"}, {publicLookup(), PACKAGE_PREFIX + "TestCls$PrivateSIC"} @@ -84,9 +85,10 @@ public class TestFindClass { /** * Assertion: @throws IllegalAccessException if the class is not accessible, using the allowed access modes. */ - @Test(dataProvider = "illegalAccessFind", expectedExceptions = {ClassNotFoundException.class}) + @ParameterizedTest + @MethodSource("illegalAccessFind") public void illegalAccessExceptionTest(Lookup lookup, String className) throws IllegalAccessException, ClassNotFoundException { - lookup.findClass(className); + assertThrows(ClassNotFoundException.class, () -> lookup.findClass(className)); } @Test @@ -104,8 +106,8 @@ public class TestFindClass { lookup().findClass("[Lp.Foo$T;"); } - @Test(expectedExceptions = {NullPointerException.class}) + @Test public void illegalArgument() throws IllegalAccessException, ClassNotFoundException { - lookup().findClass(null); + assertThrows(NullPointerException.class, () -> lookup().findClass(null)); } } diff --git a/test/jdk/java/lang/invoke/accessClassAndFindClass/TestLookup.java b/test/jdk/java/lang/invoke/accessClassAndFindClass/TestLookup.java index 555213bedcc..b0f2e00adbc 100644 --- a/test/jdk/java/lang/invoke/accessClassAndFindClass/TestLookup.java +++ b/test/jdk/java/lang/invoke/accessClassAndFindClass/TestLookup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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,15 +23,15 @@ /* @test * @compile TestLookup.java TestCls.java - * @run testng/othervm -ea -esa test.java.lang.invoke.TestLookup + * @run junit/othervm -ea -esa test.java.lang.invoke.TestLookup */ package test.java.lang.invoke; -import org.testng.annotations.Test; - import static java.lang.invoke.MethodHandles.*; -import static org.testng.AssertJUnit.*; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; public class TestLookup { @@ -43,10 +43,10 @@ public class TestLookup { assertNull(lookup2.lookupClass().getClassLoader()); } - @Test(expectedExceptions = {ClassNotFoundException.class}) + @Test public void testPublicCannotLoadUserClass() throws IllegalAccessException, ClassNotFoundException { Lookup lookup = publicLookup(); - lookup.findClass("test.java.lang.invoke.TestCls"); + assertThrows(ClassNotFoundException.class, () -> lookup.findClass("test.java.lang.invoke.TestCls")); } @Test diff --git a/test/jdk/java/lang/invoke/callerSensitive/CallerSensitiveAccess.java b/test/jdk/java/lang/invoke/callerSensitive/CallerSensitiveAccess.java index a6359162629..67aa90ba99c 100644 --- a/test/jdk/java/lang/invoke/callerSensitive/CallerSensitiveAccess.java +++ b/test/jdk/java/lang/invoke/callerSensitive/CallerSensitiveAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* @test * @bug 8196830 8235351 8257874 * @modules java.base/jdk.internal.reflect - * @run testng/othervm CallerSensitiveAccess + * @run junit/othervm CallerSensitiveAccess * @summary Check Lookup findVirtual, findStatic and unreflect behavior with * caller sensitive methods with focus on AccessibleObject.setAccessible */ @@ -50,17 +50,16 @@ import java.util.stream.Stream; import jdk.internal.reflect.CallerSensitive; -import org.testng.annotations.DataProvider; -import org.testng.annotations.NoInjection; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class CallerSensitiveAccess { /** * Caller sensitive methods in APIs exported by java.base. */ - @DataProvider(name = "callerSensitiveMethods") static Object[][] callerSensitiveMethods() { try (Stream stream = callerSensitiveMethods(Object.class.getModule())) { return stream.map(m -> new Object[]{m, shortDescription(m)}) @@ -72,34 +71,35 @@ public class CallerSensitiveAccess { * Using publicLookup, attempt to use findVirtual or findStatic to obtain a * method handle to a caller sensitive method. */ - @Test(dataProvider = "callerSensitiveMethods", - expectedExceptions = IllegalAccessException.class) - public void testPublicLookupFind(@NoInjection Method method, String desc) throws Exception { + @ParameterizedTest + @MethodSource("callerSensitiveMethods") + public void testPublicLookupFind(Method method, String desc) throws Exception { Lookup lookup = MethodHandles.publicLookup(); Class refc = method.getDeclaringClass(); String name = method.getName(); MethodType mt = MethodType.methodType(method.getReturnType(), method.getParameterTypes()); - if (Modifier.isStatic(method.getModifiers())) { - lookup.findStatic(refc, name, mt); - } else { - lookup.findVirtual(refc, name, mt); - } + assertThrows(IllegalAccessException.class, () -> { + if (Modifier.isStatic(method.getModifiers())) { + lookup.findStatic(refc, name, mt); + } else { + lookup.findVirtual(refc, name, mt); + } + }); } /** * Using publicLookup, attempt to use unreflect to obtain a method handle to a * caller sensitive method. */ - @Test(dataProvider = "callerSensitiveMethods", - expectedExceptions = IllegalAccessException.class) - public void testPublicLookupUnreflect(@NoInjection Method method, String desc) throws Exception { - MethodHandles.publicLookup().unreflect(method); + @ParameterizedTest + @MethodSource("callerSensitiveMethods") + public void testPublicLookupUnreflect(Method method, String desc) throws Exception { + assertThrows(IllegalAccessException.class, () -> MethodHandles.publicLookup().unreflect(method)); } /** * public accessible caller sensitive methods in APIs exported by java.base. */ - @DataProvider(name = "accessibleCallerSensitiveMethods") static Object[][] accessibleCallerSensitiveMethods() { try (Stream stream = callerSensitiveMethods(Object.class.getModule())) { return stream @@ -114,41 +114,43 @@ public class CallerSensitiveAccess { * Using publicLookup, attempt to use unreflect to obtain a method handle to a * caller sensitive method. */ - @Test(dataProvider = "accessibleCallerSensitiveMethods", - expectedExceptions = IllegalAccessException.class) - public void testLookupUnreflect(@NoInjection Method method, String desc) throws Exception { - MethodHandles.publicLookup().unreflect(method); + @ParameterizedTest + @MethodSource("accessibleCallerSensitiveMethods") + public void testLookupUnreflect(Method method, String desc) throws Exception { + assertThrows(IllegalAccessException.class, () -> MethodHandles.publicLookup().unreflect(method)); } /** * Using a Lookup with no original access that can't lookup caller-sensitive * method */ - @Test(dataProvider = "callerSensitiveMethods", - expectedExceptions = IllegalAccessException.class) - public void testLookupNoOriginalAccessFind(@NoInjection Method method, String desc) throws Exception { + @ParameterizedTest + @MethodSource("callerSensitiveMethods") + public void testLookupNoOriginalAccessFind(Method method, String desc) throws Exception { Lookup lookup = MethodHandles.lookup().dropLookupMode(Lookup.ORIGINAL); assertTrue(lookup.hasFullPrivilegeAccess()); Class refc = method.getDeclaringClass(); String name = method.getName(); MethodType mt = MethodType.methodType(method.getReturnType(), method.getParameterTypes()); - if (Modifier.isStatic(method.getModifiers())) { - lookup.findStatic(refc, name, mt); - } else { - lookup.findVirtual(refc, name, mt); - } + assertThrows(IllegalAccessException.class, () -> { + if (Modifier.isStatic(method.getModifiers())) { + lookup.findStatic(refc, name, mt); + } else { + lookup.findVirtual(refc, name, mt); + } + }); } /** * Using a Lookup with no original access that can't unreflect caller-sensitive * method */ - @Test(dataProvider = "callerSensitiveMethods", - expectedExceptions = IllegalAccessException.class) - public void testLookupNoOriginalAccessUnreflect(@NoInjection Method method, String desc) throws Exception { + @ParameterizedTest + @MethodSource("callerSensitiveMethods") + public void testLookupNoOriginalAccessUnreflect(Method method, String desc) throws Exception { Lookup lookup = MethodHandles.lookup().dropLookupMode(Lookup.ORIGINAL); assertTrue(lookup.hasFullPrivilegeAccess()); - lookup.unreflect(method); + assertThrows(IllegalAccessException.class, () -> lookup.unreflect(method)); } // -- Test method handles to setAccessible -- @@ -156,21 +158,12 @@ public class CallerSensitiveAccess { private int aField; Field accessibleField() { - try { - return getClass().getDeclaredField("aField"); - } catch (NoSuchFieldException e) { - fail(); - return null; - } + var clazz = getClass(); + return assertDoesNotThrow(() -> clazz.getDeclaredField("aField")); } Field inaccessibleField() { - try { - return String.class.getDeclaredField("hash"); - } catch (NoSuchFieldException e) { - fail(); - return null; - } + return assertDoesNotThrow(() -> String.class.getDeclaredField("hash")); } void findAndInvokeSetAccessible(Class refc, Field f) throws Throwable { @@ -215,23 +208,23 @@ public class CallerSensitiveAccess { * Create a method handle to setAccessible and attempt to use it to suppress * access to an inaccessible member. */ - @Test(expectedExceptions = InaccessibleObjectException.class) + @Test public void testSetAccessible5() throws Throwable { - findAndInvokeSetAccessible(AccessibleObject.class, inaccessibleField()); + assertThrows(InaccessibleObjectException.class, () -> findAndInvokeSetAccessible(AccessibleObject.class, inaccessibleField())); } - @Test(expectedExceptions = InaccessibleObjectException.class) + @Test public void testSetAccessible6() throws Throwable { - findAndInvokeSetAccessible(Field.class, inaccessibleField()); + assertThrows(InaccessibleObjectException.class, () -> findAndInvokeSetAccessible(Field.class, inaccessibleField())); } - @Test(expectedExceptions = InaccessibleObjectException.class) + @Test public void testSetAccessible7() throws Throwable { Method m = AccessibleObject.class.getMethod("setAccessible", boolean.class); - unreflectAndInvokeSetAccessible(m, inaccessibleField()); + assertThrows(InaccessibleObjectException.class, () -> unreflectAndInvokeSetAccessible(m, inaccessibleField())); } - @Test(expectedExceptions = InaccessibleObjectException.class) + @Test public void testSetAccessible8() throws Throwable { Method m = Field.class.getMethod("setAccessible", boolean.class); - unreflectAndInvokeSetAccessible(m, inaccessibleField()); + assertThrows(InaccessibleObjectException.class, () -> unreflectAndInvokeSetAccessible(m, inaccessibleField())); } @@ -241,7 +234,6 @@ public class CallerSensitiveAccess { * Custom AccessibleObject objects. One class overrides setAccessible, the other * does not override this method. */ - @DataProvider(name = "customAccessibleObjects") static Object[][] customAccessibleObjectClasses() { return new Object[][] { { new S1() }, { new S2() } }; } @@ -271,20 +263,20 @@ public class CallerSensitiveAccess { * Using publicLookup, create a method handle to setAccessible and invoke it * on a custom AccessibleObject object. */ - @Test(expectedExceptions = IllegalAccessException.class) + @Test public void testPublicLookupSubclass1() throws Throwable { // S1 does not override setAccessible - findAndInvokeSetAccessible(MethodHandles.publicLookup(), new S1()); + assertThrows(IllegalAccessException.class, () -> findAndInvokeSetAccessible(MethodHandles.publicLookup(), new S1())); } @Test public void testPublicLookupSubclass2() throws Throwable { // S2 overrides setAccessible findAndInvokeSetAccessible(MethodHandles.publicLookup(), new S2()); } - @Test(expectedExceptions = IllegalAccessException.class) + @Test public void testPublicLookupSubclass3() throws Throwable { // S1 does not override setAccessible - unreflectAndInvokeSetAccessible(MethodHandles.publicLookup(), new S1()); + assertThrows(IllegalAccessException.class, () -> unreflectAndInvokeSetAccessible(MethodHandles.publicLookup(), new S1())); } @Test public void testPublicLookupSubclass4() throws Throwable { @@ -296,11 +288,13 @@ public class CallerSensitiveAccess { * Using a full power lookup, create a method handle to setAccessible and * invoke it on a custom AccessibleObject object. */ - @Test(dataProvider = "customAccessibleObjects") + @ParameterizedTest + @MethodSource("customAccessibleObjectClasses") public void testLookupSubclass1(AccessibleObject obj) throws Throwable { findAndInvokeSetAccessible(MethodHandles.lookup(), obj); } - @Test(dataProvider = "customAccessibleObjects") + @ParameterizedTest + @MethodSource("customAccessibleObjectClasses") public void testLookupSubclass2(AccessibleObject obj) throws Throwable { unreflectAndInvokeSetAccessible(MethodHandles.lookup(), obj); } @@ -309,13 +303,13 @@ public class CallerSensitiveAccess { * Using a full power lookup, create a method handle to setAccessible on a * sub-class of AccessibleObject and then attempt to invoke it on a Field object. */ - @Test(dataProvider = "customAccessibleObjects", - expectedExceptions = ClassCastException.class) + @ParameterizedTest + @MethodSource("customAccessibleObjectClasses") public void testLookupSubclass3(AccessibleObject obj) throws Throwable { MethodType mt = MethodType.methodType(void.class, boolean.class); Lookup lookup = MethodHandles.lookup(); MethodHandle mh = lookup.findVirtual(obj.getClass(), "setAccessible", mt); - mh.invoke(accessibleField(), true); // should throw ClassCastException + assertThrows(ClassCastException.class, () -> mh.invoke(accessibleField(), true)); } /** @@ -333,29 +327,29 @@ public class CallerSensitiveAccess { mh.invoke(f, true); assertTrue(f.isAccessible()); } - @Test(expectedExceptions = InaccessibleObjectException.class) + @Test public void testLookupSubclass5() throws Throwable { // S1 does not override setAccessible Method m = S1.class.getMethod("setAccessible", boolean.class); assertTrue(m.getDeclaringClass() == AccessibleObject.class); MethodHandle mh = MethodHandles.lookup().unreflect(m); - mh.invoke(inaccessibleField(), true); // should throw InaccessibleObjectException + assertThrows(InaccessibleObjectException.class, () -> mh.invoke(inaccessibleField(), true)); } - @Test(expectedExceptions = ClassCastException.class) + @Test public void testLookupSubclass6() throws Throwable { // S2 overrides setAccessible Method m = S2.class.getMethod("setAccessible", boolean.class); assertTrue(m.getDeclaringClass() == S2.class); MethodHandle mh = MethodHandles.lookup().unreflect(m); - mh.invoke(accessibleField(), true); // should throw ClassCastException + assertThrows(ClassCastException.class, () -> mh.invoke(accessibleField(), true)); } - @Test(expectedExceptions = ClassCastException.class) + @Test public void testLookupSubclass7() throws Throwable { // S2 overrides setAccessible Method m = S2.class.getMethod("setAccessible", boolean.class); assertTrue(m.getDeclaringClass() == S2.class); MethodHandle mh = MethodHandles.lookup().unreflect(m); - mh.invoke(inaccessibleField(), true); // should throw ClassCastException + assertThrows(ClassCastException.class, () -> mh.invoke(inaccessibleField(), true)); } /** @@ -373,7 +367,7 @@ public class CallerSensitiveAccess { // Field::getInt mh = MethodHandles.lookup().findVirtual(Field.class, "getInt", MethodType.methodType(int.class, Object.class)); int value = (int)mh.invokeExact(f, (Object)null); - assertTrue(value == 5); + assertEquals(5, value); } private static class Inner { @@ -400,7 +394,7 @@ public class CallerSensitiveAccess { * exported by a named module. */ static Stream callerSensitiveMethods(Module module) { - assert module.isNamed(); + assertTrue(module.isNamed()); ModuleReference mref = module.getLayer().configuration() .findModule(module.getName()) .orElseThrow(() -> new RuntimeException()) diff --git a/test/jdk/java/lang/invoke/condy/BootstrapMethodJumboArgsTest.java b/test/jdk/java/lang/invoke/condy/BootstrapMethodJumboArgsTest.java index 0357afce668..4a2ad3f3091 100644 --- a/test/jdk/java/lang/invoke/condy/BootstrapMethodJumboArgsTest.java +++ b/test/jdk/java/lang/invoke/condy/BootstrapMethodJumboArgsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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,12 +27,10 @@ * @summary Test bootstrap methods throwing an exception * @library /java/lang/invoke/common * @build test.java.lang.invoke.lib.InstructionHelper - * @run testng BootstrapMethodJumboArgsTest - * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 BootstrapMethodJumboArgsTest + * @run junit BootstrapMethodJumboArgsTest + * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 BootstrapMethodJumboArgsTest */ -import org.testng.Assert; -import org.testng.annotations.Test; import test.java.lang.invoke.lib.InstructionHelper; import java.lang.invoke.ConstantCallSite; @@ -43,6 +41,10 @@ import java.util.stream.IntStream; import static java.lang.invoke.MethodType.methodType; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + public class BootstrapMethodJumboArgsTest { static final MethodHandles.Lookup L = MethodHandles.lookup(); @@ -93,7 +95,7 @@ public class BootstrapMethodJumboArgsTest { Object.class, Object[].class), expected); Object[] actual = (Object[]) mh.invoke(); - Assert.assertEquals(actual, expected); + assertArrayEquals(expected, actual); } { @@ -103,7 +105,7 @@ public class BootstrapMethodJumboArgsTest { Object.class, Object.class, Object[].class), expected); Object[] actual = (Object[]) mh.invoke(); - Assert.assertEquals(actual, expected); + assertArrayEquals(expected, actual); } { @@ -113,7 +115,7 @@ public class BootstrapMethodJumboArgsTest { Object.class, Object.class, Object.class, Object[].class), expected); Object[] actual = (Object[]) mh.invoke(); - Assert.assertEquals(actual, expected); + assertArrayEquals(expected, actual); } } @@ -128,7 +130,7 @@ public class BootstrapMethodJumboArgsTest { Object.class, Object[].class), expected); Object[] actual = (Object[]) mh.invoke(); - Assert.assertEquals(actual, expected); + assertArrayEquals(expected, actual); } { @@ -138,7 +140,7 @@ public class BootstrapMethodJumboArgsTest { Object.class, Object.class, Object[].class), expected); Object[] actual = (Object[]) mh.invoke(); - Assert.assertEquals(actual, expected); + assertArrayEquals(expected, actual); } { @@ -148,7 +150,7 @@ public class BootstrapMethodJumboArgsTest { Object.class, Object.class, Object.class, Object[].class), expected); Object[] actual = (Object[]) mh.invoke(); - Assert.assertEquals(actual, expected); + assertArrayEquals(expected, actual); } } } diff --git a/test/jdk/java/lang/invoke/condy/CondyBSMException.java b/test/jdk/java/lang/invoke/condy/CondyBSMException.java index 7aa25c5cd95..1c9f867bc8b 100644 --- a/test/jdk/java/lang/invoke/condy/CondyBSMException.java +++ b/test/jdk/java/lang/invoke/condy/CondyBSMException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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,12 +27,10 @@ * @summary Test bootstrap methods throwing an exception * @library /java/lang/invoke/common * @build test.java.lang.invoke.lib.InstructionHelper - * @run testng CondyBSMException - * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyBSMException + * @run junit CondyBSMException + * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyBSMException */ -import org.testng.Assert; -import org.testng.annotations.Test; import test.java.lang.invoke.lib.InstructionHelper; import java.lang.invoke.MethodHandle; @@ -41,6 +39,10 @@ import java.lang.reflect.Constructor; import static java.lang.invoke.MethodType.methodType; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + public class CondyBSMException { @Test @@ -70,26 +72,17 @@ public class CondyBSMException { static void test(String message, Class... ts) { MethodHandle mh = thrower(message, ts[ts.length - 1]); - Throwable caught = null; - try { - mh.invoke(); - } catch (Throwable t) { - caught = t; - } - - if (caught == null) { - Assert.fail("Throwable expected"); - } + Throwable caught = assertThrows(Throwable.class, mh::invoke); String actualMessage = null; for (int i = 0; i < ts.length; i++) { + int level = i; + assertInstanceOf(ts[i], caught, () -> "Level %d".formatted(level)); actualMessage = caught.getMessage(); - Assert.assertNotNull(caught); - Assert.assertTrue(ts[i].isAssignableFrom(caught.getClass())); caught = caught.getCause(); } - Assert.assertEquals(actualMessage, message); + assertEquals(message, actualMessage); } static Throwable throwingBsm(MethodHandles.Lookup l, String name, Class type) throws Throwable { diff --git a/test/jdk/java/lang/invoke/condy/CondyBSMInvocation.java b/test/jdk/java/lang/invoke/condy/CondyBSMInvocation.java index e9050126a79..897ee40b444 100644 --- a/test/jdk/java/lang/invoke/condy/CondyBSMInvocation.java +++ b/test/jdk/java/lang/invoke/condy/CondyBSMInvocation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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,13 +27,10 @@ * @summary Test basic invocation of bootstrap methods * @library /java/lang/invoke/common * @build test.java.lang.invoke.lib.InstructionHelper - * @run testng CondyBSMInvocation - * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyBSMInvocation + * @run junit CondyBSMInvocation + * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyBSMInvocation */ - -import org.testng.Assert; -import org.testng.annotations.Test; import test.java.lang.invoke.lib.InstructionHelper; import java.lang.constant.ConstantDesc; @@ -48,6 +45,10 @@ import java.util.stream.Stream; import static java.lang.invoke.MethodType.methodType; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + public class CondyBSMInvocation { static final MethodHandles.Lookup L = MethodHandles.lookup(); @@ -59,11 +60,7 @@ public class CondyBSMInvocation { "bsm", methodType(Object.class) ); - try { - mh.invoke(); - Assert.fail("NoSuchMethodError expected to be thrown"); - } catch (NoSuchMethodError e) { - } + assertThrows(NoSuchMethodError.class, mh::invoke); } static MethodHandle[] bsms(String bsmName) { @@ -114,11 +111,7 @@ public class CondyBSMInvocation { "shape_bsm", bsm.type() ); - try { - Object r = mh.invoke(); - Assert.fail("BootstrapMethodError expected to be thrown for " + bsm); - } catch (BootstrapMethodError e) { - } + assertThrows(BootstrapMethodError.class, mh::invoke); } } @@ -139,11 +132,7 @@ public class CondyBSMInvocation { "sig_bsm", bsm.type() ); - try { - Object r = mh.invoke(); - Assert.fail("BootstrapMethodError expected to be thrown for " + bsm); - } catch (BootstrapMethodError e) { - } + assertThrows(BootstrapMethodError.class, mh::invoke); } } @@ -202,7 +191,7 @@ public class CondyBSMInvocation { static void assertAll(Object... as) { for (int i = 0; i < as.length; i++) { - Assert.assertEquals(as[i], i); + assertEquals(i, as[i]); } } @@ -219,7 +208,7 @@ public class CondyBSMInvocation { ); Object r = mh.invoke(); - Assert.assertEquals(r, Integer.toString(n)); + assertEquals(Integer.toString(n), r); } { @@ -231,7 +220,7 @@ public class CondyBSMInvocation { ); Object r = mh.invoke(); - Assert.assertEquals(r, Integer.toString(9)); + assertEquals(Integer.toString(9), r); } } @@ -248,13 +237,8 @@ public class CondyBSMInvocation { IntStream.range(0, n - 1).boxed().toArray(ConstantDesc[]::new) ); - try { - Object r = mh.invoke(); - Assert.fail("BootstrapMethodError expected to be thrown for arrity " + n); - } catch (BootstrapMethodError e) { - Throwable t = e.getCause(); - Assert.assertTrue(WrongMethodTypeException.class.isAssignableFrom(t.getClass())); - } + var e = assertThrows(BootstrapMethodError.class, mh::invoke); + assertInstanceOf(WrongMethodTypeException.class, e.getCause()); } } } diff --git a/test/jdk/java/lang/invoke/condy/CondyBSMValidationTest.java b/test/jdk/java/lang/invoke/condy/CondyBSMValidationTest.java index d255202866f..e6c2aacea63 100644 --- a/test/jdk/java/lang/invoke/condy/CondyBSMValidationTest.java +++ b/test/jdk/java/lang/invoke/condy/CondyBSMValidationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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,28 +27,29 @@ * @summary Test invalid name in name and type * @library /java/lang/invoke/common * @build test.java.lang.invoke.lib.InstructionHelper - * @run testng CondyBSMValidationTest - * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyBSMValidationTest + * @run junit CondyBSMValidationTest + * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyBSMValidationTest */ -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import test.java.lang.invoke.lib.InstructionHelper; -import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.util.stream.Stream; import static java.lang.invoke.MethodType.methodType; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class CondyBSMValidationTest { static final MethodHandles.Lookup L = MethodHandles.lookup(); static final String BSM_TYPE = methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class) .toMethodDescriptorString(); - @DataProvider - public Object[][] invalidSignaturesProvider() throws Exception { + public static Object[][] invalidSignaturesProvider() throws Exception { return Stream.of(BSM_TYPE.replace("(", ""), BSM_TYPE.replace(")", ""), BSM_TYPE.replace("(", "").replace(")", ""), @@ -57,15 +58,13 @@ public class CondyBSMValidationTest { .map(e -> new Object[]{e}).toArray(Object[][]::new); } - @Test(dataProvider = "invalidSignaturesProvider") + @ParameterizedTest + @MethodSource("invalidSignaturesProvider") public void testInvalidBSMSignature(String sig) throws Exception { - try { - MethodHandle mh = InstructionHelper.ldcDynamicConstant( - L, "name", "Ljava/lang/Object;", - "bsm", sig - ); - } catch (IllegalArgumentException e) { - Assert.assertTrue(e.getMessage().contains("Bad method descriptor")); - } + var e = assertThrows(IllegalArgumentException.class, () -> InstructionHelper.ldcDynamicConstant( + L, "name", "Ljava/lang/Object;", + "bsm", sig + )); + assertTrue(e.getMessage().contains("Bad method descriptor")); } } diff --git a/test/jdk/java/lang/invoke/condy/CondyInterfaceWithOverpassMethods.java b/test/jdk/java/lang/invoke/condy/CondyInterfaceWithOverpassMethods.java index 9fd35ed21f0..fe477d87657 100644 --- a/test/jdk/java/lang/invoke/condy/CondyInterfaceWithOverpassMethods.java +++ b/test/jdk/java/lang/invoke/condy/CondyInterfaceWithOverpassMethods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,20 +27,20 @@ * @summary Test for an interface using condy with default overpass methods * @library /java/lang/invoke/common * @build test.java.lang.invoke.lib.InstructionHelper - * @run testng CondyInterfaceWithOverpassMethods - * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyInterfaceWithOverpassMethods + * @run junit CondyInterfaceWithOverpassMethods + * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyInterfaceWithOverpassMethods */ import java.lang.classfile.ClassFile; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; import test.java.lang.invoke.lib.InstructionHelper; import java.lang.constant.*; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -@Test +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + public class CondyInterfaceWithOverpassMethods { interface A { int a(); @@ -52,14 +52,14 @@ public class CondyInterfaceWithOverpassMethods { // Generated class with methods containing condy ldc - Class gc; + static Class gc; public static Object bsm(MethodHandles.Lookup l, String name, Class type) { return name; } - @BeforeClass - public void generateClass() throws Exception { + @BeforeAll + public static void generateClass() throws Exception { // interface B extends A { // // Overpass for method A.a // diff --git a/test/jdk/java/lang/invoke/condy/CondyNameValidationTest.java b/test/jdk/java/lang/invoke/condy/CondyNameValidationTest.java index 6178b85236b..b380c28dc94 100644 --- a/test/jdk/java/lang/invoke/condy/CondyNameValidationTest.java +++ b/test/jdk/java/lang/invoke/condy/CondyNameValidationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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,13 +27,10 @@ * @summary Test invalid name in name and type * @library /java/lang/invoke/common * @build test.java.lang.invoke.lib.InstructionHelper - * @run testng CondyNameValidationTest - * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyNameValidationTest + * @run junit CondyNameValidationTest + * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyNameValidationTest */ -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import test.java.lang.invoke.lib.InstructionHelper; import java.lang.invoke.MethodHandle; @@ -43,12 +40,17 @@ import java.util.stream.Stream; import static java.lang.invoke.MethodType.methodType; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class CondyNameValidationTest { static final MethodHandles.Lookup L = MethodHandles.lookup(); static final MethodType BSM_TYPE = methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class); - @DataProvider - public Object[][] invalidNamesProvider() { + public static Object[][] invalidNamesProvider() { return Stream.of( new Object[]{"", "zero-length member name"}, new Object[]{".", "Invalid member name"}, @@ -59,26 +61,24 @@ public class CondyNameValidationTest { .toArray(Object[][]::new); } - @Test(dataProvider = "invalidNamesProvider") + @ParameterizedTest + @MethodSource("invalidNamesProvider") public void testInvalidNames(String name, String errMessContent) throws Exception { - try { - MethodHandle mh = InstructionHelper.ldcDynamicConstant( - L, name, Object.class, - "bsm", BSM_TYPE - ); - } catch (IllegalArgumentException e) { - Assert.assertTrue(e.getMessage().contains(errMessContent)); - } + var e = assertThrows(IllegalArgumentException.class, () -> InstructionHelper.ldcDynamicConstant( + L, name, Object.class, + "bsm", BSM_TYPE + )); + assertTrue(e.getMessage().contains(errMessContent)); } - @DataProvider - public Object[][] validNamesProvider() throws Exception { + public static Object[][] validNamesProvider() throws Exception { return Stream.of("", "") .map(e -> new Object[]{e}).toArray(Object[][]::new); } - @Test(dataProvider = "validNamesProvider") + @ParameterizedTest + @MethodSource("validNamesProvider") public void testValidNames(String name) throws Exception { MethodHandle mh = InstructionHelper.ldcDynamicConstant( L, name, Object.class, diff --git a/test/jdk/java/lang/invoke/condy/CondyNestedTest.java b/test/jdk/java/lang/invoke/condy/CondyNestedTest.java index 8eb71ec93a3..192bbeaa46f 100644 --- a/test/jdk/java/lang/invoke/condy/CondyNestedTest.java +++ b/test/jdk/java/lang/invoke/condy/CondyNestedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,24 +26,25 @@ * @bug 8186046 * @summary Test nested dynamic constant declarations that are recursive * @compile CondyNestedTest_Code.jcod - * @run testng CondyNestedTest - * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyNestedTest + * @run junit CondyNestedTest + * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyNestedTest */ -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandles; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + public class CondyNestedTest { static final Class[] THROWABLES = {InvocationTargetException.class, StackOverflowError.class}; private static final MethodHandles.Lookup L = MethodHandles.lookup(); - Class c; + static Class c; // static final MethodHandles.Lookup L = MethodHandles.lookup(); // @@ -243,28 +244,17 @@ public class CondyNestedTest { // } static void test(Method m, Class... ts) { - Throwable caught = null; - try { - m.invoke(null); - } catch (Throwable t) { - caught = t; - } + Throwable caught = assertThrows(Throwable.class, () -> m.invoke(null)); - if (caught == null) { - Assert.fail("Throwable expected"); - } - - String actualMessage = null; for (int i = 0; i < ts.length; i++) { - actualMessage = caught.getMessage(); - Assert.assertNotNull(caught); - Assert.assertTrue(ts[i].isAssignableFrom(caught.getClass())); + int level = i; + assertInstanceOf(ts[i], caught, () -> "Level %d".formatted(level)); caught = caught.getCause(); } } - @BeforeClass - public void findClass() throws Exception { + @BeforeAll + public static void findClass() throws Exception { c = Class.forName("CondyNestedTest_Code"); } diff --git a/test/jdk/java/lang/invoke/condy/CondyRepeatFailedResolution.java b/test/jdk/java/lang/invoke/condy/CondyRepeatFailedResolution.java index 7ef5c610150..b7ccb4944fb 100644 --- a/test/jdk/java/lang/invoke/condy/CondyRepeatFailedResolution.java +++ b/test/jdk/java/lang/invoke/condy/CondyRepeatFailedResolution.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,28 +26,28 @@ * @bug 8186211 * @summary Test basic invocation of multiple ldc's of the same dynamic constant that fail resolution * @library /java/lang/invoke/common - * @run testng CondyRepeatFailedResolution - * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyRepeatFailedResolution + * @run junit CondyRepeatFailedResolution + * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyRepeatFailedResolution */ import java.lang.classfile.ClassFile; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - import java.lang.constant.*; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -@Test +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + public class CondyRepeatFailedResolution { // Counter used to determine if a given BSM is invoked more than once static int bsm_called = 0; // Generated class with methods containing condy ldc - Class gc; + static Class gc; // Bootstrap method used to represent primitive values // that cannot be represented directly in the constant pool, @@ -90,8 +90,8 @@ public class CondyRepeatFailedResolution { } } - @BeforeClass - public void generateClass() throws Exception { + @BeforeAll + public static void generateClass() throws Exception { String genClassName = CondyRepeatFailedResolution.class.getSimpleName() + "$Code"; String bsmClassDesc = CondyRepeatFailedResolution.class.descriptorString(); String bsmMethodName = "intConversion"; @@ -319,29 +319,21 @@ public class CondyRepeatFailedResolution { Method m = gc.getDeclaredMethod(name); bsm_called = 0; - try { + InvocationTargetException e1 = assertThrows(InvocationTargetException.class, () -> { Object r1 = m.invoke(null); - Assert.fail("InvocationTargetException expected to be thrown after first invocation"); - } catch (InvocationTargetException e1) { - // bsm_called should have been incremented prior to the exception - Assert.assertEquals(bsm_called, 1); - Assert.assertTrue(e1.getCause() instanceof BootstrapMethodError); - // Try invoking method again to ensure that the bootstrap - // method is not invoked twice and a resolution failure - // results. - try { - Object r2 = m.invoke(null); - Assert.fail("InvocationTargetException expected to be thrown after second invocation"); - } catch (InvocationTargetException e2) { - // bsm_called should remain at 1 since the bootstrap - // method should not have been invoked. - Assert.assertEquals(bsm_called, 1); - Assert.assertTrue(e2.getCause() instanceof BootstrapMethodError); - } catch (Throwable t2) { - Assert.fail("InvocationTargetException expected to be thrown"); - } - } catch (Throwable t1) { - Assert.fail("InvocationTargetException expected to be thrown"); - } + }); + // bsm_called should have been incremented prior to the exception + assertEquals(1, bsm_called); + assertInstanceOf(BootstrapMethodError.class, e1.getCause()); + // Try invoking method again to ensure that the bootstrap + // method is not invoked twice and a resolution failure + // results. + InvocationTargetException e2 = assertThrows(InvocationTargetException.class, () -> { + Object r2 = m.invoke(null); + }); + // bsm_called should remain at 1 since the bootstrap + // method should not have been invoked. + assertEquals(1, bsm_called); + assertInstanceOf(BootstrapMethodError.class, e2.getCause()); } } diff --git a/test/jdk/java/lang/invoke/condy/CondyReturnPrimitiveTest.java b/test/jdk/java/lang/invoke/condy/CondyReturnPrimitiveTest.java index d6c0748c97c..4c0dd42a1a2 100644 --- a/test/jdk/java/lang/invoke/condy/CondyReturnPrimitiveTest.java +++ b/test/jdk/java/lang/invoke/condy/CondyReturnPrimitiveTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,23 @@ * @test * @bug 8186046 * @summary Test for condy BSMs returning primitive values or null - * @run testng CondyReturnPrimitiveTest - * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyReturnPrimitiveTest + * @run junit CondyReturnPrimitiveTest + * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyReturnPrimitiveTest */ import java.lang.classfile.ClassFile; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - import java.lang.constant.*; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Method; import java.util.concurrent.atomic.AtomicInteger; -@Test +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class CondyReturnPrimitiveTest { // Counter for number of BSM calls // Use of an AtomicInteger is not strictly necessary in this test @@ -49,7 +50,7 @@ public class CondyReturnPrimitiveTest { // constant so care should be taken if a BSM operates on shared state static final AtomicInteger callCount = new AtomicInteger(); // Generated class with methods containing condy ldc - Class gc; + static Class gc; // Bootstrap method used to represent primitive values // that cannot be represented directly in the constant pool, @@ -90,8 +91,8 @@ public class CondyReturnPrimitiveTest { } } - @BeforeClass - public void generateClass() throws Exception { + @BeforeAll + public static void generateClass() throws Exception { String genClassName = CondyReturnPrimitiveTest.class.getSimpleName() + "$Code"; String bsmClassDesc = CondyReturnPrimitiveTest.class.descriptorString(); String bsmMethodName = "intConversion"; @@ -293,7 +294,7 @@ public class CondyReturnPrimitiveTest { // Ensure when run a second time that the bootstrap method is not // invoked and the constants are cached testConstants(); - Assert.assertEquals(callCount.get(), expectedCallCount); + assertEquals(expectedCallCount, callCount.get()); } @Test @@ -318,11 +319,16 @@ public class CondyReturnPrimitiveTest { testConstant("S", Short.MAX_VALUE); testConstant("Z_F", false); testConstant("Z_T", true); - testConstant("null", null); + testConstant("null", (Object) null); } void testConstant(String name, Object expected) throws Exception { Method m = gc.getDeclaredMethod(name); - Assert.assertEquals(m.invoke(null), expected); + assertEquals(expected, m.invoke(null)); + } + + void testConstant(String name, Object[] expected) throws Exception { + Method m = gc.getDeclaredMethod(name); + assertArrayEquals(expected, (Object[]) m.invoke(null)); } } diff --git a/test/jdk/java/lang/invoke/condy/CondyStaticArgumentsTest.java b/test/jdk/java/lang/invoke/condy/CondyStaticArgumentsTest.java index ba3d0e81488..075eaf4e844 100644 --- a/test/jdk/java/lang/invoke/condy/CondyStaticArgumentsTest.java +++ b/test/jdk/java/lang/invoke/condy/CondyStaticArgumentsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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,12 +27,10 @@ * @summary Test bootstrap arguments for condy * @library /java/lang/invoke/common * @build test.java.lang.invoke.lib.InstructionHelper - * @run testng CondyStaticArgumentsTest - * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyStaticArgumentsTest + * @run junit CondyStaticArgumentsTest + * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyStaticArgumentsTest */ -import org.testng.Assert; -import org.testng.annotations.Test; import test.java.lang.invoke.lib.InstructionHelper; import java.lang.constant.*; @@ -44,6 +42,9 @@ import java.util.StringJoiner; import java.util.stream.Stream; import static java.lang.invoke.MethodType.methodType; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class CondyStaticArgumentsTest { static final MethodHandles.Lookup L = MethodHandles.lookup(); @@ -109,7 +110,7 @@ public class CondyStaticArgumentsTest { mhi.getName(), MethodTypeDesc.ofDescriptor(mhi.getMethodType().descriptorString())) ); - Assert.assertEquals(mh.invoke(), "constant-name-String-1-2-3.0-4.0-Number-something-(int,long,float,double)void-11"); + assertEquals("constant-name-String-1-2-3.0-4.0-Number-something-(int,long,float,double)void-11", mh.invoke()); } static MathContext mathContext(MethodHandles.Lookup l, String value, Class type) { @@ -161,7 +162,7 @@ public class CondyStaticArgumentsTest { ) ) ); - Assert.assertEquals(mh.invoke(), "big-decimal-math-context-String-3.141593-7"); + assertEquals("big-decimal-math-context-String-3.141593-7", mh.invoke()); } @@ -194,7 +195,7 @@ public class CondyStaticArgumentsTest { InstructionHelper.classDesc(MathContext.class) ) )); - Assert.assertEquals(mh.invoke(), "big-decimal-math-context-()Ljava/lang/String;-3.141593-7"); + assertEquals("big-decimal-math-context-()Ljava/lang/String;-3.141593-7", mh.invoke()); } private static DirectMethodHandleDesc directMhDesc(String methodName) { diff --git a/test/jdk/java/lang/invoke/condy/CondyTypeValidationTest.java b/test/jdk/java/lang/invoke/condy/CondyTypeValidationTest.java index c44179ce13c..4429468bd34 100644 --- a/test/jdk/java/lang/invoke/condy/CondyTypeValidationTest.java +++ b/test/jdk/java/lang/invoke/condy/CondyTypeValidationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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,12 +27,9 @@ * @summary Test invalid name in name and type * @library /java/lang/invoke/common * @build test.java.lang.invoke.lib.InstructionHelper - * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyTypeValidationTest + * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyTypeValidationTest */ -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import test.java.lang.invoke.lib.InstructionHelper; import java.lang.invoke.MethodHandle; @@ -43,14 +40,18 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import static java.lang.invoke.MethodType.methodType; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class CondyTypeValidationTest { static final MethodHandles.Lookup L = MethodHandles.lookup(); static final String BSM_TYPE = methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class) .toMethodDescriptorString(); - @DataProvider - public Object[][] invalidTypesProvider() { + public static Object[][] invalidTypesProvider() { return Stream.of( // ByteCode API checks for the following invalid types // "", @@ -66,20 +67,19 @@ public class CondyTypeValidationTest { ).toArray(Object[][]::new); } - @Test(dataProvider = "invalidTypesProvider") + @ParameterizedTest + @MethodSource("invalidTypesProvider") public void testInvalidTypes(String type, String errMessContent) throws Exception { - try { + var e = assertThrows(IllegalArgumentException.class, () -> { MethodHandle mh = InstructionHelper.ldcDynamicConstant( L, "name", type, "bsm", BSM_TYPE ); - } catch (IllegalArgumentException e) { - Assert.assertTrue(e.getMessage().contains(errMessContent)); - } + }); + assertTrue(e.getMessage().contains(errMessContent)); } - @DataProvider - public Object[][] validTypesProvider() { + public static Object[][] validTypesProvider() { List t = new ArrayList<>(List.of("B", "C", "D", "F", "I", "J", "Ljava/lang/Object;", "S", "Z")); int l = t.size(); for (int i = 0; i < l; i++) { @@ -90,7 +90,8 @@ public class CondyTypeValidationTest { .map(e -> new Object[]{e}).toArray(Object[][]::new); } - @Test(dataProvider = "validTypesProvider") + @ParameterizedTest + @MethodSource("validTypesProvider") public void testValidTypes(String type) throws Exception { MethodHandle mh = InstructionHelper.ldcDynamicConstant( L, "name", type, diff --git a/test/jdk/java/lang/invoke/condy/CondyWithGarbageTest.java b/test/jdk/java/lang/invoke/condy/CondyWithGarbageTest.java index 5e301a193dd..a00f93b69b7 100644 --- a/test/jdk/java/lang/invoke/condy/CondyWithGarbageTest.java +++ b/test/jdk/java/lang/invoke/condy/CondyWithGarbageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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,21 +27,20 @@ * @summary Stress test ldc to ensure HotSpot correctly manages oop maps * @library /java/lang/invoke/common * @build test.java.lang.invoke.lib.InstructionHelper - * @run testng CondyWithGarbageTest - * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyWithGarbageTest + * @run junit CondyWithGarbageTest + * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyWithGarbageTest */ - import java.lang.classfile.ClassFile; import java.lang.classfile.CodeBuilder; -import org.testng.Assert; -import org.testng.annotations.Test; - import java.lang.constant.*; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import static java.lang.invoke.MethodType.methodType; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; import static test.java.lang.invoke.lib.InstructionHelper.classDesc; public class CondyWithGarbageTest { @@ -54,7 +53,7 @@ public class CondyWithGarbageTest { for (int i = 0; i < 100000; i++) { l += +((String) mh.invoke()).length(); } - Assert.assertTrue(l > 0); + assertTrue(l > 0); } public static Object bsmString(MethodHandles.Lookup l, @@ -133,7 +132,7 @@ public class CondyWithGarbageTest { for (int i = 0; i < 100000; i++) { l += +((String) mh.invoke()).length(); } - Assert.assertTrue(l > 0); + assertTrue(l > 0); } public static Object bsmStringArray(MethodHandles.Lookup l, diff --git a/test/jdk/java/lang/invoke/condy/CondyWrongType.java b/test/jdk/java/lang/invoke/condy/CondyWrongType.java index 42c69e8ab7d..1c00da922fe 100644 --- a/test/jdk/java/lang/invoke/condy/CondyWrongType.java +++ b/test/jdk/java/lang/invoke/condy/CondyWrongType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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,13 +27,10 @@ * @summary Test bootstrap methods returning the wrong type * @library /java/lang/invoke/common * @build test.java.lang.invoke.lib.InstructionHelper - * @run testng CondyWrongType - * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyWrongType + * @run junit CondyWrongType + * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyWrongType */ -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import test.java.lang.invoke.lib.InstructionHelper; import java.lang.invoke.MethodHandle; @@ -46,11 +43,15 @@ import java.util.List; import java.util.Map; import static java.lang.invoke.MethodType.methodType; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.*; public class CondyWrongType { - @DataProvider - public Object[][] primitivesProvider() throws Exception { + public static Object[][] primitivesProvider() throws Exception { Map> typeMap = Map.of( "B", byte.class, "C", char.class, @@ -81,7 +82,8 @@ public class CondyWrongType { return cases.stream().toArray(Object[][]::new); } - @Test(dataProvider = "primitivesProvider") + @ParameterizedTest + @MethodSource("primitivesProvider") public void testPrimitives(String name, String type, boolean pass) { test(name, type, pass); } @@ -106,27 +108,12 @@ public class CondyWrongType { static void test(String name, String type, boolean pass) { MethodHandle mh = caster(name, type); - Throwable caught = null; - try { - mh.invoke(); - } catch (Throwable t) { - caught = t; + if (pass) { + assertDoesNotThrow(() -> mh.invoke()); + } else { + Throwable caught = assertThrows(BootstrapMethodError.class, () -> mh.invoke()); + assertInstanceOf(ClassCastException.class, caught.getCause()); } - - if (caught == null) { - if (pass) { - return; - } else { - Assert.fail("Throwable expected"); - } - } else if (pass) { - Assert.fail("Throwable not expected"); - } - - Assert.assertTrue(BootstrapMethodError.class.isAssignableFrom(caught.getClass())); - caught = caught.getCause(); - Assert.assertNotNull(caught); - Assert.assertTrue(ClassCastException.class.isAssignableFrom(caught.getClass())); } static Object bsm(MethodHandles.Lookup l, String name, Class type) { diff --git a/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java b/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java index 829f26704f9..cef5a17eda1 100644 --- a/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java +++ b/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java @@ -27,27 +27,31 @@ * @summary Test dynamic constant bootstraps * @library /java/lang/invoke/common * @build test.java.lang.invoke.lib.InstructionHelper - * @run testng ConstantBootstrapsTest - * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 ConstantBootstrapsTest + * @run junit ConstantBootstrapsTest + * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 ConstantBootstrapsTest */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import test.java.lang.invoke.lib.InstructionHelper; - import java.lang.constant.ConstantDescs; import java.lang.constant.DirectMethodHandleDesc; import java.lang.constant.MethodHandleDesc; -import java.lang.invoke.*; +import java.lang.invoke.ConstantBootstraps; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.VarHandle; +import java.lang.invoke.WrongMethodTypeException; import java.math.BigInteger; import java.util.Collection; import java.util.List; import java.util.Map; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import test.java.lang.invoke.lib.InstructionHelper; + +import static org.junit.jupiter.api.Assertions.*; -@Test public class ConstantBootstrapsTest { static final MethodHandles.Lookup L = MethodHandles.lookup(); @@ -56,6 +60,7 @@ public class ConstantBootstrapsTest { appendParameterTypes(params); } + @Test public void testNullConstant() throws Throwable { var handle = InstructionHelper.ldcDynamicConstant(L, "_", Object.class, ConstantBootstraps.class, "nullConstant", lookupMT(Object.class)); @@ -66,12 +71,13 @@ public class ConstantBootstrapsTest { assertNull(handle.invoke()); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testNullConstantPrimitiveClass() { - ConstantBootstraps.nullConstant(MethodHandles.lookup(), null, int.class); + assertThrows(IllegalArgumentException.class, () -> ConstantBootstraps.nullConstant(MethodHandles.lookup(), null, int.class)); } + @Test public void testPrimitiveClass() throws Throwable { var pm = Map.of( "I", int.class, @@ -88,69 +94,73 @@ public class ConstantBootstrapsTest { for (var desc : pm.keySet()) { var handle = InstructionHelper.ldcDynamicConstant(L, desc, Class.class, ConstantBootstraps.class, "primitiveClass", lookupMT(Class.class)); - assertEquals(handle.invoke(), pm.get(desc)); + assertEquals(pm.get(desc), handle.invoke()); } } - @Test(expectedExceptions = NullPointerException.class) + @Test public void testPrimitiveClassNullName() { - ConstantBootstraps.primitiveClass(MethodHandles.lookup(), null, Class.class); + assertThrows(NullPointerException.class, () -> ConstantBootstraps.primitiveClass(MethodHandles.lookup(), null, Class.class)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void testPrimitiveClassNullType() { - ConstantBootstraps.primitiveClass(MethodHandles.lookup(), "I", null); + assertThrows(NullPointerException.class, () -> ConstantBootstraps.primitiveClass(MethodHandles.lookup(), "I", null)); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testPrimitiveClassEmptyName() { - ConstantBootstraps.primitiveClass(MethodHandles.lookup(), "", Class.class); + assertThrows(IllegalArgumentException.class, () -> ConstantBootstraps.primitiveClass(MethodHandles.lookup(), "", Class.class)); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testPrimitiveClassWrongNameChar() { - ConstantBootstraps.primitiveClass(MethodHandles.lookup(), "L", Class.class); + assertThrows(IllegalArgumentException.class, () -> ConstantBootstraps.primitiveClass(MethodHandles.lookup(), "L", Class.class)); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testPrimitiveClassWrongNameString() { - ConstantBootstraps.primitiveClass(MethodHandles.lookup(), "Ljava/lang/Object;", Class.class); + assertThrows(IllegalArgumentException.class, () -> ConstantBootstraps.primitiveClass(MethodHandles.lookup(), "Ljava/lang/Object;", Class.class)); } + @Test public void testEnumConstant() throws Throwable { for (var v : StackWalker.Option.values()) { var handle = InstructionHelper.ldcDynamicConstant(L, v.name(), StackWalker.Option.class, ConstantBootstraps.class, "enumConstant", lookupMT(Enum.class)); - assertEquals(handle.invoke(), v); + assertEquals(v, handle.invoke()); } } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testEnumConstantUnknown() { - ConstantBootstraps.enumConstant(MethodHandles.lookup(), "DOES_NOT_EXIST", StackWalker.Option.class); + assertThrows(IllegalArgumentException.class, () -> ConstantBootstraps.enumConstant(MethodHandles.lookup(), "DOES_NOT_EXIST", StackWalker.Option.class)); } + @Test public void testGetStaticDecl() throws Throwable { var handle = InstructionHelper.ldcDynamicConstant(L, "TYPE", Class.class, ConstantBootstraps.class, "getStaticFinal", lookupMT(Object.class, Class.class), InstructionHelper.classDesc(Integer.class)); - assertEquals(handle.invoke(), int.class); + assertEquals(int.class, handle.invoke()); } + @Test public void testGetStaticSelf() throws Throwable { var handle = InstructionHelper.ldcDynamicConstant(L, "MAX_VALUE", int.class, ConstantBootstraps.class, "getStaticFinal", lookupMT(Object.class)); - assertEquals(handle.invoke(), Integer.MAX_VALUE); + assertEquals(Integer.MAX_VALUE, handle.invoke()); handle = InstructionHelper.ldcDynamicConstant(L, "ZERO", BigInteger.class, ConstantBootstraps.class, "getStaticFinal", lookupMT(Object.class)); - assertEquals(handle.invoke(), BigInteger.ZERO); + assertEquals(BigInteger.ZERO, handle.invoke()); } + @Test public void testInvoke() throws Throwable { var handle = InstructionHelper.ldcDynamicConstant( L, "_", List.class, @@ -159,9 +169,10 @@ public class ConstantBootstrapsTest { MethodType.methodType(List.class, Object[].class).toMethodDescriptorString()), 1, 2, 3, 4 ); - assertEquals(handle.invoke(), List.of(1, 2, 3, 4)); + assertEquals(List.of(1, 2, 3, 4), handle.invoke()); } + @Test public void testInvokeAsType() throws Throwable { var handle = InstructionHelper.ldcDynamicConstant( L, "_", int.class, @@ -170,9 +181,10 @@ public class ConstantBootstrapsTest { MethodType.methodType(Integer.class, String.class).toMethodDescriptorString()), "42" ); - assertEquals(handle.invoke(), 42); + assertEquals(42, handle.invoke()); } + @Test public void testInvokeAsTypeVariableArity() throws Throwable { // The constant type is Collection but the invoke return type is List var handle = InstructionHelper.ldcDynamicConstant( @@ -182,21 +194,21 @@ public class ConstantBootstrapsTest { MethodType.methodType(List.class, Object[].class).toMethodDescriptorString()), 1, 2, 3, 4 ); - assertEquals(handle.invoke(), List.of(1, 2, 3, 4)); + assertEquals(List.of(1, 2, 3, 4), handle.invoke()); } - @Test(expectedExceptions = ClassCastException.class) + @Test public void testInvokeAsTypeClassCast() throws Throwable { - ConstantBootstraps.invoke(MethodHandles.lookup(), "_", String.class, + assertThrows(ClassCastException.class, () -> ConstantBootstraps.invoke(MethodHandles.lookup(), "_", String.class, MethodHandles.lookup().findStatic(Integer.class, "valueOf", MethodType.methodType(Integer.class, String.class)), - "42"); + "42")); } - @Test(expectedExceptions = WrongMethodTypeException.class) + @Test public void testInvokeAsTypeWrongReturnType() throws Throwable { - ConstantBootstraps.invoke(MethodHandles.lookup(), "_", short.class, + assertThrows(WrongMethodTypeException.class, () -> ConstantBootstraps.invoke(MethodHandles.lookup(), "_", short.class, MethodHandles.lookup().findStatic(Integer.class, "parseInt", MethodType.methodType(int.class, String.class)), - "42"); + "42")); } @@ -205,6 +217,7 @@ public class ConstantBootstrapsTest { public static String sf; } + @Test public void testVarHandleField() throws Throwable { var handle = InstructionHelper.ldcDynamicConstant( L, "f", VarHandle.class, @@ -214,10 +227,11 @@ public class ConstantBootstrapsTest { ); var vhandle = (VarHandle) handle.invoke(); - assertEquals(vhandle.varType(), String.class); - assertEquals(vhandle.coordinateTypes(), List.of(X.class)); + assertEquals(String.class, vhandle.varType()); + assertEquals(List.of(X.class), vhandle.coordinateTypes()); } + @Test public void testVarHandleStaticField() throws Throwable { var handle = InstructionHelper.ldcDynamicConstant( L, "sf", VarHandle.class, @@ -227,10 +241,11 @@ public class ConstantBootstrapsTest { ); var vhandle = (VarHandle) handle.invoke(); - assertEquals(vhandle.varType(), String.class); - assertEquals(vhandle.coordinateTypes(), List.of()); + assertEquals(String.class, vhandle.varType()); + assertEquals(List.of(), vhandle.coordinateTypes()); } + @Test public void testVarHandleArray() throws Throwable { var handle = InstructionHelper.ldcDynamicConstant( L, "_", VarHandle.class, @@ -239,11 +254,10 @@ public class ConstantBootstrapsTest { ); var vhandle = (VarHandle) handle.invoke(); - assertEquals(vhandle.varType(), String.class); - assertEquals(vhandle.coordinateTypes(), List.of(String[].class, int.class)); + assertEquals(String.class, vhandle.varType()); + assertEquals(List.of(String[].class, int.class), vhandle.coordinateTypes()); } - @DataProvider public static Object[][] cceCasts() { return new Object[][]{ { void.class, null }, @@ -252,12 +266,12 @@ public class ConstantBootstrapsTest { }; } - @Test(dataProvider = "cceCasts", expectedExceptions = ClassCastException.class) + @ParameterizedTest + @MethodSource("cceCasts") public void testBadCasts(Class dstType, Object value) { - ConstantBootstraps.explicitCast(null, null, dstType, value); + assertThrows(ClassCastException.class, () -> ConstantBootstraps.explicitCast(null, null, dstType, value)); } - @DataProvider public static Object[][] validCasts() { Object o = new Object(); return new Object[][]{ @@ -278,9 +292,10 @@ public class ConstantBootstrapsTest { }; } - @Test(dataProvider = "validCasts") + @ParameterizedTest + @MethodSource("validCasts") public void testSuccessfulCasts(Class dstType, Object value, Object expected) { Object actual = ConstantBootstraps.explicitCast(null, null, dstType, value); - assertEquals(actual, expected); + assertEquals(expected, actual); } } diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/BasicTest.java b/test/jdk/java/lang/invoke/defineHiddenClass/BasicTest.java index 379ae765a6b..097e7c782a5 100644 --- a/test/jdk/java/lang/invoke/defineHiddenClass/BasicTest.java +++ b/test/jdk/java/lang/invoke/defineHiddenClass/BasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * BadClassFileVersion.jcod * @build jdk.test.lib.Utils * jdk.test.lib.compiler.CompilerUtils - * @run testng/othervm BasicTest + * @run junit/othervm BasicTest */ import java.io.File; @@ -52,16 +52,16 @@ import java.util.stream.Stream; import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.Utils; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import static java.lang.classfile.ClassFile.*; import static java.lang.constant.ConstantDescs.CD_Enum; import static java.lang.constant.ConstantDescs.CD_Object; import static java.lang.invoke.MethodHandles.lookup; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; interface HiddenTest { void test(); @@ -75,7 +75,7 @@ public class BasicTest { private static byte[] hiddenClassBytes; - @BeforeTest + @BeforeAll static void setup() throws IOException { compileSources(SRC_DIR, CLASSES_DIR); hiddenClassBytes = Files.readAllBytes(CLASSES_DIR.resolve("HiddenClass.class")); @@ -114,9 +114,9 @@ public class BasicTest { Class[] intfs = c.getInterfaces(); assertTrue(c.isHidden()); assertFalse(c.isPrimitive()); - assertTrue(intfs.length == 1); - assertTrue(intfs[0] == HiddenTest.class); - assertTrue(c.getCanonicalName() == null); + assertEquals(1, intfs.length); + assertSame(HiddenTest.class, intfs[0]); + assertNull(c.getCanonicalName()); String hcName = "HiddenClass"; String hcSuffix = "0x[0-9a-f]+"; @@ -143,7 +143,7 @@ public class BasicTest { Object array = Array.newInstance(type, 2); Class arrayType = array.getClass(); assertTrue(arrayType.isArray()); - assertTrue(Array.getLength(array) == 2); + assertEquals(2, Array.getLength(array)); assertFalse(arrayType.isHidden()); String hcName = "HiddenClass"; @@ -152,11 +152,11 @@ public class BasicTest { assertTrue(arrayType.descriptorString().matches("\\[" + "L" + hcName + "." + hcSuffix + ";")); assertTrue(arrayType.getComponentType().isHidden()); - assertTrue(arrayType.getComponentType() == type); + assertSame(type, arrayType.getComponentType()); Object t = type.newInstance(); Array.set(array, 0, t); Object o = Array.get(array, 0); - assertTrue(o == t); + assertSame(t, o); } private void checkSetAccessible(Class c, String name, Class... ptypes) throws Exception { @@ -170,13 +170,8 @@ public class BasicTest { @Test public void testLambda() throws Throwable { HiddenTest t = (HiddenTest)defineHiddenClass("Lambda").newInstance(); - try { - t.test(); - } catch (Error e) { - if (!e.getMessage().equals("thrown by " + t.getClass().getName())) { - throw e; - } - } + var e = assertThrows(Error.class, t::test); + assertEquals("thrown by " + t.getClass().getName(), e.getMessage()); } // Define a hidden class that uses lambda and contains its implementation @@ -184,13 +179,8 @@ public class BasicTest { @Test public void testHiddenLambda() throws Throwable { HiddenTest t = (HiddenTest)defineHiddenClass("HiddenLambda").newInstance(); - try { - t.test(); - } catch (Error e) { - if (!e.getMessage().equals("thrown by " + t.getClass().getName())) { - throw e; - } - } + var e = assertThrows(Error.class, t::test); + assertEquals("thrown by " + t.getClass().getName(), e.getMessage()); } // Verify the nest host and nest members of a hidden class and hidden nestmate class @@ -206,19 +196,18 @@ public class BasicTest { // test nest membership and reflection API assertTrue(host.isNestmateOf(member)); - assertTrue(host.getNestHost() == host); + assertSame(host, host.getNestHost()); // getNestHost and getNestMembers return the same value when calling // on a nest member and the nest host - assertTrue(member.getNestHost() == host.getNestHost()); - assertTrue(Arrays.equals(member.getNestMembers(), host.getNestMembers())); + assertSame(host.getNestHost(), member.getNestHost()); + assertArrayEquals(member.getNestMembers(), host.getNestMembers()); // getNestMembers includes the nest host that can be a hidden class but // only includes static nest members - assertTrue(host.getNestMembers().length == 1); - assertTrue(host.getNestMembers()[0] == host); + assertEquals(1, host.getNestMembers().length); + assertSame(host, host.getNestMembers()[0]); } - @DataProvider(name = "hiddenClasses") - private Object[][] hiddenClasses() { + private static Object[][] hiddenClasses() { return new Object[][] { new Object[] { "HiddenInterface", false }, new Object[] { "AbstractClass", false }, @@ -240,7 +229,8 @@ public class BasicTest { * is not useful as it cannot be referenced and an outer/inner class * when defined as a hidden effectively becomes a final top-level class. */ - @Test(dataProvider = "hiddenClasses") + @ParameterizedTest + @MethodSource("hiddenClasses") public void defineHiddenClass(String name, boolean nestmate) throws Exception { byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(name + ".class")); Class hc; @@ -252,13 +242,12 @@ public class BasicTest { hc = lookup().defineHiddenClass(bytes, false).lookupClass(); host = hc; } - assertTrue(hc.getNestHost() == host); - assertTrue(hc.getNestMembers().length == 1); - assertTrue(hc.getNestMembers()[0] == host); + assertSame(host, hc.getNestHost()); + assertEquals(1, hc.getNestMembers().length); + assertSame(host, hc.getNestMembers()[0]); } - @DataProvider(name = "emptyClasses") - private Object[][] emptyClasses() { + private static Object[][] emptyClasses() { return new Object[][] { new Object[] { "EmptyHiddenSynthetic", ACC_SYNTHETIC }, new Object[] { "EmptyHiddenEnum", ACC_ENUM }, @@ -276,7 +265,8 @@ public class BasicTest { * enum class containing constants of its type should not be a hidden * class. */ - @Test(dataProvider = "emptyClasses") + @ParameterizedTest + @MethodSource("emptyClasses") public void emptyHiddenClass(String name, int accessFlags) throws Exception { byte[] bytes = (accessFlags == ACC_ENUM) ? classBytes(name, CD_Enum, accessFlags) : classBytes(name, accessFlags); @@ -316,7 +306,7 @@ public class BasicTest { throw new IllegalArgumentException("unexpected access flag: " + accessFlags); } assertTrue(hc.isHidden()); - assertTrue(hc.getModifiers() == (ACC_PUBLIC|accessFlags)); + assertEquals(hc.getModifiers(), ACC_PUBLIC | accessFlags); assertFalse(hc.isLocalClass()); assertFalse(hc.isMemberClass()); assertFalse(hc.isAnonymousClass()); @@ -324,8 +314,7 @@ public class BasicTest { } // These class files can't be defined as hidden classes - @DataProvider(name = "cantBeHiddenClasses") - private Object[][] cantBeHiddenClasses() { + private static Object[][] cantBeHiddenClasses() { return new Object[][] { // a hidden class can't be a field's declaring type // enum class with static final HiddenEnum[] $VALUES: @@ -342,10 +331,11 @@ public class BasicTest { /* * These class files */ - @Test(dataProvider = "cantBeHiddenClasses", expectedExceptions = NoClassDefFoundError.class) + @ParameterizedTest + @MethodSource("cantBeHiddenClasses") public void failToDeriveAsHiddenClass(String name) throws Exception { byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(name + ".class")); - Class hc = lookup().defineHiddenClass(bytes, false).lookupClass(); + assertThrows(NoClassDefFoundError.class, () -> lookup().defineHiddenClass(bytes, false).lookupClass()); } /* @@ -361,22 +351,17 @@ public class BasicTest { Class c = t.getClass(); Class[] intfs = c.getInterfaces(); - assertTrue(intfs.length == 1); - assertTrue(intfs[0] == HiddenTest.class); + assertEquals(1, intfs.length); + assertSame(HiddenTest.class, intfs[0]); - try { - // this would cause loading of class HiddenCantReflect and NCDFE due - // to error during verification - c.getDeclaredMethods(); - } catch (NoClassDefFoundError e) { - Throwable x = e.getCause(); - if (x == null || !(x instanceof ClassNotFoundException && x.getMessage().contains("HiddenCantReflect"))) { - throw e; - } + var e = assertThrows(NoClassDefFoundError.class, c::getDeclaredMethods); + Throwable x = e.getCause(); + if (x == null || !(x instanceof ClassNotFoundException && x.getMessage().contains("HiddenCantReflect"))) { + throw e; } } - @Test(expectedExceptions = { IllegalArgumentException.class }) + @Test public void cantDefineModule() throws Throwable { Path src = Paths.get("module-info.java"); Path dir = CLASSES_DIR.resolve("m"); @@ -384,35 +369,34 @@ public class BasicTest { compileSources(src, dir); byte[] bytes = Files.readAllBytes(dir.resolve("module-info.class")); - lookup().defineHiddenClass(bytes, false); + assertThrows(IllegalArgumentException.class, () -> lookup().defineHiddenClass(bytes, false)); } - @Test(expectedExceptions = { IllegalArgumentException.class }) + @Test public void cantDefineClassInAnotherPackage() throws Throwable { Path src = Paths.get("ClassInAnotherPackage.java"); Files.write(src, List.of("package p;", "public class ClassInAnotherPackage {}"), StandardCharsets.UTF_8); compileSources(src, CLASSES_DIR); byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve("p").resolve("ClassInAnotherPackage.class")); - lookup().defineHiddenClass(bytes, false); + assertThrows(IllegalArgumentException.class, () -> lookup().defineHiddenClass(bytes, false)); } - @Test(expectedExceptions = { IllegalAccessException.class }) + @Test public void lessPrivilegedLookup() throws Throwable { Lookup lookup = lookup().dropLookupMode(Lookup.PRIVATE); - lookup.defineHiddenClass(hiddenClassBytes, false); + assertThrows(IllegalAccessException.class, () -> lookup.defineHiddenClass(hiddenClassBytes, false)); } - @Test(expectedExceptions = { UnsupportedClassVersionError.class }) + @Test public void badClassFileVersion() throws Throwable { Path dir = Paths.get(System.getProperty("test.classes", ".")); byte[] bytes = Files.readAllBytes(dir.resolve("BadClassFileVersion.class")); - lookup().defineHiddenClass(bytes, false); + assertThrows(UnsupportedClassVersionError.class, () -> lookup().defineHiddenClass(bytes, false)); } // malformed class files - @DataProvider(name = "malformedClassFiles") - private Object[][] malformedClassFiles() throws IOException { + private static Object[][] malformedClassFiles() throws IOException { Path dir = Paths.get(System.getProperty("test.classes", ".")); return new Object[][] { // `this_class` has invalid CP entry @@ -424,13 +408,13 @@ public class BasicTest { }; } - @Test(dataProvider = "malformedClassFiles", expectedExceptions = ClassFormatError.class) + @ParameterizedTest + @MethodSource("malformedClassFiles") public void badClassFile(byte[] bytes) throws Throwable { - lookup().defineHiddenClass(bytes, false); + assertThrows(ClassFormatError.class, () -> lookup().defineHiddenClass(bytes, false)); } - @DataProvider(name = "nestedTypesOrAnonymousClass") - private Object[][] nestedTypesOrAnonymousClass() { + private static Object[][] nestedTypesOrAnonymousClass() { return new Object[][] { // class file with bad InnerClasses or EnclosingMethod attribute new Object[] { "Outer", null }, @@ -440,7 +424,8 @@ public class BasicTest { }; } - @Test(dataProvider = "nestedTypesOrAnonymousClass") + @ParameterizedTest + @MethodSource("nestedTypesOrAnonymousClass") public void hasInnerClassesOrEnclosingMethodAttribute(String className, String badDeclaringClassName) throws Throwable { byte[] bytes = Files.readAllBytes(CLASSES_10_DIR.resolve(className + ".class")); Class hc = lookup().defineHiddenClass(bytes, false).lookupClass(); @@ -460,21 +445,22 @@ public class BasicTest { byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve("Outer.class")); Class hc = lookup().defineHiddenClass(bytes, false).lookupClass(); assertHiddenClass(hc); - assertTrue(hc.getNestHost() == hc); + assertSame(hc, hc.getNestHost()); Class[] members = hc.getNestMembers(); - assertTrue(members.length == 1 && members[0] == hc); + assertEquals(1, members.length); + assertSame(hc, members[0]); } // a hidden class with bad InnerClasses or EnclosingMethod attribute private void hiddenClassWithBadAttribute(Class hc, String badDeclaringClassName) { assertTrue(hc.isHidden()); - assertTrue(hc.getCanonicalName() == null); + assertNull(hc.getCanonicalName()); assertTrue(hc.getName().contains("/")); if (badDeclaringClassName == null) { // the following reflection API assumes a good name in InnerClasses // or EnclosingMethod attribute can successfully be resolved. - assertTrue(hc.getSimpleName().length() > 0); + assertFalse(hc.getSimpleName().isEmpty()); assertFalse(hc.isAnonymousClass()); assertFalse(hc.isLocalClass()); assertFalse(hc.isMemberClass()); @@ -483,43 +469,34 @@ public class BasicTest { } // validation of nest membership - assertTrue(hc.getNestHost() == hc); + assertSame(hc, hc.getNestHost()); // validate the static nest membership Class[] members = hc.getNestMembers(); - assertTrue(members.length == 1 && members[0] == hc); + assertEquals(1, members.length); + assertSame(hc, members[0]); } // Class::getSimpleName, Class::isMemberClass private void declaringClassNotFound(Class c, String cn) { - try { - // fail to find declaring/enclosing class - c.isMemberClass(); - assertTrue(false); - } catch (NoClassDefFoundError e) { - if (!e.getMessage().equals(cn)) { - throw e; - } + var e = assertThrows(NoClassDefFoundError.class, c::isMemberClass); + if (!e.getMessage().equals(cn)) { + throw e; } - try { - // fail to find declaring/enclosing class - c.getSimpleName(); - assertTrue(false); - } catch (NoClassDefFoundError e) { - if (!e.getMessage().equals(cn)) { - throw e; - } + e = assertThrows(NoClassDefFoundError.class, c::getSimpleName); + if (!e.getMessage().equals(cn)) { + throw e; } } private static void singletonNest(Class hc) { - assertTrue(hc.getNestHost() == hc); - assertTrue(hc.getNestMembers().length == 1); - assertTrue(hc.getNestMembers()[0] == hc); + assertSame(hc, hc.getNestHost()); + assertEquals(1, hc.getNestMembers().length); + assertSame(hc, hc.getNestMembers()[0]); } private static void assertHiddenClass(Class hc) { assertTrue(hc.isHidden()); - assertTrue(hc.getCanonicalName() == null); + assertNull(hc.getCanonicalName()); assertTrue(hc.getName().contains("/")); assertFalse(hc.isAnonymousClass()); assertFalse(hc.isLocalClass()); diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/HiddenNestmateTest.java b/test/jdk/java/lang/invoke/defineHiddenClass/HiddenNestmateTest.java index e026a7a1387..a71029dd229 100644 --- a/test/jdk/java/lang/invoke/defineHiddenClass/HiddenNestmateTest.java +++ b/test/jdk/java/lang/invoke/defineHiddenClass/HiddenNestmateTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @library /test/lib * @build HiddenNestmateTest - * @run testng/othervm HiddenNestmateTest + * @run junit/othervm HiddenNestmateTest */ import java.lang.classfile.ClassFile; @@ -37,9 +37,6 @@ import java.lang.reflect.AccessFlag; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.stream.Stream; -import java.util.Arrays; - -import org.testng.annotations.Test; import static java.lang.constant.ConstantDescs.CD_Object; import static java.lang.constant.ConstantDescs.CD_int; @@ -48,7 +45,8 @@ import static java.lang.constant.ConstantDescs.MTD_void; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*; import static java.lang.invoke.MethodHandles.Lookup.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class HiddenNestmateTest { private static final ClassDesc CD_HiddenNestmateTest = HiddenNestmateTest.class.describeConstable().orElseThrow(); @@ -61,12 +59,12 @@ public class HiddenNestmateTest { Class hiddenClass = lookup.lookupClass(); Class nestHost = hiddenClass.getNestHost(); assertTrue(hiddenClass.isHidden()); - assertTrue(nestHost == MethodHandles.lookup().lookupClass()); + assertSame(MethodHandles.lookup().lookupClass(), nestHost); // hidden nestmate is not listed in the return array of getNestMembers assertTrue(Stream.of(nestHost.getNestMembers()).noneMatch(k -> k == hiddenClass)); assertTrue(hiddenClass.isNestmateOf(lookup.lookupClass())); - assertTrue(Arrays.equals(hiddenClass.getNestMembers(), nestHost.getNestMembers())); + assertArrayEquals(nestHost.getNestMembers(), hiddenClass.getNestMembers()); } /* @@ -78,23 +76,19 @@ public class HiddenNestmateTest { Lookup lookup = MethodHandles.lookup().defineHiddenClass(bytes, false); Class c = lookup.lookupClass(); assertTrue(lookup.hasFullPrivilegeAccess()); - assertTrue((lookup.lookupModes() & ORIGINAL) == ORIGINAL); - assertTrue(c.getNestHost() == c); // host of its own nest + assertEquals(ORIGINAL, lookup.lookupModes() & ORIGINAL); + assertSame(c, c.getNestHost()); // host of its own nest assertTrue(c.isHidden()); // invoke int test(HiddenNestmateTest o) via MethodHandle MethodHandle ctor = lookup.findConstructor(c, MethodType.methodType(void.class)); MethodHandle mh = lookup.findVirtual(c, "test", MethodType.methodType(int.class, HiddenNestmateTest.class)); - try { + assertThrows(IllegalAccessError.class, () -> { int x = (int) mh.bindTo(ctor.invoke()).invokeExact(this); - throw new RuntimeException("should fail when accessing HiddenNestmateTest.privMethod()"); - } catch (IllegalAccessError e) {} + }); // invoke int test(HiddenNestmateTest o) - try { - int x1 = testInjectedClass(c); - throw new RuntimeException("should fail when accessing HiddenNestmateTest.privMethod()"); - } catch (IllegalAccessError e) {} + assertThrows(IllegalAccessError.class, () -> testInjectedClass(c)); } /* @@ -111,11 +105,11 @@ public class HiddenNestmateTest { MethodHandle ctor = lookup.findConstructor(c, MethodType.methodType(void.class)); MethodHandle mh = lookup.findVirtual(c, "test", MethodType.methodType(int.class, HiddenNestmateTest.class)); int x = (int)mh.bindTo(ctor.invoke()).invokeExact( this); - assertTrue(x == privMethod()); + assertEquals(privMethod(), x); // invoke int test(HiddenNestmateTest o) int x1 = testInjectedClass(c); - assertTrue(x1 == privMethod()); + assertEquals(privMethod(), x1); } /* @@ -131,10 +125,10 @@ public class HiddenNestmateTest { /* * Fail to create a hidden class if dropping PRIVATE lookup mode */ - @Test(expectedExceptions = IllegalAccessException.class) + @Test public void noPrivateLookupAccess() throws Throwable { Lookup lookup = MethodHandles.lookup().dropLookupMode(Lookup.PRIVATE); - lookup.defineHiddenClass(bytes, false, NESTMATE); + assertThrows(IllegalAccessException.class, () -> lookup.defineHiddenClass(bytes, false, NESTMATE)); } public void teleportToNestmate() throws Throwable { @@ -143,8 +137,8 @@ public class HiddenNestmateTest { // Teleport to a hidden nestmate Lookup lc = MethodHandles.lookup().in(lookup.lookupClass()); - assertTrue((lc.lookupModes() & PRIVATE) != 0); - assertTrue((lc.lookupModes() & ORIGINAL) == 0); + assertNotEquals(0, lc.lookupModes() & PRIVATE); + assertEquals(0, lc.lookupModes() & ORIGINAL); Lookup lc2 = lc.defineHiddenClass(bytes, false, NESTMATE); assertNestmate(lc2); @@ -153,9 +147,9 @@ public class HiddenNestmateTest { /* * Fail to create a hidden class in a different package from the lookup class' package */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void notSamePackage() throws Throwable { - MethodHandles.lookup().defineHiddenClass(classBytes("p/HiddenInjected"), false, NESTMATE); + assertThrows(IllegalArgumentException.class, () -> MethodHandles.lookup().defineHiddenClass(classBytes("p/HiddenInjected"), false, NESTMATE)); } /* diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/LambdaNestedInnerTest.java b/test/jdk/java/lang/invoke/defineHiddenClass/LambdaNestedInnerTest.java index 9e3c8a8b318..7524e67bf9e 100644 --- a/test/jdk/java/lang/invoke/defineHiddenClass/LambdaNestedInnerTest.java +++ b/test/jdk/java/lang/invoke/defineHiddenClass/LambdaNestedInnerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @summary define a lambda proxy class whose target class has an invalid * nest membership - * @run testng/othervm p.LambdaNestedInnerTest + * @run junit/othervm p.LambdaNestedInnerTest */ package p; @@ -41,11 +41,10 @@ import java.util.Arrays; import java.util.Set; import java.util.stream.Collectors; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; - import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; public class LambdaNestedInnerTest { private static final String INNER_CLASSNAME = "p.LambdaNestedInnerTest$Inner"; @@ -68,7 +67,7 @@ public class LambdaNestedInnerTest { lambda1.run(); } - // testng may not be visible to this class + // junit may not be visible to this class private static void assertTrue(boolean x) { if (!x) { throw new AssertionError("expected true but found false"); @@ -79,8 +78,8 @@ public class LambdaNestedInnerTest { } } - @BeforeTest - public void setup() throws IOException { + @BeforeAll + public static void setup() throws IOException { String filename = INNER_CLASSNAME.replace('.', File.separatorChar) + ".class"; Path src = Paths.get(System.getProperty("test.classes"), filename); Path dest = Paths.get(DIR, filename); @@ -93,9 +92,9 @@ public class LambdaNestedInnerTest { Class inner = Class.forName(INNER_CLASSNAME); // inner class is a nest member of LambdaNestedInnerTest Class nestHost = inner.getNestHost(); - assertTrue(nestHost == LambdaNestedInnerTest.class); + assertSame(LambdaNestedInnerTest.class, nestHost); Set> members = Arrays.stream(nestHost.getNestMembers()).collect(Collectors.toSet()); - assertEquals(members, Set.of(nestHost, inner, TestLoader.class)); + assertEquals(Set.of(nestHost, inner, TestLoader.class), members); // spin lambda proxy hidden class Runnable runnable = (Runnable) inner.newInstance(); @@ -107,8 +106,8 @@ public class LambdaNestedInnerTest { URL[] urls = new URL[] { Paths.get(DIR).toUri().toURL() }; URLClassLoader loader = new URLClassLoader(urls, null); Class inner = loader.loadClass(INNER_CLASSNAME); - assertTrue(inner.getClassLoader() == loader); - assertTrue(inner.getNestHost() == inner); // linkage error ignored + assertSame(loader, inner.getClassLoader()); + assertSame(inner, inner.getNestHost()); // linkage error ignored Runnable runnable = (Runnable) inner.newInstance(); // this validates the lambda proxy class @@ -125,8 +124,8 @@ public class LambdaNestedInnerTest { TestLoader loader = new TestLoader(urls); Class inner = loader.loadClass(INNER_CLASSNAME); - assertTrue(inner.getClassLoader() == loader); - assertTrue(inner.getNestHost() == inner); // linkage error ignored. + assertSame(loader, inner.getClassLoader()); + assertSame(inner, inner.getNestHost()); // linkage error ignored. Runnable runnable = (Runnable) inner.newInstance(); // this validates the lambda proxy class diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/PreviewHiddenClass.java b/test/jdk/java/lang/invoke/defineHiddenClass/PreviewHiddenClass.java index fddbb348517..bd6c87808fe 100644 --- a/test/jdk/java/lang/invoke/defineHiddenClass/PreviewHiddenClass.java +++ b/test/jdk/java/lang/invoke/defineHiddenClass/PreviewHiddenClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -29,7 +29,7 @@ * @requires !java.enablePreview * @build jdk.test.lib.Utils * jdk.test.lib.compiler.CompilerUtils - * @run testng PreviewHiddenClass + * @run junit PreviewHiddenClass * @summary verify UnsupportedClassVersionError thrown when defining a hidden class * with preview minor version but --enable-preview is not set * @comment This test itself cannot enablePreview, or hidden class definition @@ -46,15 +46,15 @@ import java.nio.file.Paths; import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.Utils; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class PreviewHiddenClass { private static final Path SRC_DIR = Paths.get(Utils.TEST_SRC, "src"); private static final Path CLASSES_DIR = Paths.get("classes"); - @Test(expectedExceptions = { UnsupportedClassVersionError.class }) + @Test public void previewNotEnabled() throws Exception { // compile a class with --enable-preview Path sourceFile = SRC_DIR.resolve("HiddenInterface.java"); @@ -67,7 +67,7 @@ public class PreviewHiddenClass { byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve("HiddenInterface.class")); var dis = new DataInputStream(new ByteArrayInputStream(bytes)); dis.skipBytes(4); // 0xCAFEBABE - assertEquals(dis.readUnsignedShort(), 65535); // Minor version - MethodHandles.lookup().defineHiddenClass(bytes, false); + assertEquals(65535, dis.readUnsignedShort()); // Minor version + assertThrows(UnsupportedClassVersionError.class, () -> MethodHandles.lookup().defineHiddenClass(bytes, false)); } } diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/StaticInvocableTest.java b/test/jdk/java/lang/invoke/defineHiddenClass/StaticInvocableTest.java index 1c95caa97d3..ac0a29c247d 100644 --- a/test/jdk/java/lang/invoke/defineHiddenClass/StaticInvocableTest.java +++ b/test/jdk/java/lang/invoke/defineHiddenClass/StaticInvocableTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ * @summary hidden class members can't be statically invocable * @modules java.base/jdk.internal.misc * @build java.base/* - * @run testng StaticInvocableTest + * @run junit StaticInvocableTest */ import java.lang.classfile.ClassFile; @@ -38,7 +38,6 @@ import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; import java.lang.invoke.LookupHelper; import java.lang.reflect.AccessFlag; -import org.testng.annotations.Test; import static java.lang.classfile.ClassFile.ACC_PUBLIC; import static java.lang.classfile.ClassFile.ACC_STATIC; @@ -46,6 +45,7 @@ import static java.lang.constant.ConstantDescs.CD_Object; import static java.lang.constant.ConstantDescs.CD_int; import static java.lang.constant.ConstantDescs.INIT_NAME; import static java.lang.constant.ConstantDescs.MTD_void; +import org.junit.jupiter.api.Test; public class StaticInvocableTest { public static void main(String[] args) throws Throwable { diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/TypeDescriptorTest.java b/test/jdk/java/lang/invoke/defineHiddenClass/TypeDescriptorTest.java index e60cb8a5782..575eac1ccd1 100644 --- a/test/jdk/java/lang/invoke/defineHiddenClass/TypeDescriptorTest.java +++ b/test/jdk/java/lang/invoke/defineHiddenClass/TypeDescriptorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,10 +21,10 @@ * questions. */ -/** +/* * @test * @bug 8242013 - * @run testng/othervm test.TypeDescriptorTest + * @run junit/othervm test.TypeDescriptorTest * @summary Test TypeDescriptor::descriptorString for hidden classes which * cannot be used to produce ConstantDesc via ClassDesc or * MethodTypeDesc factory methods @@ -42,9 +42,10 @@ import java.nio.file.Files; import java.nio.file.Paths; import static java.lang.invoke.MethodType.*; -import org.testng.annotations.Test; -import org.testng.annotations.DataProvider; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class TypeDescriptorTest { private static final Lookup HC_LOOKUP = defineHiddenClass(); @@ -61,8 +62,7 @@ public class TypeDescriptorTest { } } - @DataProvider(name = "constables") - private Object[][] constables() throws Exception { + private static Object[][] constables() throws Exception { Class hcArray = Array.newInstance(HC, 1).getClass(); return new Object[][] { new Object[] { HC }, @@ -79,7 +79,8 @@ public class TypeDescriptorTest { * Hidden classes have no nominal descriptor. * Constable::describeConstable returns empty optional. */ - @Test(dataProvider = "constables") + @ParameterizedTest + @MethodSource("constables") public void noNominalDescriptor(Constable constable) { assertTrue(constable.describeConstable().isEmpty()); } @@ -90,27 +91,13 @@ public class TypeDescriptorTest { */ @Test public void testClassDesc() { - try { - ClassDesc.ofDescriptor(HC.descriptorString()); - assertFalse(true); - } catch (IllegalArgumentException e) {} - - try { - ClassDesc.ofDescriptor(HC.getName()); - assertFalse(true); - } catch (IllegalArgumentException e) {} - try { - ClassDesc.of(HC.getPackageName(), HC.getSimpleName()); - assertFalse(true); - } catch (IllegalArgumentException e) {} - try { - ClassDesc.of(HC.getName()); - assertFalse(true); - } catch (IllegalArgumentException e) {} + assertThrows(IllegalArgumentException.class, () -> ClassDesc.ofDescriptor(HC.descriptorString())); + assertThrows(IllegalArgumentException.class, () -> ClassDesc.ofDescriptor(HC.getName())); + assertThrows(IllegalArgumentException.class, () -> ClassDesc.of(HC.getPackageName(), HC.getSimpleName())); + assertThrows(IllegalArgumentException.class, () -> ClassDesc.of(HC.getName())); } - @DataProvider(name = "typeDescriptors") - private Object[][] typeDescriptors() throws Exception { + private static Object[][] typeDescriptors() throws Exception { Class hcArray = Array.newInstance(HC, 1, 1).getClass(); return new Object[][] { new Object[] { HC, "Ltest/HiddenClass.0x[0-9a-f]+;"}, @@ -124,26 +111,20 @@ public class TypeDescriptorTest { /* * Hidden classes have no nominal type descriptor */ - @Test(dataProvider = "typeDescriptors") + @ParameterizedTest + @MethodSource("typeDescriptors") public void testTypeDescriptor(TypeDescriptor td, String regex) throws Exception { String desc = td.descriptorString(); assertTrue(desc.matches(regex)); if (td instanceof Class) { - try { - ClassDesc.ofDescriptor(desc); - assertFalse(true); - } catch (IllegalArgumentException e) {} + assertThrows(IllegalArgumentException.class, () -> ClassDesc.ofDescriptor(desc)); } else if (td instanceof MethodType) { - try { - MethodTypeDesc.ofDescriptor(desc); - assertFalse(true); - } catch (IllegalArgumentException e) {} + assertThrows(IllegalArgumentException.class, () -> MethodTypeDesc.ofDescriptor(desc)); } } - @DataProvider(name = "methodTypes") - private Object[][] methodTypes() throws Exception { + private static Object[][] methodTypes() throws Exception { Class hcArray = Array.newInstance(HC, 1, 1).getClass(); return new Object[][] { new Object[] { methodType(HC), "\\(\\)Ltest/HiddenClass.0x[0-9a-f]+;" }, @@ -155,15 +136,13 @@ public class TypeDescriptorTest { /* * Test MethodType::toMethodDescriptorString with MethodType referencing to hidden class */ - @Test(dataProvider = "methodTypes") + @ParameterizedTest + @MethodSource("methodTypes") public void testToMethodDescriptorString(MethodType mtype, String regex) throws Exception { String desc = mtype.toMethodDescriptorString(); assertTrue(desc.matches(regex)); - try { - MethodType.fromMethodDescriptorString(desc, TypeDescriptorTest.class.getClassLoader()); - assertFalse(true); - } catch (IllegalArgumentException e) {} + assertThrows(IllegalArgumentException.class, () -> MethodType.fromMethodDescriptorString(desc, TypeDescriptorTest.class.getClassLoader())); } } diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/UnloadingTest.java b/test/jdk/java/lang/invoke/defineHiddenClass/UnloadingTest.java index b016b2f6899..45728f2ed79 100644 --- a/test/jdk/java/lang/invoke/defineHiddenClass/UnloadingTest.java +++ b/test/jdk/java/lang/invoke/defineHiddenClass/UnloadingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ * @modules jdk.compiler * @library /test/lib/ * @build jdk.test.lib.util.ForceGC - * @run testng/othervm UnloadingTest + * @run junit/othervm UnloadingTest */ import java.io.IOException; @@ -48,18 +48,16 @@ import jdk.test.lib.util.ForceGC; import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.Utils; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; - -import static java.lang.invoke.MethodHandles.lookup; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; public class UnloadingTest { private static final Path CLASSES_DIR = Paths.get("classes"); private static byte[] hiddenClassBytes; - @BeforeTest + @BeforeAll static void setup() throws IOException { Path src = Paths.get(Utils.TEST_SRC, "src", "LookupHelper.java"); if (!CompilerUtils.compile(src, CLASSES_DIR)) { @@ -116,7 +114,7 @@ public class UnloadingTest { // keep a strong reference to the nest member class Class member = unloaders[1].weakRef.get(); - assertTrue(member != null); + assertNotNull(member); // nest host and member will not be unloaded assertFalse(unloaders[0].tryUnload()); assertFalse(unloaders[1].tryUnload()); @@ -180,7 +178,7 @@ public class UnloadingTest { } else { hc = lookup.defineHiddenClass(hiddenClassBytes, false).lookupClass(); } - assertTrue(hc.getClassLoader() == lookup.lookupClass().getClassLoader()); + assertSame(lookup.lookupClass().getClassLoader(), hc.getClassLoader()); return new HiddenClassUnloader(hc); } @@ -202,7 +200,7 @@ public class UnloadingTest { } else { member = hostLookup.defineHiddenClass(hiddenClassBytes, false, NESTMATE).lookupClass(); } - assertTrue(member.getNestHost() == host); + assertSame(host, member.getNestHost()); return new HiddenClassUnloader[] { new HiddenClassUnloader(host), new HiddenClassUnloader(member) }; } diff --git a/test/jdk/java/lang/invoke/findSpecial/FindSpecialTest.java b/test/jdk/java/lang/invoke/findSpecial/FindSpecialTest.java index 9b6622a7e9c..5bb7f67c000 100644 --- a/test/jdk/java/lang/invoke/findSpecial/FindSpecialTest.java +++ b/test/jdk/java/lang/invoke/findSpecial/FindSpecialTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,12 +21,12 @@ * questions. */ -/** +/* * @test * @bug 8209005 8209078 * @library /test/lib * @build m1/* FindSpecialTest - * @run testng/othervm FindSpecialTest + * @run junit/othervm FindSpecialTest * @summary Test findSpecial and unreflectSpecial of the declaring class * of the method and the special caller are not in the same module * as the lookup class. @@ -39,7 +39,7 @@ import java.nio.file.Paths; import static jdk.test.lib.process.ProcessTools.*; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class FindSpecialTest { static final String TEST_CLASSES = System.getProperty("test.classes", "."); @@ -51,7 +51,7 @@ public class FindSpecialTest { * Run test.FindSpecial in unnamed module */ @Test - public static void callerInUnnamedModule() throws Throwable { + public void callerInUnnamedModule() throws Throwable { Path m1 = Paths.get(TEST_CLASSES, "modules", TEST_MODULE); if (Files.notExists(m1)) { throw new Error(m1 + " not exist"); @@ -66,7 +66,7 @@ public class FindSpecialTest { * Run test.FindSpecial in a named module */ @Test - public static void callerInNamedModule() throws Throwable { + public void callerInNamedModule() throws Throwable { Path modules = Paths.get(TEST_CLASSES, "modules"); if (Files.notExists(modules)) { throw new Error(modules + " not exist"); diff --git a/test/jdk/java/lang/invoke/lambda/LambdaFileEncodingSerialization.java b/test/jdk/java/lang/invoke/lambda/LambdaFileEncodingSerialization.java index 1f950ffce7e..6c505ddf471 100644 --- a/test/jdk/java/lang/invoke/lambda/LambdaFileEncodingSerialization.java +++ b/test/jdk/java/lang/invoke/lambda/LambdaFileEncodingSerialization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,36 +21,33 @@ * questions. */ -/** +/* * @test * @bug 8248231 * @summary Test to verify lambda serialization uses the correct UTF-8 encoding * @library /test/lib * @build jdk.test.lib.JDKToolFinder * jdk.test.lib.process.ProcessTools - * @run testng LambdaFileEncodingSerialization + * @run junit LambdaFileEncodingSerialization */ import java.io.File; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Arrays; import java.util.ArrayList; -import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; import jdk.test.lib.JDKToolFinder; import jdk.test.lib.process.ProcessTools; +import org.junit.jupiter.api.Test; public class LambdaFileEncodingSerialization { private static final String TEST_NAME = "TestLambdaFileEncodingSerialization"; @Test - public static void testDeserializeLambdaEncoding() throws Throwable { + public void testDeserializeLambdaEncoding() throws Throwable { String javac = JDKToolFinder.getTestJDKTool("javac"); String java = JDKToolFinder.getTestJDKTool("java"); diff --git a/test/jdk/java/lang/invoke/lambda/LambdaHiddenCaller.java b/test/jdk/java/lang/invoke/lambda/LambdaHiddenCaller.java index aed19e6ca17..0dbdff79230 100644 --- a/test/jdk/java/lang/invoke/lambda/LambdaHiddenCaller.java +++ b/test/jdk/java/lang/invoke/lambda/LambdaHiddenCaller.java @@ -29,8 +29,7 @@ import java.util.function.IntSupplier; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; /* * @test @@ -62,7 +61,7 @@ public class LambdaHiddenCaller { void testSerializableLambda() { var is = hiddenCaller.callSerializableLambda(); assertEquals(42, is.getAsInt()); - assertTrue(Serializable.class.isAssignableFrom(is.getClass())); + assertInstanceOf(Serializable.class, is); // We do not guarantee serialization functionalities yet } } diff --git a/test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java b/test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java index 60c85753d72..eb013bf01f3 100644 --- a/test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java +++ b/test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * @library /java/nio/file * @modules jdk.compiler * jdk.zipfs - * @run testng LogGeneratedClassesTest + * @run junit LogGeneratedClassesTest * @summary tests logging generated classes for lambda */ import java.io.IOException; @@ -45,24 +45,24 @@ import java.nio.file.attribute.PosixFileAttributeView; import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.process.OutputAnalyzer; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; -import org.testng.SkipException; import static java.nio.file.attribute.PosixFilePermissions.*; import static jdk.test.lib.process.ProcessTools.*; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import org.junit.jupiter.api.AfterAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; public class LogGeneratedClassesTest { static final Path DUMP_LAMBDA_PROXY_CLASS_FILES = Path.of("DUMP_LAMBDA_PROXY_CLASS_FILES"); static final Path CLASSES = Path.of("classes").toAbsolutePath(); - String longFQCN; + static String longFQCN; - @BeforeClass - public void setup() throws IOException { + @BeforeAll + public static void setup() throws IOException { final List scratch = new ArrayList<>(); scratch.clear(); scratch.add("package com.example;"); @@ -102,8 +102,8 @@ public class LogGeneratedClassesTest { CompilerUtils.compile(Path.of("."), CLASSES); } - @AfterClass - public void cleanup() throws IOException { + @AfterAll + public static void cleanup() throws IOException { Files.delete(Paths.get("TestLambda.java")); Files.delete(Paths.get("LongPackageName.java")); TestUtil.removeAll(DUMP_LAMBDA_PROXY_CLASS_FILES); @@ -132,12 +132,11 @@ public class LogGeneratedClassesTest { executeProcess(pb).shouldHaveExitValue(0); // 2 our own class files. We don't care about the others - assertEquals(Files.find( - dumpDir, - 99, - (p, a) -> p.startsWith(dumpDir.resolve("com/example")) - && a.isRegularFile()).count(), - 2, "Two lambda captured"); + assertEquals(2, Files.find( + dumpDir, + 99, + (p, a) -> p.startsWith(dumpDir.resolve("com/example")) + && a.isRegularFile()).count(), "Two lambda captured"); } @Test @@ -155,12 +154,11 @@ public class LogGeneratedClassesTest { executeProcess(pb).shouldHaveExitValue(0); // The dump directory will be created if not exist - assertEquals(Files.find( - dumpDir, - 99, - (p, a) -> p.startsWith(dumpDir.resolve("com/example")) - && a.isRegularFile()).count(), - 2, "Two lambda captured"); + assertEquals(2, Files.find( + dumpDir, + 99, + (p, a) -> p.startsWith(dumpDir.resolve("com/example")) + && a.isRegularFile()).count(), "Two lambda captured"); } @Test @@ -208,12 +206,10 @@ public class LogGeneratedClassesTest { try { fs = Files.getFileStore(Paths.get(".")); } catch (IOException e) { - throw new SkipException("WARNING: IOException occurred: " + e + ", Skipping testDumpDirNotWritable test."); - } - if (!fs.supportsFileAttributeView(PosixFileAttributeView.class)) { - // No easy way to setup readonly directory without POSIX - throw new SkipException("WARNING: POSIX is not supported. Skipping testDumpDirNotWritable test."); + Assumptions.assumeTrue(false, "WARNING: IOException occurred: " + e + ", Skipping testDumpDirNotWritable test."); + return; } + Assumptions.assumeFalse(!fs.supportsFileAttributeView(PosixFileAttributeView.class), "WARNING: POSIX is not supported. Skipping testDumpDirNotWritable test."); // No easy way to setup readonly directory without POSIX Path testDir = Path.of("readOnly"); Path dumpDir = testDir.resolve(DUMP_LAMBDA_PROXY_CLASS_FILES); @@ -221,11 +217,8 @@ public class LogGeneratedClassesTest { Files.createDirectory(dumpDir, asFileAttribute(fromString("r-xr-xr-x"))); try { - if (isWriteableDirectory(dumpDir)) { - // Skipping the test: it's allowed to write into read-only directory - // (e.g. current user is super user). - throw new SkipException("WARNING: The dump directory is writeable. Skipping testDumpDirNotWritable test."); - } + Assumptions.assumeFalse(isWriteableDirectory(dumpDir), "WARNING: The dump directory is writeable. Skipping testDumpDirNotWritable test."); // Skipping the test: it's allowed to write into read-only directory + // (e.g. current user is super user). ProcessBuilder pb = createLimitedTestJavaProcessBuilder( "-cp", CLASSES.toString(), @@ -251,10 +244,9 @@ public class LogGeneratedClassesTest { longFQCN).directory(testDir.toFile()); OutputAnalyzer outputAnalyzer = executeProcess(pb); outputAnalyzer.shouldHaveExitValue(0); - assertEquals(outputAnalyzer.asLines().stream() - .filter(s -> s.startsWith("WARNING: Exception")) - .count(), - 2, "show error each capture"); + assertEquals(2, outputAnalyzer.asLines().stream() + .filter(s -> s.startsWith("WARNING: Exception")) + .count(), "show error each capture"); // dumpLong/DUMP_LAMBDA_PROXY_CLASS_FILES/com/example/nonsense/nonsense Path dumpPath = dumpDir.resolve("com/example/nonsense"); Predicate filter = p -> p.getParent() == null || dumpPath.startsWith(p) || p.startsWith(dumpPath); @@ -269,8 +261,8 @@ public class LogGeneratedClassesTest { } }); } - assertEquals(Files.walk(dumpDir) + assertEquals(5, Files.walk(dumpDir) .filter(filter) - .count(), 5, "Two lambda captured failed to log"); + .count(), "Two lambda captured failed to log"); } } diff --git a/test/jdk/java/lang/invoke/lambda/invokeSpecial/InvokeSpecialMethodTest.java b/test/jdk/java/lang/invoke/lambda/invokeSpecial/InvokeSpecialMethodTest.java index bf1db0f822e..4b74d05f270 100644 --- a/test/jdk/java/lang/invoke/lambda/invokeSpecial/InvokeSpecialMethodTest.java +++ b/test/jdk/java/lang/invoke/lambda/invokeSpecial/InvokeSpecialMethodTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,22 +24,22 @@ /* * @test * @bug 8274848 - * @run testng InvokeSpecialMethodTest + * @run junit InvokeSpecialMethodTest * @summary ensure REF_invokeSpecial on a non-private implementation method * behaves as if `super::m` is invoked regardless of its access flag */ -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.CallSite; import java.lang.invoke.LambdaMetafactory; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import static java.lang.invoke.MethodType.methodType; +import static org.junit.jupiter.api.Assertions.assertEquals; public class InvokeSpecialMethodTest { static class MethodTest { @@ -95,8 +95,7 @@ public class InvokeSpecialMethodTest { String get(); } - @DataProvider - public Object[][] methodProvider() { + public static Object[][] methodProvider() { return new Object[][]{ {MethodTest.M_PUBLIC, "test_public"}, {MethodTest.M_PROTECTED, "test_protected"}, @@ -104,7 +103,8 @@ public class InvokeSpecialMethodTest { }; } - @Test(dataProvider = "methodProvider") + @ParameterizedTest + @MethodSource("methodProvider") void test(MethodHandle implMethod, String expected) throws Throwable { testMetafactory(implMethod, expected); testAltMetafactory(implMethod, expected); @@ -117,7 +117,7 @@ public class InvokeSpecialMethodTest { MethodTest o = new MethodTest.SubClass(); StringFactory factory = (StringFactory) cs.dynamicInvoker().invokeExact(o); String actual = factory.get(); - Assert.assertEquals(actual, expected); + assertEquals(expected, actual); } static void testAltMetafactory(MethodHandle implMethod, String expected) throws Throwable { @@ -128,6 +128,6 @@ public class InvokeSpecialMethodTest { MethodTest o = new MethodTest.SubClass(); StringFactory factory = (StringFactory) cs.dynamicInvoker().invokeExact(o); String actual = factory.get(); - Assert.assertEquals(actual, expected); + assertEquals(expected, actual); } } diff --git a/test/jdk/java/lang/invoke/lambda/superProtectedMethod/InheritedProtectedMethod.java b/test/jdk/java/lang/invoke/lambda/superProtectedMethod/InheritedProtectedMethod.java index a5cf6f68c50..fc730d790ac 100644 --- a/test/jdk/java/lang/invoke/lambda/superProtectedMethod/InheritedProtectedMethod.java +++ b/test/jdk/java/lang/invoke/lambda/superProtectedMethod/InheritedProtectedMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @library /test/lib * @build jdk.test.lib.Utils * jdk.test.lib.compiler.CompilerUtils - * @run testng/othervm InheritedProtectedMethod + * @run junit/othervm InheritedProtectedMethod * @summary Test method reference to a method inherited from its * superclass in a different package. Such method's modifier * is changed from public to protected. @@ -37,10 +37,6 @@ import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.Utils; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.io.IOException; import java.lang.reflect.Method; import java.net.URL; @@ -48,13 +44,15 @@ import java.net.URLClassLoader; import java.nio.file.Path; import java.nio.file.Paths; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; public class InheritedProtectedMethod { private static final Path SRC_DIR = Paths.get(Utils.TEST_SRC, "src"); private static final Path CLASSES_DIR = Paths.get("classes"); - @BeforeTest + @BeforeAll static void setup() throws IOException { assertTrue(CompilerUtils.compile(SRC_DIR, CLASSES_DIR)); @@ -64,13 +62,13 @@ public class InheritedProtectedMethod { } @Test - public static void run() throws Exception { + public void run() throws Exception { URLClassLoader loader = new URLClassLoader("loader", new URL[]{ CLASSES_DIR.toUri().toURL()}, ClassLoader.getPlatformClassLoader()); Class methodInvokeClass = Class.forName("MethodInvoker", false, loader); Method invokeMethod = methodInvokeClass.getMethod("invoke"); String result = (String)invokeMethod.invoke(null); - assertEquals(result, "protected inherited method"); + assertEquals("protected inherited method", result); } } diff --git a/test/jdk/java/lang/invoke/lambda/superProtectedMethod/ProtectedMethodInOtherPackage.java b/test/jdk/java/lang/invoke/lambda/superProtectedMethod/ProtectedMethodInOtherPackage.java index 666ba5c254b..980114149a8 100644 --- a/test/jdk/java/lang/invoke/lambda/superProtectedMethod/ProtectedMethodInOtherPackage.java +++ b/test/jdk/java/lang/invoke/lambda/superProtectedMethod/ProtectedMethodInOtherPackage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @bug 8227415 8254975 8270056 - * @run testng/othervm p.ProtectedMethodInOtherPackage + * @run junit/othervm p.ProtectedMethodInOtherPackage * @summary method reference to a protected method inherited from its * superclass in a different runtime package where * lambda proxy class has no access to it. @@ -47,12 +47,12 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.function.Function; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class ProtectedMethodInOtherPackage { @Test - public static void remotePackageSameLoader() { + public void remotePackageSameLoader() { Sub_I sub = new Sub_I(); sub.test(Paths.get("test")); } @@ -76,14 +76,14 @@ public class ProtectedMethodInOtherPackage { } @Test - public static void splitPackage() throws Throwable { + public void splitPackage() throws Throwable { ClassLoader parent = new Loader("loader-A", null, A.class); ClassLoader loader = new Loader("loader-B", parent, B.class); Class aClass = Class.forName(A.class.getName(), false, loader); Class bClass = Class.forName(B.class.getName(), false, loader); - assertTrue(aClass.getClassLoader() == parent); - assertTrue(bClass.getClassLoader() == loader); - assertEquals(aClass.getPackageName(), bClass.getPackageName()); + assertSame(parent, aClass.getClassLoader()); + assertSame(loader, bClass.getClassLoader()); + assertEquals(bClass.getPackageName(), aClass.getPackageName()); Object b = bClass.getDeclaredConstructor().newInstance(); @@ -102,14 +102,14 @@ public class ProtectedMethodInOtherPackage { } @Test - public static void protectedStaticMethodInSplitPackage() throws Throwable { + public void protectedStaticMethodInSplitPackage() throws Throwable { ClassLoader parent = new Loader("loader-A1", null, A1.class); ClassLoader loader = new Loader("loader-B1", parent, B1.class); Class aClass1 = Class.forName(A1.class.getName(), false, loader); Class bClass1 = Class.forName(B1.class.getName(), false, loader); - assertTrue(aClass1.getClassLoader() == parent); - assertTrue(bClass1.getClassLoader() == loader); - assertEquals(aClass1.getPackageName(), bClass1.getPackageName()); + assertSame(parent, aClass1.getClassLoader()); + assertSame(loader, bClass1.getClassLoader()); + assertEquals(bClass1.getPackageName(), aClass1.getPackageName()); // verify subclass can access a static protected method inherited from // its superclass in a split package diff --git a/test/jdk/java/lang/invoke/lookup/ChainedLookupTest.java b/test/jdk/java/lang/invoke/lookup/ChainedLookupTest.java index 0e81c6a9eec..15a46e6ca2c 100644 --- a/test/jdk/java/lang/invoke/lookup/ChainedLookupTest.java +++ b/test/jdk/java/lang/invoke/lookup/ChainedLookupTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @bug 8013527 - * @run testng/othervm ChainedLookupTest + * @run junit/othervm ChainedLookupTest * @summary Test MethodHandles.lookup method to produce the Lookup object with * proper lookup class if invoked through reflection and method handle. */ @@ -33,11 +33,11 @@ import java.lang.invoke.*; import java.lang.invoke.MethodHandles.Lookup; import java.lang.reflect.Method; -import org.testng.annotations.Test; import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class ChainedLookupTest { /** @@ -121,7 +121,7 @@ public class ChainedLookupTest { } void test(Lookup lookup, String msg) throws Throwable { - assertTrue(lookup.lookupClass() == ChainedLookupTest.class); + assertSame(ChainedLookupTest.class, lookup.lookupClass()); assertTrue(lookup.hasFullPrivilegeAccess()); MethodHandle mh = lookup.findStatic(lookup.lookupClass(), "say", methodType(void.class, String.class)); diff --git a/test/jdk/java/lang/invoke/lookup/LookupClassTest.java b/test/jdk/java/lang/invoke/lookup/LookupClassTest.java index 205bd3d893e..5970d0331dd 100644 --- a/test/jdk/java/lang/invoke/lookup/LookupClassTest.java +++ b/test/jdk/java/lang/invoke/lookup/LookupClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,44 +25,44 @@ * @test * @bug 8173975 * @summary Lookup::in throws IAE if the target class is a primitive class or array class - * @run testng/othervm LookupClassTest + * @run junit/othervm LookupClassTest */ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; public class LookupClassTest { private static final LookupClassTest[] ARRAY = new LookupClassTest[0]; - @BeforeTest - public void test() { + @BeforeAll + public static void test() { assertTrue(ARRAY.getClass().isArray()); assertSamePackage(MethodHandles.lookup(), ARRAY.getClass()); assertSamePackage(MethodHandles.publicLookup(), int.class); } - private void assertSamePackage(Lookup lookup, Class targetClass) { - assertEquals(lookup.lookupClass().getPackageName(), targetClass.getPackageName()); + private static void assertSamePackage(Lookup lookup, Class targetClass) { + assertEquals(targetClass.getPackageName(), lookup.lookupClass().getPackageName()); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void arrayLookupClass() { Lookup lookup = MethodHandles.lookup(); - lookup.in(ARRAY.getClass()); + assertThrows(IllegalArgumentException.class, () -> lookup.in(ARRAY.getClass())); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void primitiveLookupClass() { Lookup lookup = MethodHandles.publicLookup(); - lookup.in(int.class); + assertThrows(IllegalArgumentException.class, () -> lookup.in(int.class)); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void voidLookupClass() { Lookup lookup = MethodHandles.publicLookup(); - lookup.in(void.class); + assertThrows(IllegalArgumentException.class, () -> lookup.in(void.class)); } } diff --git a/test/jdk/java/lang/invoke/lookup/SpecialStatic.java b/test/jdk/java/lang/invoke/lookup/SpecialStatic.java index 31ded727d66..3ff99b9dfda 100644 --- a/test/jdk/java/lang/invoke/lookup/SpecialStatic.java +++ b/test/jdk/java/lang/invoke/lookup/SpecialStatic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @bug 8032400 * @summary JSR292: invokeSpecial: InternalError attempting to lookup a method * @compile -XDignore.symbol.file SpecialStatic.java - * @run testng test.java.lang.invoke.lookup.SpecialStatic + * @run junit test.java.lang.invoke.lookup.SpecialStatic */ package test.java.lang.invoke.lookup; @@ -38,13 +38,13 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.AccessFlag; -import org.testng.annotations.*; import static java.lang.classfile.ClassFile.ACC_PUBLIC; import static java.lang.classfile.ClassFile.ACC_STATIC; import static java.lang.constant.ConstantDescs.*; import static java.lang.constant.DirectMethodHandleDesc.Kind.SPECIAL; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; /** * Test case: @@ -105,7 +105,7 @@ public class SpecialStatic { public void testConstant() throws Throwable { MethodHandle mh = (MethodHandle)t3.getDeclaredMethod("getMethodHandle").invoke(null); int result = (int)mh.invoke(t3.newInstance()); - assertEquals(result, 1); // T1.m should be invoked. + assertEquals(1, result); // T1.m should be invoked. } @Test @@ -113,7 +113,7 @@ public class SpecialStatic { MethodHandles.Lookup lookup = (MethodHandles.Lookup)t3.getDeclaredMethod("getLookup").invoke(null); MethodHandle mh = lookup.findSpecial(t1, "m", MethodType.methodType(int.class), t3); int result = (int)mh.invoke(t3.newInstance()); - assertEquals(result, 1); // T1.m should be invoked. + assertEquals(1, result); // T1.m should be invoked. } public static byte[] dumpT1() { diff --git a/test/jdk/java/lang/invoke/modules/Driver.java b/test/jdk/java/lang/invoke/modules/Driver.java index 5c00de3ad47..11c44280309 100644 --- a/test/jdk/java/lang/invoke/modules/Driver.java +++ b/test/jdk/java/lang/invoke/modules/Driver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,9 +21,9 @@ * questions. */ -/** +/* * @test * @build m1/* m2/* Unnamed - * @run testng/othervm m1/p1.Main + * @run junit/othervm m1/p1.Main * @summary Basic test case for module access checks and Lookup.in. */ diff --git a/test/jdk/java/lang/invoke/modules/Driver1.java b/test/jdk/java/lang/invoke/modules/Driver1.java index 654ee04c9e0..4ef7130ff94 100644 --- a/test/jdk/java/lang/invoke/modules/Driver1.java +++ b/test/jdk/java/lang/invoke/modules/Driver1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,11 +21,11 @@ * questions. */ -/** +/* * @test * @bug 8173978 * @build m3/* m4/* m5/* Unnamed Unnamed1 - * @run testng/othervm m3/jdk.test.ModuleAccessTest + * @run junit/othervm m3/jdk.test.ModuleAccessTest * @summary Basic test case for module access checks and Lookup.in and * MethodHandles.privateLookupIn */ diff --git a/test/jdk/java/lang/invoke/modules/m1/module-info.java b/test/jdk/java/lang/invoke/modules/m1/module-info.java index db03841b4d0..ecd133ae6a1 100644 --- a/test/jdk/java/lang/invoke/modules/m1/module-info.java +++ b/test/jdk/java/lang/invoke/modules/m1/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,6 @@ */ module m1 { requires m2; - requires org.testng; + requires org.junit.platform.console.standalone; exports p1; } diff --git a/test/jdk/java/lang/invoke/modules/m1/p1/Main.java b/test/jdk/java/lang/invoke/modules/m1/p1/Main.java index 0a4d2fff1db..5a2a7c91999 100644 --- a/test/jdk/java/lang/invoke/modules/m1/p1/Main.java +++ b/test/jdk/java/lang/invoke/modules/m1/p1/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,26 +30,24 @@ import java.lang.invoke.MethodType; import static java.lang.invoke.MethodHandles.Lookup.*; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; /** * Basic test case for module access checks and Lookup.in. */ - -@Test public class Main { - private Class p1_Type1; // m1, exported - private Class p2_Type2; // m1, not exported - private Class q1_Type1; // m2, exported - private Class q2_Type2; // m2, not exported - private Class signalClass; // java.base, not exported - private Class unnamedClass; // class in unnamed module + private static Class p1_Type1; // m1, exported + private static Class p2_Type2; // m1, not exported + private static Class q1_Type1; // m2, exported + private static Class q2_Type2; // m2, not exported + private static Class signalClass; // java.base, not exported + private static Class unnamedClass; // class in unnamed module - @BeforeTest - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { try { p1_Type1 = Class.forName("p1.Type1"); p2_Type2 = Class.forName("p2.Type2"); @@ -64,15 +62,15 @@ public class Main { // check setup Module m1 = ModuleLayer.boot().findModule("m1").orElse(null); assertNotNull(m1); - assertTrue(p1_Type1.getModule() == m1); - assertTrue(p2_Type2.getModule() == m1); + assertSame(m1, p1_Type1.getModule()); + assertSame(m1, p2_Type2.getModule()); assertTrue(m1.isExported("p1")); assertFalse(m1.isExported("p2")); Module m2 = ModuleLayer.boot().findModule("m2").orElse(null); assertNotNull(m2); - assertTrue(q1_Type1.getModule() == m2); - assertTrue(q2_Type2.getModule() == m2); + assertSame(m2, q1_Type1.getModule()); + assertSame(m2, q2_Type2.getModule()); assertTrue(m2.isExported("q1")); assertFalse(m2.isExported("q2")); @@ -91,9 +89,10 @@ public class Main { * [A2] can access public types in packages exported by modules that m1 reads * [A3] cannot access public types in non-exported modules of modules that m1 reads */ + @Test public void testLookup() throws Exception { Lookup lookup = MethodHandles.lookup(); - assertTrue((lookup.lookupModes() & MODULE) == MODULE); // [A0] + assertEquals(MODULE, lookup.lookupModes() & MODULE); // [A0] // m1 findConstructor(lookup, p1_Type1, void.class); // [A1] @@ -116,9 +115,10 @@ public class Main { * * [A0] module and public access is not lost */ + @Test public void testToSameModule() throws Exception { Lookup lookup = MethodHandles.lookup().in(p2_Type2); - assertTrue(lookup.lookupModes() == (MODULE|PUBLIC)); // [A0] + assertEquals(MODULE | PUBLIC, lookup.lookupModes()); // [A0] // m1 findConstructor(lookup, p1_Type1, void.class); @@ -142,15 +142,16 @@ public class Main { * [A0] has PUBLIC access if accessible; otherwise no access * [A1] old lookup class becomes previous lookup class */ + @Test public void testFromNamedToNamedModule() throws Exception { // m2/q1_Type1 is accessible to m1 whereas m2/q_Type2 is not accessible Lookup lookup = MethodHandles.lookup().in(q1_Type1); - assertTrue(lookup.lookupModes() == PUBLIC); // [A0] - assertTrue(lookup.previousLookupClass() == Main.class); // [A1] + assertEquals(PUBLIC, lookup.lookupModes()); // [A0] + assertSame(Main.class, lookup.previousLookupClass()); // [A1] Lookup lookup2 = MethodHandles.lookup().in(q2_Type2); - assertTrue(lookup2.lookupModes() == 0); // [A0] - assertTrue(lookup2.previousLookupClass() == Main.class); // [A1] + assertEquals(0, lookup2.lookupModes()); // [A0] + assertSame(Main.class, lookup2.previousLookupClass()); // [A1] // m1 findConstructorExpectingIAE(lookup, p1_Type1, void.class); @@ -185,9 +186,10 @@ public class Main { * * [A0] has PUBLIC access */ + @Test public void testFromNamedToUnnamedModule() throws Exception { Lookup lookup = MethodHandles.lookup().in(unnamedClass); - assertTrue(lookup.lookupModes() == PUBLIC); // [A0] + assertEquals(PUBLIC, lookup.lookupModes()); // [A0] // m1 findConstructor(lookup, p1_Type1, void.class); // p1 is exported @@ -210,10 +212,11 @@ public class Main { * * [A0] retains PUBLIC access */ + @Test public void testFromUnnamedToNamedModule() throws Exception { Lookup lookup = MethodHandles.lookup(); lookup = MethodHandles.privateLookupIn(unnamedClass, lookup).in(p1_Type1); - assertTrue(lookup.lookupModes() == PUBLIC); // A0 + assertEquals(PUBLIC, lookup.lookupModes()); // A0 // m1 findConstructor(lookup, p1_Type1, void.class); @@ -236,9 +239,10 @@ public class Main { * * [A0] has UNCONDITIONAL access */ + @Test public void testPublicLookup() throws Exception { Lookup lookup = MethodHandles.publicLookup(); - assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0 + assertEquals(UNCONDITIONAL, lookup.lookupModes()); // A0 // m1 findConstructor(lookup, p1_Type1, void.class); @@ -261,9 +265,10 @@ public class Main { * * [A0] has UNCONDITIONAL access */ + @Test public void testPublicLookupToBaseModule() throws Exception { Lookup lookup = MethodHandles.publicLookup().in(String.class); - assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0 + assertEquals(UNCONDITIONAL, lookup.lookupModes()); // A0 // m1 findConstructor(lookup, p1_Type1, void.class); @@ -287,9 +292,10 @@ public class Main { * * [A0] has UNCONDITIONAL access */ + @Test public void testPublicLookupToAccessibleTypeInNamedModule() throws Exception { Lookup lookup = MethodHandles.publicLookup().in(p1_Type1); - assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0 + assertEquals(UNCONDITIONAL, lookup.lookupModes()); // A0 // m1 findConstructor(lookup, p1_Type1, void.class); @@ -312,9 +318,10 @@ public class Main { * * [A0] has no access */ + @Test public void testPublicLookupToInaccessibleTypeInNamedModule() throws Exception { Lookup lookup = MethodHandles.publicLookup().in(p2_Type2); - assertTrue(lookup.lookupModes() == 0); // A0 + assertEquals(0, lookup.lookupModes()); // A0 // m1 findConstructorExpectingIAE(lookup, p1_Type1, void.class); @@ -337,9 +344,10 @@ public class Main { * * [A0] has UNCONDITIONAL access */ + @Test public void testPublicLookupToUnnamedModule() throws Exception { Lookup lookup = MethodHandles.publicLookup().in(unnamedClass); - assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0 + assertEquals(UNCONDITIONAL, lookup.lookupModes()); // A0 // m1 findConstructor(lookup, p1_Type1, void.class); @@ -366,10 +374,7 @@ public class Main { Class clazz, Class rtype, Class... ptypes) throws Exception { - try { - findConstructor(lookup, clazz, rtype, ptypes); - assertTrue(false); - } catch (IllegalAccessException expected) { } + assertThrows(IllegalAccessException.class, () -> findConstructor(lookup, clazz, rtype, ptypes)); } /** diff --git a/test/jdk/java/lang/invoke/modules/m3/jdk/test/ModuleAccessTest.java b/test/jdk/java/lang/invoke/modules/m3/jdk/test/ModuleAccessTest.java index 6a1e8efe103..235c712926d 100644 --- a/test/jdk/java/lang/invoke/modules/m3/jdk/test/ModuleAccessTest.java +++ b/test/jdk/java/lang/invoke/modules/m3/jdk/test/ModuleAccessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,15 +23,12 @@ package jdk.test; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; +import java.lang.management.ThreadMXBean; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; @@ -42,7 +39,11 @@ import java.util.stream.Stream; import e1.CrackM5Access; import static java.lang.invoke.MethodHandles.Lookup.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class ModuleAccessTest { static ModuleLookup m3; @@ -55,8 +56,8 @@ public class ModuleAccessTest { static Class unnamed; static Class unnamed1; - @BeforeTest - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { m3 = new ModuleLookup("m3", 'C'); m4 = new ModuleLookup("m4", 'D'); m5 = new ModuleLookup("m5", 'E'); @@ -76,8 +77,7 @@ public class ModuleAccessTest { CrackM5Access.addReads(unnamed.getModule()); } - @DataProvider(name = "samePackage") - public Object[][] samePackage() throws Exception { + public static Object[][] samePackage() throws Exception { return new Object[][] { { m3.lookup, m3.type2 }, { privLookupIn, m3.type1 }, @@ -93,7 +93,8 @@ public class ModuleAccessTest { * [A1] no change in previous lookup class * [A2] PROTECTED, PRIVATE and ORIGINAL are dropped */ - @Test(dataProvider = "samePackage") + @ParameterizedTest + @MethodSource("samePackage") public void testLookupInSamePackage(Lookup lookup, Class targetClass) throws Exception { Class lookupClass = lookup.lookupClass(); Lookup lookup2 = lookup.in(targetClass); @@ -105,8 +106,7 @@ public class ModuleAccessTest { assertTrue(lookup2.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE|ORIGINAL))); // [A2] } - @DataProvider(name = "sameModule") - public Object[][] sameModule() throws Exception { + public static Object[][] sameModule() throws Exception { return new Object[][] { { m3.lookup, m3.type3}, { privLookupIn, m3.type3}, @@ -121,20 +121,20 @@ public class ModuleAccessTest { * [A1] no change in previous lookup class * [A2] PROTECTED, PRIVATE, PACKAGE and ORIGINAL are dropped */ - @Test(dataProvider = "sameModule") + @ParameterizedTest + @MethodSource("sameModule") public void testLookupInSameModule(Lookup lookup, Class targetClass) throws Exception { Class lookupClass = lookup.lookupClass(); Lookup lookup2 = lookup.in(targetClass); - assertTrue(lookupClass.getPackage() != targetClass.getPackage()); - assertTrue(lookupClass.getModule() == targetClass.getModule()); - assertTrue(lookup2.lookupClass() == targetClass); // [A0] - assertTrue(lookup2.previousLookupClass() == lookup.previousLookupClass()); // [A1] - assertTrue(lookup2.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE|PACKAGE|ORIGINAL))); // [A2] + assertNotSame(targetClass.getPackage(), lookupClass.getPackage()); + assertSame(targetClass.getModule(), lookupClass.getModule()); + assertSame(targetClass, lookup2.lookupClass()); // [A0] + assertSame(lookup.previousLookupClass(), lookup2.previousLookupClass()); // [A1] + assertEquals(lookup.lookupModes() & ~(PROTECTED | PRIVATE | PACKAGE | ORIGINAL), lookup2.lookupModes()); // [A2] } - @DataProvider(name = "anotherModule") - public Object[][] anotherModule() throws Exception { + public static Object[][] anotherModule() throws Exception { return new Object[][] { { m3.lookup, m4.type1, m5, m5.accessibleTypesTo(m3.module, m4.module) }, { m4.lookup, m5.type2, m3, m3.accessibleTypesTo(m4.module, m5.module) }, @@ -154,21 +154,22 @@ public class ModuleAccessTest { * [A5] can access public types in m1 exported to m0 * [A6] can access public types in m2 exported to m0 and m1 */ - @Test(dataProvider = "anotherModule") + @ParameterizedTest + @MethodSource("anotherModule") public void testLookupInAnotherModule(Lookup lookup, Class targetClass, ModuleLookup m2, Set> otherTypes) throws Exception { Class lookupClass = lookup.lookupClass(); Module m0 = lookupClass.getModule(); Module m1 = targetClass.getModule(); - assertTrue(m0 != m1); + assertNotSame(m1, m0); assertTrue(m0.canRead(m1)); assertTrue(m1.isExported(targetClass.getPackageName(), m0)); Lookup lookup2 = lookup.in(targetClass); - assertTrue(lookup2.lookupClass() == targetClass); // [A0] - assertTrue(lookup2.previousLookupClass() == lookup.lookupClass()); // [A1] - assertTrue(lookup2.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE|PACKAGE|MODULE|ORIGINAL))); // [A2] + assertSame(targetClass, lookup2.lookupClass()); // [A0] + assertSame(lookup.lookupClass(), lookup2.previousLookupClass()); // [A1] + assertEquals(lookup.lookupModes() & ~(PROTECTED | PRIVATE | PACKAGE | MODULE | ORIGINAL), lookup2.lookupModes()); // [A2] // [A3] no access to module internal type in m0 // [A4] if m1 reads m0, @@ -207,7 +208,7 @@ public class ModuleAccessTest { // [A5] can access public types exported from m2 unconditionally // [A5] can access public types exported from m2 to m0 and m1 for (Class type : otherTypes) { - assertTrue(type.getModule() == m2.module); + assertSame(m2.module, type.getModule()); testAccess(lookup2, type); } @@ -215,10 +216,7 @@ public class ModuleAccessTest { for (Class type : Set.of(m2.type1, m2.type2, m2.type3)) { if (!otherTypes.contains(type)) { // type is accessible to this lookup - try { - lookup2.accessClass(type); - assertTrue(false); - } catch (IllegalAccessException e) {} + assertThrows(IllegalAccessException.class, () -> lookup2.accessClass(type)); findConstructorExpectingIAE(lookup2, type, void.class); } @@ -227,7 +225,7 @@ public class ModuleAccessTest { public void testAccess(Lookup lookup, Class type) throws Exception { // type is accessible to this lookup - assertTrue(lookup.accessClass(type) == type); + assertSame(type, lookup.accessClass(type)); // can find constructor findConstructor(lookup, type, void.class); @@ -237,28 +235,27 @@ public class ModuleAccessTest { Module m2 = type.getModule(); assertTrue(m0 != m1 && m0 != null); - assertTrue((lookup.lookupModes() & MODULE) == 0); + assertEquals(0, lookup.lookupModes() & MODULE); assertTrue(m0 != m2 || m1 != m2); MethodHandles.Lookup lookup2 = lookup.in(type); if (m2 == m1) { // the same module of the lookup class - assertTrue(lookup2.lookupClass() == type); - assertTrue(lookup2.previousLookupClass() == lookup.previousLookupClass()); + assertSame(type, lookup2.lookupClass()); + assertSame(lookup.previousLookupClass(), lookup2.previousLookupClass()); } else if (m2 == m0) { // hop back to the module of the previous lookup class - assertTrue(lookup2.lookupClass() == type); - assertTrue(lookup2.previousLookupClass() == lookup.lookupClass()); + assertSame(type, lookup2.lookupClass()); + assertSame(lookup.lookupClass(), lookup2.previousLookupClass()); } else { // hop to a third module - assertTrue(lookup2.lookupClass() == type); - assertTrue(lookup2.previousLookupClass() == lookup.lookupClass()); - assertTrue(lookup2.lookupModes() == 0); + assertSame(type, lookup2.lookupClass()); + assertSame(lookup.lookupClass(), lookup2.previousLookupClass()); + assertEquals(0, lookup2.lookupModes()); } } - @DataProvider(name = "thirdModule") - public Object[][] thirdModule() throws Exception { + public static Object[][] thirdModule() throws Exception { return new Object[][] { { m3.lookup, m4.type1, m5.type1}, { m3.lookup, m4.type2, m5.type1}, @@ -273,7 +270,8 @@ public class ModuleAccessTest { * [A1] c1 becomes previous lookup class * [A2] all access bits are dropped */ - @Test(dataProvider = "thirdModule") + @ParameterizedTest + @MethodSource("thirdModule") public void testLookupInThirdModule(Lookup lookup, Class c1, Class c2) throws Exception { Class c0 = lookup.lookupClass(); Module m0 = c0.getModule(); @@ -287,18 +285,17 @@ public class ModuleAccessTest { assertTrue(m2.isExported(c2.getPackageName(), m0) && m2.isExported(c2.getPackageName(), m1)); Lookup lookup1 = lookup.in(c1); - assertTrue(lookup1.lookupClass() == c1); - assertTrue(lookup1.previousLookupClass() == c0); - assertTrue(lookup1.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE|PACKAGE|MODULE|ORIGINAL))); + assertSame(c1, lookup1.lookupClass()); + assertSame(c0, lookup1.previousLookupClass()); + assertEquals(lookup.lookupModes() & ~(PROTECTED | PRIVATE | PACKAGE | MODULE | ORIGINAL), lookup1.lookupModes()); Lookup lookup2 = lookup1.in(c2); - assertTrue(lookup2.lookupClass() == c2); // [A0] - assertTrue(lookup2.previousLookupClass() == c1); // [A1] - assertTrue(lookup2.lookupModes() == 0, lookup2.toString()); // [A2] + assertSame(c2, lookup2.lookupClass()); // [A0] + assertSame(c1, lookup2.previousLookupClass()); // [A1] + assertEquals(0, lookup2.lookupModes(), lookup2.toString()); // [A2] } - @DataProvider(name = "privLookupIn") - public Object[][] privLookupIn() throws Exception { + public static Object[][] privLookupIn() throws Exception { return new Object[][] { { m3.lookup, m4.type1 }, { m3.lookup, m5.type1 }, @@ -316,24 +313,22 @@ public class ModuleAccessTest { * [A2] the lookup class becomes previous lookup class * [A3] IAE thrown if lookup has no MODULE access */ - @Test(dataProvider = "privLookupIn") + @ParameterizedTest + @MethodSource("privLookupIn") public void testPrivateLookupIn(Lookup lookup, Class targetClass) throws Exception { Module m0 = lookup.lookupClass().getModule(); Module m1 = targetClass.getModule(); // privateLookupIn from m0 to m1 - assertTrue(m0 != m1); + assertNotSame(m1, m0); assertTrue(m1.isOpen(targetClass.getPackageName(), m0)); Lookup privLookup1 = MethodHandles.privateLookupIn(targetClass, lookup); - assertTrue(privLookup1.lookupModes() == (PROTECTED|PRIVATE|PACKAGE|PUBLIC)); // [A0] - assertTrue(privLookup1.lookupClass() == targetClass); // [A1] - assertTrue(privLookup1.previousLookupClass() == lookup.lookupClass()); // [A2] + assertEquals(PROTECTED | PRIVATE | PACKAGE | PUBLIC, privLookup1.lookupModes()); // [A0] + assertSame(targetClass, privLookup1.lookupClass()); // [A1] + assertSame(lookup.lookupClass(), privLookup1.previousLookupClass()); // [A2] // privLookup1 has no MODULE access; can't do privateLookupIn - try { - Lookup privLookup2 = MethodHandles.privateLookupIn(targetClass, privLookup1); // [A3] - assertFalse(privLookup2 != null); - } catch (IllegalAccessException e) {} + assertThrows(IllegalAccessException.class, () -> MethodHandles.privateLookupIn(targetClass, privLookup1)); // [A3] } /** @@ -343,9 +338,9 @@ public class ModuleAccessTest { public void testPrivateLookupAccess() throws Exception { Class staticsClass = e1.Statics.class; Lookup privLookup1 = MethodHandles.privateLookupIn(staticsClass, m4.lookup); - assertTrue((privLookup1.lookupModes() & MODULE) == 0); - assertTrue(privLookup1.lookupClass() == staticsClass); - assertTrue(privLookup1.previousLookupClass() == m4.lookup.lookupClass()); + assertEquals(0, (privLookup1.lookupModes() & MODULE)); + assertSame(staticsClass, privLookup1.lookupClass()); + assertSame(m4.lookup.lookupClass(), privLookup1.previousLookupClass()); // access private member and default package member in m5 MethodType mtype = MethodType.methodType(void.class); @@ -365,12 +360,9 @@ public class ModuleAccessTest { // lose private access Lookup privLookup2 = MethodHandles.privateLookupIn(m5.type1, m4.lookup); Lookup lookup = privLookup2.in(staticsClass); - assertTrue((lookup.lookupModes() & PRIVATE) == 0); + assertEquals(0, lookup.lookupModes() & PRIVATE); MethodHandle mh3 = lookup.findStatic(staticsClass, "packageMethod", mtype); - try { - lookup.findStatic(staticsClass, "privateMethod", mtype); - assertTrue(false); - } catch (IllegalAccessException e) {} + assertThrows(IllegalAccessException.class, () -> lookup.findStatic(staticsClass, "privateMethod", mtype)); } /** @@ -380,16 +372,16 @@ public class ModuleAccessTest { @Test public void testDropLookupMode() throws Exception { Lookup lookup = MethodHandles.privateLookupIn(m5.type1, m4.lookup); - assertTrue((lookup.lookupModes() & MODULE) == 0); + assertEquals(0, lookup.lookupModes() & MODULE); Lookup lookup1 = lookup.dropLookupMode(PRIVATE); - assertTrue(lookup1.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE))); + assertEquals(lookup1.lookupModes(), lookup.lookupModes() & ~(PROTECTED | PRIVATE)); Lookup lookup2 = lookup.dropLookupMode(PACKAGE); - assertTrue(lookup2.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE|PACKAGE))); + assertEquals(lookup2.lookupModes(), lookup.lookupModes() & ~(PROTECTED | PRIVATE | PACKAGE)); Lookup lookup3 = lookup.dropLookupMode(MODULE); - assertTrue(lookup3.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE|PACKAGE))); + assertEquals(lookup3.lookupModes(), lookup.lookupModes() & ~(PROTECTED | PRIVATE | PACKAGE)); Lookup lookup4 = lookup.dropLookupMode(PUBLIC); - assertTrue(lookup4.lookupModes() == 0); + assertEquals(0, lookup4.lookupModes()); } @@ -406,11 +398,8 @@ public class ModuleAccessTest { // drop MODULE access i.e. only PUBLIC access Lookup lookup = privLookup.dropLookupMode(MODULE); - assertTrue(lookup.lookupModes() == PUBLIC); - try { - MethodHandle mh2 = lookup.findStatic(nonPUblicType, "publicStatic", mtype); - assertFalse(mh2 != null); - } catch (IllegalAccessException e) {} + assertEquals(PUBLIC, lookup.lookupModes()); + assertThrows(IllegalAccessException.class, () -> lookup.findStatic(nonPUblicType, "publicStatic", mtype)); } @Test @@ -421,21 +410,18 @@ public class ModuleAccessTest { Lookup pub3 = pub2.in(java.lang.management.ThreadMXBean.class); Lookup pub4 = pub3.dropLookupMode(UNCONDITIONAL); - assertTrue(publicLookup.lookupClass() == Object.class); - assertTrue(publicLookup.lookupModes() == UNCONDITIONAL); - assertTrue(pub1.lookupClass() == m3.type1); - assertTrue(pub1.lookupModes() == UNCONDITIONAL); - assertTrue(pub2.lookupClass() == String.class); - assertTrue(pub2.lookupModes() == UNCONDITIONAL); - assertTrue(pub3.lookupClass() == java.lang.management.ThreadMXBean.class); - assertTrue(pub3.lookupModes() == UNCONDITIONAL); - assertTrue(pub4.lookupModes() == 0); + assertSame(Object.class, publicLookup.lookupClass()); + assertEquals(UNCONDITIONAL, publicLookup.lookupModes()); + assertSame(m3.type1, pub1.lookupClass()); + assertEquals(UNCONDITIONAL, pub1.lookupModes()); + assertSame(String.class, pub2.lookupClass()); + assertEquals(UNCONDITIONAL, pub2.lookupModes()); + assertSame(ThreadMXBean.class, pub3.lookupClass()); + assertEquals(UNCONDITIONAL, pub3.lookupModes()); + assertEquals(0, pub4.lookupModes()); // publicLookup has no MODULE access; can't do privateLookupIn - try { - Lookup pub5 = MethodHandles.privateLookupIn(m4.type1, pub1); - assertFalse(pub5 != null); - } catch (IllegalAccessException e) {} + assertThrows(IllegalAccessException.class, () -> MethodHandles.privateLookupIn(m4.type1, pub1)); } static class ModuleLookup { @@ -548,10 +534,7 @@ public class ModuleAccessTest { Class clazz, Class rtype, Class... ptypes) throws Exception { - try { - MethodHandle mh = findConstructor(lookup, clazz, rtype, ptypes); - assertTrue(false); - } catch (IllegalAccessException expected) { } + assertThrows(IllegalAccessException.class, () -> findConstructor(lookup, clazz, rtype, ptypes)); } /** diff --git a/test/jdk/java/lang/invoke/modules/m3/module-info.java b/test/jdk/java/lang/invoke/modules/m3/module-info.java index 1f47c42c196..c9d8fab20a5 100644 --- a/test/jdk/java/lang/invoke/modules/m3/module-info.java +++ b/test/jdk/java/lang/invoke/modules/m3/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ module m3 { requires m4; requires m5; - requires org.testng; + requires org.junit.platform.console.standalone; requires java.management; exports c1; opens c2 to m5; From 2c3ad0f425c75332412a5e8e5733dd0d073a09c8 Mon Sep 17 00:00:00 2001 From: Cesar Soares Lucas Date: Fri, 23 Jan 2026 17:56:04 +0000 Subject: [PATCH 163/328] 8373021: aarch64: MacroAssembler::arrays_equals reads out of bounds Reviewed-by: rkennke, aph --- src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index b8a9afc123f..27428a5c558 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -5782,6 +5782,9 @@ address MacroAssembler::arrays_equals(Register a1, Register a2, Register tmp3, // return false; bind(A_IS_NOT_NULL); ldrw(cnt1, Address(a1, length_offset)); + ldrw(tmp5, Address(a2, length_offset)); + cmp(cnt1, tmp5); + br(NE, DONE); // If lengths differ, return false // Increase loop counter by diff between base- and actual start-offset. addw(cnt1, cnt1, extra_length); lea(a1, Address(a1, start_offset)); @@ -5848,6 +5851,9 @@ address MacroAssembler::arrays_equals(Register a1, Register a2, Register tmp3, cbz(a1, DONE); ldrw(cnt1, Address(a1, length_offset)); cbz(a2, DONE); + ldrw(tmp5, Address(a2, length_offset)); + cmp(cnt1, tmp5); + br(NE, DONE); // If lengths differ, return false // Increase loop counter by diff between base- and actual start-offset. addw(cnt1, cnt1, extra_length); From e08fb3a914ac348dc691ae3fc46c6bdbc34faf46 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 23 Jan 2026 18:19:23 +0000 Subject: [PATCH 164/328] 8375221: Update code to get PrinterResolution from CUPS/IPP print service Reviewed-by: serb, psadhukhan --- .../classes/sun/print/AttributeClass.java | 24 +++++++ .../classes/sun/print/IPPPrintService.java | 67 ++++++++++--------- .../unix/native/common/awt/CUPSfuncs.c | 57 +++++++++++++++- test/jdk/javax/print/PrintablePrintDPI.java | 8 ++- 4 files changed, 120 insertions(+), 36 deletions(-) diff --git a/src/java.desktop/unix/classes/sun/print/AttributeClass.java b/src/java.desktop/unix/classes/sun/print/AttributeClass.java index 10d0714a059..3db6e310dd2 100644 --- a/src/java.desktop/unix/classes/sun/print/AttributeClass.java +++ b/src/java.desktop/unix/classes/sun/print/AttributeClass.java @@ -174,6 +174,30 @@ public final class AttributeClass { } + /** + * Returns 3 int values. + * xres, yres, resolution as either dpi or dpcm + * The resolution is just a single byte of data. + */ + public int[] getIntResolutionValue() { + int[] res = {0, 0, 0}; + byte[] bufArray = (byte[])myValue; + if (bufArray != null) { + int nBytes = 4; // 32-bit signed integer + for (int j=0; j<2; j++) { // 2 set of integers + byte[] intBytes = new byte[nBytes]; + // REMIND: # bytes should be 8 + for (int i=0; i< nBytes; i++) { + //+ 1 because the 1st byte is length + intBytes[i] = bufArray[i+(4*j)+1]; + } + res[j] = convertToInt(intBytes); + } + res[2] = (int)bufArray[9]; + } + return res; + } + /** * Returns String value. */ diff --git a/src/java.desktop/unix/classes/sun/print/IPPPrintService.java b/src/java.desktop/unix/classes/sun/print/IPPPrintService.java index 2bf326fca57..8a3b872b107 100644 --- a/src/java.desktop/unix/classes/sun/print/IPPPrintService.java +++ b/src/java.desktop/unix/classes/sun/print/IPPPrintService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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 @@ -141,7 +141,7 @@ public final class IPPPrintService implements PrintService, SunPrinterJobService private MediaSizeName[] mediaSizeNames; private CustomMediaSizeName[] customMediaSizeNames; private int defaultMediaIndex; - private int[] rawResolutions = null; + private int[] ppdResolutions = null; private PrinterResolution[] printerResolutions = null; private boolean isCupsPrinter; private boolean init; @@ -205,8 +205,7 @@ public final class IPPPrintService implements PrintService, SunPrinterJobService OrientationRequested.PORTRAIT, new PageRanges(1), //PresentationDirection, - // CUPS does not supply printer-resolution attribute - //new PrinterResolution(300, 300, PrinterResolution.DPI), + new PrinterResolution(300, 300, PrinterResolution.DPI), //PrintQuality.NORMAL, new RequestingUserName("", Locale.getDefault()), //SheetCollate.UNCOLLATED, //CUPS has no sheet collate? @@ -467,7 +466,9 @@ public final class IPPPrintService implements PrintService, SunPrinterJobService : getSupportedOutputBins(); customMediaSizeNames = cps.getCustomMediaSizeNames(); defaultMediaIndex = cps.getDefaultMediaIndex(); - rawResolutions = cps.getRawResolutions(); + if (ppdResolutions == null) { + ppdResolutions = cps.getRawResolutions(); + } } urlConnection.disconnect(); init = true; @@ -821,14 +822,7 @@ public final class IPPPrintService implements PrintService, SunPrinterJobService } } } else if (category == PrinterResolution.class) { - PrinterResolution[] supportedRes = getPrintResolutions(); - if (supportedRes == null) { - return null; - } - PrinterResolution []arr = - new PrinterResolution[supportedRes.length]; - System.arraycopy(supportedRes, 0, arr, 0, supportedRes.length); - return arr; + return getPrintResolutions(); } else if (category == OutputBin.class) { return Arrays.copyOf(outputBins, outputBins.length); } @@ -1137,8 +1131,6 @@ public final class IPPPrintService implements PrintService, SunPrinterJobService catList.add(Chromaticity.class); } - // CUPS does not report printer resolution via IPP but it - // may be gleaned from the PPD. PrinterResolution[] supportedRes = getPrintResolutions(); if (supportedRes != null && (supportedRes.length > 0)) { catList.add(PrinterResolution.class); @@ -1264,7 +1256,6 @@ public final class IPPPrintService implements PrintService, SunPrinterJobService } } - @Override public synchronized PrintServiceAttributeSet getAttributes() { if (!init) { @@ -1684,9 +1675,7 @@ public final class IPPPrintService implements PrintService, SunPrinterJobService } else if (category == PrinterResolution.class) { PrinterResolution[] supportedRes = getPrintResolutions(); if ((supportedRes != null) && (supportedRes.length > 0)) { - return supportedRes[0]; - } else { - return new PrinterResolution(300, 300, PrinterResolution.DPI); + return supportedRes[0]; } } else if (category == OutputBin.class) { if (attribClass != null) { @@ -1697,26 +1686,40 @@ public final class IPPPrintService implements PrintService, SunPrinterJobService return null; } + /* Called only from contexts that have called initAttributes(). + * Try IPP first, and if that produces nothing, fall back to the PPD + */ private PrinterResolution[] getPrintResolutions() { + int[] rawResolutions = null; if (printerResolutions == null) { - if (rawResolutions == null) { - printerResolutions = new PrinterResolution[0]; - } else { - int numRes = rawResolutions.length / 2; - PrinterResolution[] pres = new PrinterResolution[numRes]; - for (int i=0; i < numRes; i++) { - pres[i] = new PrinterResolution(rawResolutions[i*2], - rawResolutions[i*2+1], - PrinterResolution.DPI); - } - printerResolutions = pres; + AttributeClass attribClass = (getAttMap != null) ? + getAttMap.get("printer-resolution-supported") + : null; + if (attribClass != null) { + rawResolutions = attribClass.getIntResolutionValue(); } + if (rawResolutions == null) { + rawResolutions = ppdResolutions; + } + if (rawResolutions == null) { + rawResolutions = new int[] { 300, 300, 3 } ; + } + int numRes = rawResolutions.length / 3; + PrinterResolution[] pres = new PrinterResolution[numRes]; + for (int i = 0; i < numRes; i++) { + int units = (rawResolutions[i*3+2] == 4) ? PrinterResolution.DPCM : PrinterResolution.DPI; + pres[i] = new PrinterResolution(rawResolutions[i*3], + rawResolutions[i*3+1], + units); + } + printerResolutions = pres; } - return printerResolutions; + return printerResolutions.clone(); } private boolean isSupportedResolution(PrinterResolution res) { - PrinterResolution[] supportedRes = getPrintResolutions(); + PrinterResolution[] supportedRes = + (PrinterResolution[])getSupportedAttributeValues(PrinterResolution.class, null, null); if (supportedRes != null) { for (int i=0; iNewObject(env, intCls, intCtr, 3); + CHECK_NULL(dpi); // NOTE: cupsGetPPD returns a pointer to a filename of a temporary file. // unlink() must be called to remove the file after using it. @@ -672,6 +691,7 @@ Java_sun_print_CUPSPrinter_getResolutions(JNIEnv *env, CHECK_NULL(ryObj); (*env)->CallBooleanMethod(env, arrayList, arrListAddMID, rxObj); (*env)->CallBooleanMethod(env, arrayList, arrListAddMID, ryObj); + (*env)->CallBooleanMethod(env, arrayList, arrListAddMID, dpi); } for (i = 0; i < resolution->num_choices; i++) { @@ -700,6 +720,41 @@ Java_sun_print_CUPSPrinter_getResolutions(JNIEnv *env, CHECK_NULL(ryObj); (*env)->CallBooleanMethod(env, arrayList, arrListAddMID, rxObj); (*env)->CallBooleanMethod(env, arrayList, arrListAddMID, ryObj); + (*env)->CallBooleanMethod(env, arrayList, arrListAddMID, dpi); + } + } + + } else { + ppd_attr_t *defresolution = j2d_ppdFindAttr(ppd, "DefaultResolution", NULL); + if (defresolution == NULL) { + defresolution = j2d_ppdFindAttr(ppd, "Resolution", NULL); + } + if (defresolution != NULL) { + int matches = sscanf(defresolution->value, "%dx%ddpi", &defx, &defy); + if (matches == 2) { + if (defx <= 0 || defy <= 0) { + defx = 0; + defy = 0; + } + } else { + matches = sscanf(defresolution->value, "%ddpi", &defx); + if (matches == 1) { + if (defx <= 0) { + defx = 0; + } else { + defy = defx; + } + } + } + if (defx > 0) { + jobject rxObj, ryObj; + rxObj = (*env)->NewObject(env, intCls, intCtr, defx); + CHECK_NULL(rxObj); + ryObj = (*env)->NewObject(env, intCls, intCtr, defy); + CHECK_NULL(ryObj); + (*env)->CallBooleanMethod(env, arrayList, arrListAddMID, rxObj); + (*env)->CallBooleanMethod(env, arrayList, arrListAddMID, ryObj); + (*env)->CallBooleanMethod(env, arrayList, arrListAddMID, dpi); } } } diff --git a/test/jdk/javax/print/PrintablePrintDPI.java b/test/jdk/javax/print/PrintablePrintDPI.java index 6cae2be532c..6b5e83df233 100644 --- a/test/jdk/javax/print/PrintablePrintDPI.java +++ b/test/jdk/javax/print/PrintablePrintDPI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2025, BELLSOFT. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -54,7 +54,7 @@ import java.awt.print.PrinterJob; /* * @test - * @bug 8251928 + * @bug 8251928 8375221 * @key printer * @summary Printable.print method should reflect printer's DPI * @library /java/awt/regtesthelpers @@ -201,7 +201,9 @@ public class PrintablePrintDPI implements Printable { attributeSet.add(OrientationRequested.PORTRAIT); job.setPrintService(printService); job.setPrintable(this); - job.print(attributeSet); + if (job.printDialog(attributeSet)) { + job.print(attributeSet); + } } catch (PrinterException ex) { throw new RuntimeException(ex); } From e88edd0bc63e0a39f42a6a9e1ced61a79f84ad73 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 23 Jan 2026 18:53:48 +0000 Subject: [PATCH 165/328] 8375338: sun/awt/image/ImageRepresentation/LUTCompareTest.java fails with -Xcheck:jni Reviewed-by: aivanov, serb, krk --- .../share/native/libawt/awt/image/awt_ImageRep.c | 6 +++--- .../sun/awt/image/ImageRepresentation/LUTCompareTest.java | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/java.desktop/share/native/libawt/awt/image/awt_ImageRep.c b/src/java.desktop/share/native/libawt/awt/image/awt_ImageRep.c index 6079b9e76b8..3cb2df0e0e9 100644 --- a/src/java.desktop/share/native/libawt/awt/image/awt_ImageRep.c +++ b/src/java.desktop/share/native/libawt/awt/image/awt_ImageRep.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -227,7 +227,7 @@ Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls, /* Release the locked arrays */ (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT); (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, jdata, dstData, JNI_ABORT); + (*env)->ReleasePrimitiveArrayCritical(env, jdata, dstData, 0); return JNI_TRUE; } @@ -385,7 +385,7 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls, } (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, jdata, dstData, JNI_ABORT); + (*env)->ReleasePrimitiveArrayCritical(env, jdata, dstData, 0); return JNI_TRUE; } diff --git a/test/jdk/sun/awt/image/ImageRepresentation/LUTCompareTest.java b/test/jdk/sun/awt/image/ImageRepresentation/LUTCompareTest.java index aca2ff1071c..498fe227651 100644 --- a/test/jdk/sun/awt/image/ImageRepresentation/LUTCompareTest.java +++ b/test/jdk/sun/awt/image/ImageRepresentation/LUTCompareTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, 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,12 +23,13 @@ /* * @test - * @bug 6570475 + * @bug 6570475 8375338 * @summary Test verifies that palette comparison procedure of * ImageRepresentation class does not produce extra transparent * pixels. * - * @run main LUTCompareTest + * @run main/othervm LUTCompareTest + * @run main/othervm -Xcheck:jni LUTCompareTest */ From e617ccd529657440eaf20ed68794fea6f6c07fee Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 23 Jan 2026 19:12:54 +0000 Subject: [PATCH 166/328] 8375480: Remove usage of AppContext from javax/swing/text Reviewed-by: serb, psadhukhan --- .../javax/swing/text/JTextComponent.java | 45 ++---- .../classes/javax/swing/text/LayoutQueue.java | 22 +-- .../javax/swing/text/html/HTMLEditorKit.java | 14 +- .../javax/swing/text/html/parser/DTD.java | 28 +--- .../javax/swing/text/html/parser/Element.java | 12 +- .../text/html/parser/ParserDelegator.java | 14 +- .../swing/Security/6938813/bug6938813.java | 128 ------------------ .../swing/text/LayoutQueue/Test6588003.java | 60 -------- .../swing/text/html/parser/Test8017492.java | 94 ------------- 9 files changed, 36 insertions(+), 381 deletions(-) delete mode 100644 test/jdk/javax/swing/Security/6938813/bug6938813.java delete mode 100644 test/jdk/javax/swing/text/LayoutQueue/Test6588003.java delete mode 100644 test/jdk/javax/swing/text/html/parser/Test8017492.java diff --git a/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java b/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java index 03e04d1c1a7..59cee1e12ee 100644 --- a/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java +++ b/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,9 +62,6 @@ import javax.accessibility.*; import javax.print.attribute.*; -import sun.awt.AppContext; - - import sun.swing.PrintingStatus; import sun.swing.SwingUtilities2; import sun.swing.text.TextComponentPrintable; @@ -1097,22 +1094,16 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A return getKeymapTable().get(nm); } - private static HashMap getKeymapTable() { - synchronized (KEYMAP_TABLE) { - AppContext appContext = AppContext.getAppContext(); - @SuppressWarnings("unchecked") - HashMap keymapTable = - (HashMap)appContext.get(KEYMAP_TABLE); - if (keymapTable == null) { - keymapTable = new HashMap(17); - appContext.put(KEYMAP_TABLE, keymapTable); - //initialize default keymap - Keymap binding = addKeymap(DEFAULT_KEYMAP, null); - binding.setDefaultAction(new - DefaultEditorKit.DefaultKeyTypedAction()); - } - return keymapTable; + private static HashMap keymapTable; + + private static synchronized HashMap getKeymapTable() { + if (keymapTable == null) { + keymapTable = new HashMap(17); + //initialize default keymap + Keymap binding = addKeymap(DEFAULT_KEYMAP, null); + binding.setDefaultAction(new DefaultEditorKit.DefaultKeyTypedAction()); } + return keymapTable; } /** @@ -1653,7 +1644,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A public void removeNotify() { super.removeNotify(); if (getFocusedComponent() == this) { - AppContext.getAppContext().remove(FOCUSED_COMPONENT); + focusedComponent = null; } } @@ -4084,13 +4075,14 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A } } + private static JTextComponent focusedComponent; + /** * Returns the JTextComponent that most recently had focus. The returned * value may currently have focus. */ static final JTextComponent getFocusedComponent() { - return (JTextComponent)AppContext.getAppContext(). - get(FOCUSED_COMPONENT); + return focusedComponent; } @SuppressWarnings("deprecation") @@ -4105,9 +4097,6 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A return modifiers; } - private static final Object KEYMAP_TABLE = - new StringBuilder("JTextComponent_KeymapTable"); - // // member variables used for on-the-spot input method // editing style support @@ -4438,9 +4427,6 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A } } - private static final Object FOCUSED_COMPONENT = - new StringBuilder("JTextComponent_FocusedComponent"); - /** * The default keymap that will be shared by all * JTextComponent instances unless they @@ -4493,8 +4479,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A // --- FocusListener methods ----------------------------------- public void focusGained(FocusEvent fe) { - AppContext.getAppContext().put(FOCUSED_COMPONENT, - fe.getSource()); + focusedComponent = (JTextComponent)fe.getSource(); } public void focusLost(FocusEvent fe) { diff --git a/src/java.desktop/share/classes/javax/swing/text/LayoutQueue.java b/src/java.desktop/share/classes/javax/swing/text/LayoutQueue.java index 6801a84da5b..1a4e7315eb4 100644 --- a/src/java.desktop/share/classes/javax/swing/text/LayoutQueue.java +++ b/src/java.desktop/share/classes/javax/swing/text/LayoutQueue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package javax.swing.text; import java.util.Vector; -import sun.awt.AppContext; /** * A queue of text layout tasks. @@ -36,11 +35,11 @@ import sun.awt.AppContext; */ public class LayoutQueue { - private static final Object DEFAULT_QUEUE = new Object(); - private Vector tasks; private Thread worker; + private static LayoutQueue defaultQueue; + /** * Construct a layout queue. */ @@ -53,15 +52,10 @@ public class LayoutQueue { * @return the default layout queue */ public static LayoutQueue getDefaultQueue() { - AppContext ac = AppContext.getAppContext(); - synchronized (DEFAULT_QUEUE) { - LayoutQueue defaultQueue = (LayoutQueue) ac.get(DEFAULT_QUEUE); - if (defaultQueue == null) { - defaultQueue = new LayoutQueue(); - ac.put(DEFAULT_QUEUE, defaultQueue); - } - return defaultQueue; + if (defaultQueue == null) { + defaultQueue = new LayoutQueue(); } + return defaultQueue; } /** @@ -70,9 +64,7 @@ public class LayoutQueue { * @param q the new queue. */ public static void setDefaultQueue(LayoutQueue q) { - synchronized (DEFAULT_QUEUE) { - AppContext.getAppContext().put(DEFAULT_QUEUE, q); - } + defaultQueue = q; } /** diff --git a/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java b/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java index 53ceea32668..b5b75e1067b 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -92,7 +92,6 @@ import javax.swing.text.ViewFactory; import javax.swing.text.html.parser.ParserDelegator; import sun.swing.SwingAccessor; -import sun.awt.AppContext; import static java.nio.charset.StandardCharsets.ISO_8859_1; @@ -432,11 +431,7 @@ public class HTMLEditorKit extends StyledEditorKit implements Accessible { * @param s a StyleSheet */ public void setStyleSheet(StyleSheet s) { - if (s == null) { - AppContext.getAppContext().remove(DEFAULT_STYLES_KEY); - } else { - AppContext.getAppContext().put(DEFAULT_STYLES_KEY, s); - } + defaultStyles = s; } /** @@ -448,12 +443,8 @@ public class HTMLEditorKit extends StyledEditorKit implements Accessible { * @return the StyleSheet */ public StyleSheet getStyleSheet() { - AppContext appContext = AppContext.getAppContext(); - StyleSheet defaultStyles = (StyleSheet) appContext.get(DEFAULT_STYLES_KEY); - if (defaultStyles == null) { defaultStyles = new StyleSheet(); - appContext.put(DEFAULT_STYLES_KEY, defaultStyles); try (InputStream is = HTMLEditorKit.getResourceAsStream(DEFAULT_CSS); InputStreamReader isr = new InputStreamReader(is, ISO_8859_1); Reader r = new BufferedReader(isr)) @@ -692,6 +683,7 @@ public class HTMLEditorKit extends StyledEditorKit implements Accessible { private static final ViewFactory defaultFactory = new HTMLFactory(); MutableAttributeSet input; + private static StyleSheet defaultStyles = null; private static final Object DEFAULT_STYLES_KEY = new Object(); private LinkController linkHandler = new LinkController(); private static Parser defaultParser = null; diff --git a/src/java.desktop/share/classes/javax/swing/text/html/parser/DTD.java b/src/java.desktop/share/classes/javax/swing/text/html/parser/DTD.java index e9999c679eb..d3a4fa76306 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/parser/DTD.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/parser/DTD.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,6 @@ package javax.swing.text.html.parser; -import sun.awt.AppContext; - import java.io.PrintStream; import java.io.File; import java.io.FileInputStream; @@ -403,11 +401,6 @@ class DTD implements DTDConstants { return name; } - /** - * The hashtable key of DTDs in AppContext. - */ - private static final Object DTD_HASH_KEY = new Object(); - /** * Put a name and appropriate DTD to hashtable. * @@ -415,7 +408,7 @@ class DTD implements DTDConstants { * @param dtd the DTD */ public static void putDTDHash(String name, DTD dtd) { - getDtdHash().put(name, dtd); + DTD_MAP.put(name, dtd); } /** @@ -430,27 +423,14 @@ class DTD implements DTDConstants { */ public static DTD getDTD(String name) throws IOException { name = name.toLowerCase(); - DTD dtd = getDtdHash().get(name); + DTD dtd = DTD_MAP.get(name); if (dtd == null) dtd = new DTD(name); return dtd; } - private static Hashtable getDtdHash() { - AppContext appContext = AppContext.getAppContext(); - - @SuppressWarnings("unchecked") - Hashtable result = (Hashtable) appContext.get(DTD_HASH_KEY); - - if (result == null) { - result = new Hashtable(); - - appContext.put(DTD_HASH_KEY, result); - } - - return result; - } + private static final Hashtable DTD_MAP = new Hashtable(); /** * Recreates a DTD from an archived format. diff --git a/src/java.desktop/share/classes/javax/swing/text/html/parser/Element.java b/src/java.desktop/share/classes/javax/swing/text/html/parser/Element.java index cf8ea622c9b..8dd00373636 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/parser/Element.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/parser/Element.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ package javax.swing.text.html.parser; import java.io.Serializable; import java.util.BitSet; import java.util.Map; -import sun.awt.AppContext; /** * An element as described in a DTD using the ELEMENT construct. @@ -107,17 +106,14 @@ public final class Element implements DTDConstants, Serializable { this.name = name; this.index = index; if (index > getMaxIndex()) { - AppContext.getAppContext().put(MAX_INDEX_KEY, index); + maxIndex = index; } } - private static final Object MAX_INDEX_KEY = new Object(); + private static int maxIndex = 0; static int getMaxIndex() { - Integer value = (Integer) AppContext.getAppContext().get(MAX_INDEX_KEY); - return (value != null) - ? value.intValue() - : 0; + return maxIndex; } /** diff --git a/src/java.desktop/share/classes/javax/swing/text/html/parser/ParserDelegator.java b/src/java.desktop/share/classes/javax/swing/text/html/parser/ParserDelegator.java index 2d541abc06f..6971f313558 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/parser/ParserDelegator.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/parser/ParserDelegator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,6 @@ */ package javax.swing.text.html.parser; -import sun.awt.AppContext; - import javax.swing.text.html.HTMLEditorKit; import java.io.BufferedInputStream; import java.io.IOException; @@ -52,7 +50,8 @@ import java.io.Serializable; */ @SuppressWarnings("serial") // Same-version serialization only public class ParserDelegator extends HTMLEditorKit.Parser implements Serializable { - private static final Object DTD_KEY = new Object(); + + private static DTD dtd = null; /** * Sets the default DTD. @@ -62,10 +61,6 @@ public class ParserDelegator extends HTMLEditorKit.Parser implements Serializabl } private static synchronized DTD getDefaultDTD() { - AppContext appContext = AppContext.getAppContext(); - - DTD dtd = (DTD) appContext.get(DTD_KEY); - if (dtd == null) { DTD _dtd = null; // (PENDING) Hate having to hard code! @@ -77,10 +72,7 @@ public class ParserDelegator extends HTMLEditorKit.Parser implements Serializabl System.out.println("Throw an exception: could not get default dtd: " + nm); } dtd = createDTD(_dtd, nm); - - appContext.put(DTD_KEY, dtd); } - return dtd; } diff --git a/test/jdk/javax/swing/Security/6938813/bug6938813.java b/test/jdk/javax/swing/Security/6938813/bug6938813.java deleted file mode 100644 index 8f5e3fc3505..00000000000 --- a/test/jdk/javax/swing/Security/6938813/bug6938813.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2010, 2017, 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 - * @key headful - * @bug 6938813 - * @summary Swing mutable statics - * @author Pavel Porvatov - * @modules java.desktop/javax.swing.text.html.parser:open - * @modules java.desktop/sun.awt - */ - -import sun.awt.AppContext; -import sun.awt.SunToolkit; - -import javax.swing.text.html.HTMLEditorKit; -import javax.swing.text.html.StyleSheet; -import javax.swing.text.html.parser.DTD; -import javax.swing.text.html.parser.ParserDelegator; -import java.lang.reflect.Field; - -public class bug6938813 { - public static final String DTD_KEY = "dtd_key"; - - private static volatile StyleSheet styleSheet; - - public static void main(String[] args) throws Exception { - // Run validation and init values for this AppContext - validate(); - - Thread thread = new ThreadInAnotherAppContext(); - - thread.start(); - thread.join(); - } - - private static void validate() throws Exception { - AppContext appContext = AppContext.getAppContext(); - - assertTrue(DTD.getDTD(DTD_KEY).getName().equals(DTD_KEY), "DTD.getDTD() mixed AppContexts"); - - // Spoil hash value - DTD invalidDtd = DTD.getDTD("invalid DTD"); - - DTD.putDTDHash(DTD_KEY, invalidDtd); - - assertTrue(DTD.getDTD(DTD_KEY) == invalidDtd, "Something wrong with DTD.getDTD()"); - - Object dtdKey = getParserDelegator_DTD_KEY(); - - assertTrue(appContext.get(dtdKey) == null, "ParserDelegator mixed AppContexts"); - - // Init default DTD - new ParserDelegator(); - - Object dtdValue = appContext.get(dtdKey); - - assertTrue(dtdValue != null, "ParserDelegator.defaultDTD isn't initialized"); - - // Try reinit default DTD - new ParserDelegator(); - - assertTrue(dtdValue == appContext.get(dtdKey), "ParserDelegator.defaultDTD created a duplicate"); - - HTMLEditorKit htmlEditorKit = new HTMLEditorKit(); - - if (styleSheet == null) { - // First AppContext - styleSheet = htmlEditorKit.getStyleSheet(); - - assertTrue(styleSheet != null, "htmlEditorKit.getStyleSheet() returns null"); - assertTrue(htmlEditorKit.getStyleSheet() == styleSheet, "Something wrong with htmlEditorKit.getStyleSheet()"); - } else { - assertTrue(htmlEditorKit.getStyleSheet() != styleSheet, "HtmlEditorKit.getStyleSheet() mixed AppContexts"); - } - } - - private static void assertTrue(boolean b, String msg) { - if (!b) { - throw new RuntimeException("Test failed: " + msg); - } - } - - private static Object getParserDelegator_DTD_KEY() throws Exception { - Field field = ParserDelegator.class.getDeclaredField("DTD_KEY"); - - field.setAccessible(true); - - return field.get(null); - } - - private static class ThreadInAnotherAppContext extends Thread { - public ThreadInAnotherAppContext() { - super(new ThreadGroup("6938813"), "ThreadInAnotherAppContext"); - } - - public void run() { - SunToolkit.createNewAppContext(); - - try { - validate(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - } -} diff --git a/test/jdk/javax/swing/text/LayoutQueue/Test6588003.java b/test/jdk/javax/swing/text/LayoutQueue/Test6588003.java deleted file mode 100644 index 561ac594a47..00000000000 --- a/test/jdk/javax/swing/text/LayoutQueue/Test6588003.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2007, 2015, 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 6588003 - @summary LayoutQueue should not share its DefaultQueue across AppContexts - @author Peter Zhelezniakov - @modules java.desktop/sun.awt - @run main Test6588003 -*/ - -import javax.swing.text.LayoutQueue; -import sun.awt.SunToolkit; - -public class Test6588003 implements Runnable { - private static final LayoutQueue DEFAULT = new LayoutQueue(); - - public static void main(String[] args) throws InterruptedException { - LayoutQueue.setDefaultQueue(DEFAULT); - - ThreadGroup group = new ThreadGroup("Test6588003"); - Thread thread = new Thread(group, new Test6588003()); - thread.start(); - thread.join(); - - if (LayoutQueue.getDefaultQueue() != DEFAULT) { - throw new RuntimeException("Sharing detected"); - } - } - - public void run() { - SunToolkit.createNewAppContext(); - - if (LayoutQueue.getDefaultQueue() == DEFAULT) { - throw new RuntimeException("Sharing detected"); - } - - LayoutQueue.setDefaultQueue(new LayoutQueue()); - } -} diff --git a/test/jdk/javax/swing/text/html/parser/Test8017492.java b/test/jdk/javax/swing/text/html/parser/Test8017492.java deleted file mode 100644 index dbc1e125cf7..00000000000 --- a/test/jdk/javax/swing/text/html/parser/Test8017492.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.util.Vector; -import javax.swing.text.html.HTML; -import javax.swing.text.html.HTMLDocument; -import javax.swing.text.html.HTMLEditorKit; -import javax.swing.text.html.parser.DTD; -import javax.swing.text.html.parser.Element; -import sun.awt.SunToolkit; - -/* - * @test - * @bug 8017492 - * @modules java.desktop/sun.awt - * @run main/othervm Test8017492 - * @summary Tests for OutOfMemoryError/NegativeArraySizeException - * @author Sergey Malenkov - */ - -public class Test8017492 { - public static void main(String[] args) throws Exception { - Runnable task = new Runnable() { - @Override - public void run() { - try { - SunToolkit.createNewAppContext(); - DTD dtd = DTD.getDTD("dtd"); - dtd.elements = new Vector() { - @Override - public synchronized int size() { - return Integer.MAX_VALUE; - } - }; - dtd.getElement("element"); - } - catch (Exception exception) { - throw new Error("unexpected", exception); - } - } - }; - // run task with different AppContext - Thread thread = new Thread(new ThreadGroup("$$$"), task); - thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread thread, Throwable throwable) { - throwable.printStackTrace(); - throw new RuntimeException(throwable); - } - }); - thread.start(); - thread.join(); - // add error handling - SunToolkit.createNewAppContext(); - HTMLDocument document = new HTMLDocument() { - @Override - public HTMLEditorKit.ParserCallback getReader(int pos) { - return getReader(pos, 0, 0, null); - } - - @Override - public HTMLEditorKit.ParserCallback getReader(int pos, int popDepth, int pushDepth, HTML.Tag insertTag) { - return new HTMLDocument.HTMLReader(pos, popDepth, pushDepth, insertTag) { - @Override - public void handleError(String error, int pos) { - throw new Error(error); - } - }; - } - }; - // run parser - new HTMLEditorKit().insertHTML(document, 0, "text", 0, 0, null); - } -} From e55124041e0181ca14ed95dc5f94d404b7900029 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Fri, 23 Jan 2026 19:46:40 +0000 Subject: [PATCH 167/328] 8375549: ConcurrentModificationException if jdk.crypto.disabledAlgorithms has multiple entries with known oid Reviewed-by: mullan, coffeys --- .../util/CryptoAlgorithmConstraints.java | 8 ++-- .../crypto/Cipher/TestDisabledWithOids.java | 47 +++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 test/jdk/javax/crypto/Cipher/TestDisabledWithOids.java diff --git a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java index a8649106a38..ad3beab350f 100644 --- a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java +++ b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -82,8 +82,10 @@ public class CryptoAlgorithmConstraints extends AbstractAlgorithmConstraints { CryptoAlgorithmConstraints(String propertyName) { super(null); disabledServices = getAlgorithms(propertyName, true); - debug("Before " + Arrays.deepToString(disabledServices.toArray())); - for (String dk : disabledServices) { + String[] entries = disabledServices.toArray(new String[0]); + debug("Before " + Arrays.deepToString(entries)); + + for (String dk : entries) { int idx = dk.indexOf("."); if (idx < 1 || idx == dk.length() - 1) { // wrong syntax: missing "." or empty service or algorithm diff --git a/test/jdk/javax/crypto/Cipher/TestDisabledWithOids.java b/test/jdk/javax/crypto/Cipher/TestDisabledWithOids.java new file mode 100644 index 00000000000..d1d9fa7a5bb --- /dev/null +++ b/test/jdk/javax/crypto/Cipher/TestDisabledWithOids.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2026, 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 8375549 + * @summary Test JCE layer algorithm restriction using algorithms w/ oids + * @library /test/lib + * @run main/othervm -Djdk.crypto.disabledAlgorithms=Cipher.DES,Cipher.RSA/ECB/PKCS1Padding TestDisabledWithOids + * @run main/othervm -Djdk.crypto.disabledAlgorithms=Cipher.RSA/ECB/PKCS1Padding,Cipher.DES TestDisabledWithOids + */ +import java.security.NoSuchAlgorithmException; +import javax.crypto.Cipher; +import jdk.test.lib.Utils; + +public class TestDisabledWithOids { + public static void main(String[] args) throws Exception { + String algo1 = "RSA/ECB/PKCS1Padding"; + String algo2 = "DES"; + + Utils.runAndCheckException(() -> Cipher.getInstance(algo1), + NoSuchAlgorithmException.class); + Utils.runAndCheckException(() -> Cipher.getInstance(algo2), + NoSuchAlgorithmException.class); + System.out.println("Done"); + } +} From 44b74e165e2d3ea79397d6f1ddbef94f51ac56c7 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 23 Jan 2026 20:20:22 +0000 Subject: [PATCH 168/328] 8375351: Remove usage of AppContext from print implementation Reviewed-by: serb, tr --- .../javax/print/PrintServiceLookup.java | 42 ++++--------------- .../print/StreamPrintServiceFactory.java | 18 +++----- .../FlushCustomClassLoader.java | 11 ----- 3 files changed, 15 insertions(+), 56 deletions(-) diff --git a/src/java.desktop/share/classes/javax/print/PrintServiceLookup.java b/src/java.desktop/share/classes/javax/print/PrintServiceLookup.java index 15a7fbbaa00..ee3f6a449b7 100644 --- a/src/java.desktop/share/classes/javax/print/PrintServiceLookup.java +++ b/src/java.desktop/share/classes/javax/print/PrintServiceLookup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,6 @@ import java.util.ServiceLoader; import javax.print.attribute.AttributeSet; -import sun.awt.AppContext; /** * Implementations of this class provide lookup services for print services @@ -58,35 +57,14 @@ public abstract class PrintServiceLookup { protected PrintServiceLookup() {} /** - * Contains a lists of services. + * The list of lookup services. */ - static class Services { - - /** - * The list of lookup services. - */ - private ArrayList listOfLookupServices = null; - - /** - * The list of registered services. - */ - private ArrayList registeredServices = null; - } + private static ArrayList listOfLookupServices = null; /** - * Returns the services from the current appcontext. - * - * @return the services + * The list of registered services. */ - private static Services getServicesForContext() { - Services services = - (Services)AppContext.getAppContext().get(Services.class); - if (services == null) { - services = new Services(); - AppContext.getAppContext().put(Services.class, services); - } - return services; - } + private static ArrayList registeredServices = null; /** * Returns the list of lookup services. @@ -94,7 +72,7 @@ public abstract class PrintServiceLookup { * @return the list of lookup services */ private static ArrayList getListOfLookupServices() { - return getServicesForContext().listOfLookupServices; + return listOfLookupServices; } /** @@ -103,8 +81,7 @@ public abstract class PrintServiceLookup { * @return the list of lookup services */ private static ArrayList initListOfLookupServices() { - ArrayList listOfLookupServices = new ArrayList<>(); - getServicesForContext().listOfLookupServices = listOfLookupServices; + listOfLookupServices = new ArrayList<>(); return listOfLookupServices; } @@ -114,7 +91,7 @@ public abstract class PrintServiceLookup { * @return the list of registered services */ private static ArrayList getRegisteredServices() { - return getServicesForContext().registeredServices; + return registeredServices; } /** @@ -123,8 +100,7 @@ public abstract class PrintServiceLookup { * @return the list of registered services */ private static ArrayList initRegisteredServices() { - ArrayList registeredServices = new ArrayList<>(); - getServicesForContext().registeredServices = registeredServices; + registeredServices = new ArrayList<>(); return registeredServices; } diff --git a/src/java.desktop/share/classes/javax/print/StreamPrintServiceFactory.java b/src/java.desktop/share/classes/javax/print/StreamPrintServiceFactory.java index 7d696f14a94..2667587e9b2 100644 --- a/src/java.desktop/share/classes/javax/print/StreamPrintServiceFactory.java +++ b/src/java.desktop/share/classes/javax/print/StreamPrintServiceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -33,8 +33,6 @@ import java.util.ServiceLoader; import javax.print.attribute.PrintRequestAttributeSet; -import sun.awt.AppContext; - /** * A {@code StreamPrintServiceFactory} is the factory for * {@link StreamPrintService} instances, which can print to an output stream in @@ -63,24 +61,20 @@ public abstract class StreamPrintServiceFactory { static class Services { /** - * The list of factories which will be stored per appcontext. + * The list of factories. */ private ArrayList listOfFactories = null; } + private static final Services SERVICES = new Services(); + /** - * Returns the services from the current appcontext. + * Returns the singleton Services instance. * * @return the services */ private static Services getServices() { - Services services = - (Services)AppContext.getAppContext().get(Services.class); - if (services == null) { - services = new Services(); - AppContext.getAppContext().put(Services.class, services); - } - return services; + return SERVICES; } /** diff --git a/test/jdk/javax/print/PrintServiceLookup/FlushCustomClassLoader.java b/test/jdk/javax/print/PrintServiceLookup/FlushCustomClassLoader.java index c16fe0e5a82..8125b656de4 100644 --- a/test/jdk/javax/print/PrintServiceLookup/FlushCustomClassLoader.java +++ b/test/jdk/javax/print/PrintServiceLookup/FlushCustomClassLoader.java @@ -56,17 +56,6 @@ public final class FlushCustomClassLoader { } private static Reference getLoader(String m) throws Exception { - /* - * The print services are stored per the AppContext, and each AppContext - * caches the "current" class loader during creation. - * see javax.print.PrintServiceLookup. - * - * To prevent AppContext from cache our test loader we force AppContext - * creation early by the invokeAndWait. - * The "EventQueue.invokeAndWait(() -> {});" can be removed when the - * AppContext usage will be deleted in the PrintServiceLookup - */ - EventQueue.invokeAndWait(() -> {}); URL url = FlushCustomClassLoader.class.getProtectionDomain() .getCodeSource().getLocation(); From a3b1aa9f7dce30a1c5967cb15a5d523e3d7ea72d Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Sat, 24 Jan 2026 08:43:37 +0000 Subject: [PATCH 169/328] 8374482: SA does not handle signal handler frame in mixed jstack Reviewed-by: cjplummer, kevinw --- .../linux/native/libsaproc/symtab.c | 25 +++++- .../hotspot/debugger/linux/LinuxDebugger.java | 11 ++- .../debugger/linux/LinuxDebuggerLocal.java | 8 +- .../linux/amd64/LinuxAMD64CFrame.java | 56 +++++++++++++- .../linux/amd64/LinuxAMD64ThreadContext.java | 22 +++++- .../sa/TestJhsdbJstackMixedCore.java | 76 +++++++++++++++++++ 6 files changed, 188 insertions(+), 10 deletions(-) create mode 100644 test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c index 07cbb46d045..c8f3fb2ed4c 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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 @@ -550,14 +550,33 @@ uintptr_t search_symbol(struct symtab* symtab, uintptr_t base, return (uintptr_t) NULL; } +static bool is_in(uintptr_t offset, struct elf_symbol* sym) { + if (sym->size == 0 && offset == sym->offset) { + // offset points to the top of the symbol. + // Some functions have size 0. For example, __restore_rt() (signal trampoline + // in glibc) would be detected as out of the function incorrectly, even if it + // points to the top of the instruction address, because the size of + // __restore_rt() is 0 (you can see this with "readelf -s libc.so.6" when + // debug symbols are available). + // Hence we need to treat this as a special case if the function size is 0, + // only the exact symbol address should be treated as inside. + return true; + } else if (offset >= sym->offset && offset < sym->offset + sym->size) { + // offset is in address range of the symbol + return true; + } + + // offset is out of address range of the symbol + return false; +} + const char* nearest_symbol(struct symtab* symtab, uintptr_t offset, uintptr_t* poffset) { int n = 0; if (!symtab) return NULL; for (; n < symtab->num_symbols; n++) { struct elf_symbol* sym = &(symtab->symbols[n]); - if (sym->name != NULL && - offset >= sym->offset && offset < sym->offset + sym->size) { + if (sym->name != NULL && is_in(offset, sym)) { if (poffset) *poffset = (offset - sym->offset); return sym->name; } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java index 1106d846eca..a53b8a0a282 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, 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 @@ -33,6 +33,14 @@ import sun.jvm.hotspot.debugger.cdbg.*; by the architecture-specific subpackages. */ public interface LinuxDebugger extends JVMDebugger { + // SIGHANDLER_NAMES holds the name of signal handler. + public static final List SIGHANDLER_NAMES = List.of( + // For AMD64 + // - sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c in glibc + // - gdb/amd64-linux-tdep.c in GDB + "__restore_rt" + ); + public String addressValueToString(long address) throws DebuggerException; public boolean readJBoolean(long address) throws DebuggerException; public byte readJByte(long address) throws DebuggerException; @@ -52,6 +60,7 @@ public interface LinuxDebugger extends JVMDebugger { public long[] getThreadIntegerRegisterSet(int lwp_id) throws DebuggerException; public long getAddressValue(Address addr) throws DebuggerException; public Address findLibPtrByAddress(Address pc); + public boolean isSignalTrampoline(Address pc); // For LinuxCDebugger public List getThreadList(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java index 261df12c8f1..9a75511e44d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, 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 @@ -130,6 +130,12 @@ public class LinuxDebuggerLocal extends DebuggerBase implements LinuxDebugger { : new LinuxAddress(this, ptr); } + @Override + public boolean isSignalTrampoline(Address pc) { + var sym = lookup(getAddressValue(pc)); + return sym == null ? false : SIGHANDLER_NAMES.contains(sym.getName()); + } + // Note on Linux threads are really processes. When target process is // attached by a serviceability agent thread, only that thread can do // ptrace operations on the target. This is because from kernel's point diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java index 612203634f3..4bf6a0305a3 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,9 +24,12 @@ package sun.jvm.hotspot.debugger.linux.amd64; +import java.util.function.Function; + import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.amd64.*; import sun.jvm.hotspot.debugger.linux.*; +import sun.jvm.hotspot.debugger.linux.amd64.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; import sun.jvm.hotspot.runtime.*; @@ -34,6 +37,36 @@ import sun.jvm.hotspot.runtime.amd64.*; public final class LinuxAMD64CFrame extends BasicCFrame { + private static LinuxAMD64CFrame getFrameFromReg(LinuxDebugger dbg, Function getreg) { + Address rip = getreg.apply(AMD64ThreadContext.RIP); + Address rsp = getreg.apply(AMD64ThreadContext.RSP); + Address libptr = dbg.findLibPtrByAddress(rip); + Address cfa = getreg.apply(AMD64ThreadContext.RBP); + DwarfParser dwarf = null; + + if (libptr != null) { // Native frame + dwarf = new DwarfParser(libptr); + try { + dwarf.processDwarf(rip); + } catch (DebuggerException e) { + // DWARF processing should succeed when the frame is native + // but it might fail if Common Information Entry (CIE) has language + // personality routine and/or Language Specific Data Area (LSDA). + return new LinuxAMD64CFrame(dbg, rsp, cfa, rip, dwarf, true); + } + + cfa = getreg.apply(dwarf.getCFARegister()) + .addOffsetTo(dwarf.getCFAOffset()); + } + + return (cfa == null) ? null + : new LinuxAMD64CFrame(dbg, rsp, cfa, rip, dwarf); + } + + public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, Address rip, ThreadContext context) { + return getFrameFromReg(dbg, context::getRegisterAsAddress); + } + public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, Address rsp, Address rip, ThreadContext context) { Address libptr = dbg.findLibPtrByAddress(rip); Address cfa = context.getRegisterAsAddress(AMD64ThreadContext.RBP); @@ -80,8 +113,12 @@ public final class LinuxAMD64CFrame extends BasicCFrame { // override base class impl to avoid ELF parsing public ClosestSymbol closestSymbolToPC() { Address symAddr = use1ByteBeforeToLookup ? pc().addOffsetTo(-1) : pc(); - // try native lookup in debugger. - return dbg.lookup(dbg.getAddressValue(symAddr)); + + // Returns a special symbol if the address is signal handler, + // otherwise returns closest symbol generated by LinuxDebugger. + return dbg.isSignalTrampoline(symAddr) + ? new ClosestSymbol("", 0) + : dbg.lookup(dbg.getAddressValue(symAddr)); } public Address pc() { @@ -159,7 +196,12 @@ public final class LinuxAMD64CFrame extends BasicCFrame { return null; } - return isValidFrame(nextCFA, isNative) ? nextCFA : null; + if (dbg.isSignalTrampoline(senderPC)) { + // Return without frame check if sender is signal trampoline. + return nextCFA; + } else { + return isValidFrame(nextCFA, isNative) ? nextCFA : null; + } } @Override @@ -173,6 +215,12 @@ public final class LinuxAMD64CFrame extends BasicCFrame { return null; } + if (dbg.isSignalTrampoline(pc())) { + // RSP points signal context + // https://github.com/torvalds/linux/blob/v6.17/arch/x86/kernel/signal.c#L94 + return getFrameFromReg(dbg, r -> LinuxAMD64ThreadContext.getRegFromSignalTrampoline(this.rsp, r.intValue())); + } + ThreadContext context = th.getContext(); Address nextRSP = sp != null ? sp : getNextRSP(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64ThreadContext.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64ThreadContext.java index 3884bab796b..8b2a7301cf2 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64ThreadContext.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64ThreadContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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,6 +27,7 @@ package sun.jvm.hotspot.debugger.linux.amd64; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.amd64.*; import sun.jvm.hotspot.debugger.linux.*; +import sun.jvm.hotspot.runtime.*; public class LinuxAMD64ThreadContext extends AMD64ThreadContext { private LinuxDebugger debugger; @@ -43,4 +44,23 @@ public class LinuxAMD64ThreadContext extends AMD64ThreadContext { public Address getRegisterAsAddress(int index) { return debugger.newAddress(getRegister(index)); } + + public static Address getRegFromSignalTrampoline(Address sp, int index) { + // ucontext_t is located at top of stack. + // See definition of rt_sigframe in arch/x86/include/asm/sigframe.h + // in Linux Kernel. + Address addrUCMContext = sp.addOffsetTo(40); // offsetof(ucontext_t, uc_mcontext) = 40 + Address addrGRegs = addrUCMContext; // gregs is located at top of ucontext_t + + // They are from sys/ucontext.h + final int REG_RBP = 10; + final int REG_RSP = 15; + final int REG_RIP = 16; + return switch(index) { + case AMD64ThreadContext.RBP -> addrGRegs.getAddressAt(REG_RBP * VM.getVM().getAddressSize()); + case AMD64ThreadContext.RSP -> addrGRegs.getAddressAt(REG_RSP * VM.getVM().getAddressSize()); + case AMD64ThreadContext.RIP -> addrGRegs.getAddressAt(REG_RIP * VM.getVM().getAddressSize()); + default -> throw new IllegalArgumentException("Unsupported register index: " + index); + }; + } } diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java new file mode 100644 index 00000000000..b8b19c743e9 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, NTT DATA + * 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 jdk.test.lib.JDKToolFinder; +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.SA.SATestUtils; +import jdk.test.lib.Utils; +import jdk.test.lib.apps.LingeredApp; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.util.CoreUtils; + +/** + * @test + * @bug 8374482 + * @requires (os.family == "linux") & (vm.hasSA) + * @requires os.arch == "amd64" + * @library /test/lib + * @run driver TestJhsdbJstackMixedCore + */ +public class TestJhsdbJstackMixedCore { + + private static void runJstackMixed(String coreFileName) throws Exception { + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jhsdb"); + launcher.addVMArgs(Utils.getTestJavaOpts()); + launcher.addToolArg("jstack"); + launcher.addToolArg("--mixed"); + launcher.addToolArg("--exe"); + launcher.addToolArg(JDKToolFinder.getTestJDKTool("java")); + launcher.addToolArg("--core"); + launcher.addToolArg(coreFileName); + + ProcessBuilder pb = SATestUtils.createProcessBuilder(launcher); + Process jhsdb = pb.start(); + OutputAnalyzer out = new OutputAnalyzer(jhsdb); + + jhsdb.waitFor(); + + System.out.println(out.getStdout()); + System.err.println(out.getStderr()); + + out.shouldContain(""); + out.shouldContain("Java_jdk_test_lib_apps_LingeredApp_crash"); + } + + public static void main(String... args) throws Throwable { + LingeredApp app = new LingeredApp(); + app.setForceCrash(true); + LingeredApp.startApp(app, CoreUtils.getAlwaysPretouchArg(true)); + app.waitAppTerminate(); + + String crashOutput = app.getOutput().getStdout(); + String coreFileName = CoreUtils.getCoreFileLocation(crashOutput, app.getPid()); + runJstackMixed(coreFileName); + } +} From a40dbce495db9959624b72ff619e2e7ae7f7fb8b Mon Sep 17 00:00:00 2001 From: Lei Zhu Date: Sat, 24 Jan 2026 14:19:40 +0000 Subject: [PATCH 170/328] 8374293: Jshell throws an error and crashes when using keyword Public Reviewed-by: jlahoda --- .../classes/jdk/jshell/SourceCodeAnalysisImpl.java | 14 ++++---------- .../langtools/jdk/jshell/SnippetHighlightTest.java | 12 +++++++++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java index d5b44b569a4..1cf0c85702f 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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 @@ -43,7 +43,6 @@ import com.sun.source.tree.NewClassTree; import com.sun.source.tree.Scope; import com.sun.source.tree.Tree; import com.sun.source.tree.Tree.Kind; -import static com.sun.source.tree.Tree.Kind.METHOD; import com.sun.source.tree.TypeParameterTree; import com.sun.source.tree.VariableTree; import com.sun.source.tree.YieldTree; @@ -81,6 +80,7 @@ import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.function.Predicate; +import java.util.TreeSet; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; @@ -114,7 +114,6 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Optional; import java.util.Set; -import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.BiConsumer; @@ -149,14 +148,10 @@ import javax.tools.JavaFileManager.Location; import javax.tools.StandardLocation; import jdk.jshell.ExpressionToTypeInfo.ExpressionInfo; -import static jdk.jshell.Util.REPL_DOESNOTMATTER_CLASS_NAME; import static jdk.jshell.SourceCodeAnalysis.Completeness.DEFINITELY_INCOMPLETE; import static jdk.jshell.TreeDissector.printType; import static java.util.stream.Collectors.joining; -import static javax.lang.model.element.ElementKind.CONSTRUCTOR; -import static javax.lang.model.element.ElementKind.MODULE; -import static javax.lang.model.element.ElementKind.PACKAGE; import javax.lang.model.type.IntersectionType; import javax.lang.model.util.Elements; @@ -815,7 +810,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { }; String wrappedCode = codeWrap.wrapped(); return this.proc.taskFactory.analyze(codeWrap, task -> { - List result = new ArrayList<>(); + TreeSet result = new TreeSet<>(Comparator.comparing(Highlight::start).thenComparing(Highlight::end)); CompilationUnitTree cut = task.cuTrees().iterator().next(); Trees trees = task.trees(); SourcePositions sp = trees.getSourcePositions(); @@ -1050,8 +1045,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { } }.scan(cut, null); result.removeIf(h -> h.start() == h.end()); - Collections.sort(result, (h1, h2) -> h1.start() - h2.start()); - return result; + return new ArrayList<>(result); }); } diff --git a/test/langtools/jdk/jshell/SnippetHighlightTest.java b/test/langtools/jdk/jshell/SnippetHighlightTest.java index dbf3418af83..33f7f263617 100644 --- a/test/langtools/jdk/jshell/SnippetHighlightTest.java +++ b/test/langtools/jdk/jshell/SnippetHighlightTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8274148 8301580 8359497 + * @bug 8274148 8301580 8359497 8374293 * @summary Check snippet highlighting * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -122,6 +122,13 @@ public class SnippetHighlightTest extends KullaTesting { """); } + @Test // 8374293: The returned Highlights should not overlap + public void testHighlightsOverlap() { + assertHighlights("public void E test()", "Highlight[start=0, end=6, attributes=[KEYWORD]]", + "Highlight[start=7, end=11, attributes=[KEYWORD]]", + "Highlight[start=14, end=18, attributes=[DECLARATION]]"); + } + private void assertHighlights(String code, String... expected) { List completions = computeHighlights(code); assertEquals(Arrays.asList(expected), completions, "Input: " + code + ", " + completions.toString()); @@ -134,7 +141,6 @@ public class SnippetHighlightTest extends KullaTesting { getAnalysis().highlights(code); return highlights.stream() .map(h -> h.toString()) - .distinct() .collect(Collectors.toList()); } } From 932556026d6d49fe6f74d4ec4afcb72448611766 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Sun, 25 Jan 2026 01:08:31 +0000 Subject: [PATCH 171/328] 8375683: Add notes for sctp tests Reviewed-by: erikj, vyazici --- doc/testing.html | 16 ++++++++++++++++ doc/testing.md | 26 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/doc/testing.html b/doc/testing.html index 31f4fbd1778..195153c8612 100644 --- a/doc/testing.html +++ b/doc/testing.html @@ -72,6 +72,7 @@ id="toc-notes-for-specific-tests">Notes for Specific Tests
  • Non-US locale
  • PKCS11 Tests
  • +
  • SCTP Tests
  • Testing Ahead-of-time Optimizations
  • @@ -621,6 +622,21 @@ element of the appropriate @Artifact class. (See JTREG="JAVA_OPTIONS=-Djdk.test.lib.artifacts.nsslib-linux_aarch64=/path/to/NSS-libs"

    For more notes about the PKCS11 tests, please refer to test/jdk/sun/security/pkcs11/README.

    +

    SCTP Tests

    +

    The SCTP tests require the SCTP runtime library, which is often not +installed by default in popular Linux distributions. Without this +library, the SCTP tests will be skipped. If you want to enable the SCTP +tests, you should install the SCTP library before running the tests.

    +

    For distributions using the .deb packaging format and the apt tool +(such as Debian, Ubuntu, etc.), try this:

    +
    sudo apt install libsctp1
    +sudo modprobe sctp
    +lsmod | grep sctp
    +

    For distributions using the .rpm packaging format and the dnf tool +(such as Fedora, Red Hat, etc.), try this:

    +
    sudo dnf install -y lksctp-tools
    +sudo modprobe sctp
    +lsmod | grep sctp

    Testing Ahead-of-time Optimizations

    One way to improve test coverage of ahead-of-time (AOT) optimizations diff --git a/doc/testing.md b/doc/testing.md index b95f59de9fd..d0e54aab02b 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -640,6 +640,32 @@ $ make test TEST="jtreg:sun/security/pkcs11/Secmod/AddTrustedCert.java" \ For more notes about the PKCS11 tests, please refer to test/jdk/sun/security/pkcs11/README. + +### SCTP Tests + +The SCTP tests require the SCTP runtime library, which is often not installed +by default in popular Linux distributions. Without this library, the SCTP tests +will be skipped. If you want to enable the SCTP tests, you should install the +SCTP library before running the tests. + +For distributions using the .deb packaging format and the apt tool +(such as Debian, Ubuntu, etc.), try this: + +``` +sudo apt install libsctp1 +sudo modprobe sctp +lsmod | grep sctp +``` + +For distributions using the .rpm packaging format and the dnf tool +(such as Fedora, Red Hat, etc.), try this: + +``` +sudo dnf install -y lksctp-tools +sudo modprobe sctp +lsmod | grep sctp +``` + ### Testing Ahead-of-time Optimizations One way to improve test coverage of ahead-of-time (AOT) optimizations in From 38b66b12581a3745a37589e32aa0fc880d27b4d4 Mon Sep 17 00:00:00 2001 From: Xiaohong Gong Date: Mon, 26 Jan 2026 01:50:57 +0000 Subject: [PATCH 172/328] 8374043: C2: assert(_base >= VectorMask && _base <= VectorZ) failed: Not a Vector Reviewed-by: qamai, vlivanov --- src/hotspot/share/opto/vectorIntrinsics.cpp | 4 ++++ src/hotspot/share/opto/vectornode.cpp | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/opto/vectorIntrinsics.cpp b/src/hotspot/share/opto/vectorIntrinsics.cpp index 65d54e076b6..883a0526053 100644 --- a/src/hotspot/share/opto/vectorIntrinsics.cpp +++ b/src/hotspot/share/opto/vectorIntrinsics.cpp @@ -175,6 +175,10 @@ Node* GraphKit::unbox_vector(Node* v, const TypeInstPtr* vbox_type, BasicType el assert(check_vbox(vbox_type), ""); const TypeVect* vt = TypeVect::make(elem_bt, num_elem, is_vector_mask(vbox_type->instance_klass())); Node* unbox = gvn().transform(new VectorUnboxNode(C, vt, v, merged_memory())); + if (gvn().type(unbox)->isa_vect() == nullptr) { + assert(gvn().type(unbox) == Type::TOP, "sanity"); + return nullptr; // not a vector + } return unbox; } diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index 271dc901dcb..7401efaf7c2 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, 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 @@ -1919,6 +1919,15 @@ Node* VectorMaskToLongNode::Ideal_MaskAll(PhaseGVN* phase) { // saved with a predicate type. if (in1->Opcode() == Op_VectorStoreMask) { Node* mask = in1->in(1); + // Skip the optimization if the mask is dead. + if (phase->type(mask) == Type::TOP) { + return nullptr; + } + // If the ideal graph is transformed correctly, the input mask should be a + // vector type node. Following optimization can ignore the mismatched type + // issue. But we still keep the sanity check for the mask type by using + // "is_vect()" in the assertion below, so that there can be less optimizations + // evolved before the compiler finally runs into a problem. assert(!Matcher::mask_op_prefers_predicate(Opcode(), mask->bottom_type()->is_vect()), "sanity"); in1 = mask; } From 90b546925397ff7cdd1591291e1b87d0bac5604a Mon Sep 17 00:00:00 2001 From: Arno Zeller Date: Mon, 26 Jan 2026 08:34:56 +0000 Subject: [PATCH 173/328] 8375999: com/sun/jndi/ldap/LdapPoolTimeoutTest.java fails sporadically on Windows Reviewed-by: jpai, mbaesken --- test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java b/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java index b47433ca16f..b139f12da25 100644 --- a/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java +++ b/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -131,6 +131,7 @@ public class LdapPoolTimeoutTest { || msg.contains("No route to host") || msg.contains("Timed out waiting for lock") || msg.contains("Connect timed out") + || msg.contains("Connection timed out") || msg.contains("Timeout exceeded while waiting for a connection"))) { // got the expected exception System.out.println("Received expected NamingException with message: " + msg); From 2af271e5e64260f05c01cb94bcf95f80fd69b4ff Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 26 Jan 2026 09:12:39 +0000 Subject: [PATCH 174/328] 8375436: G1: Convert G1CardSet classes to use Atomic Reviewed-by: kbarrett, iwalulya --- src/hotspot/share/gc/g1/g1CardSet.cpp | 89 +++++++++---------- src/hotspot/share/gc/g1/g1CardSet.hpp | 29 +++--- .../share/gc/g1/g1CardSetContainers.hpp | 36 ++++---- .../gc/g1/g1CardSetContainers.inline.hpp | 49 +++++----- src/hotspot/share/gc/g1/g1CardSetMemory.cpp | 3 +- .../gtest/gc/g1/test_g1CardSetContainers.cpp | 19 ++-- 6 files changed, 115 insertions(+), 110 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index 3441e6bc608..60ad63e812c 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -29,7 +29,6 @@ #include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/gcTraceTime.inline.hpp" #include "memory/allocation.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/globals_extension.hpp" #include "runtime/java.hpp" #include "utilities/bitMap.inline.hpp" @@ -192,32 +191,32 @@ const char* G1CardSetConfiguration::mem_object_type_name_str(uint index) { void G1CardSetCoarsenStats::reset() { STATIC_ASSERT(ARRAY_SIZE(_coarsen_from) == ARRAY_SIZE(_coarsen_collision)); for (uint i = 0; i < ARRAY_SIZE(_coarsen_from); i++) { - _coarsen_from[i] = 0; - _coarsen_collision[i] = 0; + _coarsen_from[i].store_relaxed(0); + _coarsen_collision[i].store_relaxed(0); } } void G1CardSetCoarsenStats::set(G1CardSetCoarsenStats& other) { STATIC_ASSERT(ARRAY_SIZE(_coarsen_from) == ARRAY_SIZE(_coarsen_collision)); for (uint i = 0; i < ARRAY_SIZE(_coarsen_from); i++) { - _coarsen_from[i] = other._coarsen_from[i]; - _coarsen_collision[i] = other._coarsen_collision[i]; + _coarsen_from[i].store_relaxed(other._coarsen_from[i].load_relaxed()); + _coarsen_collision[i].store_relaxed(other._coarsen_collision[i].load_relaxed()); } } void G1CardSetCoarsenStats::subtract_from(G1CardSetCoarsenStats& other) { STATIC_ASSERT(ARRAY_SIZE(_coarsen_from) == ARRAY_SIZE(_coarsen_collision)); for (uint i = 0; i < ARRAY_SIZE(_coarsen_from); i++) { - _coarsen_from[i] = other._coarsen_from[i] - _coarsen_from[i]; - _coarsen_collision[i] = other._coarsen_collision[i] - _coarsen_collision[i]; + _coarsen_from[i].store_relaxed(other._coarsen_from[i].load_relaxed() - _coarsen_from[i].load_relaxed()); + _coarsen_collision[i].store_relaxed(other._coarsen_collision[i].load_relaxed() - _coarsen_collision[i].load_relaxed()); } } void G1CardSetCoarsenStats::record_coarsening(uint tag, bool collision) { assert(tag < ARRAY_SIZE(_coarsen_from), "tag %u out of bounds", tag); - AtomicAccess::inc(&_coarsen_from[tag], memory_order_relaxed); + _coarsen_from[tag].add_then_fetch(1u, memory_order_relaxed); if (collision) { - AtomicAccess::inc(&_coarsen_collision[tag], memory_order_relaxed); + _coarsen_collision[tag].add_then_fetch(1u, memory_order_relaxed); } } @@ -228,13 +227,13 @@ void G1CardSetCoarsenStats::print_on(outputStream* out) { "Inline->AoC %zu (%zu) " "AoC->BitMap %zu (%zu) " "BitMap->Full %zu (%zu) ", - _coarsen_from[0], _coarsen_collision[0], - _coarsen_from[1], _coarsen_collision[1], + _coarsen_from[0].load_relaxed(), _coarsen_collision[0].load_relaxed(), + _coarsen_from[1].load_relaxed(), _coarsen_collision[1].load_relaxed(), // There is no BitMap at the first level so we can't . - _coarsen_from[3], _coarsen_collision[3], - _coarsen_from[4], _coarsen_collision[4], - _coarsen_from[5], _coarsen_collision[5], - _coarsen_from[6], _coarsen_collision[6] + _coarsen_from[3].load_relaxed(), _coarsen_collision[3].load_relaxed(), + _coarsen_from[4].load_relaxed(), _coarsen_collision[4].load_relaxed(), + _coarsen_from[5].load_relaxed(), _coarsen_collision[5].load_relaxed(), + _coarsen_from[6].load_relaxed(), _coarsen_collision[6].load_relaxed() ); } @@ -248,7 +247,7 @@ class G1CardSetHashTable : public CHeapObj { // the per region cardsets. const static uint GroupBucketClaimSize = 4; // Did we insert at least one card in the table? - bool volatile _inserted_card; + Atomic _inserted_card; G1CardSetMemoryManager* _mm; CardSetHash _table; @@ -311,10 +310,10 @@ public: G1CardSetHashTableValue value(region_idx, G1CardSetInlinePtr()); bool inserted = _table.insert_get(Thread::current(), lookup, value, found, should_grow); - if (!_inserted_card && inserted) { + if (!_inserted_card.load_relaxed() && inserted) { // It does not matter to us who is setting the flag so a regular atomic store // is sufficient. - AtomicAccess::store(&_inserted_card, true); + _inserted_card.store_relaxed(true); } return found.value(); @@ -343,9 +342,9 @@ public: } void reset() { - if (AtomicAccess::load(&_inserted_card)) { + if (_inserted_card.load_relaxed()) { _table.unsafe_reset(InitialLogTableSize); - AtomicAccess::store(&_inserted_card, false); + _inserted_card.store_relaxed(false); } } @@ -455,14 +454,14 @@ void G1CardSet::free_mem_object(ContainerPtr container) { _mm->free(container_type_to_mem_object_type(type), value); } -G1CardSet::ContainerPtr G1CardSet::acquire_container(ContainerPtr volatile* container_addr) { +G1CardSet::ContainerPtr G1CardSet::acquire_container(Atomic* container_addr) { // Update reference counts under RCU critical section to avoid a // use-after-cleapup bug where we increment a reference count for // an object whose memory has already been cleaned up and reused. GlobalCounter::CriticalSection cs(Thread::current()); while (true) { // Get ContainerPtr and increment refcount atomically wrt to memory reuse. - ContainerPtr container = AtomicAccess::load_acquire(container_addr); + ContainerPtr container = container_addr->load_acquire(); uint cs_type = container_type(container); if (container == FullCardSet || cs_type == ContainerInlinePtr) { return container; @@ -503,15 +502,15 @@ class G1ReleaseCardsets : public StackObj { G1CardSet* _card_set; using ContainerPtr = G1CardSet::ContainerPtr; - void coarsen_to_full(ContainerPtr* container_addr) { + void coarsen_to_full(Atomic* container_addr) { while (true) { - ContainerPtr cur_container = AtomicAccess::load_acquire(container_addr); + ContainerPtr cur_container = container_addr->load_acquire(); uint cs_type = G1CardSet::container_type(cur_container); if (cur_container == G1CardSet::FullCardSet) { return; } - ContainerPtr old_value = AtomicAccess::cmpxchg(container_addr, cur_container, G1CardSet::FullCardSet); + ContainerPtr old_value = container_addr->compare_exchange(cur_container, G1CardSet::FullCardSet); if (old_value == cur_container) { _card_set->release_and_maybe_free_container(cur_container); @@ -523,7 +522,7 @@ class G1ReleaseCardsets : public StackObj { public: explicit G1ReleaseCardsets(G1CardSet* card_set) : _card_set(card_set) { } - void operator ()(ContainerPtr* container_addr) { + void operator ()(Atomic* container_addr) { coarsen_to_full(container_addr); } }; @@ -544,10 +543,10 @@ G1AddCardResult G1CardSet::add_to_howl(ContainerPtr parent_container, ContainerPtr container; uint bucket = _config->howl_bucket_index(card_in_region); - ContainerPtr volatile* bucket_entry = howl->container_addr(bucket); + Atomic* bucket_entry = howl->container_addr(bucket); while (true) { - if (AtomicAccess::load(&howl->_num_entries) >= _config->cards_in_howl_threshold()) { + if (howl->_num_entries.load_relaxed() >= _config->cards_in_howl_threshold()) { return Overflow; } @@ -571,7 +570,7 @@ G1AddCardResult G1CardSet::add_to_howl(ContainerPtr parent_container, } if (increment_total && add_result == Added) { - AtomicAccess::inc(&howl->_num_entries, memory_order_relaxed); + howl->_num_entries.add_then_fetch(1u, memory_order_relaxed); } if (to_transfer != nullptr) { @@ -588,7 +587,7 @@ G1AddCardResult G1CardSet::add_to_bitmap(ContainerPtr container, uint card_in_re return bitmap->add(card_offset, _config->cards_in_howl_bitmap_threshold(), _config->max_cards_in_howl_bitmap()); } -G1AddCardResult G1CardSet::add_to_inline_ptr(ContainerPtr volatile* container_addr, ContainerPtr container, uint card_in_region) { +G1AddCardResult G1CardSet::add_to_inline_ptr(Atomic* container_addr, ContainerPtr container, uint card_in_region) { G1CardSetInlinePtr value(container_addr, container); return value.add(card_in_region, _config->inline_ptr_bits_per_card(), _config->max_cards_in_inline_ptr()); } @@ -610,7 +609,7 @@ G1CardSet::ContainerPtr G1CardSet::create_coarsened_array_of_cards(uint card_in_ return new_container; } -bool G1CardSet::coarsen_container(ContainerPtr volatile* container_addr, +bool G1CardSet::coarsen_container(Atomic* container_addr, ContainerPtr cur_container, uint card_in_region, bool within_howl) { @@ -640,7 +639,7 @@ bool G1CardSet::coarsen_container(ContainerPtr volatile* container_addr, ShouldNotReachHere(); } - ContainerPtr old_value = AtomicAccess::cmpxchg(container_addr, cur_container, new_container); // Memory order? + ContainerPtr old_value = container_addr->compare_exchange(cur_container, new_container); // Memory order? if (old_value == cur_container) { // Success. Indicate that the cards from the current card set must be transferred // by this caller. @@ -687,7 +686,7 @@ void G1CardSet::transfer_cards(G1CardSetHashTableValue* table_entry, ContainerPt assert(container_type(source_container) == ContainerHowl, "must be"); // Need to correct for that the Full remembered set occupies more cards than the // AoCS before. - AtomicAccess::add(&_num_occupied, _config->max_cards_in_region() - table_entry->_num_occupied, memory_order_relaxed); + _num_occupied.add_then_fetch(_config->max_cards_in_region() - table_entry->_num_occupied.load_relaxed(), memory_order_relaxed); } } @@ -713,18 +712,18 @@ void G1CardSet::transfer_cards_in_howl(ContainerPtr parent_container, diff -= 1; G1CardSetHowl* howling_array = container_ptr(parent_container); - AtomicAccess::add(&howling_array->_num_entries, diff, memory_order_relaxed); + howling_array->_num_entries.add_then_fetch(diff, memory_order_relaxed); G1CardSetHashTableValue* table_entry = get_container(card_region); assert(table_entry != nullptr, "Table entry not found for transferred cards"); - AtomicAccess::add(&table_entry->_num_occupied, diff, memory_order_relaxed); + table_entry->_num_occupied.add_then_fetch(diff, memory_order_relaxed); - AtomicAccess::add(&_num_occupied, diff, memory_order_relaxed); + _num_occupied.add_then_fetch(diff, memory_order_relaxed); } } -G1AddCardResult G1CardSet::add_to_container(ContainerPtr volatile* container_addr, +G1AddCardResult G1CardSet::add_to_container(Atomic* container_addr, ContainerPtr container, uint card_region, uint card_in_region, @@ -827,8 +826,8 @@ G1AddCardResult G1CardSet::add_card(uint card_region, uint card_in_region, bool } if (increment_total && add_result == Added) { - AtomicAccess::inc(&table_entry->_num_occupied, memory_order_relaxed); - AtomicAccess::inc(&_num_occupied, memory_order_relaxed); + table_entry->_num_occupied.add_then_fetch(1u, memory_order_relaxed); + _num_occupied.add_then_fetch(1u, memory_order_relaxed); } if (should_grow_table) { _table->grow(); @@ -853,7 +852,7 @@ bool G1CardSet::contains_card(uint card_region, uint card_in_region) { return false; } - ContainerPtr container = table_entry->_container; + ContainerPtr container = table_entry->_container.load_relaxed(); if (container == FullCardSet) { // contains_card() is not a performance critical method so we do not hide that // case in the switch below. @@ -889,7 +888,7 @@ void G1CardSet::print_info(outputStream* st, uintptr_t card) { return; } - ContainerPtr container = table_entry->_container; + ContainerPtr container = table_entry->_container.load_relaxed(); if (container == FullCardSet) { st->print("FULL card set)"); return; @@ -940,7 +939,7 @@ void G1CardSet::iterate_cards_during_transfer(ContainerPtr const container, Card void G1CardSet::iterate_containers(ContainerPtrClosure* cl, bool at_safepoint) { auto do_value = [&] (G1CardSetHashTableValue* value) { - cl->do_containerptr(value->_region_idx, value->_num_occupied, value->_container); + cl->do_containerptr(value->_region_idx, value->_num_occupied.load_relaxed(), value->_container.load_relaxed()); return true; }; @@ -1001,11 +1000,11 @@ bool G1CardSet::occupancy_less_or_equal_to(size_t limit) const { } bool G1CardSet::is_empty() const { - return _num_occupied == 0; + return _num_occupied.load_relaxed() == 0; } size_t G1CardSet::occupied() const { - return _num_occupied; + return _num_occupied.load_relaxed(); } size_t G1CardSet::num_containers() { @@ -1051,7 +1050,7 @@ size_t G1CardSet::static_mem_size() { void G1CardSet::clear() { _table->reset(); - _num_occupied = 0; + _num_occupied.store_relaxed(0); _mm->flush(); } diff --git a/src/hotspot/share/gc/g1/g1CardSet.hpp b/src/hotspot/share/gc/g1/g1CardSet.hpp index 9cefc4b1c22..64ddf0ca6a4 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.hpp +++ b/src/hotspot/share/gc/g1/g1CardSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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,6 +27,7 @@ #include "memory/allocation.hpp" #include "memory/memRegion.hpp" +#include "runtime/atomic.hpp" #include "utilities/concurrentHashTable.hpp" class G1CardSetAllocOptions; @@ -154,8 +155,8 @@ public: private: // Indices are "from" indices. - size_t _coarsen_from[NumCoarsenCategories]; - size_t _coarsen_collision[NumCoarsenCategories]; + Atomic _coarsen_from[NumCoarsenCategories]; + Atomic _coarsen_collision[NumCoarsenCategories]; public: G1CardSetCoarsenStats() { reset(); } @@ -271,11 +272,11 @@ private: // Total number of cards in this card set. This is a best-effort value, i.e. there may // be (slightly) more cards in the card set than this value in reality. - size_t _num_occupied; + Atomic _num_occupied; ContainerPtr make_container_ptr(void* value, uintptr_t type); - ContainerPtr acquire_container(ContainerPtr volatile* container_addr); + ContainerPtr acquire_container(Atomic* container_addr); // Returns true if the card set container should be released bool release_container(ContainerPtr container); // Release card set and free if needed. @@ -288,7 +289,7 @@ private: // coarsen_container does not transfer cards from cur_container // to the new container. Transfer is achieved by transfer_cards. // Returns true if this was the thread that coarsened the container (and added the card). - bool coarsen_container(ContainerPtr volatile* container_addr, + bool coarsen_container(Atomic* container_addr, ContainerPtr cur_container, uint card_in_region, bool within_howl = false); @@ -300,9 +301,9 @@ private: void transfer_cards(G1CardSetHashTableValue* table_entry, ContainerPtr source_container, uint card_region); void transfer_cards_in_howl(ContainerPtr parent_container, ContainerPtr source_container, uint card_region); - G1AddCardResult add_to_container(ContainerPtr volatile* container_addr, ContainerPtr container, uint card_region, uint card, bool increment_total = true); + G1AddCardResult add_to_container(Atomic* container_addr, ContainerPtr container, uint card_region, uint card, bool increment_total = true); - G1AddCardResult add_to_inline_ptr(ContainerPtr volatile* container_addr, ContainerPtr container, uint card_in_region); + G1AddCardResult add_to_inline_ptr(Atomic* container_addr, ContainerPtr container, uint card_in_region); G1AddCardResult add_to_array(ContainerPtr container, uint card_in_region); G1AddCardResult add_to_bitmap(ContainerPtr container, uint card_in_region); G1AddCardResult add_to_howl(ContainerPtr parent_container, uint card_region, uint card_in_region, bool increment_total = true); @@ -366,7 +367,6 @@ public: size_t num_containers(); - static G1CardSetCoarsenStats coarsen_stats(); static void print_coarsen_stats(outputStream* out); // Returns size of the actual remembered set containers in bytes. @@ -412,8 +412,15 @@ public: using ContainerPtr = G1CardSet::ContainerPtr; const uint _region_idx; - uint volatile _num_occupied; - ContainerPtr volatile _container; + Atomic _num_occupied; + Atomic _container; + + // Copy constructor needed for use in ConcurrentHashTable. + G1CardSetHashTableValue(const G1CardSetHashTableValue& other) : + _region_idx(other._region_idx), + _num_occupied(other._num_occupied.load_relaxed()), + _container(other._container.load_relaxed()) + { } G1CardSetHashTableValue(uint region_idx, ContainerPtr container) : _region_idx(region_idx), _num_occupied(0), _container(container) { } }; diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp index 72c7795be2e..78551479e06 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ #include "gc/g1/g1CardSet.hpp" #include "memory/allocation.hpp" -#include "runtime/atomicAccess.hpp" +#include "runtime/atomic.hpp" #include "utilities/bitMap.hpp" #include "utilities/globalDefinitions.hpp" @@ -67,7 +67,7 @@ class G1CardSetInlinePtr : public StackObj { using ContainerPtr = G1CardSet::ContainerPtr; - ContainerPtr volatile * _value_addr; + Atomic* _value_addr; ContainerPtr _value; static const uint SizeFieldLen = 3; @@ -103,7 +103,7 @@ public: explicit G1CardSetInlinePtr(ContainerPtr value) : G1CardSetInlinePtr(nullptr, value) {} - G1CardSetInlinePtr(ContainerPtr volatile* value_addr, ContainerPtr value) : _value_addr(value_addr), _value(value) { + G1CardSetInlinePtr(Atomic* value_addr, ContainerPtr value) : _value_addr(value_addr), _value(value) { assert(G1CardSet::container_type(_value) == G1CardSet::ContainerInlinePtr, "Value " PTR_FORMAT " is not a valid G1CardSetInlinePtr.", p2i(_value)); } @@ -145,13 +145,13 @@ public: // All but inline pointers are of this kind. For those, card entries are stored // directly in the ContainerPtr of the ConcurrentHashTable node. class G1CardSetContainer { - uintptr_t _ref_count; + Atomic _ref_count; protected: ~G1CardSetContainer() = default; public: G1CardSetContainer() : _ref_count(3) { } - uintptr_t refcount() const { return AtomicAccess::load_acquire(&_ref_count); } + uintptr_t refcount() const { return _ref_count.load_acquire(); } bool try_increment_refcount(); @@ -172,7 +172,7 @@ public: using ContainerPtr = G1CardSet::ContainerPtr; private: EntryCountType _size; - EntryCountType volatile _num_entries; + Atomic _num_entries; // VLA implementation. EntryDataType _data[1]; @@ -180,10 +180,10 @@ private: static const EntryCountType EntryMask = LockBitMask - 1; class G1CardSetArrayLocker : public StackObj { - EntryCountType volatile* _num_entries_addr; + Atomic* _num_entries_addr; EntryCountType _local_num_entries; public: - G1CardSetArrayLocker(EntryCountType volatile* value); + G1CardSetArrayLocker(Atomic* value); EntryCountType num_entries() const { return _local_num_entries; } void inc_num_entries() { @@ -192,7 +192,7 @@ private: } ~G1CardSetArrayLocker() { - AtomicAccess::release_store(_num_entries_addr, _local_num_entries); + _num_entries_addr->release_store(_local_num_entries); } }; @@ -213,7 +213,7 @@ public: template void iterate(CardVisitor& found); - size_t num_entries() const { return _num_entries & EntryMask; } + size_t num_entries() const { return _num_entries.load_relaxed() & EntryMask; } static size_t header_size_in_bytes(); @@ -223,7 +223,7 @@ public: }; class G1CardSetBitMap : public G1CardSetContainer { - size_t _num_bits_set; + Atomic _num_bits_set; BitMap::bm_word_t _bits[1]; public: @@ -236,7 +236,7 @@ public: return bm.at(card_idx); } - uint num_bits_set() const { return (uint)_num_bits_set; } + uint num_bits_set() const { return (uint)_num_bits_set.load_relaxed(); } template void iterate(CardVisitor& found, size_t const size_in_bits, uint offset); @@ -255,10 +255,10 @@ class G1CardSetHowl : public G1CardSetContainer { public: typedef uint EntryCountType; using ContainerPtr = G1CardSet::ContainerPtr; - EntryCountType volatile _num_entries; + Atomic _num_entries; private: // VLA implementation. - ContainerPtr _buckets[1]; + Atomic _buckets[1]; // Do not add class member variables beyond this point. // Iterates over the given ContainerPtr with at index in this Howl card set, @@ -268,14 +268,14 @@ private: ContainerPtr at(EntryCountType index) const; - ContainerPtr const* buckets() const; + Atomic const* buckets() const; public: G1CardSetHowl(EntryCountType card_in_region, G1CardSetConfiguration* config); - ContainerPtr const* container_addr(EntryCountType index) const; + Atomic const* container_addr(EntryCountType index) const; - ContainerPtr* container_addr(EntryCountType index); + Atomic* container_addr(EntryCountType index); bool contains(uint card_idx, G1CardSetConfiguration* config); // Iterates over all ContainerPtrs in this Howl card set, applying a CardOrRangeVisitor diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp index 1958309f517..3c6fb9d1a02 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -67,7 +67,7 @@ inline G1AddCardResult G1CardSetInlinePtr::add(uint card_idx, uint bits_per_card return Overflow; } ContainerPtr new_value = merge(_value, card_idx, num_cards, bits_per_card); - ContainerPtr old_value = AtomicAccess::cmpxchg(_value_addr, _value, new_value, memory_order_relaxed); + ContainerPtr old_value = _value_addr->compare_exchange(_value, new_value, memory_order_relaxed); if (_value == old_value) { return Added; } @@ -126,7 +126,7 @@ inline bool G1CardSetContainer::try_increment_refcount() { } uintptr_t new_value = old_value + 2; - uintptr_t ref_count = AtomicAccess::cmpxchg(&_ref_count, old_value, new_value); + uintptr_t ref_count = _ref_count.compare_exchange(old_value, new_value); if (ref_count == old_value) { return true; } @@ -137,7 +137,7 @@ inline bool G1CardSetContainer::try_increment_refcount() { inline uintptr_t G1CardSetContainer::decrement_refcount() { uintptr_t old_value = refcount(); assert((old_value & 0x1) != 0 && old_value >= 3, "precondition"); - return AtomicAccess::sub(&_ref_count, 2u); + return _ref_count.sub_then_fetch(2u); } inline G1CardSetArray::G1CardSetArray(uint card_in_region, EntryCountType num_cards) : @@ -149,14 +149,13 @@ inline G1CardSetArray::G1CardSetArray(uint card_in_region, EntryCountType num_ca *entry_addr(0) = checked_cast(card_in_region); } -inline G1CardSetArray::G1CardSetArrayLocker::G1CardSetArrayLocker(EntryCountType volatile* num_entries_addr) : +inline G1CardSetArray::G1CardSetArrayLocker::G1CardSetArrayLocker(Atomic* num_entries_addr) : _num_entries_addr(num_entries_addr) { SpinYield s; - EntryCountType num_entries = AtomicAccess::load(_num_entries_addr) & EntryMask; + EntryCountType num_entries = _num_entries_addr->load_relaxed() & EntryMask; while (true) { - EntryCountType old_value = AtomicAccess::cmpxchg(_num_entries_addr, - num_entries, - (EntryCountType)(num_entries | LockBitMask)); + EntryCountType old_value = _num_entries_addr->compare_exchange(num_entries, + (EntryCountType)(num_entries | LockBitMask)); if (old_value == num_entries) { // Succeeded locking the array. _local_num_entries = num_entries; @@ -174,7 +173,7 @@ inline G1CardSetArray::EntryDataType const* G1CardSetArray::base_addr() const { } inline G1CardSetArray::EntryDataType const* G1CardSetArray::entry_addr(EntryCountType index) const { - assert(index < _num_entries, "precondition"); + assert(index < _num_entries.load_relaxed(), "precondition"); return base_addr() + index; } @@ -189,7 +188,7 @@ inline G1CardSetArray::EntryDataType G1CardSetArray::at(EntryCountType index) co inline G1AddCardResult G1CardSetArray::add(uint card_idx) { assert(card_idx < (1u << (sizeof(EntryDataType) * BitsPerByte)), "Card index %u does not fit allowed card value range.", card_idx); - EntryCountType num_entries = AtomicAccess::load_acquire(&_num_entries) & EntryMask; + EntryCountType num_entries = _num_entries.load_acquire() & EntryMask; EntryCountType idx = 0; for (; idx < num_entries; idx++) { if (at(idx) == card_idx) { @@ -223,7 +222,7 @@ inline G1AddCardResult G1CardSetArray::add(uint card_idx) { } inline bool G1CardSetArray::contains(uint card_idx) { - EntryCountType num_entries = AtomicAccess::load_acquire(&_num_entries) & EntryMask; + EntryCountType num_entries = _num_entries.load_acquire() & EntryMask; for (EntryCountType idx = 0; idx < num_entries; idx++) { if (at(idx) == card_idx) { @@ -235,7 +234,7 @@ inline bool G1CardSetArray::contains(uint card_idx) { template void G1CardSetArray::iterate(CardVisitor& found) { - EntryCountType num_entries = AtomicAccess::load_acquire(&_num_entries) & EntryMask; + EntryCountType num_entries = _num_entries.load_acquire() & EntryMask; for (EntryCountType idx = 0; idx < num_entries; idx++) { found(at(idx)); } @@ -256,11 +255,11 @@ inline G1CardSetBitMap::G1CardSetBitMap(uint card_in_region, uint size_in_bits) inline G1AddCardResult G1CardSetBitMap::add(uint card_idx, size_t threshold, size_t size_in_bits) { BitMapView bm(_bits, size_in_bits); - if (_num_bits_set >= threshold) { + if (_num_bits_set.load_relaxed() >= threshold) { return bm.at(card_idx) ? Found : Overflow; } if (bm.par_set_bit(card_idx)) { - AtomicAccess::inc(&_num_bits_set, memory_order_relaxed); + _num_bits_set.add_then_fetch(1u, memory_order_relaxed); return Added; } return Found; @@ -276,22 +275,22 @@ inline size_t G1CardSetBitMap::header_size_in_bytes() { return offset_of(G1CardSetBitMap, _bits); } -inline G1CardSetHowl::ContainerPtr const* G1CardSetHowl::container_addr(EntryCountType index) const { - assert(index < _num_entries, "precondition"); +inline Atomic const* G1CardSetHowl::container_addr(EntryCountType index) const { + assert(index < _num_entries.load_relaxed(), "precondition"); return buckets() + index; } -inline G1CardSetHowl::ContainerPtr* G1CardSetHowl::container_addr(EntryCountType index) { - return const_cast(const_cast(this)->container_addr(index)); +inline Atomic* G1CardSetHowl::container_addr(EntryCountType index) { + return const_cast*>(const_cast(this)->container_addr(index)); } inline G1CardSetHowl::ContainerPtr G1CardSetHowl::at(EntryCountType index) const { - return *container_addr(index); + return (*container_addr(index)).load_relaxed(); } -inline G1CardSetHowl::ContainerPtr const* G1CardSetHowl::buckets() const { +inline Atomic const* G1CardSetHowl::buckets() const { const void* ptr = reinterpret_cast(this) + header_size_in_bytes(); - return reinterpret_cast(ptr); + return reinterpret_cast const*>(ptr); } inline G1CardSetHowl::G1CardSetHowl(EntryCountType card_in_region, G1CardSetConfiguration* config) : @@ -300,7 +299,7 @@ inline G1CardSetHowl::G1CardSetHowl(EntryCountType card_in_region, G1CardSetConf EntryCountType num_buckets = config->num_buckets_in_howl(); EntryCountType bucket = config->howl_bucket_index(card_in_region); for (uint i = 0; i < num_buckets; ++i) { - *container_addr(i) = G1CardSetInlinePtr(); + container_addr(i)->store_relaxed(G1CardSetInlinePtr()); if (i == bucket) { G1CardSetInlinePtr value(container_addr(i), at(i)); value.add(card_in_region, config->inline_ptr_bits_per_card(), config->max_cards_in_inline_ptr()); @@ -310,8 +309,8 @@ inline G1CardSetHowl::G1CardSetHowl(EntryCountType card_in_region, G1CardSetConf inline bool G1CardSetHowl::contains(uint card_idx, G1CardSetConfiguration* config) { EntryCountType bucket = config->howl_bucket_index(card_idx); - ContainerPtr* array_entry = container_addr(bucket); - ContainerPtr container = AtomicAccess::load_acquire(array_entry); + Atomic* array_entry = container_addr(bucket); + ContainerPtr container = array_entry->load_acquire(); switch (G1CardSet::container_type(container)) { case G1CardSet::ContainerArrayOfCards: { diff --git a/src/hotspot/share/gc/g1/g1CardSetMemory.cpp b/src/hotspot/share/gc/g1/g1CardSetMemory.cpp index d13a6fe2dca..60602ef942b 100644 --- a/src/hotspot/share/gc/g1/g1CardSetMemory.cpp +++ b/src/hotspot/share/gc/g1/g1CardSetMemory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ #include "gc/g1/g1CardSetContainers.inline.hpp" #include "gc/g1/g1CardSetMemory.inline.hpp" #include "gc/g1/g1MonotonicArena.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/ostream.hpp" G1CardSetAllocator::G1CardSetAllocator(const char* name, diff --git a/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp b/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp index d83d8ffeef6..91951b35405 100644 --- a/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp @@ -25,6 +25,7 @@ #include "gc/g1/g1HeapRegionBounds.inline.hpp" #include "gc/shared/cardTable.hpp" #include "memory/allocation.inline.hpp" +#include "runtime/atomic.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/powerOfTwo.hpp" #include "unittest.hpp" @@ -82,48 +83,48 @@ void G1CardSetContainersTest::cardset_inlineptr_test(uint bits_per_card) { G1AddCardResult res; - G1CardSet::ContainerPtr value = G1CardSetInlinePtr(); + Atomic value{}; for (uint i = 0; i < CardsPerSet; i++) { { - G1CardSetInlinePtr cards(&value, value); + G1CardSetInlinePtr cards(&value, value.load_relaxed()); res = cards.add(i + 1, bits_per_card, CardsPerSet); ASSERT_TRUE(res == Added); } { - G1CardSetInlinePtr cards(&value, value); + G1CardSetInlinePtr cards(&value, value.load_relaxed()); ASSERT_TRUE(cards.contains(i + 1, bits_per_card)); } } for (uint i = 0; i < CardsPerSet; i++) { - G1CardSetInlinePtr cards(value); + G1CardSetInlinePtr cards(value.load_relaxed()); ASSERT_TRUE(cards.contains(i + 1, bits_per_card)); } // Try to add again, should all return that the card had been added. for (uint i = 0; i < CardsPerSet; i++) { - G1CardSetInlinePtr cards(&value, value); + G1CardSetInlinePtr cards(&value, value.load_relaxed()); res = cards.add(i + 1, bits_per_card, CardsPerSet); ASSERT_TRUE(res == Found); } // Should be no more space in set. { - G1CardSetInlinePtr cards(&value, value); + G1CardSetInlinePtr cards(&value, value.load_relaxed()); res = cards.add(CardsPerSet + 1, bits_per_card, CardsPerSet); ASSERT_TRUE(res == Overflow); } // Cards should still be in the set. for (uint i = 0; i < CardsPerSet; i++) { - G1CardSetInlinePtr cards(value); + G1CardSetInlinePtr cards(value.load_relaxed()); ASSERT_TRUE(cards.contains(i + 1, bits_per_card)); } // Boundary cards should not be in the set. { - G1CardSetInlinePtr cards(value); + G1CardSetInlinePtr cards(value.load_relaxed()); ASSERT_TRUE(!cards.contains(0, bits_per_card)); ASSERT_TRUE(!cards.contains(CardsPerSet + 1, bits_per_card)); } @@ -131,7 +132,7 @@ void G1CardSetContainersTest::cardset_inlineptr_test(uint bits_per_card) { // Verify iteration finds all cards too and only those. { G1FindCardsInRange found(1, CardsPerSet); - G1CardSetInlinePtr cards(value); + G1CardSetInlinePtr cards(value.load_relaxed()); cards.iterate(found, bits_per_card); found.verify_all_found(); } From e7cadd90b2872364443873aa4b4b4664bcf02f4d Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 26 Jan 2026 09:15:32 +0000 Subject: [PATCH 175/328] 8375981: G1: Convert G1RemSet helper classes to use Atomic Reviewed-by: shade, iwalulya --- src/hotspot/share/gc/g1/g1RemSet.cpp | 50 ++++++++++++++++------------ 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index c7724de280f..0c9a0fad8f2 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -50,7 +50,7 @@ #include "memory/resourceArea.hpp" #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" +#include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" @@ -107,46 +107,48 @@ class G1RemSetScanState : public CHeapObj { // Set of (unique) regions that can be added to concurrently. class G1DirtyRegions : public CHeapObj { uint* _buffer; - uint _cur_idx; + Atomic _cur_idx; size_t _max_reserved_regions; - bool* _contains; + Atomic* _contains; public: G1DirtyRegions(size_t max_reserved_regions) : _buffer(NEW_C_HEAP_ARRAY(uint, max_reserved_regions, mtGC)), _cur_idx(0), _max_reserved_regions(max_reserved_regions), - _contains(NEW_C_HEAP_ARRAY(bool, max_reserved_regions, mtGC)) { + _contains(NEW_C_HEAP_ARRAY(Atomic, max_reserved_regions, mtGC)) { reset(); } ~G1DirtyRegions() { FREE_C_HEAP_ARRAY(uint, _buffer); - FREE_C_HEAP_ARRAY(bool, _contains); + FREE_C_HEAP_ARRAY(Atomic, _contains); } void reset() { - _cur_idx = 0; - ::memset(_contains, false, _max_reserved_regions * sizeof(bool)); + _cur_idx.store_relaxed(0); + for (uint i = 0; i < _max_reserved_regions; i++) { + _contains[i].store_relaxed(false); + } } - uint size() const { return _cur_idx; } + uint size() const { return _cur_idx.load_relaxed(); } uint at(uint idx) const { - assert(idx < _cur_idx, "Index %u beyond valid regions", idx); + assert(idx < size(), "Index %u beyond valid regions", idx); return _buffer[idx]; } void add_dirty_region(uint region) { - if (_contains[region]) { + if (_contains[region].load_relaxed()) { return; } - bool marked_as_dirty = AtomicAccess::cmpxchg(&_contains[region], false, true) == false; + bool marked_as_dirty = _contains[region].compare_set(false, true); if (marked_as_dirty) { - uint allocated = AtomicAccess::fetch_then_add(&_cur_idx, 1u); + uint allocated = _cur_idx.fetch_then_add(1u); _buffer[allocated] = region; } } @@ -155,9 +157,11 @@ class G1RemSetScanState : public CHeapObj { void merge(const G1DirtyRegions* other) { for (uint i = 0; i < other->size(); i++) { uint region = other->at(i); - if (!_contains[region]) { - _buffer[_cur_idx++] = region; - _contains[region] = true; + if (!_contains[region].load_relaxed()) { + uint cur = _cur_idx.load_relaxed(); + _buffer[cur] = region; + _cur_idx.store_relaxed(cur + 1); + _contains[region].store_relaxed(true); } } } @@ -173,7 +177,7 @@ class G1RemSetScanState : public CHeapObj { class G1ClearCardTableTask : public G1AbstractSubTask { G1CollectedHeap* _g1h; G1DirtyRegions* _regions; - uint volatile _cur_dirty_regions; + Atomic _cur_dirty_regions; G1RemSetScanState* _scan_state; @@ -210,8 +214,9 @@ class G1ClearCardTableTask : public G1AbstractSubTask { void do_work(uint worker_id) override { const uint num_regions_per_worker = num_cards_per_worker / (uint)G1HeapRegion::CardsPerRegion; - while (_cur_dirty_regions < _regions->size()) { - uint next = AtomicAccess::fetch_then_add(&_cur_dirty_regions, num_regions_per_worker); + uint cur = _cur_dirty_regions.load_relaxed(); + while (cur < _regions->size()) { + uint next = _cur_dirty_regions.fetch_then_add(num_regions_per_worker); uint max = MIN2(next + num_regions_per_worker, _regions->size()); for (uint i = next; i < max; i++) { @@ -226,6 +231,7 @@ class G1ClearCardTableTask : public G1AbstractSubTask { // old regions use it for old->collection set candidates, so they should not be cleared // either. } + cur = max; } } }; @@ -1115,7 +1121,7 @@ class G1MergeHeapRootsTask : public WorkerTask { bool _initial_evacuation; - volatile bool _fast_reclaim_handled; + Atomic _fast_reclaim_handled; public: G1MergeHeapRootsTask(G1RemSetScanState* scan_state, uint num_workers, bool initial_evacuation) : @@ -1143,8 +1149,8 @@ public: // 1. eager-reclaim candidates if (_initial_evacuation && g1h->has_humongous_reclaim_candidates() && - !_fast_reclaim_handled && - !AtomicAccess::cmpxchg(&_fast_reclaim_handled, false, true)) { + !_fast_reclaim_handled.load_relaxed() && + _fast_reclaim_handled.compare_set(false, true)) { G1GCParPhaseTimesTracker subphase_x(p, G1GCPhaseTimes::MergeER, worker_id); From 4597046984dedfd28bd76bd00dfc4b13ccb38dd4 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 26 Jan 2026 09:16:11 +0000 Subject: [PATCH 176/328] 8375974: G1: Convert G1FullCollector to use Atomic Reviewed-by: kbarrett, iwalulya --- src/hotspot/share/gc/g1/g1FullCollector.cpp | 6 +++--- src/hotspot/share/gc/g1/g1FullCollector.hpp | 2 +- src/hotspot/share/gc/g1/g1FullCollector.inline.hpp | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index 7395df01760..6c8cc7028cc 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -134,10 +134,10 @@ G1FullCollector::G1FullCollector(G1CollectedHeap* heap, _compaction_points = NEW_C_HEAP_ARRAY(G1FullGCCompactionPoint*, _num_workers, mtGC); _live_stats = NEW_C_HEAP_ARRAY(G1RegionMarkStats, _heap->max_num_regions(), mtGC); - _compaction_tops = NEW_C_HEAP_ARRAY(HeapWord*, _heap->max_num_regions(), mtGC); + _compaction_tops = NEW_C_HEAP_ARRAY(Atomic, _heap->max_num_regions(), mtGC); for (uint j = 0; j < heap->max_num_regions(); j++) { _live_stats[j].clear(); - _compaction_tops[j] = nullptr; + ::new (&_compaction_tops[j]) Atomic{}; } _partial_array_state_manager = new PartialArrayStateManager(_num_workers); @@ -167,7 +167,7 @@ G1FullCollector::~G1FullCollector() { FREE_C_HEAP_ARRAY(G1FullGCMarker*, _markers); FREE_C_HEAP_ARRAY(G1FullGCCompactionPoint*, _compaction_points); - FREE_C_HEAP_ARRAY(HeapWord*, _compaction_tops); + FREE_C_HEAP_ARRAY(Atomic, _compaction_tops); FREE_C_HEAP_ARRAY(G1RegionMarkStats, _live_stats); } diff --git a/src/hotspot/share/gc/g1/g1FullCollector.hpp b/src/hotspot/share/gc/g1/g1FullCollector.hpp index 28ecffad944..7e455b07013 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.hpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.hpp @@ -96,7 +96,7 @@ class G1FullCollector : StackObj { G1FullGCHeapRegionAttr _region_attr_table; - HeapWord* volatile* _compaction_tops; + Atomic* _compaction_tops; public: G1FullCollector(G1CollectedHeap* heap, diff --git a/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp b/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp index b52f3d79604..0c201f0e43f 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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 @@ -63,11 +63,11 @@ void G1FullCollector::update_from_skip_compacting_to_compacting(uint region_idx) } void G1FullCollector::set_compaction_top(G1HeapRegion* r, HeapWord* value) { - AtomicAccess::store(&_compaction_tops[r->hrm_index()], value); + _compaction_tops[r->hrm_index()].store_relaxed(value); } HeapWord* G1FullCollector::compaction_top(G1HeapRegion* r) const { - return AtomicAccess::load(&_compaction_tops[r->hrm_index()]); + return _compaction_tops[r->hrm_index()].load_relaxed(); } void G1FullCollector::set_has_compaction_targets() { From a49986c62f4bcc4656f4ce0c7804a96875e9b6c6 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 26 Jan 2026 09:16:41 +0000 Subject: [PATCH 177/328] 8375964: G1: Convert G1BuildCandidateRegionsTask to use Atomic Reviewed-by: shade, iwalulya --- src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp b/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp index d9496410c12..e7bab32129e 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp @@ -203,13 +203,13 @@ class G1BuildCandidateRegionsTask : public WorkerTask { G1CollectedHeap* _g1h; G1HeapRegionClaimer _hrclaimer; - uint volatile _num_regions_added; + Atomic _num_regions_added; G1BuildCandidateArray _result; void update_totals(uint num_regions) { if (num_regions > 0) { - AtomicAccess::add(&_num_regions_added, num_regions); + _num_regions_added.add_then_fetch(num_regions); } } @@ -221,7 +221,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask { void prune(G1HeapRegion** data) { G1Policy* p = G1CollectedHeap::heap()->policy(); - uint num_candidates = AtomicAccess::load(&_num_regions_added); + uint num_candidates = _num_regions_added.load_relaxed(); uint min_old_cset_length = p->calc_min_old_cset_length(num_candidates); uint num_pruned = 0; @@ -254,7 +254,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask { wasted_bytes, allowed_waste); - AtomicAccess::sub(&_num_regions_added, num_pruned, memory_order_relaxed); + _num_regions_added.sub_then_fetch(num_pruned, memory_order_relaxed); } public: @@ -275,7 +275,7 @@ public: _result.sort_by_gc_efficiency(); prune(_result.array()); candidates->set_candidates_from_marking(_result.array(), - _num_regions_added); + _num_regions_added.load_relaxed()); } }; From c3360ff51155bdd62b758c163351f57f4b410606 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 26 Jan 2026 09:17:01 +0000 Subject: [PATCH 178/328] 8375983: G1: Convert G1ConcurrentRefineStats to use Atomic Reviewed-by: kbarrett, iwalulya --- .../share/gc/g1/g1ConcurrentRefine.cpp | 1 + .../share/gc/g1/g1ConcurrentRefineStats.cpp | 32 +++-- .../share/gc/g1/g1ConcurrentRefineStats.hpp | 68 +++++----- .../gc/g1/g1ConcurrentRefineStats.inline.hpp | 118 ++++++++++++++++++ .../gc/g1/g1ConcurrentRefineSweepTask.cpp | 1 + .../gc/g1/g1ConcurrentRefineSweepTask.hpp | 2 +- .../share/gc/g1/g1ConcurrentRefineThread.cpp | 2 +- .../share/gc/g1/g1ConcurrentRefineThread.hpp | 1 - src/hotspot/share/gc/g1/g1Policy.cpp | 2 +- .../share/gc/g1/g1YoungGCPreEvacuateTasks.cpp | 1 - 10 files changed, 177 insertions(+), 51 deletions(-) create mode 100644 src/hotspot/share/gc/g1/g1ConcurrentRefineStats.inline.hpp diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp index ed6a9ad4292..8546e6e2d64 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp @@ -28,6 +28,7 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1ConcurrentRefine.hpp" +#include "gc/g1/g1ConcurrentRefineStats.inline.hpp" #include "gc/g1/g1ConcurrentRefineSweepTask.hpp" #include "gc/g1/g1ConcurrentRefineThread.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.cpp index 83a09c55a3f..5160d5ed036 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ * */ -#include "gc/g1/g1ConcurrentRefineStats.hpp" +#include "gc/g1/g1ConcurrentRefineStats.inline.hpp" #include "runtime/atomicAccess.hpp" #include "runtime/timer.hpp" @@ -39,19 +39,27 @@ G1ConcurrentRefineStats::G1ConcurrentRefineStats() : {} void G1ConcurrentRefineStats::add_atomic(G1ConcurrentRefineStats* other) { - AtomicAccess::add(&_sweep_duration, other->_sweep_duration, memory_order_relaxed); - AtomicAccess::add(&_yield_during_sweep_duration, other->_yield_during_sweep_duration, memory_order_relaxed); + _sweep_duration.add_then_fetch(other->_sweep_duration.load_relaxed(), memory_order_relaxed); + _yield_during_sweep_duration.add_then_fetch(other->yield_during_sweep_duration(), memory_order_relaxed); - AtomicAccess::add(&_cards_scanned, other->_cards_scanned, memory_order_relaxed); - AtomicAccess::add(&_cards_clean, other->_cards_clean, memory_order_relaxed); - AtomicAccess::add(&_cards_not_parsable, other->_cards_not_parsable, memory_order_relaxed); - AtomicAccess::add(&_cards_already_refer_to_cset, other->_cards_already_refer_to_cset, memory_order_relaxed); - AtomicAccess::add(&_cards_refer_to_cset, other->_cards_refer_to_cset, memory_order_relaxed); - AtomicAccess::add(&_cards_no_cross_region, other->_cards_no_cross_region, memory_order_relaxed); + _cards_scanned.add_then_fetch(other->cards_scanned(), memory_order_relaxed); + _cards_clean.add_then_fetch(other->cards_clean(), memory_order_relaxed); + _cards_not_parsable.add_then_fetch(other->cards_not_parsable(), memory_order_relaxed); + _cards_already_refer_to_cset.add_then_fetch(other->cards_already_refer_to_cset(), memory_order_relaxed); + _cards_refer_to_cset.add_then_fetch(other->cards_refer_to_cset(), memory_order_relaxed); + _cards_no_cross_region.add_then_fetch(other->cards_no_cross_region(), memory_order_relaxed); - AtomicAccess::add(&_refine_duration, other->_refine_duration, memory_order_relaxed); + _refine_duration.add_then_fetch(other->refine_duration(), memory_order_relaxed); } void G1ConcurrentRefineStats::reset() { - *this = G1ConcurrentRefineStats(); + _sweep_duration.store_relaxed(0); + _yield_during_sweep_duration.store_relaxed(0); + _cards_scanned.store_relaxed(0); + _cards_clean.store_relaxed(0); + _cards_not_parsable.store_relaxed(0); + _cards_already_refer_to_cset.store_relaxed(0); + _cards_refer_to_cset.store_relaxed(0); + _cards_no_cross_region.store_relaxed(0); + _refine_duration.store_relaxed(0); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.hpp b/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.hpp index ce22f4317df..5f57c56ba6c 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,61 +26,61 @@ #define SHARE_GC_G1_G1CONCURRENTREFINESTATS_HPP #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/ticks.hpp" // Collection of statistics for concurrent refinement processing. // Used for collecting per-thread statistics and for summaries over a // collection of threads. class G1ConcurrentRefineStats : public CHeapObj { - jlong _sweep_duration; // Time spent sweeping the table finding non-clean cards - // and refining them. - jlong _yield_during_sweep_duration; // Time spent yielding during the sweep (not doing the sweep). + Atomic _sweep_duration; // Time spent sweeping the table finding non-clean cards + // and refining them. + Atomic _yield_during_sweep_duration; // Time spent yielding during the sweep (not doing the sweep). - size_t _cards_scanned; // Total number of cards scanned. - size_t _cards_clean; // Number of cards found clean. - size_t _cards_not_parsable; // Number of cards we could not parse and left unrefined. - size_t _cards_already_refer_to_cset;// Number of cards marked found to be already young. - size_t _cards_refer_to_cset; // Number of dirty cards that were recently found to contain a to-cset reference. - size_t _cards_no_cross_region; // Number of dirty cards that were dirtied, but then cleaned again by the mutator. + Atomic _cards_scanned; // Total number of cards scanned. + Atomic _cards_clean; // Number of cards found clean. + Atomic _cards_not_parsable; // Number of cards we could not parse and left unrefined. + Atomic _cards_already_refer_to_cset;// Number of cards marked found to be already young. + Atomic _cards_refer_to_cset; // Number of dirty cards that were recently found to contain a to-cset reference. + Atomic _cards_no_cross_region; // Number of dirty cards that were dirtied, but then cleaned again by the mutator. - jlong _refine_duration; // Time spent during actual refinement. + Atomic _refine_duration; // Time spent during actual refinement. public: G1ConcurrentRefineStats(); // Time spent performing sweeping the refinement table (includes actual refinement, // but not yield time). - jlong sweep_duration() const { return _sweep_duration - _yield_during_sweep_duration; } - jlong yield_during_sweep_duration() const { return _yield_during_sweep_duration; } - jlong refine_duration() const { return _refine_duration; } + inline jlong sweep_duration() const; + inline jlong yield_during_sweep_duration() const; + inline jlong refine_duration() const; // Number of refined cards. - size_t refined_cards() const { return cards_not_clean(); } + inline size_t refined_cards() const; - size_t cards_scanned() const { return _cards_scanned; } - size_t cards_clean() const { return _cards_clean; } - size_t cards_not_clean() const { return _cards_scanned - _cards_clean; } - size_t cards_not_parsable() const { return _cards_not_parsable; } - size_t cards_already_refer_to_cset() const { return _cards_already_refer_to_cset; } - size_t cards_refer_to_cset() const { return _cards_refer_to_cset; } - size_t cards_no_cross_region() const { return _cards_no_cross_region; } + inline size_t cards_scanned() const; + inline size_t cards_clean() const; + inline size_t cards_not_clean() const; + inline size_t cards_not_parsable() const; + inline size_t cards_already_refer_to_cset() const; + inline size_t cards_refer_to_cset() const; + inline size_t cards_no_cross_region() const; // Number of cards that were marked dirty and in need of refinement. This includes cards recently // found to refer to the collection set as they originally were dirty. - size_t cards_pending() const { return cards_not_clean() - _cards_already_refer_to_cset; } + inline size_t cards_pending() const; - size_t cards_to_cset() const { return _cards_already_refer_to_cset + _cards_refer_to_cset; } + inline size_t cards_to_cset() const; - void inc_sweep_time(jlong t) { _sweep_duration += t; } - void inc_yield_during_sweep_duration(jlong t) { _yield_during_sweep_duration += t; } - void inc_refine_duration(jlong t) { _refine_duration += t; } + inline void inc_sweep_time(jlong t); + inline void inc_yield_during_sweep_duration(jlong t); + inline void inc_refine_duration(jlong t); - void inc_cards_scanned(size_t increment) { _cards_scanned += increment; } - void inc_cards_clean(size_t increment) { _cards_clean += increment; } - void inc_cards_not_parsable() { _cards_not_parsable++; } - void inc_cards_already_refer_to_cset() { _cards_already_refer_to_cset++; } - void inc_cards_refer_to_cset() { _cards_refer_to_cset++; } - void inc_cards_no_cross_region() { _cards_no_cross_region++; } + inline void inc_cards_scanned(size_t increment); + inline void inc_cards_clean(size_t increment); + inline void inc_cards_not_parsable(); + inline void inc_cards_already_refer_to_cset(); + inline void inc_cards_refer_to_cset(); + inline void inc_cards_no_cross_region(); void add_atomic(G1ConcurrentRefineStats* other); diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.inline.hpp b/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.inline.hpp new file mode 100644 index 00000000000..5460dc35bba --- /dev/null +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.inline.hpp @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2026, 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.inline 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_G1_G1CONCURRENTREFINESTATS_INLINE_HPP +#define SHARE_GC_G1_G1CONCURRENTREFINESTATS_INLINE_HPP + +#include "gc/g1/g1ConcurrentRefineStats.hpp" + +inline jlong G1ConcurrentRefineStats::sweep_duration() const { + return _sweep_duration.load_relaxed() - yield_during_sweep_duration(); +} + +inline jlong G1ConcurrentRefineStats::yield_during_sweep_duration() const { + return _yield_during_sweep_duration.load_relaxed(); +} + +inline jlong G1ConcurrentRefineStats::refine_duration() const { + return _refine_duration.load_relaxed(); +} + +inline size_t G1ConcurrentRefineStats::refined_cards() const { + return cards_not_clean(); +} + +inline size_t G1ConcurrentRefineStats::cards_scanned() const { + return _cards_scanned.load_relaxed(); +} + +inline size_t G1ConcurrentRefineStats::cards_clean() const { + return _cards_clean.load_relaxed(); +} + +inline size_t G1ConcurrentRefineStats::cards_not_clean() const { + return cards_scanned() - cards_clean(); +} + +inline size_t G1ConcurrentRefineStats::cards_not_parsable() const { + return _cards_not_parsable.load_relaxed(); +} + +inline size_t G1ConcurrentRefineStats::cards_already_refer_to_cset() const { + return _cards_already_refer_to_cset.load_relaxed(); +} + +inline size_t G1ConcurrentRefineStats::cards_refer_to_cset() const { + return _cards_refer_to_cset.load_relaxed(); +} + +inline size_t G1ConcurrentRefineStats::cards_no_cross_region() const { + return _cards_no_cross_region.load_relaxed(); +} + +inline size_t G1ConcurrentRefineStats::cards_pending() const { + return cards_not_clean() - cards_already_refer_to_cset(); +} + +inline size_t G1ConcurrentRefineStats::cards_to_cset() const { + return cards_already_refer_to_cset() + cards_refer_to_cset(); +} + +inline void G1ConcurrentRefineStats::inc_sweep_time(jlong t) { + _sweep_duration.store_relaxed(_sweep_duration.load_relaxed() + t); +} + +inline void G1ConcurrentRefineStats::inc_yield_during_sweep_duration(jlong t) { + _yield_during_sweep_duration.store_relaxed(yield_during_sweep_duration() + t); +} + +inline void G1ConcurrentRefineStats::inc_refine_duration(jlong t) { + _refine_duration.store_relaxed(refine_duration() + t); +} + +inline void G1ConcurrentRefineStats::inc_cards_scanned(size_t increment) { + _cards_scanned.store_relaxed(cards_scanned() + increment); +} + +inline void G1ConcurrentRefineStats::inc_cards_clean(size_t increment) { + _cards_clean.store_relaxed(cards_clean() + increment); +} + +inline void G1ConcurrentRefineStats::inc_cards_not_parsable() { + _cards_not_parsable.store_relaxed(cards_not_parsable() + 1); +} + +inline void G1ConcurrentRefineStats::inc_cards_already_refer_to_cset() { + _cards_already_refer_to_cset.store_relaxed(cards_already_refer_to_cset() + 1); +} + +inline void G1ConcurrentRefineStats::inc_cards_refer_to_cset() { + _cards_refer_to_cset.store_relaxed(cards_refer_to_cset() + 1); +} + +inline void G1ConcurrentRefineStats::inc_cards_no_cross_region() { + _cards_no_cross_region.store_relaxed(cards_no_cross_region() + 1); +} + +#endif // SHARE_GC_G1_G1CONCURRENTREFINESTATS_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefineSweepTask.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefineSweepTask.cpp index ca5bc9ebe5f..ce944f2254d 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefineSweepTask.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineSweepTask.cpp @@ -24,6 +24,7 @@ #include "gc/g1/g1CardTableClaimTable.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1ConcurrentRefineStats.inline.hpp" #include "gc/g1/g1ConcurrentRefineSweepTask.hpp" class G1RefineRegionClosure : public G1HeapRegionClosure { diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefineSweepTask.hpp b/src/hotspot/share/gc/g1/g1ConcurrentRefineSweepTask.hpp index bf24c5ae850..827b9a3c402 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefineSweepTask.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineSweepTask.hpp @@ -25,10 +25,10 @@ #ifndef SHARE_GC_G1_G1CONCURRENTREFINESWEEPTASK_HPP #define SHARE_GC_G1_G1CONCURRENTREFINESWEEPTASK_HPP -#include "gc/g1/g1ConcurrentRefineStats.hpp" #include "gc/shared/workerThread.hpp" class G1CardTableClaimTable; +class G1ConcurrentRefineStats; class G1ConcurrentRefineSweepTask : public WorkerTask { G1CardTableClaimTable* _scan_state; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.cpp index eccfe466d48..6b51e5eef62 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.cpp @@ -26,7 +26,7 @@ #include "gc/g1/g1CardTableClaimTable.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ConcurrentRefine.hpp" -#include "gc/g1/g1ConcurrentRefineStats.hpp" +#include "gc/g1/g1ConcurrentRefineStats.inline.hpp" #include "gc/g1/g1ConcurrentRefineSweepTask.hpp" #include "gc/g1/g1ConcurrentRefineThread.hpp" #include "gc/shared/gcTraceTime.inline.hpp" diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.hpp b/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.hpp index 7cdc001d348..2ecbdc668eb 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.hpp @@ -25,7 +25,6 @@ #ifndef SHARE_GC_G1_G1CONCURRENTREFINETHREAD_HPP #define SHARE_GC_G1_G1CONCURRENTREFINETHREAD_HPP -#include "gc/g1/g1ConcurrentRefineStats.hpp" #include "gc/shared/concurrentGCThread.hpp" #include "runtime/mutex.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 8818b477aae..1d0b29c303e 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -32,7 +32,7 @@ #include "gc/g1/g1ConcurrentMark.hpp" #include "gc/g1/g1ConcurrentMarkThread.inline.hpp" #include "gc/g1/g1ConcurrentRefine.hpp" -#include "gc/g1/g1ConcurrentRefineStats.hpp" +#include "gc/g1/g1ConcurrentRefineStats.inline.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" #include "gc/g1/g1HeapRegionRemSet.inline.hpp" diff --git a/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp index b11213ddeb3..c0870b7a726 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp @@ -23,7 +23,6 @@ */ #include "gc/g1/g1CollectedHeap.inline.hpp" -#include "gc/g1/g1ConcurrentRefineStats.hpp" #include "gc/g1/g1RegionPinCache.inline.hpp" #include "gc/g1/g1ThreadLocalData.hpp" #include "gc/g1/g1YoungGCPreEvacuateTasks.hpp" From 0bc2dc3401f01b4727077a9844194d1654c3138c Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 26 Jan 2026 09:17:22 +0000 Subject: [PATCH 179/328] 8375971: G1: Convert G1EvacStats to use Atomic Reviewed-by: iwalulya, kbarrett --- .../share/gc/g1/g1CollectedHeap.inline.hpp | 1 + src/hotspot/share/gc/g1/g1EvacStats.cpp | 31 ++++++++----- src/hotspot/share/gc/g1/g1EvacStats.hpp | 42 +++++++----------- .../share/gc/g1/g1EvacStats.inline.hpp | 44 +++++++++++++++---- 4 files changed, 74 insertions(+), 44 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp index 958b171444e..8782b65b6f9 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp @@ -31,6 +31,7 @@ #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1EvacFailureRegions.hpp" +#include "gc/g1/g1EvacStats.inline.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" #include "gc/g1/g1HeapRegionManager.inline.hpp" #include "gc/g1/g1HeapRegionRemSet.hpp" diff --git a/src/hotspot/share/gc/g1/g1EvacStats.cpp b/src/hotspot/share/gc/g1/g1EvacStats.cpp index 049175a4ecc..1d54b184e64 100644 --- a/src/hotspot/share/gc/g1/g1EvacStats.cpp +++ b/src/hotspot/share/gc/g1/g1EvacStats.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,13 +22,24 @@ * */ -#include "gc/g1/g1EvacStats.hpp" +#include "gc/g1/g1EvacStats.inline.hpp" #include "gc/shared/gc_globals.hpp" #include "gc/shared/gcId.hpp" #include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "runtime/globals.hpp" +void G1EvacStats::reset() { + PLABStats::reset(); + _region_end_waste.store_relaxed(0); + _regions_filled.store_relaxed(0); + _num_plab_filled.store_relaxed(0); + _direct_allocated.store_relaxed(0); + _num_direct_allocated.store_relaxed(0); + _failure_used.store_relaxed(0); + _failure_waste.store_relaxed(0); +} + void G1EvacStats::log_plab_allocation() { log_debug(gc, plab)("%s PLAB allocation: " "allocated: %zuB, " @@ -51,13 +62,13 @@ void G1EvacStats::log_plab_allocation() { "failure used: %zuB, " "failure wasted: %zuB", _description, - _region_end_waste * HeapWordSize, - _regions_filled, - _num_plab_filled, - _direct_allocated * HeapWordSize, - _num_direct_allocated, - _failure_used * HeapWordSize, - _failure_waste * HeapWordSize); + region_end_waste() * HeapWordSize, + regions_filled(), + num_plab_filled(), + direct_allocated() * HeapWordSize, + num_direct_allocated(), + failure_used() * HeapWordSize, + failure_waste() * HeapWordSize); } void G1EvacStats::log_sizing(size_t calculated_words, size_t net_desired_words) { @@ -109,7 +120,7 @@ size_t G1EvacStats::compute_desired_plab_size() const { // threads do not allocate anything but a few rather large objects. In this // degenerate case the PLAB size would simply quickly tend to minimum PLAB size, // which is an okay reaction. - size_t const used_for_waste_calculation = used() > _region_end_waste ? used() - _region_end_waste : 0; + size_t const used_for_waste_calculation = used() > region_end_waste() ? used() - region_end_waste() : 0; size_t const total_waste_allowed = used_for_waste_calculation * TargetPLABWastePct; return (size_t)((double)total_waste_allowed / (100 - G1LastPLABAverageOccupancy)); diff --git a/src/hotspot/share/gc/g1/g1EvacStats.hpp b/src/hotspot/share/gc/g1/g1EvacStats.hpp index e6eb80442d6..b250d4580b5 100644 --- a/src/hotspot/share/gc/g1/g1EvacStats.hpp +++ b/src/hotspot/share/gc/g1/g1EvacStats.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, 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,6 +27,7 @@ #include "gc/shared/gcUtil.hpp" #include "gc/shared/plab.hpp" +#include "runtime/atomic.hpp" // Records various memory allocation statistics gathered during evacuation. All sizes // are in HeapWords. @@ -36,30 +37,21 @@ class G1EvacStats : public PLABStats { AdaptiveWeightedAverage _net_plab_size_filter; // Integrator with decay - size_t _region_end_waste; // Number of words wasted due to skipping to the next region. - uint _regions_filled; // Number of regions filled completely. - size_t _num_plab_filled; // Number of PLABs filled and retired. - size_t _direct_allocated; // Number of words allocated directly into the regions. - size_t _num_direct_allocated; // Number of direct allocation attempts. + Atomic _region_end_waste; // Number of words wasted due to skipping to the next region. + Atomic _regions_filled; // Number of regions filled completely. + Atomic _num_plab_filled; // Number of PLABs filled and retired. + Atomic _direct_allocated; // Number of words allocated directly into the regions. + Atomic _num_direct_allocated; // Number of direct allocation attempts. // Number of words in live objects remaining in regions that ultimately suffered an // evacuation failure. This is used in the regions when the regions are made old regions. - size_t _failure_used; + Atomic _failure_used; // Number of words wasted in regions which failed evacuation. This is the sum of space // for objects successfully copied out of the regions (now dead space) plus waste at the // end of regions. - size_t _failure_waste; + Atomic _failure_waste; - virtual void reset() { - PLABStats::reset(); - _region_end_waste = 0; - _regions_filled = 0; - _num_plab_filled = 0; - _direct_allocated = 0; - _num_direct_allocated = 0; - _failure_used = 0; - _failure_waste = 0; - } + virtual void reset(); void log_plab_allocation(); void log_sizing(size_t calculated_words, size_t net_desired_words); @@ -77,16 +69,16 @@ public: // Should be called at the end of a GC pause. void adjust_desired_plab_size(); - uint regions_filled() const { return _regions_filled; } - size_t num_plab_filled() const { return _num_plab_filled; } - size_t region_end_waste() const { return _region_end_waste; } - size_t direct_allocated() const { return _direct_allocated; } - size_t num_direct_allocated() const { return _num_direct_allocated; } + uint regions_filled() const; + size_t num_plab_filled() const; + size_t region_end_waste() const; + size_t direct_allocated() const; + size_t num_direct_allocated() const; // Amount of space in heapwords used in the failing regions when an evacuation failure happens. - size_t failure_used() const { return _failure_used; } + size_t failure_used() const; // Amount of space in heapwords wasted (unused) in the failing regions when an evacuation failure happens. - size_t failure_waste() const { return _failure_waste; } + size_t failure_waste() const; inline void add_num_plab_filled(size_t value); inline void add_direct_allocated(size_t value); diff --git a/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp b/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp index c90598a30cb..2bd3b37719a 100644 --- a/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp +++ b/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, 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,28 +27,54 @@ #include "gc/g1/g1EvacStats.hpp" -#include "runtime/atomicAccess.hpp" +inline uint G1EvacStats::regions_filled() const { + return _regions_filled.load_relaxed(); +} + +inline size_t G1EvacStats::num_plab_filled() const { + return _num_plab_filled.load_relaxed(); +} + +inline size_t G1EvacStats::region_end_waste() const { + return _region_end_waste.load_relaxed(); +} + +inline size_t G1EvacStats::direct_allocated() const { + return _direct_allocated.load_relaxed(); +} + +inline size_t G1EvacStats::num_direct_allocated() const { + return _num_direct_allocated.load_relaxed(); +} + +inline size_t G1EvacStats::failure_used() const { + return _failure_used.load_relaxed(); +} + +inline size_t G1EvacStats::failure_waste() const { + return _failure_waste.load_relaxed(); +} inline void G1EvacStats::add_direct_allocated(size_t value) { - AtomicAccess::add(&_direct_allocated, value, memory_order_relaxed); + _direct_allocated.add_then_fetch(value, memory_order_relaxed); } inline void G1EvacStats::add_num_plab_filled(size_t value) { - AtomicAccess::add(&_num_plab_filled, value, memory_order_relaxed); + _num_plab_filled.add_then_fetch(value, memory_order_relaxed); } inline void G1EvacStats::add_num_direct_allocated(size_t value) { - AtomicAccess::add(&_num_direct_allocated, value, memory_order_relaxed); + _num_direct_allocated.add_then_fetch(value, memory_order_relaxed); } inline void G1EvacStats::add_region_end_waste(size_t value) { - AtomicAccess::add(&_region_end_waste, value, memory_order_relaxed); - AtomicAccess::inc(&_regions_filled, memory_order_relaxed); + _region_end_waste.add_then_fetch(value, memory_order_relaxed); + _regions_filled.add_then_fetch(1u, memory_order_relaxed); } inline void G1EvacStats::add_failure_used_and_waste(size_t used, size_t waste) { - AtomicAccess::add(&_failure_used, used, memory_order_relaxed); - AtomicAccess::add(&_failure_waste, waste, memory_order_relaxed); + _failure_used.add_then_fetch(used, memory_order_relaxed); + _failure_waste.add_then_fetch(waste, memory_order_relaxed); } #endif // SHARE_GC_G1_G1EVACSTATS_INLINE_HPP From 90d065e677535e3f7caa7507f1526062b50ecc67 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 26 Jan 2026 09:42:49 +0000 Subject: [PATCH 180/328] 8375712: Convert java/lang/runtime tests to use JUnit Reviewed-by: liach --- .../ExactnessConversionsSupportTest.java | 54 ++-- .../java/lang/runtime/ObjectMethodsTest.java | 47 ++-- .../lang/runtime/SwitchBootstrapsTest.java | 251 +++++++----------- 3 files changed, 142 insertions(+), 210 deletions(-) diff --git a/test/jdk/java/lang/runtime/ExactnessConversionsSupportTest.java b/test/jdk/java/lang/runtime/ExactnessConversionsSupportTest.java index 6e1ef8e4c9f..3fbdfc5e9ab 100644 --- a/test/jdk/java/lang/runtime/ExactnessConversionsSupportTest.java +++ b/test/jdk/java/lang/runtime/ExactnessConversionsSupportTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, 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,46 +21,20 @@ * questions. */ -import org.testng.annotations.Test; - -import java.io.Serializable; -import java.lang.Enum.EnumDesc; -import java.lang.classfile.ClassFile; -import java.lang.constant.ClassDesc; -import java.lang.constant.ConstantDescs; -import java.lang.constant.MethodTypeDesc; -import java.lang.invoke.CallSite; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.reflect.AccessFlag; import java.lang.runtime.ExactConversionsSupport; -import java.lang.runtime.SwitchBootstraps; -import java.util.concurrent.atomic.AtomicBoolean; - -import static org.testng.Assert.*; +import org.junit.jupiter.api.Test; /** * @test * @bug 8304487 * @summary Verify boundary and special cases of exact conversion predicates * @compile ExactnessConversionsSupportTest.java - * @run testng/othervm ExactnessConversionsSupportTest + * @run junit/othervm ExactnessConversionsSupportTest */ -@Test public class ExactnessConversionsSupportTest { - public static void main(String[] args) { - testByte(); - testShort(); - testChar(); - testInt(); - testLong(); - testFloat(); - testDouble(); - } - - public static void testByte() { + @Test + public void testByte() { assertEquals(true, ExactConversionsSupport.isIntToByteExact((byte) (Byte.MAX_VALUE))); assertEquals(true, ExactConversionsSupport.isIntToByteExact((byte) (0))); assertEquals(true, ExactConversionsSupport.isIntToByteExact((byte) (Byte.MIN_VALUE))); @@ -92,7 +66,8 @@ public class ExactnessConversionsSupportTest { assertEquals(false, ExactConversionsSupport.isDoubleToByteExact(-0.0d)); assertEquals(true, ExactConversionsSupport.isDoubleToByteExact(+0.0d)); } - public static void testShort() { + @Test + public void testShort() { assertEquals(true, ExactConversionsSupport.isIntToShortExact((byte) (Byte.MAX_VALUE))); assertEquals(true, ExactConversionsSupport.isIntToShortExact((byte) (0))); assertEquals(true, ExactConversionsSupport.isIntToShortExact((byte) (Byte.MIN_VALUE))); @@ -125,7 +100,8 @@ public class ExactnessConversionsSupportTest { assertEquals(false, ExactConversionsSupport.isDoubleToShortExact(-0.0d)); assertEquals(true, ExactConversionsSupport.isDoubleToShortExact(+0.0d)); } - public static void testChar() { + @Test + public void testChar() { assertEquals(true, ExactConversionsSupport.isIntToCharExact((byte) (Byte.MAX_VALUE))); assertEquals(true, ExactConversionsSupport.isIntToCharExact((byte) (0))); assertEquals(false, ExactConversionsSupport.isIntToCharExact((byte) (Byte.MIN_VALUE))); @@ -157,7 +133,8 @@ public class ExactnessConversionsSupportTest { assertEquals(false, ExactConversionsSupport.isDoubleToCharExact(-0.0d)); assertEquals(true, ExactConversionsSupport.isDoubleToCharExact(+0.0d)); } - public static void testInt() { + @Test + public void testInt() { assertEquals(false, ExactConversionsSupport.isLongToIntExact((Long.MAX_VALUE))); assertEquals(true, ExactConversionsSupport.isLongToIntExact((0L))); assertEquals(false, ExactConversionsSupport.isLongToIntExact((Long.MIN_VALUE))); @@ -178,7 +155,8 @@ public class ExactnessConversionsSupportTest { assertEquals(false, ExactConversionsSupport.isDoubleToIntExact((-0.0d))); assertEquals(true, ExactConversionsSupport.isDoubleToIntExact((+0.0d))); } - public static void testLong() { + @Test + public void testLong() { assertEquals(false, ExactConversionsSupport.isFloatToLongExact((Float.MAX_VALUE))); assertEquals(true, ExactConversionsSupport.isFloatToLongExact(((float) 0))); assertEquals(false, ExactConversionsSupport.isFloatToLongExact((Float.MIN_VALUE))); @@ -196,7 +174,8 @@ public class ExactnessConversionsSupportTest { assertEquals(false, ExactConversionsSupport.isDoubleToLongExact((-0.0d))); assertEquals(true, ExactConversionsSupport.isDoubleToLongExact((+0.0d))); } - public static void testFloat() { + @Test + public void testFloat() { assertEquals(true, ExactConversionsSupport.isIntToFloatExact(((byte) (Byte.MAX_VALUE)))); assertEquals(true, ExactConversionsSupport.isIntToFloatExact(((byte) (0)))); assertEquals(true, ExactConversionsSupport.isIntToFloatExact(((byte) (Byte.MIN_VALUE)))); @@ -220,7 +199,8 @@ public class ExactnessConversionsSupportTest { assertEquals(true, ExactConversionsSupport.isDoubleToFloatExact((-0.0d))); assertEquals(true, ExactConversionsSupport.isDoubleToFloatExact((+0.0d))); } - public static void testDouble() { + @Test + public void testDouble() { assertEquals(false, ExactConversionsSupport.isLongToDoubleExact((Long.MAX_VALUE))); assertEquals(true, ExactConversionsSupport.isLongToDoubleExact((0L))); assertEquals(true, ExactConversionsSupport.isLongToDoubleExact((Long.MIN_VALUE))); diff --git a/test/jdk/java/lang/runtime/ObjectMethodsTest.java b/test/jdk/java/lang/runtime/ObjectMethodsTest.java index 62c8b034ed1..951d3b68383 100644 --- a/test/jdk/java/lang/runtime/ObjectMethodsTest.java +++ b/test/jdk/java/lang/runtime/ObjectMethodsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 8246774 * @summary Basic tests for ObjectMethods - * @run testng ObjectMethodsTest + * @run junit ObjectMethodsTest */ import java.util.List; @@ -34,14 +34,14 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.runtime.ObjectMethods; -import org.testng.annotations.Test; import static java.lang.invoke.MethodType.methodType; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertThrows; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -@Test +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; + public class ObjectMethodsTest { public static class C { @@ -80,6 +80,7 @@ public class ObjectMethodsTest { static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + @Test public void testEqualsC() throws Throwable { CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "equals", C.EQUALS_DESC, C.class, C.NAME_LIST, C.ACCESSORS); MethodHandle handle = cs.dynamicInvoker(); @@ -92,6 +93,7 @@ public class ObjectMethodsTest { assertFalse((boolean)handle.invokeExact(c, new Object())); } + @Test public void testEqualsEmpty() throws Throwable { CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "equals", Empty.EQUALS_DESC, Empty.class, Empty.NAME_LIST, Empty.ACCESSORS); MethodHandle handle = cs.dynamicInvoker(); @@ -102,45 +104,50 @@ public class ObjectMethodsTest { assertFalse((boolean)handle.invokeExact(e, new Object())); } + @Test public void testHashCodeC() throws Throwable { CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "hashCode", C.HASHCODE_DESC, C.class, "x;y", C.ACCESSORS); MethodHandle handle = cs.dynamicInvoker(); C c = new C(6, 7); int hc = (int)handle.invokeExact(c); - assertEquals(hc, hashCombiner(c.x(), c.y())); + assertEquals(hashCombiner(c.x(), c.y()), hc); - assertEquals((int)handle.invokeExact(new C(100, 1)), hashCombiner(100, 1)); - assertEquals((int)handle.invokeExact(new C(0, 0)), hashCombiner(0, 0)); - assertEquals((int)handle.invokeExact(new C(-1, 100)), hashCombiner(-1, 100)); - assertEquals((int)handle.invokeExact(new C(100, 1)), hashCombiner(100, 1)); - assertEquals((int)handle.invokeExact(new C(100, -1)), hashCombiner(100, -1)); + assertEquals(hashCombiner(100, 1), (int)handle.invokeExact(new C(100, 1))); + assertEquals(hashCombiner(0, 0), (int)handle.invokeExact(new C(0, 0))); + assertEquals(hashCombiner(-1, 100), (int)handle.invokeExact(new C(-1, 100))); + assertEquals(hashCombiner(100, 1), (int)handle.invokeExact(new C(100, 1))); + assertEquals(hashCombiner(100, -1), (int)handle.invokeExact(new C(100, -1))); } + @Test public void testHashCodeEmpty() throws Throwable { CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "hashCode", Empty.HASHCODE_DESC, Empty.class, "", Empty.ACCESSORS); MethodHandle handle = cs.dynamicInvoker(); Empty e = new Empty(); - assertEquals((int)handle.invokeExact(e), 0); + assertEquals(0, (int)handle.invokeExact(e)); } + @Test public void testToStringC() throws Throwable { CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, C.class, C.NAME_LIST, C.ACCESSORS); MethodHandle handle = cs.dynamicInvoker(); - assertEquals((String)handle.invokeExact(new C(8, 9)), "C[x=8, y=9]" ); - assertEquals((String)handle.invokeExact(new C(10, 11)), "C[x=10, y=11]" ); - assertEquals((String)handle.invokeExact(new C(100, -9)), "C[x=100, y=-9]"); - assertEquals((String)handle.invokeExact(new C(0, 0)), "C[x=0, y=0]" ); + assertEquals("C[x=8, y=9]", (String)handle.invokeExact(new C(8, 9)) ); + assertEquals("C[x=10, y=11]", (String)handle.invokeExact(new C(10, 11)) ); + assertEquals("C[x=100, y=-9]", (String)handle.invokeExact(new C(100, -9))); + assertEquals("C[x=0, y=0]", (String)handle.invokeExact(new C(0, 0)) ); } + @Test public void testToStringEmpty() throws Throwable { CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "toString", Empty.TO_STRING_DESC, Empty.class, Empty.NAME_LIST, Empty.ACCESSORS); MethodHandle handle = cs.dynamicInvoker(); - assertEquals((String)handle.invokeExact(new Empty()), "Empty[]"); + assertEquals("Empty[]", (String)handle.invokeExact(new Empty())); } Class NPE = NullPointerException.class; Class IAE = IllegalArgumentException.class; + @Test public void exceptions() { assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "badName", C.EQUALS_DESC, C.class, C.NAME_LIST, C.ACCESSORS)); assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, C.class, "x;y;z", C.ACCESSORS)); diff --git a/test/jdk/java/lang/runtime/SwitchBootstrapsTest.java b/test/jdk/java/lang/runtime/SwitchBootstrapsTest.java index 3a8608866dc..061ce2ae241 100644 --- a/test/jdk/java/lang/runtime/SwitchBootstrapsTest.java +++ b/test/jdk/java/lang/runtime/SwitchBootstrapsTest.java @@ -35,21 +35,20 @@ import java.lang.runtime.SwitchBootstraps; import java.util.concurrent.atomic.AtomicBoolean; import java.lang.classfile.ClassFile; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @test * @bug 8318144 * @enablePreview * @compile SwitchBootstrapsTest.java - * @run testng/othervm SwitchBootstrapsTest + * @run junit/othervm SwitchBootstrapsTest */ -@Test public class SwitchBootstrapsTest { public static final MethodHandle BSM_TYPE_SWITCH; @@ -70,14 +69,14 @@ public class SwitchBootstrapsTest { private void testType(Object target, int start, int result, Object... labels) throws Throwable { MethodType switchType = MethodType.methodType(int.class, Object.class, int.class); MethodHandle indy = ((CallSite) BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", switchType, labels)).dynamicInvoker(); - assertEquals((int) indy.invoke(target, start), result); + assertEquals(result, (int) indy.invoke(target, start)); assertEquals(-1, (int) indy.invoke(null, start)); } private void testPrimitiveType(Object target, Class targetType, int start, int result, Object... labels) throws Throwable { MethodType switchType = MethodType.methodType(int.class, targetType, int.class); MethodHandle indy = ((CallSite) BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", switchType, labels)).dynamicInvoker(); - assertEquals((int) indy.invoke(target, start), result); + assertEquals(result, (int) indy.invoke(target, start)); } private void testEnum(Enum target, int start, int result, Object... labels) throws Throwable { @@ -87,7 +86,7 @@ public class SwitchBootstrapsTest { private void testEnum(Class targetClass, Enum target, int start, int result, Object... labels) throws Throwable { MethodType switchType = MethodType.methodType(int.class, targetClass, int.class); MethodHandle indy = ((CallSite) BSM_ENUM_SWITCH.invoke(MethodHandles.lookup(), "", switchType, labels)).dynamicInvoker(); - assertEquals((int) indy.invoke(target, start), result); + assertEquals(result, (int) indy.invoke(target, start)); assertEquals(-1, (int) indy.invoke(null, start)); } @@ -100,6 +99,7 @@ public class SwitchBootstrapsTest { C; } + @Test public void testTypes() throws Throwable { testType("", 0, 0, String.class, Object.class); testType("", 0, 0, Object.class); @@ -138,6 +138,7 @@ public class SwitchBootstrapsTest { }, 0, 1, 1L); } + @Test public void testPrimitiveTypes() throws Throwable { testPrimitiveType((short) 1, short.class, 0, 1, String.class); testPrimitiveType((byte) 1, byte.class,0, 1, String.class, byte.class); @@ -150,52 +151,32 @@ public class SwitchBootstrapsTest { testPrimitiveType(true, boolean.class,0, 1, String.class, boolean.class); } + @Test public void testEnums() throws Throwable { testEnum(E1.A, 0, 2, "B", "C", "A", E1.class); testEnum(E1.B, 0, 0, "B", "C", "A", E1.class); testEnum(E1.B, 1, 3, "B", "C", "A", E1.class); - try { - testEnum(E1.B, 0, -1, E2.class); - fail("Didn't get the expected exception."); - } catch (IllegalArgumentException ex) { - //OK - } - try { - testEnum(E1.B, 0, -1, String.class); - fail("Didn't get the expected exception."); - } catch (IllegalArgumentException ex) { - //OK - } - try { - testEnum(E1.B, 0, -1, 10); - fail("Didn't get the expected exception."); - } catch (IllegalArgumentException ex) { - //OK - } - try { - testEnum(E1.B, 0, -1, new Object()); - fail("Didn't get the expected exception."); - } catch (IllegalArgumentException ex) { - //OK - } - try { - testEnum(E1.B, 0, -1, new Object[] { null }); - fail("Didn't get the expected exception."); - } catch (IllegalArgumentException ex) { - //OK - } - try { - testEnum(E1.B, 0, -1, ""); - fail("Didn't get the expected exception."); - } catch (IllegalArgumentException ex) { - //OK - } - try { - testEnum(E1.B, 0, -1, (Object[]) null); - fail("Didn't get the expected exception."); - } catch (NullPointerException ex) { - //OK - } + assertThrows(IllegalArgumentException.class, () -> + testEnum(E1.B, 0, -1, E2.class) + ); + assertThrows(IllegalArgumentException.class, () -> + testEnum(E1.B, 0, -1, String.class) + ); + assertThrows(IllegalArgumentException.class, () -> + testEnum(E1.B, 0, -1, 10) + ); + assertThrows(IllegalArgumentException.class, () -> + testEnum(E1.B, 0, -1, new Object()) + ); + assertThrows(IllegalArgumentException.class, () -> + testEnum(E1.B, 0, -1, new Object[] { null }) + ); + assertThrows(IllegalArgumentException.class, () -> + testEnum(E1.B, 0, -1, "") + ); + assertThrows(NullPointerException.class, () -> + testEnum(E1.B, 0, -1, (Object[]) null) + ); testEnum(E1.B, 0, 0, "B", "A"); testEnum(E1.A, 0, 1, "B", "A"); testEnum(E1.A, 0, 0, "A", "A", "B"); @@ -208,9 +189,10 @@ public class SwitchBootstrapsTest { //null invocation name: MethodType switchType = MethodType.methodType(int.class, E1.class, int.class); MethodHandle indy = ((CallSite) BSM_ENUM_SWITCH.invoke(MethodHandles.lookup(), null, switchType)).dynamicInvoker(); - assertEquals((int) indy.invoke(E1.A, 0), 0); + assertEquals(0, (int) indy.invoke(E1.A, 0)); } + @Test public void testEnumsWithConstants() throws Throwable { enum E { A {}, @@ -239,18 +221,16 @@ public class SwitchBootstrapsTest { testEnum(E.class, E.C, 2, 2, "A", "B"); } + @Test public void testWrongSwitchTypes() throws Throwable { MethodType[] switchTypes = new MethodType[] { MethodType.methodType(int.class, Object.class), MethodType.methodType(int.class, Object.class, Integer.class) }; for (MethodType switchType : switchTypes) { - try { - BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", switchType); - fail("Didn't get the expected exception."); - } catch (IllegalArgumentException ex) { - //OK, expected - } + assertThrows(IllegalArgumentException.class, () -> + BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", switchType) + ); } MethodType[] enumSwitchTypes = new MethodType[] { MethodType.methodType(int.class, Enum.class), @@ -259,25 +239,21 @@ public class SwitchBootstrapsTest { MethodType.methodType(int.class, Enum.class, Integer.class) }; for (MethodType enumSwitchType : enumSwitchTypes) { - try { - BSM_ENUM_SWITCH.invoke(MethodHandles.lookup(), "", enumSwitchType); - fail("Didn't get the expected exception."); - } catch (IllegalArgumentException ex) { - //OK, expected - } + assertThrows(IllegalArgumentException.class, () -> + BSM_ENUM_SWITCH.invoke(MethodHandles.lookup(), "", enumSwitchType) + ); } } + @Test public void testSwitchLabelTypes() throws Throwable { enum E {A} - try { - testType(E.A, 0, -1, E.A); - fail("Didn't get the expected exception."); - } catch (IllegalArgumentException ex) { - //OK, expected - } + assertThrows(IllegalArgumentException.class, () -> + testType(E.A, 0, -1, E.A) + ); } + @Test public void testSwitchQualifiedEnum() throws Throwable { enum E {A, B, C} Object[] labels = new Object[] { @@ -290,41 +266,31 @@ public class SwitchBootstrapsTest { testType(E.C, 0, 2, labels); } + @Test public void testNullLabels() throws Throwable { MethodType switchType = MethodType.methodType(int.class, Object.class, int.class); - try { - BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", switchType, (Object[]) null); - fail("Didn't get the expected exception."); - } catch (NullPointerException ex) { - //OK - } - try { + assertThrows(NullPointerException.class, () -> + BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", switchType, (Object[]) null) + ); + assertThrows(IllegalArgumentException.class, () -> BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", switchType, - new Object[] {1, null, String.class}); - fail("Didn't get the expected exception."); - } catch (IllegalArgumentException ex) { - //OK - } + new Object[] {1, null, String.class}) + ); MethodType enumSwitchType = MethodType.methodType(int.class, E1.class, int.class); - try { - BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", enumSwitchType, (Object[]) null); - fail("Didn't get the expected exception."); - } catch (NullPointerException ex) { - //OK - } - try { + assertThrows(NullPointerException.class, () -> + BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", enumSwitchType, (Object[]) null) + ); + assertThrows(IllegalArgumentException.class, () -> BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", enumSwitchType, - new Object[] {1, null, String.class}); - fail("Didn't get the expected exception."); - } catch (IllegalArgumentException ex) { - //OK - } + new Object[] {1, null, String.class}) + ); //null invocationName is OK: BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), null, switchType, new Object[] {Object.class}); } private static AtomicBoolean enumInitialized = new AtomicBoolean(); + @Test public void testEnumInitialization1() throws Throwable { enumInitialized.set(false); @@ -340,13 +306,14 @@ public class SwitchBootstrapsTest { CallSite invocation = (CallSite) BSM_ENUM_SWITCH.invoke(MethodHandles.lookup(), "", enumSwitchType, new Object[] {"A"}); assertFalse(enumInitialized.get()); - assertEquals(invocation.dynamicInvoker().invoke(null, 0), -1); + assertEquals(-1, invocation.dynamicInvoker().invoke(null, 0)); assertFalse(enumInitialized.get()); E e = E.A; assertTrue(enumInitialized.get()); - assertEquals(invocation.dynamicInvoker().invoke(e, 0), 0); + assertEquals(0, invocation.dynamicInvoker().invoke(e, 0)); } + @Test public void testEnumInitialization2() throws Throwable { enumInitialized.set(false); @@ -365,60 +332,46 @@ public class SwitchBootstrapsTest { }; CallSite invocation = (CallSite) BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", switchType, labels); assertFalse(enumInitialized.get()); - assertEquals(invocation.dynamicInvoker().invoke(null, 0), -1); + assertEquals(-1, invocation.dynamicInvoker().invoke(null, 0)); assertFalse(enumInitialized.get()); - assertEquals(invocation.dynamicInvoker().invoke("test", 0), 1); + assertEquals(1, invocation.dynamicInvoker().invoke("test", 0)); assertFalse(enumInitialized.get()); E e = E.A; assertTrue(enumInitialized.get()); - assertEquals(invocation.dynamicInvoker().invoke(e, 0), 0); + assertEquals(0, invocation.dynamicInvoker().invoke(e, 0)); } + @Test public void testIncorrectEnumLabels() throws Throwable { - try { - testEnum(E1.B, 0, -1, "B", 1); - fail("Didn't get the expected exception."); - } catch (IllegalArgumentException ex) { - //OK - } - try { - testEnum(E1.B, 0, -1, "B", null); - fail("Didn't get the expected exception."); - } catch (IllegalArgumentException ex) { - //OK - } + assertThrows(IllegalArgumentException.class, () -> + testEnum(E1.B, 0, -1, "B", 1) + ); + assertThrows(IllegalArgumentException.class, () -> + testEnum(E1.B, 0, -1, "B", null) + ); } + @Test public void testIncorrectEnumStartIndex() throws Throwable { - try { - testEnum(E1.B, -1, -1, "B"); - fail("Didn't get the expected exception."); - } catch (IndexOutOfBoundsException ex) { - //OK - } - try { - testEnum(E1.B, 2, -1, "B"); - fail("Didn't get the expected exception."); - } catch (IndexOutOfBoundsException ex) { - //OK - } + assertThrows(IndexOutOfBoundsException.class, () -> + testEnum(E1.B, -1, -1, "B") + ); //OK + assertThrows(IndexOutOfBoundsException.class, () -> + testEnum(E1.B, 2, -1, "B") + ); } + @Test public void testIncorrectTypeStartIndex() throws Throwable { - try { - testType("", -1, -1, ""); - fail("Didn't get the expected exception."); - } catch (IndexOutOfBoundsException ex) { - //OK - } - try { - testType("", 2, -1, ""); - fail("Didn't get the expected exception."); - } catch (IndexOutOfBoundsException ex) { - //OK - } + assertThrows(IndexOutOfBoundsException.class, () -> + testType("", -1, -1, "") + ); + assertThrows(IndexOutOfBoundsException.class, () -> + testType("", 2, -1, "") + ); } + @Test public void testHiddenClassAsCaseLabel() throws Throwable { MethodHandles.Lookup lookup = MethodHandles.lookup(); byte[] classBytes = createClass(); @@ -448,30 +401,22 @@ public class SwitchBootstrapsTest { }); } + @Test public void testNullLookup() throws Throwable { - try { + assertThrows(NullPointerException.class, () -> { MethodType switchType = MethodType.methodType(int.class, Object.class, int.class); BSM_TYPE_SWITCH.invoke(null, "", switchType, Object.class); - fail("Didn't get the expected exception."); - } catch (NullPointerException ex) { - //OK - } + }); enum E {} - try { + assertThrows(NullPointerException.class, () -> { MethodType switchType = MethodType.methodType(int.class, E.class, int.class); BSM_ENUM_SWITCH.invoke(null, "", switchType, - new Object[] {}); - fail("Didn't get the expected exception."); - } catch (NullPointerException ex) { - //OK - } - try { + new Object[] {}); + }); + assertThrows(NullPointerException.class, () -> { MethodType switchType = MethodType.methodType(int.class, E.class, int.class); BSM_ENUM_SWITCH.invoke(null, "", switchType, - new Object[] {"A"}); - fail("Didn't get the expected exception."); - } catch (NullPointerException ex) { - //OK - } + new Object[] {"A"}); + }); } } From 42c0126fb2067b5f792e99af9ad131bab7502c08 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 26 Jan 2026 09:47:52 +0000 Subject: [PATCH 181/328] 8376119: G1: Convert volatiles in G1CMMarkStack to Atomic Reviewed-by: kbarrett, iwalulya --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 16 ++++++++-------- src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 10 +++++----- .../share/gc/g1/g1ConcurrentMark.inline.hpp | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 52591f7ce5f..2bbfb5032b3 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -291,9 +291,9 @@ void G1CMMarkStack::expand() { _chunk_allocator.try_expand(); } -void G1CMMarkStack::add_chunk_to_list(TaskQueueEntryChunk* volatile* list, TaskQueueEntryChunk* elem) { - elem->next = *list; - *list = elem; +void G1CMMarkStack::add_chunk_to_list(Atomic* list, TaskQueueEntryChunk* elem) { + elem->next = list->load_relaxed(); + list->store_relaxed(elem); } void G1CMMarkStack::add_chunk_to_chunk_list(TaskQueueEntryChunk* elem) { @@ -307,10 +307,10 @@ void G1CMMarkStack::add_chunk_to_free_list(TaskQueueEntryChunk* elem) { add_chunk_to_list(&_free_list, elem); } -G1CMMarkStack::TaskQueueEntryChunk* G1CMMarkStack::remove_chunk_from_list(TaskQueueEntryChunk* volatile* list) { - TaskQueueEntryChunk* result = *list; +G1CMMarkStack::TaskQueueEntryChunk* G1CMMarkStack::remove_chunk_from_list(Atomic* list) { + TaskQueueEntryChunk* result = list->load_relaxed(); if (result != nullptr) { - *list = (*list)->next; + list->store_relaxed(list->load_relaxed()->next); } return result; } @@ -364,8 +364,8 @@ bool G1CMMarkStack::par_pop_chunk(G1TaskQueueEntry* ptr_arr) { void G1CMMarkStack::set_empty() { _chunks_in_chunk_list = 0; - _chunk_list = nullptr; - _free_list = nullptr; + _chunk_list.store_relaxed(nullptr); + _free_list.store_relaxed(nullptr); _chunk_allocator.reset(); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 52a1b133439..836d7793f81 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -210,17 +210,17 @@ private: ChunkAllocator _chunk_allocator; char _pad0[DEFAULT_PADDING_SIZE]; - TaskQueueEntryChunk* volatile _free_list; // Linked list of free chunks that can be allocated by users. + Atomic _free_list; // Linked list of free chunks that can be allocated by users. char _pad1[DEFAULT_PADDING_SIZE - sizeof(TaskQueueEntryChunk*)]; - TaskQueueEntryChunk* volatile _chunk_list; // List of chunks currently containing data. + Atomic _chunk_list; // List of chunks currently containing data. volatile size_t _chunks_in_chunk_list; char _pad2[DEFAULT_PADDING_SIZE - sizeof(TaskQueueEntryChunk*) - sizeof(size_t)]; // Atomically add the given chunk to the list. - void add_chunk_to_list(TaskQueueEntryChunk* volatile* list, TaskQueueEntryChunk* elem); + void add_chunk_to_list(Atomic* list, TaskQueueEntryChunk* elem); // Atomically remove and return a chunk from the given list. Returns null if the // list is empty. - TaskQueueEntryChunk* remove_chunk_from_list(TaskQueueEntryChunk* volatile* list); + TaskQueueEntryChunk* remove_chunk_from_list(Atomic* list); void add_chunk_to_chunk_list(TaskQueueEntryChunk* elem); void add_chunk_to_free_list(TaskQueueEntryChunk* elem); @@ -252,7 +252,7 @@ private: // Return whether the chunk list is empty. Racy due to unsynchronized access to // _chunk_list. - bool is_empty() const { return _chunk_list == nullptr; } + bool is_empty() const { return _chunk_list.load_relaxed() == nullptr; } size_t capacity() const { return _chunk_allocator.capacity(); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp index fe72c68d4eb..2f4824e4cae 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp @@ -90,7 +90,7 @@ inline void G1CMMarkStack::iterate(Fn fn) const { size_t num_chunks = 0; - TaskQueueEntryChunk* cur = _chunk_list; + TaskQueueEntryChunk* cur = _chunk_list.load_relaxed(); while (cur != nullptr) { guarantee(num_chunks <= _chunks_in_chunk_list, "Found %zu oop chunks which is more than there should be", num_chunks); From 48d636872f1bd239d12823bf2f9d4aa32384f5e5 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 26 Jan 2026 10:15:57 +0000 Subject: [PATCH 182/328] 8376293: Bad copyright header in g1ConcurrentRefineStats.inline.hpp breaks the build Reviewed-by: mhaessig, chagedorn --- src/hotspot/share/gc/g1/g1ConcurrentRefineStats.inline.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.inline.hpp b/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.inline.hpp index 5460dc35bba..e1a296c6494 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.inline.hpp @@ -8,7 +8,7 @@ * * 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.inline See the GNU General Public License + * 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). * From 30675faa67d1bbb4acc729a841493bb8311416af Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Mon, 26 Jan 2026 11:18:21 +0000 Subject: [PATCH 183/328] 8375653: C2: CmpUNode::sub is not monotonic Reviewed-by: chagedorn, mchevalier --- src/hotspot/share/opto/subnode.cpp | 131 +++-------- .../compiler/c2/gvn/CmpUNodeValueTests.java | 209 ++++++++++++++++++ .../compiler/ccp/TestCmpUMonotonicity.java | 68 ++++++ 3 files changed, 312 insertions(+), 96 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/gvn/CmpUNodeValueTests.java create mode 100644 test/hotspot/jtreg/compiler/ccp/TestCmpUMonotonicity.java diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index a10cd2a8d5b..548df58eb35 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -745,71 +745,40 @@ const Type* CmpINode::Value(PhaseGVN* phase) const { // Simplify a CmpU (compare 2 integers) node, based on local information. // If both inputs are constants, compare them. -const Type *CmpUNode::sub( const Type *t1, const Type *t2 ) const { - assert(!t1->isa_ptr(), "obsolete usage of CmpU"); +const Type* CmpUNode::sub(const Type* t1, const Type* t2) const { + const TypeInt* r0 = t1->is_int(); + const TypeInt* r1 = t2->is_int(); - // comparing two unsigned ints - const TypeInt *r0 = t1->is_int(); // Handy access - const TypeInt *r1 = t2->is_int(); - - // Current installed version - // Compare ranges for non-overlap - juint lo0 = r0->_lo; - juint hi0 = r0->_hi; - juint lo1 = r1->_lo; - juint hi1 = r1->_hi; - - // If either one has both negative and positive values, - // it therefore contains both 0 and -1, and since [0..-1] is the - // full unsigned range, the type must act as an unsigned bottom. - bool bot0 = ((jint)(lo0 ^ hi0) < 0); - bool bot1 = ((jint)(lo1 ^ hi1) < 0); - - if (bot0 || bot1) { - // All unsigned values are LE -1 and GE 0. - if (lo0 == 0 && hi0 == 0) { - return TypeInt::CC_LE; // 0 <= bot - } else if ((jint)lo0 == -1 && (jint)hi0 == -1) { - return TypeInt::CC_GE; // -1 >= bot - } else if (lo1 == 0 && hi1 == 0) { - return TypeInt::CC_GE; // bot >= 0 - } else if ((jint)lo1 == -1 && (jint)hi1 == -1) { - return TypeInt::CC_LE; // bot <= -1 - } - } else { - // We can use ranges of the form [lo..hi] if signs are the same. - assert(lo0 <= hi0 && lo1 <= hi1, "unsigned ranges are valid"); - // results are reversed, '-' > '+' for unsigned compare - if (hi0 < lo1) { - return TypeInt::CC_LT; // smaller - } else if (lo0 > hi1) { - return TypeInt::CC_GT; // greater - } else if (hi0 == lo1 && lo0 == hi1) { - return TypeInt::CC_EQ; // Equal results - } else if (lo0 >= hi1) { - return TypeInt::CC_GE; - } else if (hi0 <= lo1) { - // Check for special case in Hashtable::get. (See below.) - if ((jint)lo0 >= 0 && (jint)lo1 >= 0 && is_index_range_check()) - return TypeInt::CC_LT; - return TypeInt::CC_LE; - } - } // Check for special case in Hashtable::get - the hash index is // mod'ed to the table size so the following range check is useless. // Check for: (X Mod Y) CmpU Y, where the mod result and Y both have // to be positive. // (This is a gross hack, since the sub method never // looks at the structure of the node in any other case.) - if ((jint)lo0 >= 0 && (jint)lo1 >= 0 && is_index_range_check()) + if (r0->_lo >= 0 && r1->_lo >= 0 && is_index_range_check()) { return TypeInt::CC_LT; + } + + if (r0->_uhi < r1->_ulo) { + return TypeInt::CC_LT; + } else if (r0->_ulo > r1->_uhi) { + return TypeInt::CC_GT; + } else if (r0->is_con() && r1->is_con()) { + // Since r0->_ulo == r0->_uhi == r0->get_con(), we only reach here if the constants are equal + assert(r0->get_con() == r1->get_con(), "must reach a previous branch otherwise"); + return TypeInt::CC_EQ; + } else if (r0->_uhi == r1->_ulo) { + return TypeInt::CC_LE; + } else if (r0->_ulo == r1->_uhi) { + return TypeInt::CC_GE; + } const Type* joined = r0->join(r1); if (joined == Type::TOP) { return TypeInt::CC_NE; } - return TypeInt::CC; // else use worst case results + return TypeInt::CC; } const Type* CmpUNode::Value(PhaseGVN* phase) const { @@ -963,51 +932,21 @@ const Type *CmpLNode::sub( const Type *t1, const Type *t2 ) const { // Simplify a CmpUL (compare 2 unsigned longs) node, based on local information. // If both inputs are constants, compare them. const Type* CmpULNode::sub(const Type* t1, const Type* t2) const { - assert(!t1->isa_ptr(), "obsolete usage of CmpUL"); - - // comparing two unsigned longs - const TypeLong* r0 = t1->is_long(); // Handy access + const TypeLong* r0 = t1->is_long(); const TypeLong* r1 = t2->is_long(); - // Current installed version - // Compare ranges for non-overlap - julong lo0 = r0->_lo; - julong hi0 = r0->_hi; - julong lo1 = r1->_lo; - julong hi1 = r1->_hi; - - // If either one has both negative and positive values, - // it therefore contains both 0 and -1, and since [0..-1] is the - // full unsigned range, the type must act as an unsigned bottom. - bool bot0 = ((jlong)(lo0 ^ hi0) < 0); - bool bot1 = ((jlong)(lo1 ^ hi1) < 0); - - if (bot0 || bot1) { - // All unsigned values are LE -1 and GE 0. - if (lo0 == 0 && hi0 == 0) { - return TypeInt::CC_LE; // 0 <= bot - } else if ((jlong)lo0 == -1 && (jlong)hi0 == -1) { - return TypeInt::CC_GE; // -1 >= bot - } else if (lo1 == 0 && hi1 == 0) { - return TypeInt::CC_GE; // bot >= 0 - } else if ((jlong)lo1 == -1 && (jlong)hi1 == -1) { - return TypeInt::CC_LE; // bot <= -1 - } - } else { - // We can use ranges of the form [lo..hi] if signs are the same. - assert(lo0 <= hi0 && lo1 <= hi1, "unsigned ranges are valid"); - // results are reversed, '-' > '+' for unsigned compare - if (hi0 < lo1) { - return TypeInt::CC_LT; // smaller - } else if (lo0 > hi1) { - return TypeInt::CC_GT; // greater - } else if (hi0 == lo1 && lo0 == hi1) { - return TypeInt::CC_EQ; // Equal results - } else if (lo0 >= hi1) { - return TypeInt::CC_GE; - } else if (hi0 <= lo1) { - return TypeInt::CC_LE; - } + if (r0->_uhi < r1->_ulo) { + return TypeInt::CC_LT; + } else if (r0->_ulo > r1->_uhi) { + return TypeInt::CC_GT; + } else if (r0->is_con() && r1->is_con()) { + // Since r0->_ulo == r0->_uhi == r0->get_con(), we only reach here if the constants are equal + assert(r0->get_con() == r1->get_con(), "must reach a previous branch otherwise"); + return TypeInt::CC_EQ; + } else if (r0->_uhi == r1->_ulo) { + return TypeInt::CC_LE; + } else if (r0->_ulo == r1->_uhi) { + return TypeInt::CC_GE; } const Type* joined = r0->join(r1); @@ -1015,7 +954,7 @@ const Type* CmpULNode::sub(const Type* t1, const Type* t2) const { return TypeInt::CC_NE; } - return TypeInt::CC; // else use worst case results + return TypeInt::CC; } //============================================================================= diff --git a/test/hotspot/jtreg/compiler/c2/gvn/CmpUNodeValueTests.java b/test/hotspot/jtreg/compiler/c2/gvn/CmpUNodeValueTests.java new file mode 100644 index 00000000000..cbcbda3422f --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/gvn/CmpUNodeValueTests.java @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2026, 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.c2.gvn; + +import compiler.lib.generators.Generators; +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +/* + * @test + * @bug 8375653 + * @summary Test that Value computations of CmpUNode are being performed as expected. + * @library /test/lib / + * @run driver ${test.main.class} + */ +public class CmpUNodeValueTests { + public static void main(String[] args) { + TestFramework.run(); + } + + @DontInline + public static int one() { + return 1; + } + + // Move to a separate method to prevent javac folding the constant comparison + @ForceInline + public static int oneInline() { + return 1; + } + + @Run(test = {"testIntControl", "testIntLT", "testIntLE", "testIntGT", "testIntGE", "testIntEQ", "testIntNE", + "testLongControl", "testLongLT", "testLongLE", "testLongGT", "testLongGE", "testLongEQ", "testLongNE"}) + public void run() { + var stream = Generators.G.longs(); + long x = stream.next(); + long y = stream.next(); + + Asserts.assertEQ(0, testIntControl(false, false)); + Asserts.assertEQ(0, testIntControl(false, true)); + Asserts.assertEQ(0, testIntControl(true, false)); + Asserts.assertEQ(1, testIntControl(true, true)); + Asserts.assertEQ(0, testIntLT((int) x)); + Asserts.assertEQ(0, testIntLE(false, false)); + Asserts.assertEQ(0, testIntLE(false, true)); + Asserts.assertEQ(0, testIntLE(true, false)); + Asserts.assertEQ(0, testIntLE(true, true)); + Asserts.assertEQ(0, testIntGT(false, false)); + Asserts.assertEQ(0, testIntGT(false, true)); + Asserts.assertEQ(0, testIntGT(true, false)); + Asserts.assertEQ(0, testIntGT(true, true)); + Asserts.assertEQ(0, testIntGE((int) x, (int) y)); + Asserts.assertEQ(0, testIntEQ()); + Asserts.assertEQ(0, testIntNE(false, false)); + Asserts.assertEQ(0, testIntNE(false, true)); + Asserts.assertEQ(0, testIntNE(true, false)); + Asserts.assertEQ(0, testIntNE(true, true)); + + Asserts.assertEQ(0, testLongControl(false, false)); + Asserts.assertEQ(0, testLongControl(false, true)); + Asserts.assertEQ(0, testLongControl(true, false)); + Asserts.assertEQ(1, testLongControl(true, true)); + Asserts.assertEQ(0, testLongLT((int) x, false)); + Asserts.assertEQ(0, testLongLT((int) x, true)); + Asserts.assertEQ(0, testLongLE(false, false)); + Asserts.assertEQ(0, testLongLE(false, true)); + Asserts.assertEQ(0, testLongLE(true, false)); + Asserts.assertEQ(0, testLongLE(true, true)); + Asserts.assertEQ(0, testLongGT(false, false)); + Asserts.assertEQ(0, testLongGT(false, true)); + Asserts.assertEQ(0, testLongGT(true, false)); + Asserts.assertEQ(0, testLongGT(true, true)); + Asserts.assertEQ(0, testLongGE((int) x, (int) y)); + Asserts.assertEQ(0, testLongEQ()); + Asserts.assertEQ(0, testLongNE(false, false)); + Asserts.assertEQ(0, testLongNE(false, true)); + Asserts.assertEQ(0, testLongNE(true, false)); + Asserts.assertEQ(0, testLongNE(true, true)); + } + + @Test + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true"}, counts = {IRNode.CMP_U, "1"}) + int testIntControl(boolean b1, boolean b2) { + int v1 = b1 ? 1 : -1; + int v2 = b2 ? 1 : 0; + return Integer.compareUnsigned(v1, v2) > 0 ? 0 : one(); + } + + @Test + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true"}, failOn = {IRNode.CMP_U, IRNode.CALL}) + int testIntLT(int x) { + int v1 = x & Integer.MAX_VALUE; // Unset the highest bit, make v1 non-negative + int v2 = Integer.MIN_VALUE; + return Integer.compareUnsigned(v1, v2) < 0 ? 0 : one(); + } + + @Test + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true"}, failOn = {IRNode.CMP_U, IRNode.CALL}) + int testIntLE(boolean b1, boolean b2) { + int v1 = b1 ? 2 : 0; + int v2 = b2 ? -1 : 2; + return Integer.compareUnsigned(v1, v2) <= 0 ? 0 : one(); + } + + @Test + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true"}, failOn = {IRNode.CMP_U, IRNode.CALL}) + int testIntGT(boolean b1, boolean b2) { + int v1 = b1 ? Integer.MIN_VALUE : Integer.MAX_VALUE; + int v2 = b2 ? 0 : 2; + return Integer.compareUnsigned(v1, v2) > 0 ? 0 : one(); + } + + @Test + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true"}, failOn = {IRNode.CMP_U, IRNode.CALL}) + int testIntGE(int x, int y) { + int v1 = x | Integer.MIN_VALUE; // Set the highest bit, make v1 negative + int v2 = y & Integer.MAX_VALUE; // Unset the highest bit, make v2 non-negative + return Integer.compareUnsigned(v1, v2) >= 0 ? 0 : one(); + } + + @Test + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true"}, failOn = {IRNode.CMP_U, IRNode.CALL}) + int testIntEQ() { + return Integer.compareUnsigned(oneInline(), 1) == 0 ? 0 : one(); + } + + @Test + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true"}, failOn = {IRNode.CMP_U, IRNode.CALL}) + int testIntNE(boolean b1, boolean b2) { + int v1 = b1 ? 1 : -1; + int v2 = b2 ? 0 : 2; + return Integer.compareUnsigned(v1, v2) != 0 ? 0 : one(); + } + + @Test + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true"}, counts = {IRNode.CMP_UL, "1"}) + int testLongControl(boolean b1, boolean b2) { + long v1 = b1 ? 1 : -1; + long v2 = b2 ? 1 : 0; + return Long.compareUnsigned(v1, v2) > 0 ? 0 : one(); + } + + + @Test + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true"}, failOn = {IRNode.CMP_UL, IRNode.CALL}) + int testLongLT(int x, boolean b2) { + long v1 = Integer.toUnsignedLong(x); + long v2 = Integer.MIN_VALUE; + return Long.compareUnsigned(v1, v2) < 0 ? 0 : one(); + } + + @Test + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true"}, failOn = {IRNode.CMP_UL, IRNode.CALL}) + int testLongLE(boolean b1, boolean b2) { + long v1 = b1 ? 2 : 0; + long v2 = b2 ? -1 : 2; + return Long.compareUnsigned(v1, v2) <= 0 ? 0 : one(); + } + + @Test + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true"}, failOn = {IRNode.CMP_UL, IRNode.CALL}) + int testLongGT(boolean b1, boolean b2) { + long v1 = b1 ? Long.MIN_VALUE : Long.MAX_VALUE; + long v2 = b2 ? 0 : 2; + return Long.compareUnsigned(v1, v2) > 0 ? 0 : one(); + } + + @Test + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true"}, failOn = {IRNode.CMP_UL, IRNode.CALL}) + int testLongGE(int x, int y) { + long v1 = x | Long.MIN_VALUE; // Set the highest bit, make v1 negative + long v2 = y & Long.MAX_VALUE; // Unset the highest bit, make v2 non-negative + return Long.compareUnsigned(v1, v2) >= 0 ? 0 : one(); + } + + @Test + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true"}, failOn = {IRNode.CMP_UL, IRNode.CALL}) + int testLongEQ() { + return Long.compareUnsigned(oneInline(), 1L) == 0 ? 0 : one(); + } + + @Test + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true"}, failOn = {IRNode.CMP_UL, IRNode.CALL}) + int testLongNE(boolean b1, boolean b2) { + long v1 = b1 ? 1 : -1; + long v2 = b2 ? 0 : 2; + return Long.compareUnsigned(v1, v2) != 0 ? 0 : one(); + } +} diff --git a/test/hotspot/jtreg/compiler/ccp/TestCmpUMonotonicity.java b/test/hotspot/jtreg/compiler/ccp/TestCmpUMonotonicity.java new file mode 100644 index 00000000000..5ebdd9469fc --- /dev/null +++ b/test/hotspot/jtreg/compiler/ccp/TestCmpUMonotonicity.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2026, 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.ccp; + +/* + * @test + * @bug 8375653 + * @summary Test that CmpUNode::sub conforms monotonicity + * + * @run main ${test.main.class} + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,${test.main.class}::test* ${test.main.class} + */ +public class TestCmpUMonotonicity { + public static void main(String[] args) { + for (int i = 0; i < 20000; i++) { + testInt(true, 1, 100, 2); + testInt(false, 1, 100, 2); + testLong(true, 1, 100, 2); + testLong(false, 1, 100, 2); + } + } + + private static int testInt(boolean b, int start, int limit, int step) { + int v2 = b ? 1 : -1; + int v1 = 0; + for (int i = start; i < limit; i *= step) { + if (Integer.compareUnsigned(v1, v2) < 0) { + v1 = 2; + } else { + v1 = 0; + } + } + return v1; + } + + private static long testLong(boolean b, int start, int limit, int step) { + long v2 = b ? 1 : -1; + long v1 = 0; + for (int i = start; i < limit; i *= step) { + if (Long.compareUnsigned(v1, v2) < 0) { + v1 = 2; + } else { + v1 = 0; + } + } + return v1; + } +} From 0f1b96a50a3a79fd699bf34121df8451ffa37b8f Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 26 Jan 2026 11:38:05 +0000 Subject: [PATCH 184/328] 8375684: Avoid leak in KeystoreImpl.m when using CFArrayCreateMutable Reviewed-by: clanger --- .../macosx/native/libosxsecurity/KeystoreImpl.m | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m index 31572eaeb81..6d8eb832370 100644 --- a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m +++ b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, 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 @@ -134,10 +134,11 @@ static OSStatus completeCertChain( CFArrayAppendValue(certArray, identity); /* the single element in certs-to-be-evaluated comes from the identity */ - ortn = SecIdentityCopyCertificate(identity, &certRef); - if(ortn) { + ortn = SecIdentityCopyCertificate(identity, &certRef); + if (ortn) { /* should never happen */ cssmPerror("SecIdentityCopyCertificate", ortn); + CFRelease(certArray); return ortn; } @@ -283,6 +284,7 @@ static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore, jmethodID jm_ OSStatus err = SecIdentitySearchCreate(NULL, 0, &identitySearch); SecIdentityRef theIdentity = NULL; OSErr searchResult = noErr; + CFArrayRef certChain = NULL; do { searchResult = SecIdentitySearchCopyNext(identitySearch, &theIdentity); @@ -291,7 +293,6 @@ static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore, jmethodID jm_ // Get the cert from the identity, then generate a chain. SecCertificateRef certificate; SecIdentityCopyCertificate(theIdentity, &certificate); - CFArrayRef certChain = NULL; // *** Should do something with this error... err = completeCertChain(theIdentity, NULL, TRUE, &certChain); @@ -357,6 +358,11 @@ static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore, jmethodID jm_ if ((*env)->ExceptionCheck(env)) { goto errOut; } + + if (certChain != NULL) { + CFRelease(certChain); + certChain = NULL; + } } } while (searchResult == noErr); @@ -364,6 +370,9 @@ errOut: if (identitySearch != NULL) { CFRelease(identitySearch); } + if (certChain != NULL) { + CFRelease(certChain); + } } #define ADD(list, str) { \ From de5c7a9e8607b2a6219d98f9b81ddce4ca92baef Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Mon, 26 Jan 2026 12:16:05 +0000 Subject: [PATCH 185/328] 8374676: ZGC: Convert zAbort to use Atomic Reviewed-by: stefank, tschatzl --- src/hotspot/share/gc/z/zAbort.cpp | 7 +++---- src/hotspot/share/gc/z/zAbort.hpp | 5 +++-- src/hotspot/share/gc/z/zAbort.inline.hpp | 6 ++---- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/gc/z/zAbort.cpp b/src/hotspot/share/gc/z/zAbort.cpp index 3310793f730..82523ddebe8 100644 --- a/src/hotspot/share/gc/z/zAbort.cpp +++ b/src/hotspot/share/gc/z/zAbort.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,9 @@ */ #include "gc/z/zAbort.hpp" -#include "runtime/atomicAccess.hpp" -volatile bool ZAbort::_should_abort = false; +Atomic ZAbort::_should_abort{}; void ZAbort::abort() { - AtomicAccess::store(&_should_abort, true); + _should_abort.store_relaxed(true); } diff --git a/src/hotspot/share/gc/z/zAbort.hpp b/src/hotspot/share/gc/z/zAbort.hpp index 925b0a79ac3..64633752d5d 100644 --- a/src/hotspot/share/gc/z/zAbort.hpp +++ b/src/hotspot/share/gc/z/zAbort.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,10 +25,11 @@ #define SHARE_GC_Z_ZABORT_HPP #include "memory/allStatic.hpp" +#include "runtime/atomic.hpp" class ZAbort : public AllStatic { private: - static volatile bool _should_abort; + static Atomic _should_abort; public: static bool should_abort(); diff --git a/src/hotspot/share/gc/z/zAbort.inline.hpp b/src/hotspot/share/gc/z/zAbort.inline.hpp index 37503e25f70..856179e9d2a 100644 --- a/src/hotspot/share/gc/z/zAbort.inline.hpp +++ b/src/hotspot/share/gc/z/zAbort.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,10 +26,8 @@ #include "gc/z/zAbort.hpp" -#include "runtime/atomicAccess.hpp" - inline bool ZAbort::should_abort() { - return AtomicAccess::load(&_should_abort); + return _should_abort.load_relaxed(); } #endif // SHARE_GC_Z_ZABORT_INLINE_HPP From 8a9127fc2d1f8c1cba952744e1a5a7533bb03537 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Mon, 26 Jan 2026 12:57:23 +0000 Subject: [PATCH 186/328] 8376118: java/net/httpclient/StreamingBody.java fails intermittently on Windows Reviewed-by: vyazici, jpai --- .../java/net/httpclient/StreamingBody.java | 223 +++++++++++++++--- 1 file changed, 190 insertions(+), 33 deletions(-) diff --git a/test/jdk/java/net/httpclient/StreamingBody.java b/test/jdk/java/net/httpclient/StreamingBody.java index c2ad19cf7b7..3fb4f29208e 100644 --- a/test/jdk/java/net/httpclient/StreamingBody.java +++ b/test/jdk/java/net/httpclient/StreamingBody.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,12 @@ * @test * @summary Exercise a streaming subscriber ( InputStream ) without holding a * strong (or any ) reference to the client. + * @key randomness * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext - * @run testng/othervm + * @run junit/othervm * -Djdk.httpclient.HttpClient.log=trace,headers,requests - * StreamingBody + * ${test.main.class} */ import java.io.IOException; @@ -40,13 +41,15 @@ import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; +import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import javax.net.ssl.SSLContext; import jdk.httpclient.test.lib.common.HttpServerAdapters; +import jdk.test.lib.RandomFactory; import jdk.test.lib.net.SimpleSSLContext; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.System.out; import static java.net.http.HttpClient.Version.HTTP_1_1; import static java.net.http.HttpClient.Version.HTTP_2; @@ -55,8 +58,21 @@ import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; import static java.net.http.HttpOption.H3_DISCOVERY; import static java.nio.charset.StandardCharsets.UTF_8; import static java.net.http.HttpClient.Builder.NO_PROXY; -import static org.testng.Assert.assertEquals; +import org.junit.jupiter.api.AfterAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.extension.TestWatcher; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class StreamingBody implements HttpServerAdapters { private static final SSLContext sslContext = SimpleSSLContext.findSSLContext(); @@ -71,10 +87,105 @@ public class StreamingBody implements HttpServerAdapters { String https2URI; String http3URI; + static final AtomicLong clientCount = new AtomicLong(); + static final AtomicLong serverCount = new AtomicLong(); + static final ConcurrentMap FAILURES = new ConcurrentHashMap<>(); + private static boolean stopAfterFirstFailure() { + return true; + } + + static final long start = System.nanoTime(); + public static String now() { + long now = System.nanoTime() - start; + long secs = now / 1000_000_000; + long mill = (now % 1000_000_000) / 1000_000; + long nan = now % 1000_000; + return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan); + } + + final static class TestStopper implements TestWatcher, BeforeEachCallback { + final AtomicReference failed = new AtomicReference<>(); + TestStopper() { } + @Override + public void testFailed(ExtensionContext context, Throwable cause) { + if (stopAfterFirstFailure()) { + String msg = "Aborting due to: " + cause; + failed.compareAndSet(null, msg); + FAILURES.putIfAbsent(context.getDisplayName(), cause); + System.out.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n", + now(), context.getDisplayName(), cause); + System.err.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n", + now(), context.getDisplayName(), cause); + } + } + + @Override + public void beforeEach(ExtensionContext context) { + String msg = failed.get(); + Assumptions.assumeTrue(msg == null, msg); + } + } + + @RegisterExtension + static final TestStopper stopper = new TestStopper(); + + /// The GCTrigger triggers GC at random intervals to + /// help garbage collecting HttpClient intances. This test + /// wants to verify that HttpClient instances which are no + /// longer strongly referenced are not garbage collected + /// before pending HTTP requests are finished. The test + /// creates many client instances (up to 500) and relies + /// on the GC to collect them, since it does not want to + /// keep a strong reference, and therefore cannot not call + /// close(). This can put extra load on the machine since + /// we can't (and don't want to) control when the GC will + /// intervene. The purpose of this class is to trigger the + /// GC at random intervals to 1. help garbage collect client + /// instances earlier, thus reducing the load on the machine, + /// and 2. potentially trigger bugs if the client gets + /// inadvertently GC'ed before the request is finished + /// (which is the bug we're testing for here). + static class GCTrigger { + private final long gcinterval; + private final Thread runner; + private volatile boolean stop; + private final static Random RANDOM = RandomFactory.getRandom(); + + GCTrigger(long gcinterval) { + this.gcinterval = Math.clamp(gcinterval, 100, Long.MAX_VALUE/2); + runner = Thread.ofPlatform().daemon().unstarted(this::loop); + } + + private void loop() { + long min = gcinterval / 2; + long max = gcinterval + min; + while (!stop) { + try { + Thread.sleep(RANDOM.nextLong(min, max)); + } catch (InterruptedException x) { + stop = true; + break; + } + out.println(now() + "triggering gc"); + System.gc(); + } + } + + public void start() { + runner.start(); + } + + public void stop() throws InterruptedException { + stop = true; + runner.interrupt(); + runner.join(); + } + } + + static GCTrigger gcTrigger; static final String MESSAGE = "StreamingBody message body"; static final int ITERATIONS = 100; - @DataProvider(name = "positive") public Object[][] positive() { return new Object[][] { { http3URI, }, @@ -94,72 +205,118 @@ public class StreamingBody implements HttpServerAdapters { return builder; } - @Test(dataProvider = "positive") + @ParameterizedTest + @MethodSource("positive") void test(String uriString) throws Exception { - out.printf("%n---- starting (%s) ----%n", uriString); + out.printf("%n%s---- starting (%s) ----%n", now(), uriString); URI uri = URI.create(uriString); HttpRequest request = newRequestBuilder(uri).build(); for (int i=0; i< ITERATIONS; i++) { - out.println("iteration: " + i); - var builder = uriString.contains("/http3/") - ? newClientBuilderForH3() - : HttpClient.newBuilder(); - HttpResponse response = builder - .sslContext(sslContext) - .proxy(NO_PROXY) - .build() - .sendAsync(request, BodyHandlers.ofInputStream()) - .join(); + try { + out.println(now() + "iteration: " + i); + var builder = uriString.contains("/http3/") + ? newClientBuilderForH3() + : HttpClient.newBuilder(); + clientCount.incrementAndGet(); - String body = new String(response.body().readAllBytes(), UTF_8); - out.println("Got response: " + response); - out.println("Got body Path: " + body); + // we want to relinquish the reference to the HttpClient facade + // as soon as possible. We're using `ofInputStream()` because + // the HttpResponse will be returned almost immediately, before + // the response is read. Similarly we use sendAsync() because + // this will return a CompletableFuture and not wait for the + // request to complete within a method called on the client + // facade. + HttpResponse response = builder + .sslContext(sslContext) + .proxy(NO_PROXY) + .build() + .sendAsync(request, BodyHandlers.ofInputStream()) + .join(); - assertEquals(response.statusCode(), 200); - assertEquals(body, MESSAGE); + String body = new String(response.body().readAllBytes(), UTF_8); + out.println("Got response: " + response); + out.println("Got body Path: " + body); + + assertEquals(200, response.statusCode()); + assertEquals(MESSAGE, body); + } catch (Throwable t) { + String msg = "%stest(%s)[%s] failed: %s" + .formatted(now(), uriString, i, t); + out.println(msg); + throw new AssertionError(msg, t); + } } } // -- Infrastructure - @BeforeTest + @BeforeAll public void setup() throws Exception { httpTestServer = HttpTestServer.create(HTTP_1_1); httpTestServer.addHandler(new MessageHandler(), "/http1/streamingbody/"); httpURI = "http://" + httpTestServer.serverAuthority() + "/http1/streamingbody/w"; + serverCount.incrementAndGet(); httpsTestServer = HttpTestServer.create(HTTP_1_1, sslContext); httpsTestServer.addHandler(new MessageHandler(),"/https1/streamingbody/"); httpsURI = "https://" + httpsTestServer.serverAuthority() + "/https1/streamingbody/x"; + serverCount.incrementAndGet(); http2TestServer = HttpTestServer.create(HTTP_2); http2TestServer.addHandler(new MessageHandler(), "/http2/streamingbody/"); http2URI = "http://" + http2TestServer.serverAuthority() + "/http2/streamingbody/y"; + serverCount.incrementAndGet(); https2TestServer = HttpTestServer.create(HTTP_2, sslContext); https2TestServer.addHandler(new MessageHandler(), "/https2/streamingbody/"); https2URI = "https://" + https2TestServer.serverAuthority() + "/https2/streamingbody/z"; + serverCount.incrementAndGet(); http3TestServer = HttpTestServer.create(HTTP_3_URI_ONLY, sslContext); http3TestServer.addHandler(new MessageHandler(), "/http3/streamingbody/"); http3URI = "https://" + http3TestServer.serverAuthority() + "/http3/streamingbody/z"; + serverCount.incrementAndGet(); + + gcTrigger = new GCTrigger(500); httpTestServer.start(); httpsTestServer.start(); http2TestServer.start(); https2TestServer.start(); http3TestServer.start(); + gcTrigger.start(); } - @AfterTest + @AfterAll public void teardown() throws Exception { - httpTestServer.stop(); - httpsTestServer.stop(); - http2TestServer.stop(); - https2TestServer.stop(); - http3TestServer.stop(); + try { + httpTestServer.stop(); + httpsTestServer.stop(); + http2TestServer.stop(); + https2TestServer.stop(); + http3TestServer.stop(); + gcTrigger.stop(); + } finally { + printFailedTests(); + } + } + + static final void printFailedTests() { + out.println("\n========================="); + try { + out.printf("%n%sCreated %s servers and %s clients%n", + now(), serverCount.get(), clientCount.get()); + if (FAILURES.isEmpty()) return; + out.println("Failed tests: "); + FAILURES.entrySet().forEach((e) -> { + out.printf("\t%s: %s%n", e.getKey(), e.getValue()); + e.getValue().printStackTrace(out); + }); + } finally { + out.println("\n=========================\n"); + } } static class MessageHandler implements HttpTestHandler { From 37cb22826a8f644c699228b8a68852b59933ead5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Mon, 26 Jan 2026 13:28:04 +0000 Subject: [PATCH 187/328] 8373679: Link color accessibility issue in dark theme Reviewed-by: liach, nbenalla --- .../internal/doclets/formats/html/resources/stylesheet.css | 7 +++++++ .../checkStylesheetClasses/CheckStylesheetClasses.java | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css index 53b9d8ca6b2..6198df5c2f3 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css @@ -163,6 +163,13 @@ \ '); --current-theme-svg: url("moon.svg"); + div.block a[href], div.horizontal-scroll a[href], div.inherited-list h3 a[href], header > div a[href], + .hierarchy a[href], .index a[href], div.caption a[href], .sub-title a[href], .deprecation-comment a[href], + .serialized-class-details a[href] { + text-decoration: underline; + text-decoration-thickness: 0.02em; + text-underline-offset: 0.12em; + } } /* * Styles for individual HTML elements. diff --git a/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java b/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java index ee1fa538a57..6740bace528 100644 --- a/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java +++ b/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java @@ -122,7 +122,7 @@ public class CheckStylesheetClasses { "modifiers", "permits", "return-type"); // misc: these are defined in HtmlStyle, and used by the doclet - removeAll(htmlStyleNames, "col-plain", "external-link", "header", "index", + removeAll(htmlStyleNames, "col-plain", "external-link", "header", "package-uses", "packages", "permits-note", "serialized-package-container", "source-container"); From 319e21e9b48b4a9646c803e23d16f0b7df827d3f Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Mon, 26 Jan 2026 13:44:06 +0000 Subject: [PATCH 188/328] 8374677: ZGC: Convert zArray to use Atomic Reviewed-by: stefank, tschatzl --- src/hotspot/share/gc/z/zArray.hpp | 8 +++++--- src/hotspot/share/gc/z/zArray.inline.hpp | 7 +++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/z/zArray.hpp b/src/hotspot/share/gc/z/zArray.hpp index 2c2f8a5dbfb..d39def4096e 100644 --- a/src/hotspot/share/gc/z/zArray.hpp +++ b/src/hotspot/share/gc/z/zArray.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ #include "cppstdlib/type_traits.hpp" #include "memory/allocation.hpp" -#include "runtime/atomicAccess.hpp" +#include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "runtime/thread.hpp" #include "utilities/growableArray.hpp" @@ -78,7 +78,9 @@ public: template class ZArrayIteratorImpl : public StackObj { private: - size_t _next; + using NextType = std::conditional_t, size_t>; + + NextType _next; const size_t _end; const T* const _array; diff --git a/src/hotspot/share/gc/z/zArray.inline.hpp b/src/hotspot/share/gc/z/zArray.inline.hpp index 9e2bc19118e..15caa54ebab 100644 --- a/src/hotspot/share/gc/z/zArray.inline.hpp +++ b/src/hotspot/share/gc/z/zArray.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ #include "gc/z/zArray.hpp" #include "gc/z/zLock.inline.hpp" -#include "runtime/atomicAccess.hpp" template ZArraySlice::ZArraySlice(T* data, int len) @@ -130,7 +129,7 @@ inline bool ZArrayIteratorImpl::next_serial(size_t* index) { template inline bool ZArrayIteratorImpl::next_parallel(size_t* index) { - const size_t claimed_index = AtomicAccess::fetch_then_add(&_next, 1u, memory_order_relaxed); + const size_t claimed_index = _next.fetch_then_add(1u, memory_order_relaxed); if (claimed_index < _end) { *index = claimed_index; @@ -177,7 +176,7 @@ inline bool ZArrayIteratorImpl::next_if(T* elem, Function predicate template inline bool ZArrayIteratorImpl::next_index(size_t* index) { - if (Parallel) { + if constexpr (Parallel) { return next_parallel(index); } else { return next_serial(index); From 512f95cf2632167149e2118853ab4d6d636fe0a3 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Mon, 26 Jan 2026 13:53:12 +0000 Subject: [PATCH 189/328] 8374678: ZGC: Convert zForwarding to use Atomic Reviewed-by: stefank, eosterlund --- src/hotspot/share/gc/z/vmStructs_z.hpp | 3 +- src/hotspot/share/gc/z/zForwarding.cpp | 45 +++++++++---------- src/hotspot/share/gc/z/zForwarding.hpp | 13 +++--- src/hotspot/share/gc/z/zForwarding.inline.hpp | 14 +++--- 4 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/hotspot/share/gc/z/vmStructs_z.hpp b/src/hotspot/share/gc/z/vmStructs_z.hpp index a88dae188d3..de32b964a51 100644 --- a/src/hotspot/share/gc/z/vmStructs_z.hpp +++ b/src/hotspot/share/gc/z/vmStructs_z.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -111,7 +111,6 @@ typedef ZValue ZPerNUMAZPartition; \ nonstatic_field(ZForwarding, _virtual, const ZVirtualMemory) \ nonstatic_field(ZForwarding, _object_alignment_shift, const size_t) \ - volatile_nonstatic_field(ZForwarding, _ref_count, int) \ nonstatic_field(ZForwarding, _entries, const ZAttachedArrayForForwarding) \ nonstatic_field(ZForwardingEntry, _entry, uint64_t) \ nonstatic_field(ZAttachedArrayForForwarding, _length, const size_t) diff --git a/src/hotspot/share/gc/z/zForwarding.cpp b/src/hotspot/share/gc/z/zForwarding.cpp index 820bb9dbc35..92fc1bc89df 100644 --- a/src/hotspot/share/gc/z/zForwarding.cpp +++ b/src/hotspot/share/gc/z/zForwarding.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, 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 @@ -29,7 +29,6 @@ #include "gc/z/zStat.hpp" #include "gc/z/zUtils.inline.hpp" #include "logging/log.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/align.hpp" // @@ -50,7 +49,7 @@ // bool ZForwarding::claim() { - return AtomicAccess::cmpxchg(&_claimed, false, true) == false; + return _claimed.compare_set(false, true); } void ZForwarding::in_place_relocation_start(zoffset relocated_watermark) { @@ -60,7 +59,7 @@ void ZForwarding::in_place_relocation_start(zoffset relocated_watermark) { // Support for ZHeap::is_in checks of from-space objects // in a page that is in-place relocating - AtomicAccess::store(&_in_place_thread, Thread::current()); + _in_place_thread.store_relaxed(Thread::current()); _in_place_top_at_start = _page->top(); } @@ -76,17 +75,17 @@ void ZForwarding::in_place_relocation_finish() { } // Disable relaxed ZHeap::is_in checks - AtomicAccess::store(&_in_place_thread, (Thread*)nullptr); + _in_place_thread.store_relaxed(nullptr); } bool ZForwarding::in_place_relocation_is_below_top_at_start(zoffset offset) const { // Only the relocating thread is allowed to know about the old relocation top. - return AtomicAccess::load(&_in_place_thread) == Thread::current() && offset < _in_place_top_at_start; + return _in_place_thread.load_relaxed() == Thread::current() && offset < _in_place_top_at_start; } bool ZForwarding::retain_page(ZRelocateQueue* queue) { for (;;) { - const int32_t ref_count = AtomicAccess::load_acquire(&_ref_count); + const int32_t ref_count = _ref_count.load_acquire(); if (ref_count == 0) { // Released @@ -101,7 +100,7 @@ bool ZForwarding::retain_page(ZRelocateQueue* queue) { return false; } - if (AtomicAccess::cmpxchg(&_ref_count, ref_count, ref_count + 1) == ref_count) { + if (_ref_count.compare_set(ref_count, ref_count + 1)) { // Retained return true; } @@ -110,11 +109,11 @@ bool ZForwarding::retain_page(ZRelocateQueue* queue) { void ZForwarding::in_place_relocation_claim_page() { for (;;) { - const int32_t ref_count = AtomicAccess::load(&_ref_count); + const int32_t ref_count = _ref_count.load_relaxed(); assert(ref_count > 0, "Invalid state"); // Invert reference count - if (AtomicAccess::cmpxchg(&_ref_count, ref_count, -ref_count) != ref_count) { + if (!_ref_count.compare_set(ref_count, -ref_count)) { continue; } @@ -122,7 +121,7 @@ void ZForwarding::in_place_relocation_claim_page() { // and we have now claimed the page. Otherwise we wait until it is claimed. if (ref_count != 1) { ZLocker locker(&_ref_lock); - while (AtomicAccess::load_acquire(&_ref_count) != -1) { + while (_ref_count.load_acquire() != -1) { _ref_lock.wait(); } } @@ -134,12 +133,12 @@ void ZForwarding::in_place_relocation_claim_page() { void ZForwarding::release_page() { for (;;) { - const int32_t ref_count = AtomicAccess::load(&_ref_count); + const int32_t ref_count = _ref_count.load_relaxed(); assert(ref_count != 0, "Invalid state"); if (ref_count > 0) { // Decrement reference count - if (AtomicAccess::cmpxchg(&_ref_count, ref_count, ref_count - 1) != ref_count) { + if (!_ref_count.compare_set(ref_count, ref_count - 1)) { continue; } @@ -152,7 +151,7 @@ void ZForwarding::release_page() { } } else { // Increment reference count - if (AtomicAccess::cmpxchg(&_ref_count, ref_count, ref_count + 1) != ref_count) { + if (!_ref_count.compare_set(ref_count, ref_count + 1)) { continue; } @@ -171,9 +170,9 @@ void ZForwarding::release_page() { ZPage* ZForwarding::detach_page() { // Wait until released - if (AtomicAccess::load_acquire(&_ref_count) != 0) { + if (_ref_count.load_acquire() != 0) { ZLocker locker(&_ref_lock); - while (AtomicAccess::load_acquire(&_ref_count) != 0) { + while (_ref_count.load_acquire() != 0) { _ref_lock.wait(); } } @@ -182,16 +181,16 @@ ZPage* ZForwarding::detach_page() { } ZPage* ZForwarding::page() { - assert(AtomicAccess::load(&_ref_count) != 0, "The page has been released/detached"); + assert(_ref_count.load_relaxed() != 0, "The page has been released/detached"); return _page; } void ZForwarding::mark_done() { - AtomicAccess::store(&_done, true); + _done.store_relaxed(true); } bool ZForwarding::is_done() const { - return AtomicAccess::load(&_done); + return _done.load_relaxed(); } // @@ -288,7 +287,7 @@ void ZForwarding::relocated_remembered_fields_publish() { // used to have remembered set entries. Now publish the fields to // the YC. - const ZPublishState res = AtomicAccess::cmpxchg(&_relocated_remembered_fields_state, ZPublishState::none, ZPublishState::published); + const ZPublishState res = _relocated_remembered_fields_state.compare_exchange(ZPublishState::none, ZPublishState::published); // none: OK to publish // published: Not possible - this operation makes this transition @@ -319,7 +318,7 @@ void ZForwarding::relocated_remembered_fields_notify_concurrent_scan_of() { // Invariant: The page is being retained assert(ZGeneration::young()->is_phase_mark(), "Only called when"); - const ZPublishState res = AtomicAccess::cmpxchg(&_relocated_remembered_fields_state, ZPublishState::none, ZPublishState::reject); + const ZPublishState res = _relocated_remembered_fields_state.compare_exchange(ZPublishState::none, ZPublishState::reject); // none: OC has not completed relocation // published: OC has completed and published all relocated remembered fields @@ -340,7 +339,7 @@ void ZForwarding::relocated_remembered_fields_notify_concurrent_scan_of() { // OC relocation already collected and published fields // Still notify concurrent scanning and reject the collected data from the OC - const ZPublishState res2 = AtomicAccess::cmpxchg(&_relocated_remembered_fields_state, ZPublishState::published, ZPublishState::reject); + const ZPublishState res2 = _relocated_remembered_fields_state.compare_exchange(ZPublishState::published, ZPublishState::reject); assert(res2 == ZPublishState::published, "Should not fail"); log_debug(gc, remset)("Forwarding remset eager and reject: " PTR_FORMAT " " PTR_FORMAT, untype(start()), untype(end())); @@ -368,7 +367,7 @@ bool ZForwarding::relocated_remembered_fields_published_contains(volatile zpoint } void ZForwarding::verify() const { - guarantee(_ref_count != 0, "Invalid reference count"); + guarantee(_ref_count.load_relaxed() != 0, "Invalid reference count"); guarantee(_page != nullptr, "Invalid page"); uint32_t live_objects = 0; diff --git a/src/hotspot/share/gc/z/zForwarding.hpp b/src/hotspot/share/gc/z/zForwarding.hpp index 29b5cf4aabe..72319bd2ebb 100644 --- a/src/hotspot/share/gc/z/zForwarding.hpp +++ b/src/hotspot/share/gc/z/zForwarding.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ #include "gc/z/zPageAge.hpp" #include "gc/z/zPageType.hpp" #include "gc/z/zVirtualMemory.hpp" +#include "runtime/atomic.hpp" class ObjectClosure; class ZForwardingAllocator; @@ -62,13 +63,13 @@ private: const uint32_t _partition_id; const ZPageAge _from_age; const ZPageAge _to_age; - volatile bool _claimed; + Atomic _claimed; mutable ZConditionLock _ref_lock; - volatile int32_t _ref_count; - volatile bool _done; + Atomic _ref_count; + Atomic _done; // Relocated remembered set fields support - volatile ZPublishState _relocated_remembered_fields_state; + Atomic _relocated_remembered_fields_state; PointerArray _relocated_remembered_fields_array; uint32_t _relocated_remembered_fields_publish_young_seqnum; @@ -77,7 +78,7 @@ private: zoffset_end _in_place_top_at_start; // Debugging - volatile Thread* _in_place_thread; + Atomic _in_place_thread; ZForwardingEntry* entries() const; ZForwardingEntry at(ZForwardingCursor* cursor) const; diff --git a/src/hotspot/share/gc/z/zForwarding.inline.hpp b/src/hotspot/share/gc/z/zForwarding.inline.hpp index 45b5d495e79..02f61eb5b05 100644 --- a/src/hotspot/share/gc/z/zForwarding.inline.hpp +++ b/src/hotspot/share/gc/z/zForwarding.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, 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 @@ -196,7 +196,7 @@ void ZForwarding::oops_do_in_forwarded_via_table(Function function) { } inline bool ZForwarding::in_place_relocation() const { - assert(AtomicAccess::load(&_ref_count) != 0, "The page has been released/detached"); + assert(_ref_count.load_relaxed() != 0, "The page has been released/detached"); return _in_place; } @@ -307,7 +307,7 @@ inline void ZForwarding::relocated_remembered_fields_register(volatile zpointer* // Invariant: Page is being retained assert(ZGeneration::young()->is_phase_mark(), "Only called when"); - const ZPublishState res = AtomicAccess::load(&_relocated_remembered_fields_state); + const ZPublishState res = _relocated_remembered_fields_state.load_relaxed(); // none: Gather remembered fields // published: Have already published fields - not possible since they haven't been @@ -327,7 +327,7 @@ inline void ZForwarding::relocated_remembered_fields_register(volatile zpointer* // Returns true iff the page is being (or about to be) relocated by the OC // while the YC gathered the remembered fields of the "from" page. inline bool ZForwarding::relocated_remembered_fields_is_concurrently_scanned() const { - return AtomicAccess::load(&_relocated_remembered_fields_state) == ZPublishState::reject; + return _relocated_remembered_fields_state.load_relaxed() == ZPublishState::reject; } template @@ -335,7 +335,7 @@ inline void ZForwarding::relocated_remembered_fields_apply_to_published(Function // Invariant: Page is not being retained assert(ZGeneration::young()->is_phase_mark(), "Only called when"); - const ZPublishState res = AtomicAccess::load_acquire(&_relocated_remembered_fields_state); + const ZPublishState res = _relocated_remembered_fields_state.load_acquire(); // none: Nothing published - page had already been relocated before YC started // published: OC relocated and published relocated remembered fields @@ -363,14 +363,14 @@ inline void ZForwarding::relocated_remembered_fields_apply_to_published(Function // collection. Mark that it is unsafe (and unnecessary) to call scan_page // on the page in the page table. assert(res != ZPublishState::accept, "Unexpected"); - AtomicAccess::store(&_relocated_remembered_fields_state, ZPublishState::reject); + _relocated_remembered_fields_state.store_relaxed(ZPublishState::reject); } else { log_debug(gc, remset)("scan_forwarding failed retain safe " PTR_FORMAT, untype(start())); // Guaranteed that the page was fully relocated and removed from page table. // Because of this we can signal to scan_page that any page found in page table // of the same slot as the current forwarding is a page that is safe to scan, // and in fact must be scanned. - AtomicAccess::store(&_relocated_remembered_fields_state, ZPublishState::accept); + _relocated_remembered_fields_state.store_relaxed(ZPublishState::accept); } } From fef85ff932055cd5385633f3b283e6201cdcaa68 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Mon, 26 Jan 2026 14:13:48 +0000 Subject: [PATCH 190/328] 8374679: ZGC: Convert zForwardingAllocator to use Atomic Reviewed-by: stefank, tschatzl --- src/hotspot/share/gc/z/zForwardingAllocator.cpp | 5 +++-- src/hotspot/share/gc/z/zForwardingAllocator.hpp | 9 +++++---- src/hotspot/share/gc/z/zForwardingAllocator.inline.hpp | 7 +++---- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/gc/z/zForwardingAllocator.cpp b/src/hotspot/share/gc/z/zForwardingAllocator.cpp index 0b4e6c7b08c..451a1d62754 100644 --- a/src/hotspot/share/gc/z/zForwardingAllocator.cpp +++ b/src/hotspot/share/gc/z/zForwardingAllocator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ ZForwardingAllocator::~ZForwardingAllocator() { } void ZForwardingAllocator::reset(size_t size) { - _start = _top = REALLOC_C_HEAP_ARRAY(char, _start, size, mtGC); + _start = REALLOC_C_HEAP_ARRAY(char, _start, size, mtGC); + _top.store_relaxed(_start); _end = _start + size; } diff --git a/src/hotspot/share/gc/z/zForwardingAllocator.hpp b/src/hotspot/share/gc/z/zForwardingAllocator.hpp index 8424fe6cd70..62d84885692 100644 --- a/src/hotspot/share/gc/z/zForwardingAllocator.hpp +++ b/src/hotspot/share/gc/z/zForwardingAllocator.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,13 +24,14 @@ #ifndef SHARE_GC_Z_ZFORWARDINGALLOCATOR_HPP #define SHARE_GC_Z_ZFORWARDINGALLOCATOR_HPP +#include "runtime/atomic.hpp" #include "utilities/globalDefinitions.hpp" class ZForwardingAllocator { private: - char* _start; - char* _end; - char* _top; + char* _start; + char* _end; + Atomic _top; public: ZForwardingAllocator(); diff --git a/src/hotspot/share/gc/z/zForwardingAllocator.inline.hpp b/src/hotspot/share/gc/z/zForwardingAllocator.inline.hpp index dc71507175c..c8811c84ede 100644 --- a/src/hotspot/share/gc/z/zForwardingAllocator.inline.hpp +++ b/src/hotspot/share/gc/z/zForwardingAllocator.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ #include "gc/z/zForwardingAllocator.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/debug.hpp" inline size_t ZForwardingAllocator::size() const { @@ -34,11 +33,11 @@ inline size_t ZForwardingAllocator::size() const { } inline bool ZForwardingAllocator::is_full() const { - return _top == _end; + return _top.load_relaxed() == _end; } inline void* ZForwardingAllocator::alloc(size_t size) { - char* const addr = AtomicAccess::fetch_then_add(&_top, size); + char* const addr = _top.fetch_then_add(size); assert(addr + size <= _end, "Allocation should never fail"); return addr; } From b59f49a1c3e370f794291a1f948e67d2651ece11 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Mon, 26 Jan 2026 14:28:39 +0000 Subject: [PATCH 191/328] 8374680: ZGC: Convert zGeneration to use Atomic Reviewed-by: stefank, tschatzl --- src/hotspot/share/gc/z/zGeneration.cpp | 21 ++++++++++----------- src/hotspot/share/gc/z/zGeneration.hpp | 9 +++++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index a8c646bf895..27f352a624f 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -56,7 +56,6 @@ #include "logging/log.hpp" #include "memory/universe.hpp" #include "prims/jvmtiTagMap.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/continuation.hpp" #include "runtime/handshake.hpp" #include "runtime/safepoint.hpp" @@ -298,33 +297,33 @@ bool ZGeneration::is_relocate_queue_active() const { void ZGeneration::reset_statistics() { assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); - _freed = 0; - _promoted = 0; - _compacted = 0; + _freed.store_relaxed(0u); + _promoted.store_relaxed(0u); + _compacted.store_relaxed(0u); } size_t ZGeneration::freed() const { - return _freed; + return _freed.load_relaxed(); } void ZGeneration::increase_freed(size_t size) { - AtomicAccess::add(&_freed, size, memory_order_relaxed); + _freed.add_then_fetch(size, memory_order_relaxed); } size_t ZGeneration::promoted() const { - return _promoted; + return _promoted.load_relaxed();; } void ZGeneration::increase_promoted(size_t size) { - AtomicAccess::add(&_promoted, size, memory_order_relaxed); + _promoted.add_then_fetch(size, memory_order_relaxed); } size_t ZGeneration::compacted() const { - return _compacted; + return _compacted.load_relaxed();; } void ZGeneration::increase_compacted(size_t size) { - AtomicAccess::add(&_compacted, size, memory_order_relaxed); + _compacted.add_then_fetch(size, memory_order_relaxed); } ConcurrentGCTimer* ZGeneration::gc_timer() const { diff --git a/src/hotspot/share/gc/z/zGeneration.hpp b/src/hotspot/share/gc/z/zGeneration.hpp index 3b700361460..1371865958b 100644 --- a/src/hotspot/share/gc/z/zGeneration.hpp +++ b/src/hotspot/share/gc/z/zGeneration.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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,6 +37,7 @@ #include "gc/z/zWeakRootsProcessor.hpp" #include "gc/z/zWorkers.hpp" #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" class ThreadClosure; class ZForwardingTable; @@ -70,9 +71,9 @@ protected: ZRelocate _relocate; ZRelocationSet _relocation_set; - volatile size_t _freed; - volatile size_t _promoted; - volatile size_t _compacted; + Atomic _freed; + Atomic _promoted; + Atomic _compacted; Phase _phase; uint32_t _seqnum; From 61b722d59a799ba943476a03be3a1c7649aa0c27 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Mon, 26 Jan 2026 14:45:24 +0000 Subject: [PATCH 192/328] 8374681: ZGC: Convert zJNICritical to use Atomic Reviewed-by: tschatzl, stefank --- src/hotspot/share/gc/z/zJNICritical.cpp | 33 ++++++++++++------------- src/hotspot/share/gc/z/zJNICritical.hpp | 7 +++--- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/hotspot/share/gc/z/zJNICritical.cpp b/src/hotspot/share/gc/z/zJNICritical.cpp index 28cc70cb3b5..f50cc113936 100644 --- a/src/hotspot/share/gc/z/zJNICritical.cpp +++ b/src/hotspot/share/gc/z/zJNICritical.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ #include "gc/z/zJNICritical.hpp" #include "gc/z/zLock.inline.hpp" #include "gc/z/zStat.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/thread.inline.hpp" #include "utilities/debug.hpp" @@ -46,22 +45,22 @@ static const ZStatCriticalPhase ZCriticalPhaseJNICriticalStall("JNI Critical Stall", false /* verbose */); -volatile int64_t ZJNICritical::_count; -ZConditionLock* ZJNICritical::_lock; +Atomic ZJNICritical::_count; +ZConditionLock* ZJNICritical::_lock; void ZJNICritical::initialize() { - _count = 0; + precond(_count.load_relaxed() == 0); _lock = new ZConditionLock(); } void ZJNICritical::block() { for (;;) { - const int64_t count = AtomicAccess::load_acquire(&_count); + const int64_t count = _count.load_acquire(); if (count < 0) { // Already blocked, wait until unblocked ZLocker locker(_lock); - while (AtomicAccess::load_acquire(&_count) < 0) { + while (_count.load_acquire() < 0) { _lock->wait(); } @@ -70,7 +69,7 @@ void ZJNICritical::block() { } // Increment and invert count - if (AtomicAccess::cmpxchg(&_count, count, -(count + 1)) != count) { + if (!_count.compare_set(count, -(count + 1))) { continue; } @@ -80,7 +79,7 @@ void ZJNICritical::block() { if (count != 0) { // Wait until blocked ZLocker locker(_lock); - while (AtomicAccess::load_acquire(&_count) != -1) { + while (_count.load_acquire() != -1) { _lock->wait(); } } @@ -91,18 +90,18 @@ void ZJNICritical::block() { } void ZJNICritical::unblock() { - const int64_t count = AtomicAccess::load_acquire(&_count); + const int64_t count = _count.load_acquire(); assert(count == -1, "Invalid count"); // Notify unblocked ZLocker locker(_lock); - AtomicAccess::release_store(&_count, (int64_t)0); + _count.release_store(0); _lock->notify_all(); } void ZJNICritical::enter_inner(JavaThread* thread) { for (;;) { - const int64_t count = AtomicAccess::load_acquire(&_count); + const int64_t count = _count.load_acquire(); if (count < 0) { // Wait until unblocked @@ -112,7 +111,7 @@ void ZJNICritical::enter_inner(JavaThread* thread) { ThreadBlockInVM tbivm(thread); ZLocker locker(_lock); - while (AtomicAccess::load_acquire(&_count) < 0) { + while (_count.load_acquire() < 0) { _lock->wait(); } @@ -121,7 +120,7 @@ void ZJNICritical::enter_inner(JavaThread* thread) { } // Increment count - if (AtomicAccess::cmpxchg(&_count, count, count + 1) != count) { + if (!_count.compare_set(count, count + 1)) { continue; } @@ -142,17 +141,17 @@ void ZJNICritical::enter(JavaThread* thread) { void ZJNICritical::exit_inner() { for (;;) { - const int64_t count = AtomicAccess::load_acquire(&_count); + const int64_t count = _count.load_acquire(); assert(count != 0, "Invalid count"); if (count > 0) { // No block in progress, decrement count - if (AtomicAccess::cmpxchg(&_count, count, count - 1) != count) { + if (!_count.compare_set(count, count - 1)) { continue; } } else { // Block in progress, increment count - if (AtomicAccess::cmpxchg(&_count, count, count + 1) != count) { + if (!_count.compare_set(count, count + 1)) { continue; } diff --git a/src/hotspot/share/gc/z/zJNICritical.hpp b/src/hotspot/share/gc/z/zJNICritical.hpp index d2ba80eddba..def6001ae9f 100644 --- a/src/hotspot/share/gc/z/zJNICritical.hpp +++ b/src/hotspot/share/gc/z/zJNICritical.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,14 +25,15 @@ #define SHARE_GC_Z_ZJNICRITICAL_HPP #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" class JavaThread; class ZConditionLock; class ZJNICritical : public AllStatic { private: - static volatile int64_t _count; - static ZConditionLock* _lock; + static Atomic _count; + static ZConditionLock* _lock; static void enter_inner(JavaThread* thread); static void exit_inner(); From 99b4e05d502b68844699faa025e0d5bd51135d8f Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Mon, 26 Jan 2026 15:05:24 +0000 Subject: [PATCH 193/328] 8374682: ZGC: Convert zLiveMap to use Atomic Reviewed-by: stefank, tschatzl --- src/hotspot/share/gc/z/zLiveMap.cpp | 17 ++++++++--------- src/hotspot/share/gc/z/zLiveMap.hpp | 9 +++++---- src/hotspot/share/gc/z/zLiveMap.inline.hpp | 15 +++++++-------- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/hotspot/share/gc/z/zLiveMap.cpp b/src/hotspot/share/gc/z/zLiveMap.cpp index c4ae41b0873..8b03a97e03f 100644 --- a/src/hotspot/share/gc/z/zLiveMap.cpp +++ b/src/hotspot/share/gc/z/zLiveMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ #include "gc/z/zStat.hpp" #include "gc/z/zUtils.hpp" #include "logging/log.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/debug.hpp" #include "utilities/powerOfTwo.hpp" #include "utilities/spinYield.hpp" @@ -60,18 +59,18 @@ void ZLiveMap::reset(ZGenerationId id) { // Multiple threads can enter here, make sure only one of them // resets the marking information while the others busy wait. - for (uint32_t seqnum = AtomicAccess::load_acquire(&_seqnum); + for (uint32_t seqnum = _seqnum.load_acquire(); seqnum != generation->seqnum(); - seqnum = AtomicAccess::load_acquire(&_seqnum)) { + seqnum = _seqnum.load_acquire()) { if (seqnum != seqnum_initializing) { // No one has claimed initialization of the livemap yet - if (AtomicAccess::cmpxchg(&_seqnum, seqnum, seqnum_initializing) == seqnum) { + if (_seqnum.compare_set(seqnum, seqnum_initializing)) { // This thread claimed the initialization // Reset marking information - _live_bytes = 0; - _live_objects = 0; + _live_bytes.store_relaxed(0u); + _live_objects.store_relaxed(0u); // Clear segment claimed/live bits segment_live_bits().clear(); @@ -81,13 +80,13 @@ void ZLiveMap::reset(ZGenerationId id) { // a bit is about to be set for the first time. initialize_bitmap(); - assert(_seqnum == seqnum_initializing, "Invalid"); + assert(_seqnum.load_relaxed() == seqnum_initializing, "Invalid"); // Make sure the newly reset marking information is ordered // before the update of the page seqnum, such that when the // up-to-date seqnum is load acquired, the bit maps will not // contain stale information. - AtomicAccess::release_store(&_seqnum, generation->seqnum()); + _seqnum.release_store(generation->seqnum()); break; } } diff --git a/src/hotspot/share/gc/z/zLiveMap.hpp b/src/hotspot/share/gc/z/zLiveMap.hpp index 71457d05a41..9373f6aad98 100644 --- a/src/hotspot/share/gc/z/zLiveMap.hpp +++ b/src/hotspot/share/gc/z/zLiveMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "gc/z/zBitMap.hpp" #include "gc/z/zGenerationId.hpp" #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" class ObjectClosure; @@ -41,9 +42,9 @@ private: const uint32_t _segment_size; const int _segment_shift; - volatile uint32_t _seqnum; - volatile uint32_t _live_objects; - volatile size_t _live_bytes; + Atomic _seqnum; + Atomic _live_objects; + Atomic _live_bytes; BitMap::bm_word_t _segment_live_bits; BitMap::bm_word_t _segment_claim_bits; ZBitMap _bitmap; diff --git a/src/hotspot/share/gc/z/zLiveMap.inline.hpp b/src/hotspot/share/gc/z/zLiveMap.inline.hpp index e6176b928ff..69687d0b595 100644 --- a/src/hotspot/share/gc/z/zLiveMap.inline.hpp +++ b/src/hotspot/share/gc/z/zLiveMap.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, 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,24 +31,23 @@ #include "gc/z/zGeneration.inline.hpp" #include "gc/z/zMark.hpp" #include "gc/z/zUtils.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/debug.hpp" inline void ZLiveMap::reset() { - _seqnum = 0; + _seqnum.store_relaxed(0u); } inline bool ZLiveMap::is_marked(ZGenerationId id) const { - return AtomicAccess::load_acquire(&_seqnum) == ZGeneration::generation(id)->seqnum(); + return _seqnum.load_acquire() == ZGeneration::generation(id)->seqnum(); } inline uint32_t ZLiveMap::live_objects() const { - return _live_objects; + return _live_objects.load_relaxed(); } inline size_t ZLiveMap::live_bytes() const { - return _live_bytes; + return _live_bytes.load_relaxed(); } inline const BitMapView ZLiveMap::segment_live_bits() const { @@ -116,8 +115,8 @@ inline bool ZLiveMap::set(ZGenerationId id, BitMap::idx_t index, bool finalizabl } inline void ZLiveMap::inc_live(uint32_t objects, size_t bytes) { - AtomicAccess::add(&_live_objects, objects); - AtomicAccess::add(&_live_bytes, bytes); + _live_objects.add_then_fetch(objects); + _live_bytes.add_then_fetch(bytes); } inline BitMap::idx_t ZLiveMap::segment_start(BitMap::idx_t segment) const { From 664856757405e149bb98474872938e3a62b62302 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Mon, 26 Jan 2026 15:14:42 +0000 Subject: [PATCH 194/328] 8374683: ZGC: Convert zLock to use Atomic Reviewed-by: stefank, tschatzl --- src/hotspot/share/gc/z/zLock.hpp | 9 +++++---- src/hotspot/share/gc/z/zLock.inline.hpp | 11 +++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/gc/z/zLock.hpp b/src/hotspot/share/gc/z/zLock.hpp index 640a9fb02d3..a843f2389d7 100644 --- a/src/hotspot/share/gc/z/zLock.hpp +++ b/src/hotspot/share/gc/z/zLock.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #define SHARE_GC_Z_ZLOCK_HPP #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" #include "runtime/mutex.hpp" class ZLock : public CHeapObj { @@ -39,9 +40,9 @@ public: class ZReentrantLock { private: - ZLock _lock; - Thread* volatile _owner; - uint64_t _count; + ZLock _lock; + Atomic _owner; + uint64_t _count; public: ZReentrantLock(); diff --git a/src/hotspot/share/gc/z/zLock.inline.hpp b/src/hotspot/share/gc/z/zLock.inline.hpp index edf59be5b4c..ba5d6692521 100644 --- a/src/hotspot/share/gc/z/zLock.inline.hpp +++ b/src/hotspot/share/gc/z/zLock.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ #include "gc/z/zLock.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/javaThread.hpp" #include "runtime/os.inline.hpp" #include "utilities/debug.hpp" @@ -50,11 +49,11 @@ inline ZReentrantLock::ZReentrantLock() inline void ZReentrantLock::lock() { Thread* const thread = Thread::current(); - Thread* const owner = AtomicAccess::load(&_owner); + Thread* const owner = _owner.load_relaxed(); if (owner != thread) { _lock.lock(); - AtomicAccess::store(&_owner, thread); + _owner.store_relaxed(thread); } _count++; @@ -67,14 +66,14 @@ inline void ZReentrantLock::unlock() { _count--; if (_count == 0) { - AtomicAccess::store(&_owner, (Thread*)nullptr); + _owner.store_relaxed(nullptr); _lock.unlock(); } } inline bool ZReentrantLock::is_owned() const { Thread* const thread = Thread::current(); - Thread* const owner = AtomicAccess::load(&_owner); + Thread* const owner = _owner.load_relaxed(); return owner == thread; } From f4607ed0a7ea2504c1d72dd3dab0b21e583fa0e7 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Mon, 26 Jan 2026 15:35:59 +0000 Subject: [PATCH 195/328] 8374684: ZGC: Convert zMark to use Atomic Reviewed-by: stefank, tschatzl --- src/hotspot/share/gc/z/zMark.cpp | 16 ++++++++-------- src/hotspot/share/gc/z/zMark.hpp | 7 ++++--- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/gc/z/zMark.cpp b/src/hotspot/share/gc/z/zMark.cpp index 3b247fdd35e..03701ae9998 100644 --- a/src/hotspot/share/gc/z/zMark.cpp +++ b/src/hotspot/share/gc/z/zMark.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, 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 @@ -57,7 +57,6 @@ #include "memory/iterator.inline.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/continuation.hpp" #include "runtime/handshake.hpp" #include "runtime/javaThread.hpp" @@ -152,13 +151,14 @@ void ZMark::prepare_work() { _terminate.reset(_nworkers); // Reset flush counters - _work_nproactiveflush = _work_nterminateflush = 0; + _work_nproactiveflush.store_relaxed(0u); + _work_nterminateflush.store_relaxed(0u); } void ZMark::finish_work() { // Accumulate proactive/terminate flush counters - _nproactiveflush += _work_nproactiveflush; - _nterminateflush += _work_nterminateflush; + _nproactiveflush += _work_nproactiveflush.load_relaxed(); + _nterminateflush += _work_nterminateflush.load_relaxed(); } void ZMark::follow_work_complete() { @@ -594,7 +594,7 @@ bool ZMark::flush() { } bool ZMark::try_terminate_flush() { - AtomicAccess::inc(&_work_nterminateflush); + _work_nterminateflush.add_then_fetch(1u); _terminate.set_resurrected(false); if (ZVerifyMarking) { @@ -610,12 +610,12 @@ bool ZMark::try_proactive_flush() { return false; } - if (AtomicAccess::load(&_work_nproactiveflush) == ZMarkProactiveFlushMax) { + if (_work_nproactiveflush.load_relaxed() == ZMarkProactiveFlushMax) { // Limit reached or we're trying to terminate return false; } - AtomicAccess::inc(&_work_nproactiveflush); + _work_nproactiveflush.add_then_fetch(1u); SuspendibleThreadSetLeaver sts_leaver; return flush(); diff --git a/src/hotspot/share/gc/z/zMark.hpp b/src/hotspot/share/gc/z/zMark.hpp index cc398addeb8..72a527b957d 100644 --- a/src/hotspot/share/gc/z/zMark.hpp +++ b/src/hotspot/share/gc/z/zMark.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ #include "gc/z/zMarkStackEntry.hpp" #include "gc/z/zMarkTerminate.hpp" #include "oops/oopsHierarchy.hpp" +#include "runtime/atomic.hpp" #include "utilities/globalDefinitions.hpp" class Thread; @@ -60,8 +61,8 @@ private: ZMarkingSMR _marking_smr; ZMarkStripeSet _stripes; ZMarkTerminate _terminate; - volatile size_t _work_nproactiveflush; - volatile size_t _work_nterminateflush; + Atomic _work_nproactiveflush; + Atomic _work_nterminateflush; size_t _nproactiveflush; size_t _nterminateflush; size_t _ntrycomplete; From bbae38e510efd8877daca5118f45893bb87f6eaa Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Mon, 26 Jan 2026 16:23:30 +0000 Subject: [PATCH 196/328] 8375272: [IR Framework] Miscellaneous clean-ups Reviewed-by: mchevalier, dfenacci, thartmann --- src/hotspot/share/opto/compile.cpp | 26 +++---- src/hotspot/share/opto/compile.hpp | 6 +- .../lib/ir_framework/CompilePhase.java | 4 +- .../lib/ir_framework/TestFramework.java | 14 ++-- .../ir_framework/driver/TestVMProcess.java | 3 +- .../driver/irmatching/irmethod/IRMethod.java | 16 ++--- .../irmethod/NotCompilableIRMethod.java | 5 +- .../NotCompilableIRMethodMatchResult.java | 5 +- .../parser/ApplicableIRRulesParser.java | 39 ++++++----- .../irmatching/parser/IRMethodBuilder.java | 4 +- .../driver/irmatching/parser/TestMethod.java | 7 +- .../driver/network/testvm/java/IRRuleIds.java | 68 +++++++++++++++++++ .../lib/ir_framework/test/TestVM.java | 14 ++-- .../ir_framework/tests/TestCheckedTests.java | 14 ++-- .../ir_framework/tests/TestSetupTests.java | 12 ++-- 15 files changed, 153 insertions(+), 84 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/IRRuleIds.java diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index cea2b09e142..7d99f4a7336 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -581,7 +581,7 @@ void Compile::print_phase(const char* phase_name) { tty->print_cr("%u.\t%s", ++_phase_counter, phase_name); } -void Compile::print_ideal_ir(const char* phase_name) { +void Compile::print_ideal_ir(const char* compile_phase_name) const { // keep the following output all in one block // This output goes directly to the tty, not the compiler log. // To enable tools to match it up with the compilation activity, @@ -593,7 +593,7 @@ void Compile::print_ideal_ir(const char* phase_name) { stringStream ss; if (_output == nullptr) { - ss.print_cr("AFTER: %s", phase_name); + ss.print_cr("AFTER: %s", compile_phase_name); // Print out all nodes in ascending order of index. // It is important that we traverse both inputs and outputs of nodes, // so that we reach all nodes that are connected to Root. @@ -610,7 +610,7 @@ void Compile::print_ideal_ir(const char* phase_name) { xtty->head("ideal compile_id='%d'%s compile_phase='%s'", compile_id(), is_osr_compilation() ? " compile_kind='osr'" : "", - phase_name); + compile_phase_name); } tty->print("%s", ss.as_string()); @@ -671,7 +671,7 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, _coarsened_locks(comp_arena(), 8, 0, nullptr), _congraph(nullptr), NOT_PRODUCT(_igv_printer(nullptr) COMMA) - _unique(0), + _unique(0), _dead_node_count(0), _dead_node_list(comp_arena()), _node_arena_one(mtCompiler, Arena::Tag::tag_node), @@ -865,7 +865,7 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, #ifndef PRODUCT if (should_print_ideal()) { - print_ideal_ir("print_ideal"); + print_ideal_ir("PrintIdeal"); } #endif @@ -938,7 +938,7 @@ Compile::Compile(ciEnv* ci_env, _for_merge_stores_igvn(comp_arena(), 8, 0, nullptr), _congraph(nullptr), NOT_PRODUCT(_igv_printer(nullptr) COMMA) - _unique(0), + _unique(0), _dead_node_count(0), _dead_node_list(comp_arena()), _node_arena_one(mtCompiler, Arena::Tag::tag_node), @@ -5165,17 +5165,17 @@ void Compile::sort_macro_nodes() { } } -void Compile::print_method(CompilerPhaseType cpt, int level, Node* n) { +void Compile::print_method(CompilerPhaseType compile_phase, int level, Node* n) { if (failing_internal()) { return; } // failing_internal to not stress bailouts from printing code. EventCompilerPhase event(UNTIMED); if (event.should_commit()) { - CompilerEvent::PhaseEvent::post(event, C->_latest_stage_start_counter, cpt, C->_compile_id, level); + CompilerEvent::PhaseEvent::post(event, C->_latest_stage_start_counter, compile_phase, C->_compile_id, level); } #ifndef PRODUCT ResourceMark rm; stringStream ss; - ss.print_raw(CompilerPhaseTypeHelper::to_description(cpt)); - int iter = ++_igv_phase_iter[cpt]; + ss.print_raw(CompilerPhaseTypeHelper::to_description(compile_phase)); + int iter = ++_igv_phase_iter[compile_phase]; if (iter > 1) { ss.print(" %d", iter); } @@ -5203,8 +5203,8 @@ void Compile::print_method(CompilerPhaseType cpt, int level, Node* n) { if (should_print_phase(level)) { print_phase(name); } - if (should_print_ideal_phase(cpt)) { - print_ideal_ir(CompilerPhaseTypeHelper::to_name(cpt)); + if (should_print_ideal_phase(compile_phase)) { + print_ideal_ir(CompilerPhaseTypeHelper::to_name(compile_phase)); } #endif C->_latest_stage_start_counter.stamp(); diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 45a3a4f548f..12812424f5e 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -666,7 +666,7 @@ public: uint next_igv_idx() { return _igv_idx++; } bool trace_opto_output() const { return _trace_opto_output; } void print_phase(const char* phase_name); - void print_ideal_ir(const char* phase_name); + void print_ideal_ir(const char* compile_phase_name) const; bool should_print_ideal() const { return _directive->PrintIdealOption; } bool parsed_irreducible_loop() const { return _parsed_irreducible_loop; } void set_parsed_irreducible_loop(bool z) { _parsed_irreducible_loop = z; } @@ -680,7 +680,7 @@ public: void begin_method(); void end_method(); - void print_method(CompilerPhaseType cpt, int level, Node* n = nullptr); + void print_method(CompilerPhaseType compile_phase, int level, Node* n = nullptr); #ifndef PRODUCT bool should_print_igv(int level); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java b/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java index a536808d269..1e3ba7c314e 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, 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 @@ -161,7 +161,7 @@ public enum CompilePhase { static { for (CompilePhase phase : CompilePhase.values()) { if (phase == PRINT_IDEAL) { - PHASES_BY_PARSED_NAME.put("print_ideal", phase); + PHASES_BY_PARSED_NAME.put("PrintIdeal", phase); } else { PHASES_BY_PARSED_NAME.put(phase.name(), phase); } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java index 1fea5da52ef..137efd18136 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java @@ -183,7 +183,7 @@ public class TestFramework { private List flags; private int defaultWarmup = -1; private boolean testClassesOnBootClassPath; - private boolean isAllowNotCompilable = false; + private boolean allowNotCompilable = false; /* * Public interface methods @@ -498,7 +498,7 @@ public class TestFramework { * and else it is ignored silently. */ public TestFramework allowNotCompilable() { - this.isAllowNotCompilable = true; + this.allowNotCompilable = true; return this; } @@ -721,7 +721,7 @@ public class TestFramework { nonWhiteListedFlags.forEach((f) -> System.out.println(" - " + f)); } - System.out.println(""); + System.out.println(); } /** @@ -860,8 +860,8 @@ public class TestFramework { private List anyNonWhitelistedJTregVMAndJavaOptsFlags() { List flags = Arrays.stream(Utils.getTestJavaOpts()) .map(s -> s.replaceFirst("-XX:[+|-]?|-(?=[^D|^e])", "")) - .collect(Collectors.toList()); - List nonWhiteListedFlags = new ArrayList(); + .toList(); + List nonWhiteListedFlags = new ArrayList<>(); for (String flag : flags) { if (flag.contains("agentpath")) { throw new SkippedException("Can't run test with -javaagent"); @@ -877,10 +877,10 @@ public class TestFramework { private void runTestVM(List additionalFlags) { TestVMProcess testVMProcess = new TestVMProcess(additionalFlags, testClass, helperClasses, defaultWarmup, - isAllowNotCompilable, testClassesOnBootClassPath); + allowNotCompilable, testClassesOnBootClassPath); if (shouldVerifyIR) { try { - TestClassParser testClassParser = new TestClassParser(testClass, isAllowNotCompilable); + TestClassParser testClassParser = new TestClassParser(testClass, allowNotCompilable); Matchable testClassMatchable = testClassParser.parse(testVMProcess.getHotspotPidFileName(), testVMProcess.getApplicableIRRules()); IRMatcher matcher = new IRMatcher(testClassMatchable); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java index a172dce1991..931d687b0bc 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java @@ -38,7 +38,6 @@ import java.io.File; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; /** * This class prepares, creates, and runs the Test VM with verification of proper termination. The class also stores @@ -108,7 +107,7 @@ public class TestVMProcess { cmds.add("-XX:+UnlockDiagnosticVMOptions"); cmds.add("-XX:+WhiteBoxAPI"); // Ignore CompileCommand flags which have an impact on the profiling information. - List jtregVMFlags = Arrays.stream(Utils.getTestJavaOpts()).filter(s -> !s.contains("CompileThreshold")).collect(Collectors.toList()); + List jtregVMFlags = Arrays.stream(Utils.getTestJavaOpts()).filter(s -> !s.contains("CompileThreshold")).toList(); if (!PREFER_COMMAND_LINE_FLAGS) { cmds.addAll(jtregVMFlags); } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/IRMethod.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/IRMethod.java index 714af5c6519..893312c5196 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/IRMethod.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/IRMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import compiler.lib.ir_framework.driver.irmatching.Matchable; import compiler.lib.ir_framework.driver.irmatching.MatchableMatcher; import compiler.lib.ir_framework.driver.irmatching.irrule.IRRule; import compiler.lib.ir_framework.driver.irmatching.parser.VMInfo; +import compiler.lib.ir_framework.driver.network.testvm.java.IRRuleIds; import compiler.lib.ir_framework.shared.TestFormat; import compiler.lib.ir_framework.shared.TestFormatException; @@ -53,14 +54,14 @@ public class IRMethod implements IRMethodMatchable { private final Method method; private final MatchableMatcher matcher; - public IRMethod(Method method, int[] ruleIds, IR[] irAnnos, Compilation compilation, VMInfo vmInfo) { + public IRMethod(Method method, IRRuleIds irRuleIds, IR[] irAnnos, Compilation compilation, VMInfo vmInfo) { this.method = method; - this.matcher = new MatchableMatcher(createIRRules(method, ruleIds, irAnnos, compilation, vmInfo)); + this.matcher = new MatchableMatcher(createIRRules(method, irRuleIds, irAnnos, compilation, vmInfo)); } - private List createIRRules(Method method, int[] ruleIds, IR[] irAnnos, Compilation compilation, VMInfo vmInfo) { + private List createIRRules(Method method, IRRuleIds irRuleIds, IR[] irAnnos, Compilation compilation, VMInfo vmInfo) { List irRules = new ArrayList<>(); - for (int ruleId : ruleIds) { + for (int ruleId : irRuleIds) { try { irRules.add(new IRRule(ruleId, irAnnos[ruleId - 1], compilation, vmInfo)); } catch (TestFormatException e) { @@ -89,13 +90,12 @@ public class IRMethod implements IRMethodMatchable { return new IRMethodMatchResult(method, matcher.match()); } - List match; for (int i = 0; i < 10; i++) { // warm up - match = matcher.match(); + matcher.match(); } long startTime = System.nanoTime(); - match = matcher.match(); + List match = matcher.match(); long endTime = System.nanoTime(); long duration = (endTime - startTime); System.out.println("Verifying IR rules for " + name() + ": " + duration + " ns = " + (duration / 1000000) + " ms"); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NotCompilableIRMethod.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NotCompilableIRMethod.java index d74825c8d4f..cb99ea219fe 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NotCompilableIRMethod.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NotCompilableIRMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,7 @@ package compiler.lib.ir_framework.driver.irmatching.irmethod; import compiler.lib.ir_framework.IR; -import compiler.lib.ir_framework.Run; -import compiler.lib.ir_framework.RunMode; +import compiler.lib.ir_framework.Test; import java.lang.reflect.Method; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NotCompilableIRMethodMatchResult.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NotCompilableIRMethodMatchResult.java index 011b596cc9e..bea8dc3ab27 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NotCompilableIRMethodMatchResult.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NotCompilableIRMethodMatchResult.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,7 @@ package compiler.lib.ir_framework.driver.irmatching.irmethod; -import compiler.lib.ir_framework.Run; -import compiler.lib.ir_framework.RunMode; +import compiler.lib.ir_framework.Test; import compiler.lib.ir_framework.driver.irmatching.MatchResult; import compiler.lib.ir_framework.driver.irmatching.visitor.MatchResultVisitor; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/ApplicableIRRulesParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/ApplicableIRRulesParser.java index 7aaf0c2b285..be44c3f3d91 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/ApplicableIRRulesParser.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/ApplicableIRRulesParser.java @@ -26,12 +26,15 @@ package compiler.lib.ir_framework.driver.irmatching.parser; import compiler.lib.ir_framework.IR; import compiler.lib.ir_framework.TestFramework; import compiler.lib.ir_framework.driver.irmatching.parser.hotspot.HotSpotPidFileParser; +import compiler.lib.ir_framework.driver.network.testvm.java.IRRuleIds; import compiler.lib.ir_framework.shared.TestFormat; import compiler.lib.ir_framework.shared.TestFrameworkException; import compiler.lib.ir_framework.test.ApplicableIRRulesPrinter; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -75,15 +78,15 @@ public class ApplicableIRRulesParser { * assembly output in {@link HotSpotPidFileParser}. */ private void createTestMethodMap(String applicableIRRules, Class testClass) { - Map irRulesMap = parseApplicableIRRules(applicableIRRules); + Map irRulesMap = parseApplicableIRRules(applicableIRRules); createTestMethodsWithApplicableIRRules(testClass, irRulesMap); } /** * Read the Applicable IR Rules emitted by the Test VM to decide if an @IR rule must be checked for a method. */ - private Map parseApplicableIRRules(String applicableIRRules) { - Map irRulesMap = new HashMap<>(); + private Map parseApplicableIRRules(String applicableIRRules) { + Map irRulesMap = new HashMap<>(); String[] applicableIRRulesLines = getApplicableIRRulesLines(applicableIRRules); for (String s : applicableIRRulesLines) { String line = s.trim(); @@ -92,8 +95,8 @@ public class ApplicableIRRulesParser { throw new TestFrameworkException("Invalid Applicable IR Rules format. No comma found: " + splitLine[0]); } String testName = splitLine[0]; - int[] irRulesIdx = getRuleIndexes(splitLine); - irRulesMap.put(testName, irRulesIdx); + IRRuleIds irRuleIds = parseIrRulesIds(splitLine); + irRulesMap.put(testName, irRuleIds); } return irRulesMap; } @@ -116,24 +119,24 @@ public class ApplicableIRRulesParser { /** * Parse rule indexes from a single line of the Applicable IR Rules in the format: */ - private int[] getRuleIndexes(String[] splitLine) { - int[] irRulesIdx = new int[splitLine.length - 1]; + private IRRuleIds parseIrRulesIds(String[] splitLine) { + List irRuleIds = new ArrayList<>(); for (int i = 1; i < splitLine.length; i++) { try { - irRulesIdx[i - 1] = Integer.parseInt(splitLine[i]); + irRuleIds.add(Integer.parseInt(splitLine[i])); } catch (NumberFormatException e) { throw new TestFrameworkException("Invalid Applicable IR Rules format. No number found: " + splitLine[i]); } } - return irRulesIdx; + return new IRRuleIds(irRuleIds); } - private void createTestMethodsWithApplicableIRRules(Class testClass, Map irRulesMap) { + private void createTestMethodsWithApplicableIRRules(Class testClass, Map irRulesMap) { for (Method m : testClass.getDeclaredMethods()) { IR[] irAnnos = m.getAnnotationsByType(IR.class); if (irAnnos.length > 0) { // Validation of legal @IR attributes and placement of the annotation was already done in Test VM. - int[] irRuleIds = irRulesMap.get(m.getName()); + IRRuleIds irRuleIds = irRulesMap.get(m.getName()); validateIRRuleIds(m, irAnnos, irRuleIds); if (hasAnyApplicableIRRules(irRuleIds)) { testMethods.put(m.getName(), new TestMethod(m, irAnnos, irRuleIds)); @@ -142,18 +145,18 @@ public class ApplicableIRRulesParser { } } - private void validateIRRuleIds(Method m, IR[] irAnnos, int[] ids) { - TestFramework.check(ids != null, "Should find method name in validIrRulesMap for " + m); - TestFramework.check(ids.length > 0, "Did not find any rule indices for " + m); - TestFramework.check((ids[0] >= 1 || ids[0] == ApplicableIRRulesPrinter.NO_RULE_APPLIED) - && ids[ids.length - 1] <= irAnnos.length, + private void validateIRRuleIds(Method m, IR[] irAnnos, IRRuleIds irRuleIds) { + TestFramework.check(irRuleIds != null, "Should find method name in validIrRulesMap for " + m); + TestFramework.check(!irRuleIds.isEmpty(), "Did not find any rule indices for " + m); + TestFramework.check((irRuleIds.first() >= 1 || irRuleIds.first() == ApplicableIRRulesPrinter.NO_RULE_APPLIED) + && irRuleIds.last() <= irAnnos.length, "Invalid IR rule index found in validIrRulesMap for " + m); } /** * Does the list of IR rules contain any applicable IR rules for the given conditions? */ - private boolean hasAnyApplicableIRRules(int[] irRuleIds) { - return irRuleIds[0] != ApplicableIRRulesPrinter.NO_RULE_APPLIED; + private boolean hasAnyApplicableIRRules(IRRuleIds irRuleIds) { + return irRuleIds.first() != ApplicableIRRulesPrinter.NO_RULE_APPLIED; } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodBuilder.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodBuilder.java index d7a10acd1cd..46a237576e6 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodBuilder.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodBuilder.java @@ -71,9 +71,9 @@ class IRMethodBuilder { Test[] testAnnos = testMethod.method().getAnnotationsByType(Test.class); boolean allowMethodNotCompilable = allowNotCompilable || testAnnos[0].allowNotCompilable(); if (allowMethodNotCompilable) { - return new NotCompilableIRMethod(testMethod.method(), testMethod.irRuleIds().length); + return new NotCompilableIRMethod(testMethod.method(), testMethod.irRuleIds().count()); } else { - return new NotCompiledIRMethod(testMethod.method(), testMethod.irRuleIds().length); + return new NotCompiledIRMethod(testMethod.method(), testMethod.irRuleIds().count()); } } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethod.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethod.java index 43f27c80ac6..37989d8810b 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethod.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethod.java @@ -26,6 +26,7 @@ package compiler.lib.ir_framework.driver.irmatching.parser; import compiler.lib.ir_framework.IR; import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod; import compiler.lib.ir_framework.driver.irmatching.parser.hotspot.LoggedMethod; +import compiler.lib.ir_framework.driver.network.testvm.java.IRRuleIds; import java.lang.reflect.Method; @@ -40,9 +41,9 @@ import java.lang.reflect.Method; public class TestMethod { private final Method method; private final IR[] irAnnos; - private final int[] irRuleIds; + private final IRRuleIds irRuleIds; - public TestMethod(Method m, IR[] irAnnos, int[] irRuleIds) { + public TestMethod(Method m, IR[] irAnnos, IRRuleIds irRuleIds) { this.method = m; this.irAnnos = irAnnos; this.irRuleIds = irRuleIds; @@ -56,7 +57,7 @@ public class TestMethod { return irAnnos; } - public int[] irRuleIds() { + public IRRuleIds irRuleIds() { return irRuleIds; } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/IRRuleIds.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/IRRuleIds.java new file mode 100644 index 00000000000..b8ea1765b4f --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/IRRuleIds.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2026, 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.ir_framework.driver.network.testvm.java; + +import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Stream; + +/** + * Class to hold the indices of the applicable {@link IR @IR} rules of an {@link IRMethod}. + */ +public class IRRuleIds implements Iterable { + private final List ruleIds; + + public IRRuleIds(List ruleIds) { + this.ruleIds = ruleIds; + } + + public int first() { + return ruleIds.getFirst(); + } + + public int last() { + return ruleIds.getLast(); + } + + public boolean isEmpty() { + return ruleIds.isEmpty(); + } + + public int count() { + return ruleIds.size(); + } + + @Override + public Iterator iterator() { + return ruleIds.iterator(); + } + + public Stream stream() { + return ruleIds.stream(); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java index c5ab318d67d..c2580e087f0 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java @@ -92,7 +92,7 @@ public class TestVM { static final boolean XCOMP = Platform.isComp(); static final boolean VERBOSE = Boolean.getBoolean("Verbose"); - private static final boolean PRINT_TIMES = Boolean.getBoolean("PrintTimes"); + private static final boolean PRINT_TIMES = Boolean.getBoolean("PrintTimes") || VERBOSE; public static final boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler"); static final boolean EXCLUDE_RANDOM = Boolean.getBoolean("ExcludeRandom"); private static final String TESTLIST = System.getProperty("Test", ""); @@ -823,14 +823,14 @@ public class TestVM { forceCompileMap.forEach((key, value) -> builder.append("- ").append(key).append(" at CompLevel.").append(value) .append(System.lineSeparator())); throw new TestRunException("Could not force compile the following @ForceCompile methods:" - + System.lineSeparator() + builder.toString()); + + System.lineSeparator() + builder); } /** * Once all framework tests are collected, they are run in this method. */ private void runTests() { - TreeMap durations = (PRINT_TIMES || VERBOSE) ? new TreeMap<>() : null; + TreeMap durations = PRINT_TIMES ? new TreeMap<>() : null; long startTime = System.nanoTime(); List testList; boolean testFilterPresent = testFilterPresent(); @@ -867,11 +867,11 @@ public class TestVM { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); - builder.append(test.toString()).append(":").append(System.lineSeparator()).append(sw.toString()) + builder.append(test).append(":").append(System.lineSeparator()).append(sw) .append(System.lineSeparator()).append(System.lineSeparator()); failures++; } - if (PRINT_TIMES || VERBOSE) { + if (PRINT_TIMES) { long endTime = System.nanoTime(); long duration = (endTime - startTime); durations.put(duration, test.getName()); @@ -886,7 +886,7 @@ public class TestVM { } // Print execution times - if (VERBOSE || PRINT_TIMES) { + if (PRINT_TIMES) { TestFrameworkSocket.write("Test execution times:", PRINT_TIMES_TAG, true); for (Map.Entry entry : durations.entrySet()) { TestFrameworkSocket.write(String.format("%-25s%15d ns%n", entry.getValue() + ":", entry.getKey()), @@ -898,7 +898,7 @@ public class TestVM { // Finally, report all occurred exceptions in a nice format. String msg = System.lineSeparator() + System.lineSeparator() + "Test Failures (" + failures + ")" + System.lineSeparator() + "----------------" + "-".repeat(String.valueOf(failures).length()); - throw new TestRunException(msg + System.lineSeparator() + builder.toString()); + throw new TestRunException(msg + System.lineSeparator() + builder); } } diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java index 5b7cd3c38a8..d4c12de3e4b 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -180,6 +180,12 @@ class BadIRAndRuntimeCheckedTests { throw new BadCheckedTestException("expected"); } } + + static class BadCheckedTestException extends RuntimeException { + BadCheckedTestException(String s) { + super(s); + } + } } class BadIRCheckedTests { @@ -224,9 +230,3 @@ class BadIRCheckedTests { } } } - -class BadCheckedTestException extends RuntimeException { - BadCheckedTestException(String s) { - super(s); - } -} diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestSetupTests.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestSetupTests.java index 782a773515a..1cdb6c2797a 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestSetupTests.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestSetupTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package ir_framework.tests; import compiler.lib.ir_framework.*; import compiler.lib.ir_framework.driver.TestVMException; -import compiler.lib.ir_framework.shared.TestRunException; import java.io.ByteArrayOutputStream; import java.io.PrintStream; @@ -360,10 +359,11 @@ class TestSetupTestsWithExpectedExceptions { public void checkThrowInCheck(int x) { throw new BadCheckedTestException("expected check"); } -} -class BadCheckedTestException extends RuntimeException { - BadCheckedTestException(String s) { - super(s); + + static class BadCheckedTestException extends RuntimeException { + BadCheckedTestException(String s) { + super(s); + } } } From 67beb9cd812db2af49c62c95d69f2f27d0a20af8 Mon Sep 17 00:00:00 2001 From: Henry Jen Date: Mon, 26 Jan 2026 16:38:12 +0000 Subject: [PATCH 197/328] 8373924: Remove unreferenced ImageDecompressor::image_decompressor_close Reviewed-by: alanb --- src/java.base/share/native/libjimage/imageDecompressor.cpp | 6 +----- src/java.base/share/native/libjimage/imageDecompressor.hpp | 5 +++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/native/libjimage/imageDecompressor.cpp b/src/java.base/share/native/libjimage/imageDecompressor.cpp index 748bbf8203f..4946e645c55 100644 --- a/src/java.base/share/native/libjimage/imageDecompressor.cpp +++ b/src/java.base/share/native/libjimage/imageDecompressor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -85,10 +85,6 @@ void ImageDecompressor::image_decompressor_init() { } } -void ImageDecompressor::image_decompressor_close() { - delete[] _decompressors; -} - /* * Locate decompressor. */ diff --git a/src/java.base/share/native/libjimage/imageDecompressor.hpp b/src/java.base/share/native/libjimage/imageDecompressor.hpp index 16f354935c3..057fa15917c 100644 --- a/src/java.base/share/native/libjimage/imageDecompressor.hpp +++ b/src/java.base/share/native/libjimage/imageDecompressor.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -105,6 +105,7 @@ private: protected: ImageDecompressor(const char* name) : _name(name) { } + virtual void decompress_resource(u1* data, u1* uncompressed, ResourceHeader* header, const ImageStrings* strings) = 0; @@ -166,6 +167,6 @@ private: public: SharedStringDecompressor(const char* sym) : ImageDecompressor(sym){} void decompress_resource(u1* data, u1* uncompressed, ResourceHeader* header, - const ImageStrings* strings); + const ImageStrings* strings); }; #endif // LIBJIMAGE_IMAGEDECOMPRESSOR_HPP From b42861a2aa5bf5fde348cf17c5e40134148de1b4 Mon Sep 17 00:00:00 2001 From: Henry Jen Date: Mon, 26 Jan 2026 17:19:44 +0000 Subject: [PATCH 198/328] 8373699: JLink: ModuleReader should be closed in JlinkTask.getReleaseInfo(mref) Reviewed-by: alanb --- .../share/classes/jdk/tools/jlink/internal/JlinkTask.java | 6 +++--- 1 file changed, 3 insertions(+), 3 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 825672cfe6d..3baae08eed6 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, 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 @@ -248,8 +248,8 @@ public class JlinkTask { * Read the release.txt from the module. */ private static Optional getReleaseInfo(ModuleReference mref) { - try { - Optional release = mref.open().open(JDK_RELEASE_RESOURCE); + try (var moduleReader = mref.open()) { + Optional release = moduleReader.open(JDK_RELEASE_RESOURCE); if (release.isEmpty()) { return Optional.empty(); From 3220c4cb431a2c4eb8bb2d60f0d5046e40af69bd Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Mon, 26 Jan 2026 18:32:15 +0000 Subject: [PATCH 199/328] 8372696: Allow boot classes to explicitly opt-in for final field trusting Reviewed-by: jvernee, jrose, alanb --- src/hotspot/share/ci/ciField.cpp | 12 ++-- src/hotspot/share/ci/ciInstanceKlass.cpp | 1 + src/hotspot/share/ci/ciInstanceKlass.hpp | 5 ++ .../share/classfile/classFileParser.cpp | 9 +++ src/hotspot/share/classfile/vmSymbols.hpp | 5 +- src/hotspot/share/oops/instanceKlass.hpp | 3 + src/hotspot/share/oops/instanceKlassFlags.hpp | 1 + .../share/classes/java/util/Optional.java | 4 +- .../atomic/AtomicIntegerFieldUpdater.java | 3 + .../atomic/AtomicLongFieldUpdater.java | 3 + .../atomic/AtomicReferenceFieldUpdater.java | 3 + .../vm/annotation/TrustFinalFields.java | 57 +++++++++++++++++ .../jtreg/compiler/corelibs/OptionalFold.java | 63 +++++++++++++++++++ 13 files changed, 155 insertions(+), 14 deletions(-) create mode 100644 src/java.base/share/classes/jdk/internal/vm/annotation/TrustFinalFields.java create mode 100644 test/hotspot/jtreg/compiler/corelibs/OptionalFold.java diff --git a/src/hotspot/share/ci/ciField.cpp b/src/hotspot/share/ci/ciField.cpp index 19e05784f4d..e0c818f02fc 100644 --- a/src/hotspot/share/ci/ciField.cpp +++ b/src/hotspot/share/ci/ciField.cpp @@ -216,6 +216,10 @@ ciField::ciField(fieldDescriptor *fd) : static bool trust_final_non_static_fields(ciInstanceKlass* holder) { if (holder == nullptr) return false; + if (holder->trust_final_fields()) { + // Explicit opt-in from system classes + return true; + } // Even if general trusting is disabled, trust system-built closures in these packages. if (holder->is_in_package("java/lang/invoke") || holder->is_in_package("sun/invoke") || holder->is_in_package("java/lang/reflect") || holder->is_in_package("jdk/internal/reflect") || @@ -230,14 +234,6 @@ static bool trust_final_non_static_fields(ciInstanceKlass* holder) { // Trust final fields in records if (holder->is_record()) return true; - // Trust Atomic*FieldUpdaters: they are very important for performance, and make up one - // more reason not to use Unsafe, if their final fields are trusted. See more in JDK-8140483. - if (holder->name() == ciSymbols::java_util_concurrent_atomic_AtomicIntegerFieldUpdater_Impl() || - holder->name() == ciSymbols::java_util_concurrent_atomic_AtomicLongFieldUpdater_CASUpdater() || - holder->name() == ciSymbols::java_util_concurrent_atomic_AtomicLongFieldUpdater_LockedUpdater() || - holder->name() == ciSymbols::java_util_concurrent_atomic_AtomicReferenceFieldUpdater_Impl()) { - return true; - } return TrustFinalNonStaticFields; } diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp index 64b9acf9146..33bcabc4566 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.cpp +++ b/src/hotspot/share/ci/ciInstanceKlass.cpp @@ -65,6 +65,7 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) : _has_nonstatic_concrete_methods = ik->has_nonstatic_concrete_methods(); _is_hidden = ik->is_hidden(); _is_record = ik->is_record(); + _trust_final_fields = ik->trust_final_fields(); _nonstatic_fields = nullptr; // initialized lazily by compute_nonstatic_fields: _has_injected_fields = -1; _implementor = nullptr; // we will fill these lazily diff --git a/src/hotspot/share/ci/ciInstanceKlass.hpp b/src/hotspot/share/ci/ciInstanceKlass.hpp index a1b2d8dd12d..8ccf1fadfb7 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.hpp +++ b/src/hotspot/share/ci/ciInstanceKlass.hpp @@ -59,6 +59,7 @@ private: bool _has_nonstatic_concrete_methods; bool _is_hidden; bool _is_record; + bool _trust_final_fields; bool _has_trusted_loader; ciFlags _flags; @@ -207,6 +208,10 @@ public: return _is_record; } + bool trust_final_fields() const { + return _trust_final_fields; + } + ciInstanceKlass* get_canonical_holder(int offset); ciField* get_field_by_offset(int field_offset, bool is_static); ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static); diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index c9d9d3632b5..817d0c64d11 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -943,6 +943,7 @@ public: _java_lang_Deprecated_for_removal, _jdk_internal_vm_annotation_AOTSafeClassInitializer, _method_AOTRuntimeSetup, + _jdk_internal_vm_annotation_TrustFinalFields, _annotation_LIMIT }; const Location _location; @@ -1878,6 +1879,11 @@ AnnotationCollector::annotation_index(const ClassLoaderData* loader_data, if (!privileged) break; // only allow in privileged code return _field_Stable; } + case VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_TrustFinalFields_signature): { + if (_location != _in_class) break; // only allow for classes + if (!privileged) break; // only allow in privileged code + return _jdk_internal_vm_annotation_TrustFinalFields; + } case VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_Contended_signature): { if (_location != _in_field && _location != _in_class) { break; // only allow for fields and classes @@ -1992,6 +1998,9 @@ void ClassFileParser::ClassAnnotationCollector::apply_to(InstanceKlass* ik) { if (has_annotation(_jdk_internal_vm_annotation_AOTSafeClassInitializer)) { ik->set_has_aot_safe_initializer(); } + if (has_annotation(_jdk_internal_vm_annotation_TrustFinalFields)) { + ik->set_trust_final_fields(true); + } } #define MAX_ARGS_SIZE 255 diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 8388b98faae..79646f24d0e 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -245,10 +245,6 @@ class SerializeClosure; \ /* Concurrency support */ \ template(java_util_concurrent_locks_AbstractOwnableSynchronizer, "java/util/concurrent/locks/AbstractOwnableSynchronizer") \ - template(java_util_concurrent_atomic_AtomicIntegerFieldUpdater_Impl, "java/util/concurrent/atomic/AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl") \ - template(java_util_concurrent_atomic_AtomicLongFieldUpdater_CASUpdater, "java/util/concurrent/atomic/AtomicLongFieldUpdater$CASUpdater") \ - template(java_util_concurrent_atomic_AtomicLongFieldUpdater_LockedUpdater, "java/util/concurrent/atomic/AtomicLongFieldUpdater$LockedUpdater") \ - template(java_util_concurrent_atomic_AtomicReferenceFieldUpdater_Impl, "java/util/concurrent/atomic/AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl") \ template(jdk_internal_vm_annotation_Contended_signature, "Ljdk/internal/vm/annotation/Contended;") \ template(jdk_internal_vm_annotation_ReservedStackAccess_signature, "Ljdk/internal/vm/annotation/ReservedStackAccess;") \ template(jdk_internal_ValueBased_signature, "Ljdk/internal/ValueBased;") \ @@ -302,6 +298,7 @@ class SerializeClosure; template(jdk_internal_misc_Scoped_signature, "Ljdk/internal/misc/ScopedMemoryAccess$Scoped;") \ template(jdk_internal_vm_annotation_IntrinsicCandidate_signature, "Ljdk/internal/vm/annotation/IntrinsicCandidate;") \ template(jdk_internal_vm_annotation_Stable_signature, "Ljdk/internal/vm/annotation/Stable;") \ + template(jdk_internal_vm_annotation_TrustFinalFields_signature, "Ljdk/internal/vm/annotation/TrustFinalFields;") \ \ template(jdk_internal_vm_annotation_ChangesCurrentThread_signature, "Ljdk/internal/vm/annotation/ChangesCurrentThread;") \ template(jdk_internal_vm_annotation_JvmtiHideEvents_signature, "Ljdk/internal/vm/annotation/JvmtiHideEvents;") \ diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 23a59d26093..e370a3b7a7c 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -353,6 +353,9 @@ class InstanceKlass: public Klass { int static_oop_field_count() const { return (int)_static_oop_field_count; } void set_static_oop_field_count(u2 size) { _static_oop_field_count = size; } + bool trust_final_fields() { return _misc_flags.trust_final_fields(); } + void set_trust_final_fields(bool value) { _misc_flags.set_trust_final_fields(value); } + // Java itable int itable_length() const { return _itable_len; } void set_itable_length(int len) { _itable_len = len; } diff --git a/src/hotspot/share/oops/instanceKlassFlags.hpp b/src/hotspot/share/oops/instanceKlassFlags.hpp index 5eebaab27d1..d576805b30f 100644 --- a/src/hotspot/share/oops/instanceKlassFlags.hpp +++ b/src/hotspot/share/oops/instanceKlassFlags.hpp @@ -54,6 +54,7 @@ class InstanceKlassFlags { flag(has_localvariable_table , 1 << 11) /* has localvariable information */ \ flag(has_miranda_methods , 1 << 12) /* True if this class has miranda methods in it's vtable */ \ flag(has_final_method , 1 << 13) /* True if klass has final method */ \ + flag(trust_final_fields , 1 << 14) /* All instance final fields in this class should be trusted */ \ /* end of list */ #define IK_FLAGS_ENUM_NAME(name, value) _misc_##name = value, diff --git a/src/java.base/share/classes/java/util/Optional.java b/src/java.base/share/classes/java/util/Optional.java index 3e577bd379c..3d0375c4354 100644 --- a/src/java.base/share/classes/java/util/Optional.java +++ b/src/java.base/share/classes/java/util/Optional.java @@ -25,7 +25,7 @@ package java.util; -import jdk.internal.vm.annotation.Stable; +import jdk.internal.vm.annotation.TrustFinalFields; import java.util.function.Consumer; import java.util.function.Function; @@ -62,6 +62,7 @@ import java.util.stream.Stream; * @since 1.8 */ @jdk.internal.ValueBased +@TrustFinalFields public final class Optional { /** * Common instance for {@code empty()}. @@ -71,7 +72,6 @@ public final class Optional { /** * If non-null, the value; if null, indicates no value is present */ - @Stable private final T value; /** diff --git a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java index 2250009e8f5..70acb8a0889 100644 --- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java +++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java @@ -42,6 +42,8 @@ import java.util.function.IntUnaryOperator; import jdk.internal.misc.Unsafe; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; +import jdk.internal.vm.annotation.TrustFinalFields; + import java.lang.invoke.VarHandle; /** @@ -371,6 +373,7 @@ public abstract class AtomicIntegerFieldUpdater { /** * Standard hotspot implementation using intrinsics. */ + @TrustFinalFields private static final class AtomicIntegerFieldUpdaterImpl extends AtomicIntegerFieldUpdater { private static final Unsafe U = Unsafe.getUnsafe(); diff --git a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java index 5f0a666cb04..d3a3fe63d0f 100644 --- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java +++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java @@ -42,6 +42,8 @@ import java.util.function.LongUnaryOperator; import jdk.internal.misc.Unsafe; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; +import jdk.internal.vm.annotation.TrustFinalFields; + import java.lang.invoke.VarHandle; /** @@ -368,6 +370,7 @@ public abstract class AtomicLongFieldUpdater { return next; } + @TrustFinalFields private static final class CASUpdater extends AtomicLongFieldUpdater { private static final Unsafe U = Unsafe.getUnsafe(); private final long offset; diff --git a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java index 4a758f77a47..3d47e8e323a 100644 --- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java +++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java @@ -42,6 +42,8 @@ import java.util.function.UnaryOperator; import jdk.internal.misc.Unsafe; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; +import jdk.internal.vm.annotation.TrustFinalFields; + import java.lang.invoke.VarHandle; /** @@ -312,6 +314,7 @@ public abstract class AtomicReferenceFieldUpdater { return next; } + @TrustFinalFields private static final class AtomicReferenceFieldUpdaterImpl extends AtomicReferenceFieldUpdater { private static final Unsafe U = Unsafe.getUnsafe(); diff --git a/src/java.base/share/classes/jdk/internal/vm/annotation/TrustFinalFields.java b/src/java.base/share/classes/jdk/internal/vm/annotation/TrustFinalFields.java new file mode 100644 index 00000000000..a94f58159a2 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/vm/annotation/TrustFinalFields.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.vm.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/// Indicates all instance final fields declared in the annotated class should +/// be trusted as constants by compilers in `ciField::is_constant`. +/// +/// The compiler already treats static final fields and instance final fields in +/// record classes and hidden classes as constant. All classes in select +/// packages (Defined in `trust_final_non_static_fields` in `ciField.cpp`) in +/// the boot class loader also have their instance final fields trusted. This +/// annotation is not necessary in these cases. +/// +/// The [Stable] annotation treats fields as constants once they are not the +/// zero or null value. In comparison, a non-stable final instance field +/// trusted by this annotation can treat zero and null values as constants. +/// +/// This annotation is suitable when constant treatment of final fields is +/// performance sensitive, yet package-wide final field constant treatment may +/// be at risk from final field modifications such as serialization. +/// +/// This annotation is only recognized on classes from the boot and platform +/// class loaders and is ignored elsewhere. +/// +/// @since 26 +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface TrustFinalFields { +} diff --git a/test/hotspot/jtreg/compiler/corelibs/OptionalFold.java b/test/hotspot/jtreg/compiler/corelibs/OptionalFold.java new file mode 100644 index 00000000000..0661a2e37e6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/corelibs/OptionalFold.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.corelibs; + +import java.util.Optional; + +import compiler.lib.ir_framework.Check; +import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.IRNode; +import compiler.lib.ir_framework.Test; +import compiler.lib.ir_framework.TestFramework; + +/* + * @test + * @bug 8372696 + * @summary Verify constant folding for Optional, both present and absent + * @library /test/lib / + * @run driver ${test.main.class} + */ +public class OptionalFold { + + public static void main(String[] args) { + TestFramework.run(); + } + + // Ensure both present and empty values can fold + static final Optional ONE = Optional.of(5), TWO = Optional.empty(); + + @Test + @IR(failOn = {IRNode.ADD_I}) + public int testSum() { + return ONE.orElse(7) + TWO.orElse(12); + } + + @Check(test = "testSum") + public void checkTestSum(int res) { + if (res != 5 + 12) { + throw new RuntimeException("incorrect result: " + res); + } + } + +} From c69275ddfe8c1769ae82b4ba64b2d6d80bbd8683 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Mon, 26 Jan 2026 18:53:39 +0000 Subject: [PATCH 200/328] 8376232: Remove AppContext from Swing synth related classes Reviewed-by: serb, azvegint --- .../com/sun/java/swing/plaf/gtk/GTKStyle.java | 9 +- .../javax/swing/plaf/nimbus/Effect.java | 11 +- .../javax/swing/plaf/synth/ImagePainter.java | 16 +-- .../javax/swing/plaf/synth/Region.java | 24 ++-- .../javax/swing/plaf/synth/SynthButtonUI.java | 2 - .../swing/plaf/synth/SynthLookAndFeel.java | 51 ++----- .../swing/plaf/synth/7143614/bug7143614.java | 99 -------------- .../javax/swing/plaf/synth/Test6660049.java | 125 ------------------ 8 files changed, 30 insertions(+), 307 deletions(-) delete mode 100644 test/jdk/javax/swing/plaf/synth/7143614/bug7143614.java delete mode 100644 test/jdk/javax/swing/plaf/synth/Test6660049.java diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java index baeb249eaa8..76d7abdbce6 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java @@ -32,7 +32,6 @@ import javax.swing.*; import javax.swing.plaf.*; import javax.swing.plaf.synth.*; -import sun.awt.AppContext; import sun.awt.UNIXToolkit; import sun.swing.SwingUtilities2; import javax.swing.plaf.synth.SynthIcon; @@ -961,11 +960,11 @@ class GTKStyle extends SynthStyle implements GTKConstants { static class GTKStockIconInfo { private static Map ICON_TYPE_MAP; - private static final Object ICON_SIZE_KEY = new StringBuffer("IconSize"); + + private static Dimension[] iconSizesMap; private static Dimension[] getIconSizesMap() { - AppContext appContext = AppContext.getAppContext(); - Dimension[] iconSizes = (Dimension[])appContext.get(ICON_SIZE_KEY); + Dimension[] iconSizes = iconSizesMap; if (iconSizes == null) { iconSizes = new Dimension[7]; @@ -976,7 +975,7 @@ class GTKStyle extends SynthStyle implements GTKConstants { iconSizes[4] = new Dimension(20, 20); // GTK_ICON_SIZE_BUTTON iconSizes[5] = new Dimension(32, 32); // GTK_ICON_SIZE_DND iconSizes[6] = new Dimension(48, 48); // GTK_ICON_SIZE_DIALOG - appContext.put(ICON_SIZE_KEY, iconSizes); + iconSizesMap = iconSizes; } return iconSizes; } diff --git a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/Effect.java b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/Effect.java index 30bed2207e4..d1b7ba143b3 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/Effect.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/Effect.java @@ -24,8 +24,6 @@ */ package javax.swing.plaf.nimbus; -import sun.awt.AppContext; - import java.awt.image.BufferedImage; import java.lang.ref.SoftReference; @@ -81,13 +79,10 @@ abstract class Effect { // ================================================================================================================= // Static data cache + private static final ArrayCache ARRAY_CACHE = new ArrayCache(); + protected static ArrayCache getArrayCache() { - ArrayCache cache = (ArrayCache)AppContext.getAppContext().get(ArrayCache.class); - if (cache == null){ - cache = new ArrayCache(); - AppContext.getAppContext().put(ArrayCache.class,cache); - } - return cache; + return ARRAY_CACHE; } protected static class ArrayCache { diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/ImagePainter.java b/src/java.desktop/share/classes/javax/swing/plaf/synth/ImagePainter.java index 8a1d957b615..1171f64eb23 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/synth/ImagePainter.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/ImagePainter.java @@ -28,7 +28,6 @@ import java.awt.*; import java.lang.ref.WeakReference; import java.net.*; import javax.swing.*; -import sun.awt.AppContext; import sun.swing.plaf.synth.Paint9Painter; /** @@ -41,8 +40,6 @@ import sun.swing.plaf.synth.Paint9Painter; * @author Scott Violet */ class ImagePainter extends SynthPainter { - private static final StringBuffer CACHE_KEY = - new StringBuffer("SynthCacheKey"); private Image image; private Insets sInsets; @@ -53,22 +50,17 @@ class ImagePainter extends SynthPainter { private Paint9Painter imageCache; private boolean center; + private static volatile WeakReference cacheRef; + private static Paint9Painter getPaint9Painter() { // A SynthPainter is created per . We want the - // cache to be shared by all, and we don't use a static because we - // don't want it to persist between look and feels. For that reason - // we use a AppContext specific Paint9Painter. It's backed via + // cache to be shared by all. It's held via // a WeakRef so that it can go away if the look and feel changes. - synchronized(CACHE_KEY) { - @SuppressWarnings("unchecked") - WeakReference cacheRef = - (WeakReference)AppContext.getAppContext(). - get(CACHE_KEY); + synchronized(ImagePainter.class) { Paint9Painter painter; if (cacheRef == null || (painter = cacheRef.get()) == null) { painter = new Paint9Painter(30); cacheRef = new WeakReference(painter); - AppContext.getAppContext().put(CACHE_KEY, cacheRef); } return painter; } diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/Region.java b/src/java.desktop/share/classes/javax/swing/plaf/synth/Region.java index 5a59f3bb98d..f8a0800ff8b 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/synth/Region.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/Region.java @@ -24,8 +24,6 @@ */ package javax.swing.plaf.synth; -import sun.awt.AppContext; - import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -72,8 +70,6 @@ import javax.swing.UIDefaults; * @author Scott Violet */ public class Region { - private static final Object UI_TO_REGION_MAP_KEY = new Object(); - private static final Object LOWER_CASE_NAME_MAP_KEY = new Object(); /** * ArrowButton's are special types of buttons that also render a @@ -425,10 +421,10 @@ public class Region { */ public static final Region VIEWPORT = new Region("Viewport", false); - private static Map getUItoRegionMap() { - AppContext context = AppContext.getAppContext(); - @SuppressWarnings("unchecked") - Map map = (Map) context.get(UI_TO_REGION_MAP_KEY); + private static Map regionMap; + + private static synchronized Map getUItoRegionMap() { + Map map = regionMap; if (map == null) { map = new HashMap(); map.put("ArrowButtonUI", ARROW_BUTTON); @@ -476,18 +472,18 @@ public class Region { map.put("ToolBarSeparatorUI", TOOL_BAR_SEPARATOR); map.put("TreeUI", TREE); map.put("ViewportUI", VIEWPORT); - context.put(UI_TO_REGION_MAP_KEY, map); + regionMap = map; } return map; } - private static Map getLowerCaseNameMap() { - AppContext context = AppContext.getAppContext(); - @SuppressWarnings("unchecked") - Map map = (Map) context.get(LOWER_CASE_NAME_MAP_KEY); + private static Map lcRegionMap; + + private static synchronized Map getLowerCaseNameMap() { + Map map = lcRegionMap; if (map == null) { map = new HashMap(); - context.put(LOWER_CASE_NAME_MAP_KEY, map); + lcRegionMap = map; } return map; } diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthButtonUI.java b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthButtonUI.java index 3a3d5719605..f0c7a9a1622 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthButtonUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthButtonUI.java @@ -25,8 +25,6 @@ package javax.swing.plaf.synth; -import sun.awt.AppContext; - import javax.swing.*; import java.awt.*; import java.beans.*; diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java index 700e3ed8a38..095d675d3de 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java @@ -60,7 +60,6 @@ import javax.swing.plaf.ComponentUI; import javax.swing.plaf.InsetsUIResource; import javax.swing.plaf.basic.BasicLookAndFeel; -import sun.awt.AppContext; import sun.awt.SunToolkit; import sun.swing.DefaultLookup; import sun.swing.SwingAccessor; @@ -101,31 +100,13 @@ public class SynthLookAndFeel extends BasicLookAndFeel { static final Insets EMPTY_UIRESOURCE_INSETS = new InsetsUIResource( 0, 0, 0, 0); - /** - * AppContext key to get the current SynthStyleFactory. - */ - private static final Object STYLE_FACTORY_KEY = - new StringBuffer("com.sun.java.swing.plaf.gtk.StyleCache"); + private static ComponentUI selectedUI; + private static int selectedUIStateValue; /** - * AppContext key to get selectedUI. - */ - private static final Object SELECTED_UI_KEY = new StringBuilder("selectedUI"); - - /** - * AppContext key to get selectedUIState. - */ - private static final Object SELECTED_UI_STATE_KEY = new StringBuilder("selectedUIState"); - - /** - * The last SynthStyleFactory that was asked for from AppContext - * lastContext. + * The last SynthStyleFactory that was set. */ private static SynthStyleFactory lastFactory; - /** - * AppContext lastLAF came from. - */ - private static AppContext lastContext; /** * SynthStyleFactory for the this SynthLookAndFeel. @@ -141,7 +122,7 @@ public class SynthLookAndFeel extends BasicLookAndFeel { private Handler _handler; static ComponentUI getSelectedUI() { - return (ComponentUI) AppContext.getAppContext().get(SELECTED_UI_KEY); + return selectedUI; } /** @@ -182,23 +163,20 @@ public class SynthLookAndFeel extends BasicLookAndFeel { } } - AppContext context = AppContext.getAppContext(); - - context.put(SELECTED_UI_KEY, uix); - context.put(SELECTED_UI_STATE_KEY, Integer.valueOf(selectedUIState)); + selectedUI = uix; + selectedUIStateValue = selectedUIState; } static int getSelectedUIState() { - Integer result = (Integer) AppContext.getAppContext().get(SELECTED_UI_STATE_KEY); - - return result == null ? 0 : result.intValue(); + return selectedUIStateValue; } /** * Clears out the selected UI that was last set in setSelectedUI. */ static void resetSelectedUI() { - AppContext.getAppContext().remove(SELECTED_UI_KEY); + selectedUI = null; + selectedUIStateValue = 0; } @@ -210,12 +188,8 @@ public class SynthLookAndFeel extends BasicLookAndFeel { */ public static void setStyleFactory(SynthStyleFactory cache) { // We assume the setter is called BEFORE the getter has been invoked - // for a particular AppContext. synchronized(SynthLookAndFeel.class) { - AppContext context = AppContext.getAppContext(); lastFactory = cache; - lastContext = context; - context.put(STYLE_FACTORY_KEY, cache); } } @@ -226,13 +200,6 @@ public class SynthLookAndFeel extends BasicLookAndFeel { */ public static SynthStyleFactory getStyleFactory() { synchronized(SynthLookAndFeel.class) { - AppContext context = AppContext.getAppContext(); - - if (lastContext == context) { - return lastFactory; - } - lastContext = context; - lastFactory = (SynthStyleFactory) context.get(STYLE_FACTORY_KEY); return lastFactory; } } diff --git a/test/jdk/javax/swing/plaf/synth/7143614/bug7143614.java b/test/jdk/javax/swing/plaf/synth/7143614/bug7143614.java deleted file mode 100644 index f1e1cbb94aa..00000000000 --- a/test/jdk/javax/swing/plaf/synth/7143614/bug7143614.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2012, 2015, 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 7143614 - * @summary Issues with Synth Look&Feel - * @author Pavel Porvatov - * @modules java.desktop/javax.swing.plaf.synth:open - * @modules java.desktop/sun.awt - */ - -import sun.awt.SunToolkit; - -import javax.swing.plaf.ComponentUI; -import javax.swing.plaf.basic.BasicButtonUI; -import javax.swing.plaf.synth.SynthConstants; -import javax.swing.plaf.synth.SynthLookAndFeel; -import java.lang.reflect.Method; - -public class bug7143614 { - private static Method setSelectedUIMethod; - - private static ComponentUI componentUI = new BasicButtonUI(); - - public static void main(String[] args) throws Exception { - setSelectedUIMethod = SynthLookAndFeel.class.getDeclaredMethod("setSelectedUI", ComponentUI.class, - boolean.class, boolean.class, boolean.class, boolean.class); - setSelectedUIMethod.setAccessible(true); - - setSelectedUIMethod.invoke(null, componentUI, true, true, true, true); - - validate(); - - Thread thread = new ThreadInAnotherAppContext(); - - thread.start(); - thread.join(); - - validate(); - - System.out.println("Test bug7143614 passed."); - } - - private static void validate() throws Exception { - Method getSelectedUIMethod = SynthLookAndFeel.class.getDeclaredMethod("getSelectedUI"); - - getSelectedUIMethod.setAccessible(true); - - Method getSelectedUIStateMethod = SynthLookAndFeel.class.getDeclaredMethod("getSelectedUIState"); - - getSelectedUIStateMethod.setAccessible(true); - - if (getSelectedUIMethod.invoke(null) != componentUI) { - throw new RuntimeException("getSelectedUI returns invalid value"); - } - if (((Integer) getSelectedUIStateMethod.invoke(null)).intValue() != - (SynthConstants.SELECTED | SynthConstants.FOCUSED)) { - throw new RuntimeException("getSelectedUIState returns invalid value"); - } - - } - - private static class ThreadInAnotherAppContext extends Thread { - public ThreadInAnotherAppContext() { - super(new ThreadGroup("7143614"), "ThreadInAnotherAppContext"); - } - - public void run() { - SunToolkit.createNewAppContext(); - - try { - setSelectedUIMethod.invoke(null, null, false, false, false, false); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - } -} diff --git a/test/jdk/javax/swing/plaf/synth/Test6660049.java b/test/jdk/javax/swing/plaf/synth/Test6660049.java deleted file mode 100644 index a7486eb86c8..00000000000 --- a/test/jdk/javax/swing/plaf/synth/Test6660049.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2009, 2016, 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 - * @key headful - * @bug 6660049 6849518 - * @summary Tests the Region initialization - * @author Sergey Malenkov - * @modules java.desktop/sun.awt - */ - -import sun.awt.SunToolkit; - -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.SwingUtilities; -import javax.swing.plaf.synth.Region; -import javax.swing.plaf.synth.SynthLookAndFeel; - -public class Test6660049 implements Runnable { - public static void main(String[] args) { - SwingUtilities.invokeLater(new Test6660049( - javax.swing.JButton.class, - javax.swing.JCheckBox.class, - javax.swing.JCheckBoxMenuItem.class, - javax.swing.JColorChooser.class, - javax.swing.JComboBox.class, - javax.swing.JDesktopPane.class, - javax.swing.JEditorPane.class, - javax.swing.JFileChooser.class, - javax.swing.JFormattedTextField.class, - javax.swing.JInternalFrame.class, - javax.swing.JLabel.class, - javax.swing.JList.class, - javax.swing.JMenu.class, - javax.swing.JMenuBar.class, - javax.swing.JMenuItem.class, - javax.swing.JOptionPane.class, - javax.swing.JPanel.class, - javax.swing.JPasswordField.class, - javax.swing.JPopupMenu.class, - javax.swing.JProgressBar.class, - javax.swing.JRadioButton.class, - javax.swing.JRadioButtonMenuItem.class, - javax.swing.JRootPane.class, - javax.swing.JScrollBar.class, - javax.swing.JScrollPane.class, - javax.swing.JSeparator.class, - javax.swing.JSlider.class, - javax.swing.JSpinner.class, - javax.swing.JSplitPane.class, - javax.swing.JTabbedPane.class, - javax.swing.JTable.class, - javax.swing.JTextArea.class, - javax.swing.JTextField.class, - javax.swing.JTextPane.class, - javax.swing.JToggleButton.class, - javax.swing.JToolBar.class, - javax.swing.JToolTip.class, - javax.swing.JTree.class, - javax.swing.JViewport.class, - javax.swing.table.JTableHeader.class)); - } - - private final Class[] types; - private final Region region; - - private Test6660049(Class... types) { - this.types = types; - run(); - - this.region = new Region("Button", "ButtonUI", true) { - @Override - public String getName() { - throw new Error("6660049: exploit is available"); - } - }; - } - - public void run() { - if (this.region != null) { - SunToolkit.createNewAppContext(); - } - for (Class type : this.types) { - Region region = getRegion(type); - if (region == null) { - throw new Error("6849518: region is not initialized"); - } - } - getRegion(JButton.class).getName(); - } - - private static Region getRegion(Class type) { - try { - return SynthLookAndFeel.getRegion(type.newInstance()); - } - catch (IllegalAccessException exception) { - throw new Error("unexpected exception", exception); - } - catch (InstantiationException exception) { - throw new Error("unexpected exception", exception); - } - } -} From 82bd3831b0f1e268ae76b31a803c86094add8e92 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Mon, 26 Jan 2026 20:13:03 +0000 Subject: [PATCH 201/328] 8374538: Wrong specification of MethodHandles.constant(...) Reviewed-by: liach, jvernee --- .../share/classes/java/lang/invoke/MethodHandles.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index feb8aaaa1a9..7fde9d1dd89 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, 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 @@ -4826,7 +4826,9 @@ assert((int)twice.invokeExact(21) == 42); * Before the method handle is returned, the passed-in value is converted to the requested type. * If the requested type is primitive, widening primitive conversions are attempted, * else reference conversions are attempted. - *

    The returned method handle is equivalent to {@code identity(type).bindTo(value)}. + *

    The returned method handle is equivalent to {@code identity(type).bindTo(value)}, + * for reference types. For all types it is equivalent to + * {@code insertArguments(identity(type), 0, value)}. * @param type the return type of the desired method handle * @param value the value to return * @return a method handle of the given return type and no arguments, which always returns the given value From 12570be64ae2114587e6de4ef79f79be961023b9 Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Mon, 26 Jan 2026 21:13:01 +0000 Subject: [PATCH 202/328] 8376151: Test javax/swing/JFileChooser/4966171/bug4966171.java is failing with OOME Reviewed-by: prr, azvegint, aivanov --- test/jdk/javax/swing/JFileChooser/4966171/bug4966171.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/jdk/javax/swing/JFileChooser/4966171/bug4966171.java b/test/jdk/javax/swing/JFileChooser/4966171/bug4966171.java index f3b3ba684e6..27f26d570be 100644 --- a/test/jdk/javax/swing/JFileChooser/4966171/bug4966171.java +++ b/test/jdk/javax/swing/JFileChooser/4966171/bug4966171.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, 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 @@ -50,8 +50,8 @@ public final class bug4966171 { } private static void test() { - // Will run the test no more than 10 seconds per L&F - long endtime = System.nanoTime() + TimeUnit.SECONDS.toNanos(10); + // Will run the test no more than 5 seconds per L&F + long endtime = System.nanoTime() + TimeUnit.SECONDS.toNanos(5); while (System.nanoTime() < endtime) { try { var byteOut = new ByteArrayOutputStream(); From fdcc122a9db2f6fdeb014e9e731cd3992bb3d0f3 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 27 Jan 2026 00:15:13 +0000 Subject: [PATCH 203/328] 8376422: Run compiler/corelibs/OptionalFold.java with tiered compilation Reviewed-by: dholmes --- test/hotspot/jtreg/compiler/corelibs/OptionalFold.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/corelibs/OptionalFold.java b/test/hotspot/jtreg/compiler/corelibs/OptionalFold.java index 0661a2e37e6..1f850aaf7cd 100644 --- a/test/hotspot/jtreg/compiler/corelibs/OptionalFold.java +++ b/test/hotspot/jtreg/compiler/corelibs/OptionalFold.java @@ -41,7 +41,8 @@ import compiler.lib.ir_framework.TestFramework; public class OptionalFold { public static void main(String[] args) { - TestFramework.run(); + // Somehow fails with -XX:-TieredCompilation + TestFramework.runWithFlags("-XX:+TieredCompilation"); } // Ensure both present and empty values can fold From cba7d88ca427984ebb27a1634aab10a62c9eede1 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 27 Jan 2026 03:16:43 +0000 Subject: [PATCH 204/328] 8374549: Extend MetaspaceClosure to cover non-MetaspaceObj types Reviewed-by: kvn, asmehra --- src/hotspot/share/cds/aotGrowableArray.cpp | 34 +++ src/hotspot/share/cds/aotGrowableArray.hpp | 76 +++++ .../share/cds/aotGrowableArray.inline.hpp | 37 +++ src/hotspot/share/cds/aotMapLogger.cpp | 64 +++- src/hotspot/share/cds/aotMapLogger.hpp | 12 +- src/hotspot/share/cds/aotMetaspace.cpp | 8 + src/hotspot/share/cds/archiveBuilder.cpp | 65 ++--- src/hotspot/share/cds/archiveBuilder.hpp | 10 +- src/hotspot/share/cds/cppVtables.cpp | 55 ++-- src/hotspot/share/cds/cppVtables.hpp | 5 +- src/hotspot/share/cds/dumpAllocStats.hpp | 30 +- src/hotspot/share/cds/heapShared.cpp | 6 +- .../share/classfile/classLoaderDataShared.cpp | 81 +++--- .../share/classfile/classLoaderDataShared.hpp | 8 +- src/hotspot/share/classfile/moduleEntry.cpp | 185 +++--------- src/hotspot/share/classfile/moduleEntry.hpp | 48 ++- src/hotspot/share/classfile/modules.cpp | 13 +- src/hotspot/share/classfile/modules.hpp | 3 +- src/hotspot/share/classfile/packageEntry.cpp | 107 ++----- src/hotspot/share/classfile/packageEntry.hpp | 28 +- src/hotspot/share/memory/allocation.cpp | 24 +- src/hotspot/share/memory/allocation.hpp | 4 +- src/hotspot/share/memory/metaspaceClosure.cpp | 16 +- src/hotspot/share/memory/metaspaceClosure.hpp | 274 +++++++++++++----- .../share/memory/metaspaceClosureType.hpp | 46 +++ src/hotspot/share/oops/array.hpp | 7 +- src/hotspot/share/oops/instanceKlass.cpp | 23 +- src/hotspot/share/runtime/sharedRuntime.hpp | 4 +- src/hotspot/share/utilities/growableArray.hpp | 8 +- .../gtest/utilities/test_metaspaceClosure.cpp | 100 ++++++- 30 files changed, 864 insertions(+), 517 deletions(-) create mode 100644 src/hotspot/share/cds/aotGrowableArray.cpp create mode 100644 src/hotspot/share/cds/aotGrowableArray.hpp create mode 100644 src/hotspot/share/cds/aotGrowableArray.inline.hpp create mode 100644 src/hotspot/share/memory/metaspaceClosureType.hpp diff --git a/src/hotspot/share/cds/aotGrowableArray.cpp b/src/hotspot/share/cds/aotGrowableArray.cpp new file mode 100644 index 00000000000..ec63e7aa57f --- /dev/null +++ b/src/hotspot/share/cds/aotGrowableArray.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026, 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 "cds/aotGrowableArray.hpp" +#include "cds/aotMetaspace.hpp" +#include "memory/allocation.inline.hpp" +#include "utilities/growableArray.hpp" + +void AOTGrowableArrayHelper::deallocate(void* mem) { + if (!AOTMetaspace::in_aot_cache(mem)) { + GrowableArrayCHeapAllocator::deallocate(mem); + } +} diff --git a/src/hotspot/share/cds/aotGrowableArray.hpp b/src/hotspot/share/cds/aotGrowableArray.hpp new file mode 100644 index 00000000000..0a0c137ed07 --- /dev/null +++ b/src/hotspot/share/cds/aotGrowableArray.hpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2026, 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_AOT_AOTGROWABLEARRAY_HPP +#define SHARE_AOT_AOTGROWABLEARRAY_HPP + +#include +#include + +class AOTGrowableArrayHelper { +public: + static void deallocate(void* mem); +}; + +// An AOTGrowableArray provides the same functionality as a GrowableArray that +// uses the C heap allocator. In addition, AOTGrowableArray can be iterated with +// MetaspaceClosure. This type should be used for growable arrays that need to be +// stored in the AOT cache. See ModuleEntry::_reads for an example. +template +class AOTGrowableArray : public GrowableArrayWithAllocator> { + friend class VMStructs; + friend class GrowableArrayWithAllocator; + + static E* allocate(int max, MemTag mem_tag) { + return (E*)GrowableArrayCHeapAllocator::allocate(max, sizeof(E), mem_tag); + } + + E* allocate() { + return allocate(this->_capacity, mtClass); + } + + void deallocate(E* mem) { +#if INCLUDE_CDS + AOTGrowableArrayHelper::deallocate(mem); +#else + GrowableArrayCHeapAllocator::deallocate(mem); +#endif + } + +public: + AOTGrowableArray(int initial_capacity, MemTag mem_tag) : + GrowableArrayWithAllocator( + allocate(initial_capacity, mem_tag), + initial_capacity) {} + + AOTGrowableArray() : AOTGrowableArray(0, mtClassShared) {} + + // methods required by MetaspaceClosure + void metaspace_pointers_do(MetaspaceClosure* it); + int size_in_heapwords() const { return (int)heap_word_size(sizeof(*this)); } + MetaspaceClosureType type() const { return MetaspaceClosureType::GrowableArrayType; } + static bool is_read_only_by_default() { return false; } +}; + +#endif // SHARE_AOT_AOTGROWABLEARRAY_HPP diff --git a/src/hotspot/share/cds/aotGrowableArray.inline.hpp b/src/hotspot/share/cds/aotGrowableArray.inline.hpp new file mode 100644 index 00000000000..8c6e8cb6503 --- /dev/null +++ b/src/hotspot/share/cds/aotGrowableArray.inline.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2026, 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_CDS_AOTGROWABLEARRAY_INLINE_HPP +#define SHARE_CDS_AOTGROWABLEARRAY_INLINE_HPP + +#include "cds/aotGrowableArray.hpp" + +#include "memory/metaspaceClosure.hpp" + +template +void AOTGrowableArray::metaspace_pointers_do(MetaspaceClosure* it) { + it->push_c_array(AOTGrowableArray::data_addr(), AOTGrowableArray::capacity()); +} + +#endif // SHARE_CDS_AOTGROWABLEARRAY_INLINE_HPP diff --git a/src/hotspot/share/cds/aotMapLogger.cpp b/src/hotspot/share/cds/aotMapLogger.cpp index a252eae4b84..5e4e0956824 100644 --- a/src/hotspot/share/cds/aotMapLogger.cpp +++ b/src/hotspot/share/cds/aotMapLogger.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -29,6 +29,8 @@ #include "cds/aotStreamedHeapWriter.hpp" #include "cds/cdsConfig.hpp" #include "cds/filemap.hpp" +#include "classfile/moduleEntry.hpp" +#include "classfile/packageEntry.hpp" #include "classfile/systemDictionaryShared.hpp" #include "classfile/vmClasses.hpp" #include "logging/log.hpp" @@ -141,7 +143,7 @@ public: info._buffered_addr = ref->obj(); info._requested_addr = ref->obj(); info._bytes = ref->size() * BytesPerWord; - info._type = ref->msotype(); + info._type = ref->type(); _objs.append(info); } @@ -214,7 +216,7 @@ void AOTMapLogger::dumptime_log_metaspace_region(const char* name, DumpRegion* r info._buffered_addr = src_info->buffered_addr(); info._requested_addr = info._buffered_addr + _buffer_to_requested_delta; info._bytes = src_info->size_in_bytes(); - info._type = src_info->msotype(); + info._type = src_info->type(); objs.append(info); } @@ -332,43 +334,52 @@ void AOTMapLogger::log_metaspace_objects_impl(address region_base, address regio address buffered_addr = info._buffered_addr; address requested_addr = info._requested_addr; int bytes = info._bytes; - MetaspaceObj::Type type = info._type; - const char* type_name = MetaspaceObj::type_name(type); + MetaspaceClosureType type = info._type; + const char* type_name = MetaspaceClosure::type_name(type); log_as_hex(last_obj_base, buffered_addr, last_obj_base + _buffer_to_requested_delta); switch (type) { - case MetaspaceObj::ClassType: + case MetaspaceClosureType::ClassType: log_klass((Klass*)src, requested_addr, type_name, bytes, current); break; - case MetaspaceObj::ConstantPoolType: + case MetaspaceClosureType::ConstantPoolType: log_constant_pool((ConstantPool*)src, requested_addr, type_name, bytes, current); break; - case MetaspaceObj::ConstantPoolCacheType: + case MetaspaceClosureType::ConstantPoolCacheType: log_constant_pool_cache((ConstantPoolCache*)src, requested_addr, type_name, bytes, current); break; - case MetaspaceObj::ConstMethodType: + case MetaspaceClosureType::ConstMethodType: log_const_method((ConstMethod*)src, requested_addr, type_name, bytes, current); break; - case MetaspaceObj::MethodType: + case MetaspaceClosureType::MethodType: log_method((Method*)src, requested_addr, type_name, bytes, current); break; - case MetaspaceObj::MethodCountersType: + case MetaspaceClosureType::MethodCountersType: log_method_counters((MethodCounters*)src, requested_addr, type_name, bytes, current); break; - case MetaspaceObj::MethodDataType: + case MetaspaceClosureType::MethodDataType: log_method_data((MethodData*)src, requested_addr, type_name, bytes, current); break; - case MetaspaceObj::SymbolType: + case MetaspaceClosureType::ModuleEntryType: + log_module_entry((ModuleEntry*)src, requested_addr, type_name, bytes, current); + break; + case MetaspaceClosureType::PackageEntryType: + log_package_entry((PackageEntry*)src, requested_addr, type_name, bytes, current); + break; + case MetaspaceClosureType::GrowableArrayType: + log_growable_array((GrowableArrayBase*)src, requested_addr, type_name, bytes, current); + break; + case MetaspaceClosureType::SymbolType: log_symbol((Symbol*)src, requested_addr, type_name, bytes, current); break; - case MetaspaceObj::KlassTrainingDataType: + case MetaspaceClosureType::KlassTrainingDataType: log_klass_training_data((KlassTrainingData*)src, requested_addr, type_name, bytes, current); break; - case MetaspaceObj::MethodTrainingDataType: + case MetaspaceClosureType::MethodTrainingDataType: log_method_training_data((MethodTrainingData*)src, requested_addr, type_name, bytes, current); break; - case MetaspaceObj::CompileTrainingDataType: + case MetaspaceClosureType::CompileTrainingDataType: log_compile_training_data((CompileTrainingData*)src, requested_addr, type_name, bytes, current); break; default: @@ -421,6 +432,27 @@ void AOTMapLogger::log_method_data(MethodData* md, address requested_addr, const log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, md->method()->external_name()); } +void AOTMapLogger::log_module_entry(ModuleEntry* mod, address requested_addr, const char* type_name, + int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, + mod->name_as_C_string()); +} + +void AOTMapLogger::log_package_entry(PackageEntry* pkg, address requested_addr, const char* type_name, + int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %s - %s", p2i(requested_addr), type_name, bytes, + pkg->module()->name_as_C_string(), pkg->name_as_C_string()); +} + +void AOTMapLogger::log_growable_array(GrowableArrayBase* arr, address requested_addr, const char* type_name, + int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %d (%d)", p2i(requested_addr), type_name, bytes, + arr->length(), arr->capacity()); +} + void AOTMapLogger::log_klass(Klass* k, address requested_addr, const char* type_name, int bytes, Thread* current) { ResourceMark rm(current); diff --git a/src/hotspot/share/cds/aotMapLogger.hpp b/src/hotspot/share/cds/aotMapLogger.hpp index ba188514861..bf7ce0028b9 100644 --- a/src/hotspot/share/cds/aotMapLogger.hpp +++ b/src/hotspot/share/cds/aotMapLogger.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "cds/archiveBuilder.hpp" #include "memory/allocation.hpp" #include "memory/allStatic.hpp" +#include "memory/metaspaceClosureType.hpp" #include "oops/oopsHierarchy.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" @@ -37,9 +38,13 @@ class ArchiveStreamedHeapInfo; class CompileTrainingData; class DumpRegion; class FileMapInfo; +class GrowableArrayBase; class KlassTrainingData; +class MethodCounters; class MethodTrainingData; +class ModuleEntry; class outputStream; +class PackageEntry; // Write detailed info to a mapfile to analyze contents of the AOT cache/CDS archive. // -Xlog:aot+map* can be used both when creating an AOT cache, or when using an AOT cache. @@ -62,7 +67,7 @@ class AOTMapLogger : AllStatic { address _buffered_addr; address _requested_addr; int _bytes; - MetaspaceObj::Type _type; + MetaspaceClosureType _type; }; public: @@ -142,6 +147,9 @@ private: Thread* current); static void log_klass(Klass* k, address requested_addr, const char* type_name, int bytes, Thread* current); static void log_method(Method* m, address requested_addr, const char* type_name, int bytes, Thread* current); + static void log_module_entry(ModuleEntry* mod, address requested_addr, const char* type_name, int bytes, Thread* current); + static void log_package_entry(PackageEntry* pkg, address requested_addr, const char* type_name, int bytes, Thread* current); + static void log_growable_array(GrowableArrayBase* arr, address requested_addr, const char* type_name, int bytes, Thread* current); static void log_symbol(Symbol* s, address requested_addr, const char* type_name, int bytes, Thread* current); static void log_klass_training_data(KlassTrainingData* ktd, address requested_addr, const char* type_name, int bytes, Thread* current); static void log_method_training_data(MethodTrainingData* mtd, address requested_addr, const char* type_name, int bytes, Thread* current); diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index 79d789e0c70..683c897d855 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -698,6 +698,9 @@ public: Universe::metaspace_pointers_do(it); vmSymbols::metaspace_pointers_do(it); TrainingData::iterate_roots(it); + if (CDSConfig::is_dumping_full_module_graph()) { + ClassLoaderDataShared::iterate_roots(it); + } // The above code should find all the symbols that are referenced by the // archived classes. We just need to add the extra symbols which @@ -795,6 +798,10 @@ void VM_PopulateDumpSharedSpace::doit() { _builder.make_klasses_shareable(); AOTMetaspace::make_method_handle_intrinsics_shareable(); + if (CDSConfig::is_dumping_full_module_graph()) { + ClassLoaderDataShared::remove_unshareable_info(); + } + dump_java_heap_objects(); dump_shared_symbol_table(_builder.symbols()); @@ -1135,6 +1142,7 @@ void AOTMetaspace::dump_static_archive_impl(StaticArchiveBuilder& builder, TRAPS HeapShared::init_heap_writer(); if (CDSConfig::is_dumping_full_module_graph()) { ClassLoaderDataShared::ensure_module_entry_tables_exist(); + ClassLoaderDataShared::build_tables(CHECK); HeapShared::reset_archived_object_states(CHECK); } diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 328bed1ccfb..9161980c4be 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -243,7 +243,7 @@ bool ArchiveBuilder::gather_klass_and_symbol(MetaspaceClosure::Ref* ref, bool re if (get_follow_mode(ref) != make_a_copy) { return false; } - if (ref->msotype() == MetaspaceObj::ClassType) { + if (ref->type() == MetaspaceClosureType::ClassType) { Klass* klass = (Klass*)ref->obj(); assert(klass->is_klass(), "must be"); if (!is_excluded(klass)) { @@ -252,7 +252,7 @@ bool ArchiveBuilder::gather_klass_and_symbol(MetaspaceClosure::Ref* ref, bool re assert(klass->is_instance_klass(), "must be"); } } - } else if (ref->msotype() == MetaspaceObj::SymbolType) { + } else if (ref->type() == MetaspaceClosureType::SymbolType) { // Make sure the symbol won't be GC'ed while we are dumping the archive. Symbol* sym = (Symbol*)ref->obj(); sym->increment_refcount(); @@ -271,11 +271,6 @@ void ArchiveBuilder::gather_klasses_and_symbols() { aot_log_info(aot)("Gathering classes and symbols ... "); GatherKlassesAndSymbols doit(this); iterate_roots(&doit); -#if INCLUDE_CDS_JAVA_HEAP - if (CDSConfig::is_dumping_full_module_graph()) { - ClassLoaderDataShared::iterate_symbols(&doit); - } -#endif doit.finish(); if (CDSConfig::is_dumping_static_archive()) { @@ -446,14 +441,14 @@ bool ArchiveBuilder::gather_one_source_obj(MetaspaceClosure::Ref* ref, bool read } #ifdef ASSERT - if (ref->msotype() == MetaspaceObj::MethodType) { + if (ref->type() == MetaspaceClosureType::MethodType) { Method* m = (Method*)ref->obj(); assert(!RegeneratedClasses::has_been_regenerated((address)m->method_holder()), "Should not archive methods in a class that has been regenerated"); } #endif - if (ref->msotype() == MetaspaceObj::MethodDataType) { + if (ref->type() == MetaspaceClosureType::MethodDataType) { MethodData* md = (MethodData*)ref->obj(); md->clean_method_data(false /* always_clean */); } @@ -554,16 +549,16 @@ ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref if (CDSConfig::is_dumping_dynamic_archive() && AOTMetaspace::in_aot_cache(obj)) { // Don't dump existing shared metadata again. return point_to_it; - } else if (ref->msotype() == MetaspaceObj::MethodDataType || - ref->msotype() == MetaspaceObj::MethodCountersType || - ref->msotype() == MetaspaceObj::KlassTrainingDataType || - ref->msotype() == MetaspaceObj::MethodTrainingDataType || - ref->msotype() == MetaspaceObj::CompileTrainingDataType) { + } else if (ref->type() == MetaspaceClosureType::MethodDataType || + ref->type() == MetaspaceClosureType::MethodCountersType || + ref->type() == MetaspaceClosureType::KlassTrainingDataType || + ref->type() == MetaspaceClosureType::MethodTrainingDataType || + ref->type() == MetaspaceClosureType::CompileTrainingDataType) { return (TrainingData::need_data() || TrainingData::assembling_data()) ? make_a_copy : set_to_null; - } else if (ref->msotype() == MetaspaceObj::AdapterHandlerEntryType) { + } else if (ref->type() == MetaspaceClosureType::AdapterHandlerEntryType) { return CDSConfig::is_dumping_adapters() ? make_a_copy : set_to_null; } else { - if (ref->msotype() == MetaspaceObj::ClassType) { + if (ref->type() == MetaspaceClosureType::ClassType) { Klass* klass = (Klass*)ref->obj(); assert(klass->is_klass(), "must be"); if (RegeneratedClasses::has_been_regenerated(klass)) { @@ -620,15 +615,6 @@ void ArchiveBuilder::dump_rw_metadata() { ResourceMark rm; aot_log_info(aot)("Allocating RW objects ... "); make_shallow_copies(&_rw_region, &_rw_src_objs); - -#if INCLUDE_CDS_JAVA_HEAP - if (CDSConfig::is_dumping_full_module_graph()) { - // Archive the ModuleEntry's and PackageEntry's of the 3 built-in loaders - char* start = rw_region()->top(); - ClassLoaderDataShared::allocate_archived_tables(); - alloc_stats()->record_modules(rw_region()->top() - start, /*read_only*/false); - } -#endif } void ArchiveBuilder::dump_ro_metadata() { @@ -637,15 +623,6 @@ void ArchiveBuilder::dump_ro_metadata() { start_dump_region(&_ro_region); make_shallow_copies(&_ro_region, &_ro_src_objs); - -#if INCLUDE_CDS_JAVA_HEAP - if (CDSConfig::is_dumping_full_module_graph()) { - char* start = ro_region()->top(); - ClassLoaderDataShared::init_archived_tables(); - alloc_stats()->record_modules(ro_region()->top() - start, /*read_only*/true); - } -#endif - RegeneratedClasses::record_regenerated_objects(); } @@ -663,7 +640,7 @@ void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* s size_t alignment = SharedSpaceObjectAlignment; // alignment for the dest pointer char* oldtop = dump_region->top(); - if (src_info->msotype() == MetaspaceObj::ClassType) { + if (src_info->type() == MetaspaceClosureType::ClassType) { // Allocate space for a pointer directly in front of the future InstanceKlass, so // we can do a quick lookup from InstanceKlass* -> RunTimeClassInfo* // without building another hashtable. See RunTimeClassInfo::get_for() @@ -679,7 +656,7 @@ void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* s alignment = nth_bit(ArchiveBuilder::precomputed_narrow_klass_shift()); } #endif - } else if (src_info->msotype() == MetaspaceObj::SymbolType) { + } else if (src_info->type() == MetaspaceClosureType::SymbolType) { // Symbols may be allocated by using AllocateHeap, so their sizes // may be less than size_in_bytes() indicates. bytes = ((Symbol*)src)->byte_size(); @@ -689,7 +666,7 @@ void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* s memcpy(dest, src, bytes); // Update the hash of buffered sorted symbols for static dump so that the symbols have deterministic contents - if (CDSConfig::is_dumping_static_archive() && (src_info->msotype() == MetaspaceObj::SymbolType)) { + if (CDSConfig::is_dumping_static_archive() && (src_info->type() == MetaspaceClosureType::SymbolType)) { Symbol* buffered_symbol = (Symbol*)dest; assert(((Symbol*)src)->is_permanent(), "archived symbols must be permanent"); buffered_symbol->update_identity_hash(); @@ -704,7 +681,7 @@ void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* s } } - intptr_t* archived_vtable = CppVtables::get_archived_vtable(src_info->msotype(), (address)dest); + intptr_t* archived_vtable = CppVtables::get_archived_vtable(src_info->type(), (address)dest); if (archived_vtable != nullptr) { *(address*)dest = (address)archived_vtable; ArchivePtrMarker::mark_pointer((address*)dest); @@ -714,7 +691,7 @@ void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* s src_info->set_buffered_addr((address)dest); char* newtop = dump_region->top(); - _alloc_stats.record(src_info->msotype(), int(newtop - oldtop), src_info->read_only()); + _alloc_stats.record(src_info->type(), int(newtop - oldtop), src_info->read_only()); DEBUG_ONLY(_alloc_stats.verify((int)dump_region->used(), src_info->read_only())); } @@ -997,15 +974,15 @@ void ArchiveBuilder::make_training_data_shareable() { return; } - if (info.msotype() == MetaspaceObj::KlassTrainingDataType || - info.msotype() == MetaspaceObj::MethodTrainingDataType || - info.msotype() == MetaspaceObj::CompileTrainingDataType) { + if (info.type() == MetaspaceClosureType::KlassTrainingDataType || + info.type() == MetaspaceClosureType::MethodTrainingDataType || + info.type() == MetaspaceClosureType::CompileTrainingDataType) { TrainingData* buffered_td = (TrainingData*)info.buffered_addr(); buffered_td->remove_unshareable_info(); - } else if (info.msotype() == MetaspaceObj::MethodDataType) { + } else if (info.type() == MetaspaceClosureType::MethodDataType) { MethodData* buffered_mdo = (MethodData*)info.buffered_addr(); buffered_mdo->remove_unshareable_info(); - } else if (info.msotype() == MetaspaceObj::MethodCountersType) { + } else if (info.type() == MetaspaceClosureType::MethodCountersType) { MethodCounters* buffered_mc = (MethodCounters*)info.buffered_addr(); buffered_mc->remove_unshareable_info(); } diff --git a/src/hotspot/share/cds/archiveBuilder.hpp b/src/hotspot/share/cds/archiveBuilder.hpp index 9a628439039..9de6c02edc5 100644 --- a/src/hotspot/share/cds/archiveBuilder.hpp +++ b/src/hotspot/share/cds/archiveBuilder.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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 @@ -134,13 +134,13 @@ private: int _size_in_bytes; int _id; // Each object has a unique serial ID, starting from zero. The ID is assigned // when the object is added into _source_objs. - MetaspaceObj::Type _msotype; + MetaspaceClosureType _type; address _source_addr; // The source object to be copied. address _buffered_addr; // The copy of this object insider the buffer. public: SourceObjInfo(MetaspaceClosure::Ref* ref, bool read_only, FollowMode follow_mode) : _ptrmap_start(0), _ptrmap_end(0), _read_only(read_only), _has_embedded_pointer(false), _follow_mode(follow_mode), - _size_in_bytes(ref->size() * BytesPerWord), _id(0), _msotype(ref->msotype()), + _size_in_bytes(ref->size() * BytesPerWord), _id(0), _type(ref->type()), _source_addr(ref->obj()) { if (follow_mode == point_to_it) { _buffered_addr = ref->obj(); @@ -155,7 +155,7 @@ private: SourceObjInfo(address src, SourceObjInfo* renegerated_obj_info) : _ptrmap_start(0), _ptrmap_end(0), _read_only(false), _follow_mode(renegerated_obj_info->_follow_mode), - _size_in_bytes(0), _msotype(renegerated_obj_info->_msotype), + _size_in_bytes(0), _type(renegerated_obj_info->_type), _source_addr(src), _buffered_addr(renegerated_obj_info->_buffered_addr) {} bool should_copy() const { return _follow_mode == make_a_copy; } @@ -182,7 +182,7 @@ private: } return _buffered_addr; } - MetaspaceObj::Type msotype() const { return _msotype; } + MetaspaceClosureType type() const { return _type; } FollowMode follow_mode() const { return _follow_mode; } }; diff --git a/src/hotspot/share/cds/cppVtables.cpp b/src/hotspot/share/cds/cppVtables.cpp index f2862454286..da68fa70761 100644 --- a/src/hotspot/share/cds/cppVtables.cpp +++ b/src/hotspot/share/cds/cppVtables.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,12 +22,14 @@ * */ +#include "cds/aotGrowableArray.hpp" #include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" #include "cds/cppVtables.hpp" #include "logging/log.hpp" +#include "memory/resourceArea.hpp" #include "oops/instanceClassLoaderKlass.hpp" #include "oops/instanceMirrorKlass.hpp" #include "oops/instanceRefKlass.hpp" @@ -53,6 +55,19 @@ // + at run time: we clone the actual contents of the vtables from libjvm.so // into our own tables. + +#ifndef PRODUCT + +// AOTGrowableArray has a vtable only when in non-product builds (due to +// the virtual printing functions in AnyObj). + +using GrowableArray_ModuleEntry_ptr = AOTGrowableArray; + +#define DEBUG_CPP_VTABLE_TYPES_DO(f) \ + f(GrowableArray_ModuleEntry_ptr) \ + +#endif + // Currently, the archive contains ONLY the following types of objects that have C++ vtables. #define CPP_VTABLE_TYPES_DO(f) \ f(ConstantPool) \ @@ -68,7 +83,8 @@ f(TypeArrayKlass) \ f(KlassTrainingData) \ f(MethodTrainingData) \ - f(CompileTrainingData) + f(CompileTrainingData) \ + NOT_PRODUCT(DEBUG_CPP_VTABLE_TYPES_DO(f)) class CppVtableInfo { intptr_t _vtable_size; @@ -86,7 +102,7 @@ public: } }; -static inline intptr_t* vtable_of(const Metadata* m) { +static inline intptr_t* vtable_of(const void* m) { return *((intptr_t**)m); } @@ -116,6 +132,7 @@ CppVtableInfo* CppVtableCloner::allocate_and_initialize(const char* name) { template void CppVtableCloner::initialize(const char* name, CppVtableInfo* info) { + ResourceMark rm; T tmp; // Allocate temporary dummy metadata object to get to the original vtable. int n = info->vtable_size(); intptr_t* srcvtable = vtable_of(&tmp); @@ -268,7 +285,7 @@ void CppVtables::serialize(SerializeClosure* soc) { } } -intptr_t* CppVtables::get_archived_vtable(MetaspaceObj::Type msotype, address obj) { +intptr_t* CppVtables::get_archived_vtable(MetaspaceClosureType type, address obj) { if (!_orig_cpp_vtptrs_inited) { CPP_VTABLE_TYPES_DO(INIT_ORIG_CPP_VTPTRS); _orig_cpp_vtptrs_inited = true; @@ -276,19 +293,23 @@ intptr_t* CppVtables::get_archived_vtable(MetaspaceObj::Type msotype, address ob assert(CDSConfig::is_dumping_archive(), "sanity"); int kind = -1; - switch (msotype) { - case MetaspaceObj::SymbolType: - case MetaspaceObj::TypeArrayU1Type: - case MetaspaceObj::TypeArrayU2Type: - case MetaspaceObj::TypeArrayU4Type: - case MetaspaceObj::TypeArrayU8Type: - case MetaspaceObj::TypeArrayOtherType: - case MetaspaceObj::ConstMethodType: - case MetaspaceObj::ConstantPoolCacheType: - case MetaspaceObj::AnnotationsType: - case MetaspaceObj::RecordComponentType: - case MetaspaceObj::AdapterHandlerEntryType: - case MetaspaceObj::AdapterFingerPrintType: + switch (type) { + case MetaspaceClosureType::SymbolType: + case MetaspaceClosureType::TypeArrayU1Type: + case MetaspaceClosureType::TypeArrayU2Type: + case MetaspaceClosureType::TypeArrayU4Type: + case MetaspaceClosureType::TypeArrayU8Type: + case MetaspaceClosureType::TypeArrayOtherType: + case MetaspaceClosureType::CArrayType: + case MetaspaceClosureType::ConstMethodType: + case MetaspaceClosureType::ConstantPoolCacheType: + case MetaspaceClosureType::AnnotationsType: + case MetaspaceClosureType::ModuleEntryType: + case MetaspaceClosureType::PackageEntryType: + case MetaspaceClosureType::RecordComponentType: + case MetaspaceClosureType::AdapterHandlerEntryType: + case MetaspaceClosureType::AdapterFingerPrintType: + PRODUCT_ONLY(case MetaspaceClosureType::GrowableArrayType:) // These have no vtables. break; default: diff --git a/src/hotspot/share/cds/cppVtables.hpp b/src/hotspot/share/cds/cppVtables.hpp index b40ca036023..9e28ba020ee 100644 --- a/src/hotspot/share/cds/cppVtables.hpp +++ b/src/hotspot/share/cds/cppVtables.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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,6 +27,7 @@ #include "memory/allocation.hpp" #include "memory/allStatic.hpp" +#include "memory/metaspaceClosureType.hpp" #include "utilities/globalDefinitions.hpp" class ArchiveBuilder; @@ -40,7 +41,7 @@ class CppVtables : AllStatic { public: static void dumptime_init(ArchiveBuilder* builder); static void zero_archived_vtables(); - static intptr_t* get_archived_vtable(MetaspaceObj::Type msotype, address obj); + static intptr_t* get_archived_vtable(MetaspaceClosureType type, address obj); static void serialize(SerializeClosure* sc); static bool is_valid_shared_method(const Method* m) NOT_CDS_RETURN_(false); static char* vtables_serialized_base() { return _vtables_serialized_base; } diff --git a/src/hotspot/share/cds/dumpAllocStats.hpp b/src/hotspot/share/cds/dumpAllocStats.hpp index 7d651320e6f..4553f0f6a01 100644 --- a/src/hotspot/share/cds/dumpAllocStats.hpp +++ b/src/hotspot/share/cds/dumpAllocStats.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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,32 +27,34 @@ #include "classfile/compactHashtable.hpp" #include "memory/allocation.hpp" +#include "memory/metaspaceClosureType.hpp" // This is for dumping detailed statistics for the allocations // in the shared spaces. class DumpAllocStats : public StackObj { public: - // Here's poor man's enum inheritance -#define SHAREDSPACE_OBJ_TYPES_DO(f) \ - METASPACE_OBJ_TYPES_DO(f) \ +#define DUMPED_OBJ_TYPES_DO(f) \ + METASPACE_CLOSURE_TYPES_DO(f) \ f(SymbolHashentry) \ f(SymbolBucket) \ f(StringHashentry) \ f(StringBucket) \ - f(ModulesNatives) \ f(CppVTables) \ f(Other) +#define DUMPED_TYPE_DECLARE(name) name ## Type, +#define DUMPED_TYPE_NAME_CASE(name) case name ## Type: return #name; + enum Type { // Types are MetaspaceObj::ClassType, MetaspaceObj::SymbolType, etc - SHAREDSPACE_OBJ_TYPES_DO(METASPACE_OBJ_TYPE_DECLARE) + DUMPED_OBJ_TYPES_DO(DUMPED_TYPE_DECLARE) _number_of_types }; static const char* type_name(Type type) { switch(type) { - SHAREDSPACE_OBJ_TYPES_DO(METASPACE_OBJ_TYPE_NAME_CASE) + DUMPED_OBJ_TYPES_DO(DUMPED_TYPE_NAME_CASE) default: ShouldNotReachHere(); return nullptr; @@ -101,16 +103,12 @@ public: CompactHashtableStats* symbol_stats() { return &_symbol_stats; } CompactHashtableStats* string_stats() { return &_string_stats; } - void record(MetaspaceObj::Type type, int byte_size, bool read_only) { - assert(int(type) >= 0 && type < MetaspaceObj::_number_of_types, "sanity"); + void record(MetaspaceClosureType type, int byte_size, bool read_only) { + int t = (int)type; + assert(t >= 0 && t < (int)MetaspaceClosureType::_number_of_types, "sanity"); int which = (read_only) ? RO : RW; - _counts[which][type] ++; - _bytes [which][type] += byte_size; - } - - void record_modules(int byte_size, bool read_only) { - int which = (read_only) ? RO : RW; - _bytes [which][ModulesNativesType] += byte_size; + _counts[which][t] ++; + _bytes [which][t] += byte_size; } void record_other_type(int byte_size, bool read_only) { diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index fdc335f3799..89694c6780e 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -948,10 +948,6 @@ void HeapShared::archive_subgraphs() { true /* is_full_module_graph */); } } - - if (CDSConfig::is_dumping_full_module_graph()) { - Modules::verify_archived_modules(); - } } // diff --git a/src/hotspot/share/classfile/classLoaderDataShared.cpp b/src/hotspot/share/classfile/classLoaderDataShared.cpp index 7a7743edd03..d415fe64bac 100644 --- a/src/hotspot/share/classfile/classLoaderDataShared.cpp +++ b/src/hotspot/share/classfile/classLoaderDataShared.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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 @@ -33,6 +33,7 @@ #include "classfile/packageEntry.hpp" #include "classfile/systemDictionary.hpp" #include "logging/log.hpp" +#include "memory/metaspaceClosure.hpp" #include "runtime/handles.inline.hpp" #include "runtime/safepoint.hpp" @@ -56,9 +57,9 @@ class ArchivedClassLoaderData { public: ArchivedClassLoaderData() : _packages(nullptr), _modules(nullptr), _unnamed_module(nullptr) {} - void iterate_symbols(ClassLoaderData* loader_data, MetaspaceClosure* closure); - void allocate(ClassLoaderData* loader_data); - void init_archived_entries(ClassLoaderData* loader_data); + void iterate_roots(MetaspaceClosure* closure); + void build_tables(ClassLoaderData* loader_data, TRAPS); + void remove_unshareable_info(); ModuleEntry* unnamed_module() { return _unnamed_module; } @@ -80,17 +81,14 @@ static ModuleEntry* _archived_javabase_moduleEntry = nullptr; static int _platform_loader_root_index = -1; static int _system_loader_root_index = -1; -void ArchivedClassLoaderData::iterate_symbols(ClassLoaderData* loader_data, MetaspaceClosure* closure) { +void ArchivedClassLoaderData::iterate_roots(MetaspaceClosure* it) { assert(CDSConfig::is_dumping_full_module_graph(), "must be"); - assert_valid(loader_data); - if (loader_data != nullptr) { - loader_data->packages()->iterate_symbols(closure); - loader_data->modules() ->iterate_symbols(closure); - loader_data->unnamed_module()->iterate_symbols(closure); - } + it->push(&_packages); + it->push(&_modules); + it->push(&_unnamed_module); } -void ArchivedClassLoaderData::allocate(ClassLoaderData* loader_data) { +void ArchivedClassLoaderData::build_tables(ClassLoaderData* loader_data, TRAPS) { assert(CDSConfig::is_dumping_full_module_graph(), "must be"); assert_valid(loader_data); if (loader_data != nullptr) { @@ -98,19 +96,28 @@ void ArchivedClassLoaderData::allocate(ClassLoaderData* loader_data) { // address of the Symbols, which may be relocated at runtime due to ASLR. // So we store the packages/modules in Arrays. At runtime, we create // the hashtables using these arrays. - _packages = loader_data->packages()->allocate_archived_entries(); - _modules = loader_data->modules() ->allocate_archived_entries(); - _unnamed_module = loader_data->unnamed_module()->allocate_archived_entry(); + _packages = loader_data->packages()->build_aot_table(loader_data, CHECK); + _modules = loader_data->modules()->build_aot_table(loader_data, CHECK); + _unnamed_module = loader_data->unnamed_module(); } } -void ArchivedClassLoaderData::init_archived_entries(ClassLoaderData* loader_data) { - assert(CDSConfig::is_dumping_full_module_graph(), "must be"); - assert_valid(loader_data); - if (loader_data != nullptr) { - loader_data->packages()->init_archived_entries(_packages); - loader_data->modules() ->init_archived_entries(_modules); - _unnamed_module->init_as_archived_entry(); +void ArchivedClassLoaderData::remove_unshareable_info() { + if (_packages != nullptr) { + _packages = ArchiveBuilder::current()->get_buffered_addr(_packages); + for (int i = 0; i < _packages->length(); i++) { + _packages->at(i)->remove_unshareable_info(); + } + } + if (_modules != nullptr) { + _modules = ArchiveBuilder::current()->get_buffered_addr(_modules); + for (int i = 0; i < _modules->length(); i++) { + _modules->at(i)->remove_unshareable_info(); + } + } + if (_unnamed_module != nullptr) { + _unnamed_module = ArchiveBuilder::current()->get_buffered_addr(_unnamed_module); + _unnamed_module->remove_unshareable_info(); } } @@ -153,7 +160,6 @@ void ArchivedClassLoaderData::clear_archived_oops() { // ------------------------------ void ClassLoaderDataShared::load_archived_platform_and_system_class_loaders() { -#if INCLUDE_CDS_JAVA_HEAP // The streaming object loader prefers loading the class loader related objects before // the CLD constructor which has a NoSafepointVerifier. if (!HeapShared::is_loading_streaming_mode()) { @@ -178,7 +184,6 @@ void ClassLoaderDataShared::load_archived_platform_and_system_class_loaders() { if (system_loader_module_entry != nullptr) { system_loader_module_entry->preload_archived_oops(); } -#endif } static ClassLoaderData* null_class_loader_data() { @@ -210,28 +215,27 @@ void ClassLoaderDataShared::ensure_module_entry_table_exists(oop class_loader) { assert(met != nullptr, "sanity"); } -void ClassLoaderDataShared::iterate_symbols(MetaspaceClosure* closure) { +void ClassLoaderDataShared::build_tables(TRAPS) { assert(CDSConfig::is_dumping_full_module_graph(), "must be"); - _archived_boot_loader_data.iterate_symbols (null_class_loader_data(), closure); - _archived_platform_loader_data.iterate_symbols(java_platform_loader_data_or_null(), closure); - _archived_system_loader_data.iterate_symbols (java_system_loader_data_or_null(), closure); + _archived_boot_loader_data.build_tables(null_class_loader_data(), CHECK); + _archived_platform_loader_data.build_tables(java_platform_loader_data_or_null(), CHECK); + _archived_system_loader_data.build_tables(java_system_loader_data_or_null(), CHECK); } -void ClassLoaderDataShared::allocate_archived_tables() { +void ClassLoaderDataShared::iterate_roots(MetaspaceClosure* it) { assert(CDSConfig::is_dumping_full_module_graph(), "must be"); - _archived_boot_loader_data.allocate (null_class_loader_data()); - _archived_platform_loader_data.allocate(java_platform_loader_data_or_null()); - _archived_system_loader_data.allocate (java_system_loader_data_or_null()); + _archived_boot_loader_data.iterate_roots(it); + _archived_platform_loader_data.iterate_roots(it); + _archived_system_loader_data.iterate_roots(it); } -void ClassLoaderDataShared::init_archived_tables() { +void ClassLoaderDataShared::remove_unshareable_info() { assert(CDSConfig::is_dumping_full_module_graph(), "must be"); + _archived_boot_loader_data.remove_unshareable_info(); + _archived_platform_loader_data.remove_unshareable_info(); + _archived_system_loader_data.remove_unshareable_info(); - _archived_boot_loader_data.init_archived_entries (null_class_loader_data()); - _archived_platform_loader_data.init_archived_entries(java_platform_loader_data_or_null()); - _archived_system_loader_data.init_archived_entries (java_system_loader_data_or_null()); - - _archived_javabase_moduleEntry = ModuleEntry::get_archived_entry(ModuleEntryTable::javabase_moduleEntry()); + _archived_javabase_moduleEntry = ArchiveBuilder::current()->get_buffered_addr(ModuleEntryTable::javabase_moduleEntry()); _platform_loader_root_index = HeapShared::append_root(SystemDictionary::java_platform_loader()); _system_loader_root_index = HeapShared::append_root(SystemDictionary::java_system_loader()); @@ -271,7 +275,6 @@ ModuleEntry* ClassLoaderDataShared::archived_unnamed_module(ClassLoaderData* loa return archived_module; } - void ClassLoaderDataShared::clear_archived_oops() { assert(!CDSConfig::is_using_full_module_graph(), "must be"); _archived_boot_loader_data.clear_archived_oops(); diff --git a/src/hotspot/share/classfile/classLoaderDataShared.hpp b/src/hotspot/share/classfile/classLoaderDataShared.hpp index 39d0a89418f..2cf37310e50 100644 --- a/src/hotspot/share/classfile/classLoaderDataShared.hpp +++ b/src/hotspot/share/classfile/classLoaderDataShared.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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,11 +40,11 @@ class ClassLoaderDataShared : AllStatic { public: static void load_archived_platform_and_system_class_loaders() NOT_CDS_JAVA_HEAP_RETURN; static void restore_archived_modules_for_preloading_classes(JavaThread* current) NOT_CDS_JAVA_HEAP_RETURN; + static void build_tables(TRAPS) NOT_CDS_JAVA_HEAP_RETURN; + static void iterate_roots(MetaspaceClosure* closure) NOT_CDS_JAVA_HEAP_RETURN; + static void remove_unshareable_info() NOT_CDS_JAVA_HEAP_RETURN; #if INCLUDE_CDS_JAVA_HEAP static void ensure_module_entry_tables_exist(); - static void allocate_archived_tables(); - static void iterate_symbols(MetaspaceClosure* closure); - static void init_archived_tables(); static void serialize(SerializeClosure* f); static void clear_archived_oops(); static void restore_archived_entries_for_null_class_loader_data(); diff --git a/src/hotspot/share/classfile/moduleEntry.cpp b/src/hotspot/share/classfile/moduleEntry.cpp index 5fb3d6f2d13..b5b8aa4ef55 100644 --- a/src/hotspot/share/classfile/moduleEntry.cpp +++ b/src/hotspot/share/classfile/moduleEntry.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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,6 +23,7 @@ */ #include "cds/aotClassLocation.hpp" +#include "cds/aotGrowableArray.inline.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" @@ -37,6 +38,7 @@ #include "jni.h" #include "logging/log.hpp" #include "logging/logStream.hpp" +#include "memory/metadataFactory.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/oopHandle.inline.hpp" @@ -44,7 +46,6 @@ #include "runtime/handles.inline.hpp" #include "runtime/safepoint.hpp" #include "utilities/events.hpp" -#include "utilities/growableArray.hpp" #include "utilities/hashTable.hpp" #include "utilities/ostream.hpp" #include "utilities/quickSort.hpp" @@ -167,7 +168,7 @@ void ModuleEntry::add_read(ModuleEntry* m) { } else { if (reads() == nullptr) { // Lazily create a module's reads list - GrowableArray* new_reads = new (mtModule) GrowableArray(MODULE_READS_SIZE, mtModule); + AOTGrowableArray* new_reads = new (mtModule) AOTGrowableArray(MODULE_READS_SIZE, mtModule); set_reads(new_reads); } @@ -274,8 +275,7 @@ ModuleEntry::ModuleEntry(Handle module_handle, _has_default_read_edges(false), _must_walk_reads(false), _is_open(is_open), - _is_patched(false) - DEBUG_ONLY(COMMA _reads_is_archived(false)) { + _is_patched(false) { // Initialize fields specific to a ModuleEntry if (_name == nullptr) { @@ -394,7 +394,6 @@ ModuleEntryTable::~ModuleEntryTable() { ModuleEntryTableDeleter deleter; _table.unlink(&deleter); assert(_table.number_of_entries() == 0, "should have removed all entries"); - } void ModuleEntry::set_loader_data(ClassLoaderData* cld) { @@ -402,147 +401,51 @@ void ModuleEntry::set_loader_data(ClassLoaderData* cld) { _loader_data = cld; } +void ModuleEntry::metaspace_pointers_do(MetaspaceClosure* it) { + it->push(&_name); + it->push(&_reads); + it->push(&_version); + it->push(&_location); +} + #if INCLUDE_CDS_JAVA_HEAP -typedef HashTable< - const ModuleEntry*, - ModuleEntry*, - 557, // prime number - AnyObj::C_HEAP> ArchivedModuleEntries; -static ArchivedModuleEntries* _archive_modules_entries = nullptr; - -#ifndef PRODUCT -static int _num_archived_module_entries = 0; -static int _num_inited_module_entries = 0; -#endif - bool ModuleEntry::should_be_archived() const { return SystemDictionaryShared::is_builtin_loader(loader_data()); } -ModuleEntry* ModuleEntry::allocate_archived_entry() const { - precond(should_be_archived()); - precond(CDSConfig::is_dumping_full_module_graph()); - ModuleEntry* archived_entry = (ModuleEntry*)ArchiveBuilder::rw_region_alloc(sizeof(ModuleEntry)); - memcpy((void*)archived_entry, (void*)this, sizeof(ModuleEntry)); +void ModuleEntry::remove_unshareable_info() { + _archived_module_index = HeapShared::append_root(module_oop()); - archived_entry->_archived_module_index = HeapShared::append_root(module_oop()); - if (_archive_modules_entries == nullptr) { - _archive_modules_entries = new (mtClass)ArchivedModuleEntries(); - } - assert(_archive_modules_entries->get(this) == nullptr, "Each ModuleEntry must not be shared across ModuleEntryTables"); - _archive_modules_entries->put(this, archived_entry); - DEBUG_ONLY(_num_archived_module_entries++); - - if (CDSConfig::is_dumping_final_static_archive()) { - OopHandle null_handle; - archived_entry->_shared_pd = null_handle; - } else { - assert(archived_entry->shared_protection_domain() == nullptr, "never set during -Xshare:dump"); + if (_reads != nullptr) { + _reads->set_in_aot_cache(); } // Clear handles and restore at run time. Handles cannot be archived. + if (CDSConfig::is_dumping_final_static_archive()) { + OopHandle null_handle; + _shared_pd = null_handle; + } else { + assert(shared_protection_domain() == nullptr, "never set during -Xshare:dump"); + } + OopHandle null_handle; - archived_entry->_module_handle = null_handle; - - // For verify_archived_module_entries() - DEBUG_ONLY(_num_inited_module_entries++); - - if (log_is_enabled(Info, aot, module)) { - ResourceMark rm; - LogStream ls(Log(aot, module)::info()); - ls.print("Stored in archive: "); - archived_entry->print(&ls); - } - return archived_entry; -} - -bool ModuleEntry::has_been_archived() { - assert(!ArchiveBuilder::current()->is_in_buffer_space(this), "must be called on original ModuleEntry"); - return _archive_modules_entries->contains(this); -} - -ModuleEntry* ModuleEntry::get_archived_entry(ModuleEntry* orig_entry) { - ModuleEntry** ptr = _archive_modules_entries->get(orig_entry); - assert(ptr != nullptr && *ptr != nullptr, "must have been allocated"); - return *ptr; -} - -// This function is used to archive ModuleEntry::_reads and PackageEntry::_qualified_exports. -// GrowableArray cannot be directly archived, as it needs to be expandable at runtime. -// Write it out as an Array, and convert it back to GrowableArray at runtime. -Array* ModuleEntry::write_growable_array(GrowableArray* array) { - Array* archived_array = nullptr; - int length = (array == nullptr) ? 0 : array->length(); - if (length > 0) { - archived_array = ArchiveBuilder::new_ro_array(length); - for (int i = 0; i < length; i++) { - ModuleEntry* archived_entry = get_archived_entry(array->at(i)); - archived_array->at_put(i, archived_entry); - ArchivePtrMarker::mark_pointer((address*)archived_array->adr_at(i)); - } - } - - return archived_array; -} - -GrowableArray* ModuleEntry::restore_growable_array(Array* archived_array) { - GrowableArray* array = nullptr; - int length = (archived_array == nullptr) ? 0 : archived_array->length(); - if (length > 0) { - array = new (mtModule) GrowableArray(length, mtModule); - for (int i = 0; i < length; i++) { - ModuleEntry* archived_entry = archived_array->at(i); - array->append(archived_entry); - } - } - - return array; -} - -void ModuleEntry::iterate_symbols(MetaspaceClosure* closure) { - closure->push(&_name); - closure->push(&_version); - closure->push(&_location); -} - -void ModuleEntry::init_as_archived_entry() { - set_archived_reads(write_growable_array(reads())); + _module_handle = null_handle; _loader_data = nullptr; // re-init at runtime if (name() != nullptr) { - _shared_path_index = AOTClassLocationConfig::dumptime()->get_module_shared_path_index(_location); - _name = ArchiveBuilder::get_buffered_symbol(_name); - ArchivePtrMarker::mark_pointer((address*)&_name); + Symbol* src_location = ArchiveBuilder::current()->get_source_addr(_location); + _shared_path_index = AOTClassLocationConfig::dumptime()->get_module_shared_path_index(src_location); } else { // _shared_path_index is used only by SystemDictionary::is_shared_class_visible_impl() // for checking classes in named modules. _shared_path_index = -1; } - if (_version != nullptr) { - _version = ArchiveBuilder::get_buffered_symbol(_version); - } - if (_location != nullptr) { - _location = ArchiveBuilder::get_buffered_symbol(_location); - } JFR_ONLY(set_trace_id(0);) // re-init at runtime - - ArchivePtrMarker::mark_pointer((address*)&_reads); - ArchivePtrMarker::mark_pointer((address*)&_version); - ArchivePtrMarker::mark_pointer((address*)&_location); } -#ifndef PRODUCT -void ModuleEntry::verify_archived_module_entries() { - assert(_num_archived_module_entries == _num_inited_module_entries, - "%d ModuleEntries have been archived but %d of them have been properly initialized with archived java.lang.Module objects", - _num_archived_module_entries, _num_inited_module_entries); -} -#endif // PRODUCT - void ModuleEntry::load_from_archive(ClassLoaderData* loader_data) { assert(CDSConfig::is_using_archive(), "runtime only"); set_loader_data(loader_data); - set_reads(restore_growable_array(archived_reads())); JFR_ONLY(INIT_ID(this);) } @@ -581,38 +484,28 @@ static int compare_module_by_name(ModuleEntry* a, ModuleEntry* b) { return a->name()->fast_compare(b->name()); } -void ModuleEntryTable::iterate_symbols(MetaspaceClosure* closure) { - auto syms = [&] (const SymbolHandle& key, ModuleEntry*& m) { - m->iterate_symbols(closure); - }; - _table.iterate_all(syms); -} - -Array* ModuleEntryTable::allocate_archived_entries() { - Array* archived_modules = ArchiveBuilder::new_rw_array(_table.number_of_entries()); +Array* ModuleEntryTable::build_aot_table(ClassLoaderData* loader_data, TRAPS) { + Array* aot_table = + MetadataFactory::new_array(loader_data, _table.number_of_entries(), nullptr, CHECK_NULL); int n = 0; auto grab = [&] (const SymbolHandle& key, ModuleEntry*& m) { - archived_modules->at_put(n++, m); + m->pack_reads(); + aot_table->at_put(n++, m); + if (log_is_enabled(Info, aot, module)) { + ResourceMark rm; + LogStream ls(Log(aot, module)::info()); + ls.print("Stored in archive: "); + m->print(&ls); + } }; _table.iterate_all(grab); if (n > 1) { // Always allocate in the same order to produce deterministic archive. - QuickSort::sort(archived_modules->data(), n, compare_module_by_name); + QuickSort::sort(aot_table->data(), n, compare_module_by_name); } - for (int i = 0; i < n; i++) { - archived_modules->at_put(i, archived_modules->at(i)->allocate_archived_entry()); - ArchivePtrMarker::mark_pointer((address*)archived_modules->adr_at(i)); - } - return archived_modules; -} -void ModuleEntryTable::init_archived_entries(Array* archived_modules) { - assert(CDSConfig::is_dumping_full_module_graph(), "sanity"); - for (int i = 0; i < archived_modules->length(); i++) { - ModuleEntry* archived_entry = archived_modules->at(i); - archived_entry->init_as_archived_entry(); - } + return aot_table; } void ModuleEntryTable::load_archived_entries(ClassLoaderData* loader_data, diff --git a/src/hotspot/share/classfile/moduleEntry.hpp b/src/hotspot/share/classfile/moduleEntry.hpp index 2e1852c5369..1a0251a2c2a 100644 --- a/src/hotspot/share/classfile/moduleEntry.hpp +++ b/src/hotspot/share/classfile/moduleEntry.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,9 @@ #ifndef SHARE_CLASSFILE_MODULEENTRY_HPP #define SHARE_CLASSFILE_MODULEENTRY_HPP +#include "cds/aotGrowableArray.hpp" #include "jni.h" +#include "memory/metaspaceClosureType.hpp" #include "oops/oopHandle.hpp" #include "oops/symbol.hpp" #include "oops/symbolHandle.hpp" @@ -68,11 +70,8 @@ private: // for shared classes from this module Symbol* _name; // name of this module ClassLoaderData* _loader_data; + AOTGrowableArray* _reads; // list of modules that are readable by this module - union { - GrowableArray* _reads; // list of modules that are readable by this module - Array* _archived_reads; // List of readable modules stored in the CDS archive - }; Symbol* _version; // module version number Symbol* _location; // module location CDS_ONLY(int _shared_path_index;) // >=0 if classes in this module are in CDS archive @@ -81,7 +80,6 @@ private: bool _must_walk_reads; // walk module's reads list at GC safepoints to purge out dead modules bool _is_open; // whether the packages in the module are all unqualifiedly exported bool _is_patched; // whether the module is patched via --patch-module - DEBUG_ONLY(bool _reads_is_archived); CDS_JAVA_HEAP_ONLY(int _archived_module_index;) JFR_ONLY(DEFINE_TRACE_ID_FIELD;) @@ -120,22 +118,18 @@ public: bool can_read(ModuleEntry* m) const; bool has_reads_list() const; - GrowableArray* reads() const { - assert(!_reads_is_archived, "sanity"); + AOTGrowableArray* reads() const { return _reads; } - void set_reads(GrowableArray* r) { + void set_reads(AOTGrowableArray* r) { _reads = r; - DEBUG_ONLY(_reads_is_archived = false); } - Array* archived_reads() const { - assert(_reads_is_archived, "sanity"); - return _archived_reads; - } - void set_archived_reads(Array* r) { - _archived_reads = r; - DEBUG_ONLY(_reads_is_archived = true); + void pack_reads() { + if (_reads != nullptr) { + _reads->shrink_to_fit(); + } } + void add_read(ModuleEntry* m); void set_read_walk_required(ClassLoaderData* m_loader_data); @@ -189,6 +183,13 @@ public: const char* name_as_C_string() const { return is_named() ? name()->as_C_string() : UNNAMED_MODULE; } + + // methods required by MetaspaceClosure + void metaspace_pointers_do(MetaspaceClosure* it); + int size_in_heapwords() const { return (int)heap_word_size(sizeof(ModuleEntry)); } + MetaspaceClosureType type() const { return MetaspaceClosureType::ModuleEntryType; } + static bool is_read_only_by_default() { return false; } + void print(outputStream* st = tty) const; void verify(); @@ -198,18 +199,11 @@ public: #if INCLUDE_CDS_JAVA_HEAP bool should_be_archived() const; - void iterate_symbols(MetaspaceClosure* closure); - ModuleEntry* allocate_archived_entry() const; - void init_as_archived_entry(); - static ModuleEntry* get_archived_entry(ModuleEntry* orig_entry); - bool has_been_archived(); - static Array* write_growable_array(GrowableArray* array); - static GrowableArray* restore_growable_array(Array* archived_array); + void remove_unshareable_info(); void load_from_archive(ClassLoaderData* loader_data); void preload_archived_oops(); void restore_archived_oops(ClassLoaderData* loader_data); void clear_archived_oops(); - static void verify_archived_module_entries() PRODUCT_RETURN; #endif }; @@ -275,9 +269,7 @@ public: void verify(); #if INCLUDE_CDS_JAVA_HEAP - void iterate_symbols(MetaspaceClosure* closure); - Array* allocate_archived_entries(); - void init_archived_entries(Array* archived_modules); + Array* build_aot_table(ClassLoaderData* loader_data, TRAPS); void load_archived_entries(ClassLoaderData* loader_data, Array* archived_modules); void restore_archived_oops(ClassLoaderData* loader_data, diff --git a/src/hotspot/share/classfile/modules.cpp b/src/hotspot/share/classfile/modules.cpp index baf2acfb78c..51d09d9c47f 100644 --- a/src/hotspot/share/classfile/modules.cpp +++ b/src/hotspot/share/classfile/modules.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2016, 2026, 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 @@ -505,13 +505,10 @@ void Modules::check_archived_module_oop(oop orig_module_obj) { ClassLoaderData* loader_data = orig_module_ent->loader_data(); assert(loader_data->is_builtin_class_loader_data(), "must be"); - if (orig_module_ent->name() != nullptr) { - // For each named module, we archive both the java.lang.Module oop and the ModuleEntry. - assert(orig_module_ent->has_been_archived(), "sanity"); - } else { + precond(ArchiveBuilder::current()->has_been_archived(orig_module_ent)); + if (orig_module_ent->name() == nullptr) { // We always archive unnamed module oop for boot, platform, and system loaders. precond(orig_module_ent->should_be_archived()); - precond(orig_module_ent->has_been_archived()); if (loader_data->is_boot_class_loader_data()) { assert(!_seen_boot_unnamed_module, "only once"); @@ -529,10 +526,6 @@ void Modules::check_archived_module_oop(oop orig_module_obj) { } } -void Modules::verify_archived_modules() { - ModuleEntry::verify_archived_module_entries(); -} - class Modules::ArchivedProperty { const char* _prop; const bool _numbered; diff --git a/src/hotspot/share/classfile/modules.hpp b/src/hotspot/share/classfile/modules.hpp index 27a22c1017a..75857c8960c 100644 --- a/src/hotspot/share/classfile/modules.hpp +++ b/src/hotspot/share/classfile/modules.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,6 @@ public: TRAPS) NOT_CDS_JAVA_HEAP_RETURN; static void init_archived_modules(JavaThread* current, Handle h_platform_loader, Handle h_system_loader) NOT_CDS_JAVA_HEAP_RETURN; - static void verify_archived_modules() NOT_CDS_JAVA_HEAP_RETURN; static void dump_archived_module_info() NOT_CDS_JAVA_HEAP_RETURN; static void serialize_archived_module_info(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN; diff --git a/src/hotspot/share/classfile/packageEntry.cpp b/src/hotspot/share/classfile/packageEntry.cpp index ea2e6cd1def..3e61f2e3a3e 100644 --- a/src/hotspot/share/classfile/packageEntry.cpp +++ b/src/hotspot/share/classfile/packageEntry.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,8 @@ * */ +#include "cds/aotGrowableArray.inline.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" @@ -31,13 +33,13 @@ #include "classfile/vmSymbols.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" +#include "memory/metadataFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/array.hpp" #include "oops/symbol.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" #include "utilities/events.hpp" -#include "utilities/growableArray.hpp" #include "utilities/hashTable.hpp" #include "utilities/ostream.hpp" #include "utilities/quickSort.hpp" @@ -51,7 +53,7 @@ PackageEntry::PackageEntry(Symbol* name, ModuleEntry* module) : _qualified_exports(nullptr), _defined_by_cds_in_class_path(0) { - // name can't be null + // name can't be null -- a class in the default package gets a PackageEntry of nullptr. _name->increment_refcount(); JFR_ONLY(INIT_ID(this);) @@ -81,7 +83,7 @@ void PackageEntry::add_qexport(ModuleEntry* m) { if (!has_qual_exports_list()) { // Lazily create a package's qualified exports list. // Initial size is small, do not anticipate export lists to be large. - _qualified_exports = new (mtModule) GrowableArray(QUAL_EXP_SIZE, mtModule); + _qualified_exports = new (mtModule) AOTGrowableArray(QUAL_EXP_SIZE, mtModule); } // Determine, based on this newly established export to module m, @@ -183,12 +185,24 @@ void PackageEntry::purge_qualified_exports() { } void PackageEntry::delete_qualified_exports() { - if (_qualified_exports != nullptr) { + if (_qualified_exports != nullptr && !AOTMetaspace::in_aot_cache(_qualified_exports)) { delete _qualified_exports; } _qualified_exports = nullptr; } +void PackageEntry::pack_qualified_exports() { + if (_qualified_exports != nullptr) { + _qualified_exports->shrink_to_fit(); + } +} + +void PackageEntry::metaspace_pointers_do(MetaspaceClosure* it) { + it->push(&_name); + it->push(&_module); + it->push(&_qualified_exports); +} + PackageEntryTable::PackageEntryTable() { } PackageEntryTable::~PackageEntryTable() { @@ -212,66 +226,19 @@ PackageEntryTable::~PackageEntryTable() { } #if INCLUDE_CDS_JAVA_HEAP -typedef HashTable< - const PackageEntry*, - PackageEntry*, - 557, // prime number - AnyObj::C_HEAP> ArchivedPackageEntries; -static ArchivedPackageEntries* _archived_packages_entries = nullptr; - bool PackageEntry::should_be_archived() const { return module()->should_be_archived(); } -PackageEntry* PackageEntry::allocate_archived_entry() const { - precond(should_be_archived()); - PackageEntry* archived_entry = (PackageEntry*)ArchiveBuilder::rw_region_alloc(sizeof(PackageEntry)); - memcpy((void*)archived_entry, (void*)this, sizeof(PackageEntry)); - - if (_archived_packages_entries == nullptr) { - _archived_packages_entries = new (mtClass)ArchivedPackageEntries(); +void PackageEntry::remove_unshareable_info() { + if (_qualified_exports != nullptr) { + _qualified_exports->set_in_aot_cache(); } - assert(_archived_packages_entries->get(this) == nullptr, "Each PackageEntry must not be shared across PackageEntryTables"); - _archived_packages_entries->put(this, archived_entry); - - return archived_entry; -} - -PackageEntry* PackageEntry::get_archived_entry(PackageEntry* orig_entry) { - PackageEntry** ptr = _archived_packages_entries->get(orig_entry); - if (ptr != nullptr) { - return *ptr; - } else { - return nullptr; - } -} - -void PackageEntry::iterate_symbols(MetaspaceClosure* closure) { - closure->push(&_name); -} - -void PackageEntry::init_as_archived_entry() { - Array* archived_qualified_exports = ModuleEntry::write_growable_array(_qualified_exports); - - _name = ArchiveBuilder::get_buffered_symbol(_name); - _module = ModuleEntry::get_archived_entry(_module); - _qualified_exports = (GrowableArray*)archived_qualified_exports; _defined_by_cds_in_class_path = 0; JFR_ONLY(set_trace_id(0);) // re-init at runtime - - ArchivePtrMarker::mark_pointer((address*)&_name); - ArchivePtrMarker::mark_pointer((address*)&_module); - ArchivePtrMarker::mark_pointer((address*)&_qualified_exports); - - LogStreamHandle(Info, aot, package) st; - if (st.is_enabled()) { - st.print("archived "); - print(&st); - } } void PackageEntry::load_from_archive() { - _qualified_exports = ModuleEntry::restore_growable_array((Array*)_qualified_exports); JFR_ONLY(INIT_ID(this);) } @@ -280,14 +247,7 @@ static int compare_package_by_name(PackageEntry* a, PackageEntry* b) { return a->name()->fast_compare(b->name()); } -void PackageEntryTable::iterate_symbols(MetaspaceClosure* closure) { - auto syms = [&] (const SymbolHandle& key, PackageEntry*& p) { - p->iterate_symbols(closure); - }; - _table.iterate_all(syms); -} - -Array* PackageEntryTable::allocate_archived_entries() { +Array* PackageEntryTable::build_aot_table(ClassLoaderData* loader_data, TRAPS) { // First count the packages in named modules int n = 0; auto count = [&] (const SymbolHandle& key, PackageEntry*& p) { @@ -297,12 +257,19 @@ Array* PackageEntryTable::allocate_archived_entries() { }; _table.iterate_all(count); - Array* archived_packages = ArchiveBuilder::new_rw_array(n); + Array* archived_packages = MetadataFactory::new_array(loader_data, n, nullptr, CHECK_NULL); // reset n n = 0; auto grab = [&] (const SymbolHandle& key, PackageEntry*& p) { if (p->should_be_archived()) { + p->pack_qualified_exports(); archived_packages->at_put(n++, p); + + LogStreamHandle(Info, aot, package) st; + if (st.is_enabled()) { + st.print("archived "); + p->print(&st); + } } }; _table.iterate_all(grab); @@ -311,18 +278,8 @@ Array* PackageEntryTable::allocate_archived_entries() { // Always allocate in the same order to produce deterministic archive. QuickSort::sort(archived_packages->data(), n, compare_package_by_name); } - for (int i = 0; i < n; i++) { - archived_packages->at_put(i, archived_packages->at(i)->allocate_archived_entry()); - ArchivePtrMarker::mark_pointer((address*)archived_packages->adr_at(i)); - } - return archived_packages; -} -void PackageEntryTable::init_archived_entries(Array* archived_packages) { - for (int i = 0; i < archived_packages->length(); i++) { - PackageEntry* archived_entry = archived_packages->at(i); - archived_entry->init_as_archived_entry(); - } + return archived_packages; } void PackageEntryTable::load_archived_entries(Array* archived_packages) { diff --git a/src/hotspot/share/classfile/packageEntry.hpp b/src/hotspot/share/classfile/packageEntry.hpp index 6abf89dc60f..7b174a92287 100644 --- a/src/hotspot/share/classfile/packageEntry.hpp +++ b/src/hotspot/share/classfile/packageEntry.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,9 @@ #ifndef SHARE_CLASSFILE_PACKAGEENTRY_HPP #define SHARE_CLASSFILE_PACKAGEENTRY_HPP +#include "cds/aotGrowableArray.hpp" #include "classfile/moduleEntry.hpp" +#include "memory/metaspaceClosureType.hpp" #include "oops/symbol.hpp" #include "oops/symbolHandle.hpp" #include "runtime/atomicAccess.hpp" @@ -114,7 +116,7 @@ private: bool _must_walk_exports; // Contains list of modules this package is qualifiedly exported to. Access // to this list is protected by the Module_lock. - GrowableArray* _qualified_exports; + AOTGrowableArray* _qualified_exports; JFR_ONLY(DEFINE_TRACE_ID_FIELD;) // Initial size of a package entry's list of qualified exports. @@ -205,14 +207,24 @@ public: void purge_qualified_exports(); void delete_qualified_exports(); + void pack_qualified_exports(); // used by AOT + + // methods required by MetaspaceClosure + void metaspace_pointers_do(MetaspaceClosure* it); + int size_in_heapwords() const { return (int)heap_word_size(sizeof(PackageEntry)); } + MetaspaceClosureType type() const { return MetaspaceClosureType::PackageEntryType; } + static bool is_read_only_by_default() { return false; } + void print(outputStream* st = tty); + char* name_as_C_string() const { + assert(_name != nullptr, "name can't be null"); + return name()->as_C_string(); + } + #if INCLUDE_CDS_JAVA_HEAP bool should_be_archived() const; - void iterate_symbols(MetaspaceClosure* closure); - PackageEntry* allocate_archived_entry() const; - void init_as_archived_entry(); - static PackageEntry* get_archived_entry(PackageEntry* orig_entry); + void remove_unshareable_info(); void load_from_archive(); #endif @@ -271,9 +283,7 @@ public: void print(outputStream* st = tty); #if INCLUDE_CDS_JAVA_HEAP - void iterate_symbols(MetaspaceClosure* closure); - Array* allocate_archived_entries(); - void init_archived_entries(Array* archived_packages); + Array* build_aot_table(ClassLoaderData* loader_data, TRAPS); void load_archived_entries(Array* archived_packages); #endif }; diff --git a/src/hotspot/share/memory/allocation.cpp b/src/hotspot/share/memory/allocation.cpp index 9df91225d6f..2a109688ca6 100644 --- a/src/hotspot/share/memory/allocation.cpp +++ b/src/hotspot/share/memory/allocation.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ * */ +#include "cds/aotMetaspace.hpp" #include "memory/allocation.inline.hpp" #include "memory/arena.hpp" #include "memory/metaspace.hpp" @@ -161,12 +162,33 @@ void AnyObj::set_allocation_type(address res, allocation_type type) { } } +void AnyObj::set_in_aot_cache() { + _allocation_t[0] = 0; + _allocation_t[1] = 0; +} + +bool AnyObj::in_aot_cache() const { + if (AOTMetaspace::in_aot_cache(this)) { + precond(_allocation_t[0] == 0); + precond(_allocation_t[1] == 0); + return true; + } else { + return false; + } +} + AnyObj::allocation_type AnyObj::get_allocation_type() const { + if (in_aot_cache()) { + return STACK_OR_EMBEDDED; + } assert(~(_allocation_t[0] | allocation_mask) == (uintptr_t)this, "lost resource object"); return (allocation_type)((~_allocation_t[0]) & allocation_mask); } bool AnyObj::is_type_set() const { + if (in_aot_cache()) { + return true; + } allocation_type type = (allocation_type)(_allocation_t[1] & allocation_mask); return get_allocation_type() == type && (_allocation_t[1] - type) == (uintptr_t)(&_allocation_t[1]); diff --git a/src/hotspot/share/memory/allocation.hpp b/src/hotspot/share/memory/allocation.hpp index 963ca04aadf..15b7750a363 100644 --- a/src/hotspot/share/memory/allocation.hpp +++ b/src/hotspot/share/memory/allocation.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -420,6 +420,7 @@ class AnyObj { public: enum allocation_type { STACK_OR_EMBEDDED = 0, RESOURCE_AREA, C_HEAP, ARENA, allocation_mask = 0x3 }; static void set_allocation_type(address res, allocation_type type) NOT_DEBUG_RETURN; + void set_in_aot_cache() NOT_DEBUG_RETURN; #ifdef ASSERT private: // When this object is allocated on stack the new() operator is not @@ -429,6 +430,7 @@ class AnyObj { uintptr_t _allocation_t[2]; bool is_type_set() const; void initialize_allocation_info(); + bool in_aot_cache() const; public: allocation_type get_allocation_type() const; bool allocated_on_stack_or_embedded() const { return get_allocation_type() == STACK_OR_EMBEDDED; } diff --git a/src/hotspot/share/memory/metaspaceClosure.cpp b/src/hotspot/share/memory/metaspaceClosure.cpp index f3c6e350034..0239eadf692 100644 --- a/src/hotspot/share/memory/metaspaceClosure.cpp +++ b/src/hotspot/share/memory/metaspaceClosure.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,21 @@ * */ +#include "cds/aotGrowableArray.hpp" +#include "classfile/packageEntry.hpp" #include "memory/metaspaceClosure.hpp" +#include "oops/array.hpp" +#include "oops/instanceKlass.hpp" + +// Sanity checks +static_assert(!HAS_METASPACE_POINTERS_DO(int)); + +static_assert(HAS_METASPACE_POINTERS_DO(Array)); +static_assert(HAS_METASPACE_POINTERS_DO(Array)); +static_assert(HAS_METASPACE_POINTERS_DO(InstanceKlass)); +static_assert(HAS_METASPACE_POINTERS_DO(PackageEntry)); +static_assert(HAS_METASPACE_POINTERS_DO(AOTGrowableArray)); +static_assert(HAS_METASPACE_POINTERS_DO(AOTGrowableArray)); void MetaspaceClosure::push_impl(MetaspaceClosure::Ref* ref) { if (_enclosing_ref != nullptr) { diff --git a/src/hotspot/share/memory/metaspaceClosure.hpp b/src/hotspot/share/memory/metaspaceClosure.hpp index 329502d7a47..b6ba69d6f63 100644 --- a/src/hotspot/share/memory/metaspaceClosure.hpp +++ b/src/hotspot/share/memory/metaspaceClosure.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,11 @@ #ifndef SHARE_MEMORY_METASPACECLOSURE_HPP #define SHARE_MEMORY_METASPACECLOSURE_HPP +#include "cds/aotGrowableArray.hpp" #include "cppstdlib/type_traits.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" +#include "memory/metaspaceClosureType.hpp" #include "metaprogramming/enableIf.hpp" #include "oops/array.hpp" #include "utilities/debug.hpp" @@ -36,41 +38,27 @@ #include "utilities/macros.hpp" #include "utilities/resizableHashTable.hpp" -// The metadata hierarchy is separate from the oop hierarchy - class MetaspaceObj; // no C++ vtable -//class Array; // no C++ vtable - class Annotations; // no C++ vtable - class ConstantPoolCache; // no C++ vtable - class ConstMethod; // no C++ vtable - class MethodCounters; // no C++ vtable - class Symbol; // no C++ vtable - class Metadata; // has C++ vtable (so do all subclasses) - class ConstantPool; - class MethodData; - class Method; - class Klass; - class InstanceKlass; - class InstanceMirrorKlass; - class InstanceClassLoaderKlass; - class InstanceRefKlass; - class ArrayKlass; - class ObjArrayKlass; - class TypeArrayKlass; +// This macro just check for the existence of a member with the name "metaspace_pointers_do". If the +// parameter list is not (MetaspaceClosure* it), you will get a compilation error. +#define HAS_METASPACE_POINTERS_DO(T) HasMetaspacePointersDo::value + +template +class HasMetaspacePointersDo { + template static void* test(decltype(&U::metaspace_pointers_do)); + template static int test(...); + using test_type = decltype(test(nullptr)); +public: + static constexpr bool value = std::is_pointer_v; +}; // class MetaspaceClosure -- // -// This class is used for iterating the objects in the HotSpot Metaspaces. It +// This class is used for iterating the class metadata objects. It // provides an API to walk all the reachable objects starting from a set of // root references (such as all Klass'es in the SystemDictionary). // -// Currently it is used for compacting the CDS archive by eliminate temporary -// objects allocated during archive creation time. See ArchiveBuilder for an example. -// -// To support MetaspaceClosure, each subclass of MetaspaceObj must provide -// a method of the type void metaspace_pointers_do(MetaspaceClosure*). This method -// should call MetaspaceClosure::push() on every pointer fields of this -// class that points to a MetaspaceObj. See Annotations::metaspace_pointers_do() -// for an example. +// Currently it is used to copy class metadata into the AOT cache. +// See ArchiveBuilder for an example. class MetaspaceClosure { public: enum Writability { @@ -79,16 +67,32 @@ public: _default }; +#define METASPACE_CLOSURE_TYPE_NAME_CASE(name) case MetaspaceClosureType::name ## Type: return #name; + + static const char* type_name(MetaspaceClosureType type) { + switch(type) { + METASPACE_CLOSURE_TYPES_DO(METASPACE_CLOSURE_TYPE_NAME_CASE) + default: + ShouldNotReachHere(); + return nullptr; + } + } + // class MetaspaceClosure::Ref -- // - // MetaspaceClosure can be viewed as a very simple type of copying garbage - // collector. For it to function properly, it requires each subclass of - // MetaspaceObj to provide two methods: + // For type X to be iterable by MetaspaceClosure, X (or one of X's supertypes) must have + // the following public functions: + // void metaspace_pointers_do(MetaspaceClosure* it); + // static bool is_read_only_by_default() { return true; } // - // size_t size(); -- to determine how much data to copy - // void metaspace_pointers_do(MetaspaceClosure*); -- to locate all the embedded pointers + // In addition, if X is not a subtype of MetaspaceObj, it must have the following function: + // MetaspaceClosureType type() const; + // int size_in_heapwords() const; // - // Calling these methods would be trivial if these two were virtual methods. + // Currently, the iterable types include all subtypes of MetsapceObj, as well + // as GrowableArray, ModuleEntry and PackageEntry. + // + // Calling these functions would be trivial if these were virtual functions. // However, to save space, MetaspaceObj has NO vtable. The vtable is introduced // only in the Metadata class. // @@ -97,7 +101,7 @@ public: // so that we can statically discover the type of a object. The use of Ref // depends on the fact that: // - // [1] We don't use polymorphic pointers for MetaspaceObj's that are not subclasses + // [1] We don't use polymorphic pointers to MetaspaceObj's that are not subclasses // of Metadata. I.e., we don't do this: // class Klass { // MetaspaceObj *_obj; @@ -130,8 +134,7 @@ public: virtual bool not_null() const = 0; virtual int size() const = 0; virtual void metaspace_pointers_do(MetaspaceClosure *it) const = 0; - virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const = 0; - virtual MetaspaceObj::Type msotype() const = 0; + virtual MetaspaceClosureType type() const = 0; virtual bool is_read_only_by_default() const = 0; virtual ~Ref() {} @@ -180,7 +183,26 @@ public: } private: - // MSORef -- iterate an instance of MetaspaceObj + template ::value)> + static int get_size(T* obj) { + return obj->size(); + } + + template ::value)> + static int get_size(T* obj) { + return obj->size_in_heapwords(); + } + + static MetaspaceClosureType as_type(MetaspaceClosureType t) { + return t; + } + + static MetaspaceClosureType as_type(MetaspaceObj::Type msotype) { + precond(msotype < MetaspaceObj::_number_of_types); + return (MetaspaceClosureType)msotype; + } + + // MSORef -- iterate an instance of T, where T::metaspace_pointers_do() exists. template class MSORef : public Ref { T** _mpp; T* dereference() const { @@ -196,18 +218,20 @@ private: virtual bool is_read_only_by_default() const { return T::is_read_only_by_default(); } virtual bool not_null() const { return dereference() != nullptr; } - virtual int size() const { return dereference()->size(); } - virtual MetaspaceObj::Type msotype() const { return dereference()->type(); } + virtual int size() const { return get_size(dereference()); } + virtual MetaspaceClosureType type() const { return as_type(dereference()->type()); } virtual void metaspace_pointers_do(MetaspaceClosure *it) const { dereference()->metaspace_pointers_do(it); } - virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const { - ((T*)new_loc)->metaspace_pointers_do(it); - } }; - // abstract base class for MSOArrayRef, MSOPointerArrayRef and OtherArrayRef + //--------------------- + // Support for Array + //--------------------- + + // Abstract base class for MSOArrayRef, MSOPointerArrayRef and OtherArrayRef. + // These are used for iterating Array. template class ArrayRef : public Ref { Array** _mpp; protected: @@ -224,10 +248,10 @@ private: virtual bool is_read_only_by_default() const { return true; } virtual bool not_null() const { return dereference() != nullptr; } virtual int size() const { return dereference()->size(); } - virtual MetaspaceObj::Type msotype() const { return MetaspaceObj::array_type(sizeof(T)); } + virtual MetaspaceClosureType type() const { return as_type(MetaspaceObj::array_type(sizeof(T))); } }; - // OtherArrayRef -- iterate an instance of Array, where T is NOT a subtype of MetaspaceObj. + // OtherArrayRef -- iterate an instance of Array, where T does NOT have metaspace_pointer_do(). // T can be a primitive type, such as int, or a structure. However, we do not scan // the fields inside T, so you should not embed any pointers inside T. template class OtherArrayRef : public ArrayRef { @@ -238,13 +262,9 @@ private: Array* array = ArrayRef::dereference(); log_trace(aot)("Iter(OtherArray): %p [%d]", array, array->length()); } - virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const { - Array* array = (Array*)new_loc; - log_trace(aot)("Iter(OtherArray): %p [%d]", array, array->length()); - } }; - // MSOArrayRef -- iterate an instance of Array, where T is a subtype of MetaspaceObj. + // MSOArrayRef -- iterate an instance of Array, where T has metaspace_pointer_do(). // We recursively call T::metaspace_pointers_do() for each element in this array. template class MSOArrayRef : public ArrayRef { public: @@ -253,9 +273,6 @@ private: virtual void metaspace_pointers_do(MetaspaceClosure *it) const { metaspace_pointers_do_at_impl(it, ArrayRef::dereference()); } - virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const { - metaspace_pointers_do_at_impl(it, (Array*)new_loc); - } private: void metaspace_pointers_do_at_impl(MetaspaceClosure *it, Array* array) const { log_trace(aot)("Iter(MSOArray): %p [%d]", array, array->length()); @@ -266,7 +283,7 @@ private: } }; - // MSOPointerArrayRef -- iterate an instance of Array, where T is a subtype of MetaspaceObj. + // MSOPointerArrayRef -- iterate an instance of Array, where T has metaspace_pointer_do(). // We recursively call MetaspaceClosure::push() for each pointer in this array. template class MSOPointerArrayRef : public ArrayRef { public: @@ -275,9 +292,6 @@ private: virtual void metaspace_pointers_do(MetaspaceClosure *it) const { metaspace_pointers_do_at_impl(it, ArrayRef::dereference()); } - virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const { - metaspace_pointers_do_at_impl(it, (Array*)new_loc); - } private: void metaspace_pointers_do_at_impl(MetaspaceClosure *it, Array* array) const { log_trace(aot)("Iter(MSOPointerArray): %p [%d]", array, array->length()); @@ -288,6 +302,102 @@ private: } }; + //-------------------------------- + // Support for AOTGrowableArray + //-------------------------------- + + // Abstract base class for MSOCArrayRef, MSOPointerCArrayRef and OtherCArrayRef. + // These are used for iterating the buffer held by AOTGrowableArray. + template class CArrayRef : public Ref { + T** _mpp; + int _num_elems; // Number of elements + + int byte_size() const { + return _num_elems * sizeof(T); + } + + protected: + // C pointer arrays don't support tagged pointers. + T* dereference() const { + return *_mpp; + } + virtual void** mpp() const { + return (void**)_mpp; + } + int num_elems() const { + return _num_elems; + } + public: + CArrayRef(T** mpp, int num_elems, Writability w) + : Ref(w), _mpp(mpp), _num_elems(num_elems) { + assert(is_aligned(byte_size(), BytesPerWord), "must be"); + } + + virtual bool is_read_only_by_default() const { return false; } + virtual bool not_null() const { return dereference() != nullptr; } + virtual int size() const { return (int)heap_word_size(byte_size()); } + virtual MetaspaceClosureType type() const { return MetaspaceClosureType::CArrayType; } + }; + + // OtherCArrayRef -- iterate a C array of type T, where T does NOT have metaspace_pointer_do(). + // T can be a primitive type, such as int, or a structure. However, we do not scan + // the fields inside T, so you should not embed any pointers inside T. + template class OtherCArrayRef : public CArrayRef { + public: + OtherCArrayRef(T** mpp, int num_elems, Writability w) : CArrayRef(mpp, num_elems, w) {} + + virtual void metaspace_pointers_do(MetaspaceClosure *it) const { + T* array = CArrayRef::dereference(); + log_trace(aot)("Iter(OtherCArray): %p [%d]", array, CArrayRef::num_elems()); + } + }; + + // MSOCArrayRef -- iterate a C array of type T, where T has metaspace_pointer_do(). + // We recursively call T::metaspace_pointers_do() for each element in this array. + // This is for supporting AOTGrowableArray. + // + // E.g., PackageEntry* _pkg_entry_pointers[2]; // a buffer that has 2 PackageEntry objects + // ... + // it->push(&_pkg_entry_pointers, 2); + // /* calls _pkg_entry_pointers[0].metaspace_pointers_do(it); */ + // /* calls _pkg_entry_pointers[1].metaspace_pointers_do(it); */ + template class MSOCArrayRef : public CArrayRef { + public: + MSOCArrayRef(T** mpp, int num_elems, Writability w) : CArrayRef(mpp, num_elems, w) {} + + virtual void metaspace_pointers_do(MetaspaceClosure *it) const { + T* array = CArrayRef::dereference(); + log_trace(aot)("Iter(MSOCArray): %p [%d]", array, CArrayRef::num_elems()); + for (int i = 0; i < CArrayRef::num_elems(); i++) { + T* elm = array + i; + elm->metaspace_pointers_do(it); + } + } + }; + + // MSOPointerCArrayRef -- iterate a C array of type T*, where T has metaspace_pointer_do(). + // We recursively call MetaspaceClosure::push() for each pointer in this array. + // This is for supporting AOTGrowableArray. + // + // E.g., PackageEntry** _pkg_entry_pointers[2]; // a buffer that has 2 PackageEntry pointers + // ... + // it->push(&_pkg_entry_pointers, 2); + // /* calls _pkg_entry_pointers[0]->metaspace_pointers_do(it); */ + // /* calls _pkg_entry_pointers[1]->metaspace_pointers_do(it); */ + template class MSOPointerCArrayRef : public CArrayRef { + public: + MSOPointerCArrayRef(T*** mpp, int num_elems, Writability w) : CArrayRef(mpp, num_elems, w) {} + + virtual void metaspace_pointers_do(MetaspaceClosure *it) const { + T** array = CArrayRef::dereference(); + log_trace(aot)("Iter(MSOPointerCArray): %p [%d]", array, CArrayRef::num_elems()); + for (int i = 0; i < CArrayRef::num_elems(); i++) { + T** mpp = array + i; + it->push(mpp); + } + } + }; + // Normally, chains of references like a->b->c->d are iterated recursively. However, // if recursion is too deep, we save the Refs in _pending_refs, and push them later in // MetaspaceClosure::finish(). This avoids overflowing the C stack. @@ -330,37 +440,61 @@ public: // Array*>* a4 = ...; it->push(&a4); => MSOPointerArrayRef // Array* a5 = ...; it->push(&a5); => MSOPointerArrayRef // - // Note that the following will fail to compile (to prevent you from adding new fields - // into the MetaspaceObj subtypes that cannot be properly copied by CDS): + // AOTGrowableArrays have a separate "C array" buffer, so they are scanned in two steps: // - // MemoryPool* p = ...; it->push(&p); => MemoryPool is not a subclass of MetaspaceObj - // Array* a6 = ...; it->push(&a6); => MemoryPool is not a subclass of MetaspaceObj - // Array* a7 = ...; it->push(&a7); => int is not a subclass of MetaspaceObj + // AOTGrowableArray* ga1 = ...; it->push(&ga1); => MSORef => OtherCArrayRef + // AOTGrowableArray* ga2 = ...; it->push(&ga2); => MSORef => MSOCArrayRef + // AOTGrowableArray* ga3 = ...; it->push(&ga3); => MSORef => MSOPointerCArrayRef + // + // Note that the following will fail to compile: + // + // MemoryPool* p = ...; it->push(&p); => MemoryPool doesn't have metaspace_pointers_do + // Array* a6 = ...; it->push(&a6); => MemoryPool doesn't have metaspace_pointers_do + // Array* a7 = ...; it->push(&a7); => int doesn't have metaspace_pointers_do + // --- Regular iterable objects template void push(T** mpp, Writability w = _default) { - static_assert(std::is_base_of::value, "Do not push pointers of arbitrary types"); + static_assert(HAS_METASPACE_POINTERS_DO(T), "Do not push pointers of arbitrary types"); push_with_ref>(mpp, w); } - template ::value)> + // --- Array + template void push(Array** mpp, Writability w = _default) { push_with_ref>(mpp, w); } - template ::value)> + template void push(Array** mpp, Writability w = _default) { push_with_ref>(mpp, w); } template void push(Array** mpp, Writability w = _default) { - static_assert(std::is_base_of::value, "Do not push Arrays of arbitrary pointer types"); + static_assert(HAS_METASPACE_POINTERS_DO(T), "Do not push Arrays of arbitrary pointer types"); push_with_ref>(mpp, w); } + + // --- The buffer of AOTGrowableArray + template + void push_c_array(T** mpp, int num_elems, Writability w = _default) { + push_impl(new OtherCArrayRef(mpp, num_elems, w)); + } + + template + void push_c_array(T** mpp, int num_elems, Writability w = _default) { + push_impl(new MSOCArrayRef(mpp, num_elems, w)); + } + + template + void push_c_array(T*** mpp, int num_elems, Writability w = _default) { + static_assert(HAS_METASPACE_POINTERS_DO(T), "Do not push C arrays of arbitrary pointer types"); + push_impl(new MSOPointerCArrayRef(mpp, num_elems, w)); + } }; -// This is a special MetaspaceClosure that visits each unique MetaspaceObj once. +// This is a special MetaspaceClosure that visits each unique object once. class UniqueMetaspaceClosure : public MetaspaceClosure { static const int INITIAL_TABLE_SIZE = 15889; static const int MAX_TABLE_SIZE = 1000000; diff --git a/src/hotspot/share/memory/metaspaceClosureType.hpp b/src/hotspot/share/memory/metaspaceClosureType.hpp new file mode 100644 index 00000000000..adf6805521b --- /dev/null +++ b/src/hotspot/share/memory/metaspaceClosureType.hpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2026, 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_MEMORY_METASPACECLOSURETYPE_HPP +#define SHARE_MEMORY_METASPACECLOSURETYPE_HPP + +#include "memory/allocation.hpp" + +// MetaspaceClosure is able to iterate on MetaspaceObjs, plus the following classes +#define METASPACE_CLOSURE_TYPES_DO(f) \ + METASPACE_OBJ_TYPES_DO(f) \ + f(CArray) \ + f(GrowableArray) \ + f(ModuleEntry) \ + f(PackageEntry) \ + +#define METASPACE_CLOSURE_TYPE_DECLARE(name) name ## Type, + +enum class MetaspaceClosureType : int { + METASPACE_CLOSURE_TYPES_DO(METASPACE_CLOSURE_TYPE_DECLARE) + _number_of_types +}; + + +#endif // SHARE_MEMORY_METASPACECLOSURETYPE_HPP diff --git a/src/hotspot/share/oops/array.hpp b/src/hotspot/share/oops/array.hpp index 90dcc9dfeaf..82067e007ea 100644 --- a/src/hotspot/share/oops/array.hpp +++ b/src/hotspot/share/oops/array.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -33,6 +33,8 @@ // Array for metadata allocation +class MetaspaceClosure; + template class Array: public MetaspaceObj { friend class ArchiveBuilder; @@ -157,6 +159,9 @@ protected: st->print("Array(" PTR_FORMAT ")", p2i(this)); } + // This function does nothing. The iteration of the elements are done inside metaspaceClosure.hpp + void metaspace_pointers_do(MetaspaceClosure* it) {} + #ifndef PRODUCT void print(outputStream* st) { for (int i = 0; i< _length; i++) { diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 56a80daed60..1963327fc78 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -2693,6 +2693,10 @@ void InstanceKlass::metaspace_pointers_do(MetaspaceClosure* it) { it->push(&_nest_members); it->push(&_permitted_subclasses); it->push(&_record_components); + + if (CDSConfig::is_dumping_full_module_graph() && !defined_by_other_loaders()) { + it->push(&_package_entry); + } } #if INCLUDE_CDS @@ -2791,24 +2795,9 @@ void InstanceKlass::remove_java_mirror() { void InstanceKlass::init_shared_package_entry() { assert(CDSConfig::is_dumping_archive(), "must be"); -#if !INCLUDE_CDS_JAVA_HEAP - _package_entry = nullptr; -#else - if (CDSConfig::is_dumping_full_module_graph()) { - if (defined_by_other_loaders()) { - _package_entry = nullptr; - } else { - _package_entry = PackageEntry::get_archived_entry(_package_entry); - } - } else if (CDSConfig::is_dumping_dynamic_archive() && - CDSConfig::is_using_full_module_graph() && - AOTMetaspace::in_aot_cache(_package_entry)) { - // _package_entry is an archived package in the base archive. Leave it as is. - } else { + if (!CDSConfig::is_dumping_full_module_graph() || defined_by_other_loaders()) { _package_entry = nullptr; } - ArchivePtrMarker::mark_pointer((address**)&_package_entry); -#endif } void InstanceKlass::compute_has_loops_flag_for_methods() { diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index 140207e5d63..11bd39c839f 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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,6 @@ #include "code/vmreg.hpp" #include "interpreter/linkResolver.hpp" #include "memory/allStatic.hpp" -#include "memory/metaspaceClosure.hpp" #include "memory/resourceArea.hpp" #include "runtime/safepointVerifiers.hpp" #include "runtime/stubInfo.hpp" @@ -38,6 +37,7 @@ class AdapterHandlerEntry; class AdapterFingerPrint; +class MetaspaceClosure; class vframeStream; // Runtime is the base class for various runtime interfaces diff --git a/src/hotspot/share/utilities/growableArray.hpp b/src/hotspot/share/utilities/growableArray.hpp index 1fef271c8c0..1823a2ba861 100644 --- a/src/hotspot/share/utilities/growableArray.hpp +++ b/src/hotspot/share/utilities/growableArray.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -116,6 +116,12 @@ protected: ~GrowableArrayView() {} +protected: + // Used by AOTGrowableArray for MetaspaceClosure support. + E** data_addr() { + return &_data; + } + public: bool operator==(const GrowableArrayView& rhs) const { if (_len != rhs._len) diff --git a/test/hotspot/gtest/utilities/test_metaspaceClosure.cpp b/test/hotspot/gtest/utilities/test_metaspaceClosure.cpp index b2acf45c470..c98b38b8c3c 100644 --- a/test/hotspot/gtest/utilities/test_metaspaceClosure.cpp +++ b/test/hotspot/gtest/utilities/test_metaspaceClosure.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,6 +21,7 @@ * questions. */ +#include "cds/aotGrowableArray.inline.hpp" #include "memory/allocation.hpp" #include "memory/metadataFactory.hpp" #include "memory/metaspaceClosure.hpp" @@ -58,7 +59,7 @@ public: class MyUniqueMetaspaceClosure : public MetaspaceClosure { static constexpr int SIZE = 10; - MyMetaData* _visited[SIZE]; + void* _visited[SIZE]; int _count; public: MyUniqueMetaspaceClosure() { @@ -71,11 +72,22 @@ public: virtual bool do_ref(Ref* ref, bool read_only) { MyMetaData* ptr = (MyMetaData*)ref->obj(); assert(_count < SIZE, "out of bounds"); - _visited[_count++] = ptr; + for (int i = 0; i < _count; i++) { + if (_visited[i] == (void*)ptr) { + // We have walked this before. + return false; + } + } + + // Found a new pointer. Let's walk it + _visited[_count++] = (void*)ptr; return true; // recurse } bool has_visited(MyMetaData* p) { + return has_visited((void*)p); + } + bool has_visited(void* p) { for (int i = 0; i < SIZE; i++) { if (_visited[i] == p) { return true; @@ -83,6 +95,9 @@ public: } return false; } + int visited_count() { + return _count; + } }; // iterate an Array @@ -104,7 +119,9 @@ TEST_VM(MetaspaceClosure, MSOPointerArrayRef) { MyUniqueMetaspaceClosure closure; closure.push(&array); + closure.finish(); + EXPECT_TRUE(closure.has_visited(array)) << "must be"; EXPECT_TRUE(closure.has_visited(&x)) << "must be"; EXPECT_TRUE(closure.has_visited(&y)) << "must be"; EXPECT_TRUE(closure.has_visited(&z)) << "must be"; @@ -130,8 +147,85 @@ TEST_VM(MetaspaceClosure, MSOArrayRef) { MyUniqueMetaspaceClosure closure; closure.push(&array); + closure.finish(); + EXPECT_TRUE(closure.has_visited(array)) << "must be"; EXPECT_TRUE(closure.has_visited(&x)) << "must be"; EXPECT_TRUE(closure.has_visited(&y)) << "must be"; EXPECT_TRUE(closure.has_visited(&z)) << "must be"; } + +// iterate an Array +TEST_VM(MetaspaceClosure, OtherArrayRef) { + JavaThread* THREAD = JavaThread::current(); + ClassLoaderData* cld = ClassLoaderData::the_null_class_loader_data(); + Array* array = MetadataFactory::new_array(cld, 4, THREAD); + + MyUniqueMetaspaceClosure closure; + closure.push(&array); + closure.finish(); + + EXPECT_TRUE(closure.has_visited(array)) << "must be"; +} + +// iterate an AOTGrowableArray +TEST_VM(MetaspaceClosure, GrowableArray_MSOPointer) { + AOTGrowableArray* array = new(mtClass) AOTGrowableArray(2, mtClass); + + MyMetaData x; + MyMetaData y; + MyMetaData z; + + array->push(&x); + array->push(&y); + y._a = &z; + + MyUniqueMetaspaceClosure closure; + closure.push(&array); + closure.finish(); + + EXPECT_TRUE(closure.has_visited(array)) << "must be"; + EXPECT_TRUE(closure.has_visited(&x)) << "must be"; + EXPECT_TRUE(closure.has_visited(&y)) << "must be"; + EXPECT_TRUE(closure.has_visited(&z)) << "must be"; +} + +// iterate an AOTGrowableArray +TEST_VM(MetaspaceClosure, GrowableArray_MSO) { + AOTGrowableArray* array = new(mtClass) AOTGrowableArray(4, mtClass); + + for (int i = 0; i < array->length(); i++) { + EXPECT_TRUE(array->at(i)._a == nullptr) << "should be initialized to null"; + EXPECT_TRUE(array->at(i)._b == nullptr) << "should be initialized to null"; + } + + MyMetaData x; + MyMetaData y; + MyMetaData z; + + z._a = &x; + z._b = &y; + y._a = &z; + array->push(z); + + MyUniqueMetaspaceClosure closure; + closure.push(&array); + closure.finish(); + + EXPECT_TRUE(closure.has_visited(array)) << "must be"; + EXPECT_TRUE(closure.has_visited(&x)) << "must be"; + EXPECT_TRUE(closure.has_visited(&y)) << "must be"; + EXPECT_TRUE(closure.has_visited(&z)) << "must be"; +} + +// iterate an AOTGrowableArray +TEST_VM(MetaspaceClosure, GrowableArray_jlong) { + AOTGrowableArray* array = new(mtClass) AOTGrowableArray(4, mtClass); + + MyUniqueMetaspaceClosure closure; + closure.push(&array); + closure.finish(); + + EXPECT_TRUE(closure.has_visited(array)) << "must be"; + EXPECT_TRUE(closure.visited_count() == 2) << "must visit buffer inside GrowableArray"; +} From 5c05d6f230e34cf409529d87b71f768a384ae4b4 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 27 Jan 2026 08:26:00 +0000 Subject: [PATCH 205/328] 8374686: ZGC: Convert zMarkTerminate to use Atomic Reviewed-by: stefank, kbarrett --- src/hotspot/share/gc/z/zMarkTerminate.hpp | 9 ++-- .../share/gc/z/zMarkTerminate.inline.hpp | 45 +++++++++---------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/hotspot/share/gc/z/zMarkTerminate.hpp b/src/hotspot/share/gc/z/zMarkTerminate.hpp index cff1f8e73fa..9def3e72120 100644 --- a/src/hotspot/share/gc/z/zMarkTerminate.hpp +++ b/src/hotspot/share/gc/z/zMarkTerminate.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #define SHARE_GC_Z_ZMARKTERMINATE_HPP #include "gc/z/zLock.hpp" +#include "runtime/atomic.hpp" #include "utilities/globalDefinitions.hpp" class ZMarkStripeSet; @@ -32,9 +33,9 @@ class ZMarkStripeSet; class ZMarkTerminate { private: uint _nworkers; - volatile uint _nworking; - volatile uint _nawakening; - volatile bool _resurrected; + Atomic _nworking; + Atomic _nawakening; + Atomic _resurrected; ZConditionLock _lock; void maybe_reduce_stripes(ZMarkStripeSet* stripes, size_t used_nstripes); diff --git a/src/hotspot/share/gc/z/zMarkTerminate.inline.hpp b/src/hotspot/share/gc/z/zMarkTerminate.inline.hpp index 575044e3a39..84a545623bc 100644 --- a/src/hotspot/share/gc/z/zMarkTerminate.inline.hpp +++ b/src/hotspot/share/gc/z/zMarkTerminate.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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,6 @@ #include "gc/z/zLock.inline.hpp" #include "gc/z/zMarkStack.hpp" #include "logging/log.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/osThread.hpp" #include "runtime/thread.inline.hpp" @@ -42,24 +41,23 @@ inline ZMarkTerminate::ZMarkTerminate() _lock() {} inline void ZMarkTerminate::reset(uint nworkers) { - AtomicAccess::store(&_nworkers, nworkers); - AtomicAccess::store(&_nworking, nworkers); - _nawakening = 0; + _nworkers = nworkers; + _nworking.store_relaxed(nworkers); + _nawakening.store_relaxed(0u); } inline void ZMarkTerminate::leave() { SuspendibleThreadSetLeaver sts_leaver; ZLocker locker(&_lock); - AtomicAccess::store(&_nworking, _nworking - 1); - if (_nworking == 0) { + if (_nworking.sub_then_fetch(1u, memory_order_relaxed) == 0) { // Last thread leaving; notify waiters _lock.notify_all(); } } inline void ZMarkTerminate::maybe_reduce_stripes(ZMarkStripeSet* stripes, size_t used_nstripes) { - size_t nstripes = stripes->nstripes(); + const size_t nstripes = stripes->nstripes(); if (used_nstripes == nstripes && nstripes > 1u) { stripes->try_set_nstripes(nstripes, nstripes >> 1); } @@ -69,8 +67,7 @@ inline bool ZMarkTerminate::try_terminate(ZMarkStripeSet* stripes, size_t used_n SuspendibleThreadSetLeaver sts_leaver; ZLocker locker(&_lock); - AtomicAccess::store(&_nworking, _nworking - 1); - if (_nworking == 0) { + if (_nworking.sub_then_fetch(1u, memory_order_relaxed) == 0) { // Last thread entering termination: success _lock.notify_all(); return true; @@ -83,24 +80,24 @@ inline bool ZMarkTerminate::try_terminate(ZMarkStripeSet* stripes, size_t used_n // We either got notification about more work // or got a spurious wakeup; don't terminate - if (_nawakening > 0) { - AtomicAccess::store(&_nawakening, _nawakening - 1); + if (_nawakening.load_relaxed() > 0) { + _nawakening.sub_then_fetch(1u, memory_order_relaxed); } - if (_nworking == 0) { + if (_nworking.load_relaxed() == 0) { // We got notified all work is done; terminate return true; } - AtomicAccess::store(&_nworking, _nworking + 1); + _nworking.add_then_fetch(1u, memory_order_relaxed); return false; } inline void ZMarkTerminate::wake_up() { - uint nworking = AtomicAccess::load(&_nworking); - uint nawakening = AtomicAccess::load(&_nawakening); - if (nworking + nawakening == AtomicAccess::load(&_nworkers)) { + const uint nworking = _nworking.load_relaxed(); + const uint nawakening = _nawakening.load_relaxed(); + if (nworking + nawakening == _nworkers) { // Everyone is working or about to return; } @@ -111,24 +108,24 @@ inline void ZMarkTerminate::wake_up() { } ZLocker locker(&_lock); - if (_nworking + _nawakening != _nworkers) { + if (_nworking.load_relaxed() + _nawakening.load_relaxed() != _nworkers) { // Everyone is not working - AtomicAccess::store(&_nawakening, _nawakening + 1); + _nawakening.add_then_fetch(1u, memory_order_relaxed); _lock.notify(); } } inline bool ZMarkTerminate::saturated() const { - uint nworking = AtomicAccess::load(&_nworking); - uint nawakening = AtomicAccess::load(&_nawakening); + const uint nworking = _nworking.load_relaxed(); + const uint nawakening = _nawakening.load_relaxed(); - return nworking + nawakening == AtomicAccess::load(&_nworkers); + return nworking + nawakening == _nworkers; } inline void ZMarkTerminate::set_resurrected(bool value) { // Update resurrected if it changed if (resurrected() != value) { - AtomicAccess::store(&_resurrected, value); + _resurrected.store_relaxed(value); if (value) { log_debug(gc, marking)("Resurrection broke termination"); } else { @@ -138,7 +135,7 @@ inline void ZMarkTerminate::set_resurrected(bool value) { } inline bool ZMarkTerminate::resurrected() const { - return AtomicAccess::load(&_resurrected); + return _resurrected.load_relaxed(); } #endif // SHARE_GC_Z_ZMARKTERMINATE_INLINE_HPP From bd92c68ef0aa7615c62626eb6baf4496b0137cad Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 27 Jan 2026 08:36:41 +0000 Subject: [PATCH 206/328] 8374687: ZGC: Convert zNMethodTableIteration to use Atomic Reviewed-by: stefank, tschatzl --- src/hotspot/share/gc/z/zNMethodTableIteration.cpp | 9 ++++----- src/hotspot/share/gc/z/zNMethodTableIteration.hpp | 9 +++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/z/zNMethodTableIteration.cpp b/src/hotspot/share/gc/z/zNMethodTableIteration.cpp index bdd4270ddac..423e98dd28b 100644 --- a/src/hotspot/share/gc/z/zNMethodTableIteration.cpp +++ b/src/hotspot/share/gc/z/zNMethodTableIteration.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ #include "gc/z/zNMethodTableEntry.hpp" #include "gc/z/zNMethodTableIteration.hpp" #include "memory/iterator.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" @@ -42,11 +41,11 @@ void ZNMethodTableIteration::nmethods_do_begin(ZNMethodTableEntry* table, size_t _table = table; _size = size; - _claimed = 0; + _claimed.store_relaxed(0u); } void ZNMethodTableIteration::nmethods_do_end() { - assert(_claimed >= _size, "Failed to claim all table entries"); + assert(_claimed.load_relaxed() >= _size, "Failed to claim all table entries"); // Finish iteration _table = nullptr; @@ -57,7 +56,7 @@ void ZNMethodTableIteration::nmethods_do(NMethodClosure* cl) { // Claim table partition. Each partition is currently sized to span // two cache lines. This number is just a guess, but seems to work well. const size_t partition_size = (ZCacheLineSize * 2) / sizeof(ZNMethodTableEntry); - const size_t partition_start = MIN2(AtomicAccess::fetch_then_add(&_claimed, partition_size), _size); + const size_t partition_start = MIN2(_claimed.fetch_then_add(partition_size), _size); const size_t partition_end = MIN2(partition_start + partition_size, _size); if (partition_start == partition_end) { // End of table diff --git a/src/hotspot/share/gc/z/zNMethodTableIteration.hpp b/src/hotspot/share/gc/z/zNMethodTableIteration.hpp index 064c3eafca0..12dc096491d 100644 --- a/src/hotspot/share/gc/z/zNMethodTableIteration.hpp +++ b/src/hotspot/share/gc/z/zNMethodTableIteration.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,15 +25,16 @@ #define SHARE_GC_Z_ZNMETHODTABLEITERATION_HPP #include "gc/z/zGlobals.hpp" +#include "runtime/atomic.hpp" class NMethodClosure; class ZNMethodTableEntry; class ZNMethodTableIteration { private: - ZNMethodTableEntry* _table; - size_t _size; - ZCACHE_ALIGNED volatile size_t _claimed; + ZNMethodTableEntry* _table; + size_t _size; + ZCACHE_ALIGNED Atomic _claimed; bool in_progress() const; From 6fda44172e955d4e1d181598a97902ed5b16c57b Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 27 Jan 2026 08:42:44 +0000 Subject: [PATCH 207/328] 8374690: ZGC: Convert zRelocate to use Atomic Reviewed-by: stefank, tschatzl --- src/hotspot/share/gc/z/zRelocate.cpp | 26 +++++++++++++------------- src/hotspot/share/gc/z/zRelocate.hpp | 7 ++++--- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index da07f67d859..d51cf5abbae 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, 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 @@ -64,31 +64,31 @@ ZRelocateQueue::ZRelocateQueue() _needs_attention(0) {} bool ZRelocateQueue::needs_attention() const { - return AtomicAccess::load(&_needs_attention) != 0; + return _needs_attention.load_relaxed() != 0; } void ZRelocateQueue::inc_needs_attention() { - const int needs_attention = AtomicAccess::add(&_needs_attention, 1); + const int needs_attention = _needs_attention.add_then_fetch(1); assert(needs_attention == 1 || needs_attention == 2, "Invalid state"); } void ZRelocateQueue::dec_needs_attention() { - const int needs_attention = AtomicAccess::sub(&_needs_attention, 1); + const int needs_attention = _needs_attention.sub_then_fetch(1); assert(needs_attention == 0 || needs_attention == 1, "Invalid state"); } void ZRelocateQueue::activate(uint nworkers) { - _is_active = true; + _is_active.store_relaxed(true); join(nworkers); } void ZRelocateQueue::deactivate() { - AtomicAccess::store(&_is_active, false); + _is_active.store_relaxed(false); clear(); } bool ZRelocateQueue::is_active() const { - return AtomicAccess::load(&_is_active); + return _is_active.load_relaxed(); } void ZRelocateQueue::join(uint nworkers) { @@ -453,7 +453,7 @@ static void retire_target_page(ZGeneration* generation, ZPage* page) { class ZRelocateSmallAllocator { private: ZGeneration* const _generation; - volatile size_t _in_place_count; + Atomic _in_place_count; public: ZRelocateSmallAllocator(ZGeneration* generation) @@ -463,7 +463,7 @@ public: ZPage* alloc_and_retire_target_page(ZForwarding* forwarding, ZPage* target) { ZPage* const page = alloc_page(forwarding); if (page == nullptr) { - AtomicAccess::inc(&_in_place_count); + _in_place_count.add_then_fetch(1u); } if (target != nullptr) { @@ -493,7 +493,7 @@ public: } size_t in_place_count() const { - return _in_place_count; + return _in_place_count.load_relaxed(); } }; @@ -503,7 +503,7 @@ private: ZConditionLock _lock; ZRelocationTargets* _shared_targets; bool _in_place; - volatile size_t _in_place_count; + Atomic _in_place_count; public: ZRelocateMediumAllocator(ZGeneration* generation, ZRelocationTargets* shared_targets) @@ -539,7 +539,7 @@ public: ZPage* const to_page = alloc_page(forwarding); _shared_targets->set(partition_id, to_age, to_page); if (to_page == nullptr) { - AtomicAccess::inc(&_in_place_count); + _in_place_count.add_then_fetch(1u); _in_place = true; } @@ -579,7 +579,7 @@ public: } size_t in_place_count() const { - return _in_place_count; + return _in_place_count.load_relaxed(); } }; diff --git a/src/hotspot/share/gc/z/zRelocate.hpp b/src/hotspot/share/gc/z/zRelocate.hpp index 038efba83eb..d25536e1bce 100644 --- a/src/hotspot/share/gc/z/zRelocate.hpp +++ b/src/hotspot/share/gc/z/zRelocate.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "gc/z/zPageAge.hpp" #include "gc/z/zRelocationSet.hpp" #include "gc/z/zValue.hpp" +#include "runtime/atomic.hpp" class ZForwarding; class ZGeneration; @@ -42,8 +43,8 @@ private: uint _nworkers; uint _nsynchronized; bool _synchronize; - volatile bool _is_active; - volatile int _needs_attention; + Atomic _is_active; + Atomic _needs_attention; bool needs_attention() const; void inc_needs_attention(); From ee2deaded82e5fbd94aff7dd22cf2d5c57caa94e Mon Sep 17 00:00:00 2001 From: Varada M Date: Tue, 27 Jan 2026 10:01:02 +0000 Subject: [PATCH 208/328] 8371187: [BigEndian Platforms] Vector lane reversal error Reviewed-by: mdoerr, amitkumar --- .../jdk/incubator/vector/AbstractVector.java | 42 ++++++++++++++++++- .../jdk/incubator/vector/ByteVector.java | 8 ++++ .../jdk/incubator/vector/DoubleVector.java | 12 ++++++ .../jdk/incubator/vector/FloatVector.java | 12 ++++++ .../jdk/incubator/vector/IntVector.java | 12 ++++++ .../jdk/incubator/vector/LongVector.java | 12 ++++++ .../jdk/incubator/vector/ShortVector.java | 12 ++++++ 7 files changed, 109 insertions(+), 1 deletion(-) diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractVector.java index 350931cd443..09bb0607759 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractVector.java @@ -182,7 +182,44 @@ abstract class AbstractVector extends Vector { final AbstractVector asVectorRawTemplate(LaneType laneType) { // NOTE: This assumes that convert0('X') // respects REGISTER_ENDIAN order. - return convert0('X', vspecies().withLanes(laneType)); + return convert0('X', vspecies().withLanes(laneType)).swapIfNeeded(vspecies()); + } + + @ForceInline + protected static VectorShuffle normalizeSubLanesForSpecies(AbstractSpecies targetSpecies, int subLanesPerSrc) { + final int lanes = targetSpecies.laneCount(); + + if ((lanes % subLanesPerSrc) != 0) { + throw new IllegalArgumentException("laneCount " + lanes + " not divisible by subLanesPerSrc " + subLanesPerSrc); + } + + // Each group corresponds to one source lane. + // For each group, reverse the lanes inside that group. + final int groups = lanes / subLanesPerSrc; + int[] map = new int[lanes]; + for (int g = 0; g < groups; ++g) { + int base = g * subLanesPerSrc; + for (int j = 0; j < subLanesPerSrc; ++j) { + map[base + j] = base + (subLanesPerSrc - 1 - j); + } + } + return VectorShuffle.fromArray(targetSpecies, map, 0); + } + + @ForceInline + protected final int subLanesToSwap(AbstractSpecies srcSpecies) { + if (java.nio.ByteOrder.nativeOrder() != ByteOrder.BIG_ENDIAN) { + return -1; + } + int sBytes = srcSpecies.elementSize(); + int tBytes = vspecies().elementSize(); + + // No lane reordering needed for same size or widening reinterprets + if (sBytes == tBytes || (sBytes % tBytes) != 0) { + return -1; + } + int subLanesPerSrc = sBytes / tBytes; + return subLanesPerSrc; } /*package-private*/ @@ -242,6 +279,9 @@ abstract class AbstractVector extends Vector { /*package-private*/ abstract AbstractVector maybeSwap(ByteOrder bo); + /*package-private*/ + abstract AbstractVector swapIfNeeded(AbstractSpecies srcSpecies); + /*package-private*/ @ForceInline VectorShuffle swapBytesShuffle() { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java index 02e15d5f8dd..c071026a3b3 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java @@ -4101,6 +4101,14 @@ public abstract class ByteVector extends AbstractVector { return this; } + /*package-private*/ + @Override + @ForceInline + final + ByteVector swapIfNeeded(AbstractSpecies srcSpecies) { + return this; + } + static final int ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(Unsafe.ARRAY_BYTE_INDEX_SCALE); static final long ARRAY_BASE = diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java index 08fda9c96e6..e280ca4150c 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java @@ -3612,6 +3612,18 @@ public abstract class DoubleVector extends AbstractVector { return this; } + @Override + @ForceInline + final + DoubleVector swapIfNeeded(AbstractSpecies srcSpecies) { + int subLanesPerSrc = subLanesToSwap(srcSpecies); + if (subLanesPerSrc < 0) { + return this; + } + VectorShuffle shuffle = normalizeSubLanesForSpecies(this.vspecies(), subLanesPerSrc); + return (DoubleVector) this.rearrange(shuffle); + } + static final int ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(Unsafe.ARRAY_DOUBLE_INDEX_SCALE); static final long ARRAY_BASE = diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java index 0f70a2b81c8..35a8f4a78cf 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java @@ -3562,6 +3562,18 @@ public abstract class FloatVector extends AbstractVector { return this; } + @Override + @ForceInline + final + FloatVector swapIfNeeded(AbstractSpecies srcSpecies) { + int subLanesPerSrc = subLanesToSwap(srcSpecies); + if (subLanesPerSrc < 0) { + return this; + } + VectorShuffle shuffle = normalizeSubLanesForSpecies(this.vspecies(), subLanesPerSrc); + return (FloatVector) this.rearrange(shuffle); + } + static final int ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(Unsafe.ARRAY_FLOAT_INDEX_SCALE); static final long ARRAY_BASE = diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java index 23e703dcada..f340aed4fce 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java @@ -3720,6 +3720,18 @@ public abstract class IntVector extends AbstractVector { return this; } + @Override + @ForceInline + final + IntVector swapIfNeeded(AbstractSpecies srcSpecies) { + int subLanesPerSrc = subLanesToSwap(srcSpecies); + if (subLanesPerSrc < 0) { + return this; + } + VectorShuffle shuffle = normalizeSubLanesForSpecies(this.vspecies(), subLanesPerSrc); + return (IntVector) this.rearrange(shuffle); + } + static final int ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(Unsafe.ARRAY_INT_INDEX_SCALE); static final long ARRAY_BASE = diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java index 58bfd4d7772..b842bdebdc4 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java @@ -3655,6 +3655,18 @@ public abstract class LongVector extends AbstractVector { return this; } + @Override + @ForceInline + final + LongVector swapIfNeeded(AbstractSpecies srcSpecies) { + int subLanesPerSrc = subLanesToSwap(srcSpecies); + if (subLanesPerSrc < 0) { + return this; + } + VectorShuffle shuffle = normalizeSubLanesForSpecies(this.vspecies(), subLanesPerSrc); + return (LongVector) this.rearrange(shuffle); + } + static final int ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(Unsafe.ARRAY_LONG_INDEX_SCALE); static final long ARRAY_BASE = diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java index 7ab7e7c4417..8b4c9bc5a77 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java @@ -4074,6 +4074,18 @@ public abstract class ShortVector extends AbstractVector { return this; } + @Override + @ForceInline + final + ShortVector swapIfNeeded(AbstractSpecies srcSpecies) { + int subLanesPerSrc = subLanesToSwap(srcSpecies); + if (subLanesPerSrc < 0) { + return this; + } + VectorShuffle shuffle = normalizeSubLanesForSpecies(this.vspecies(), subLanesPerSrc); + return (ShortVector) this.rearrange(shuffle); + } + static final int ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(Unsafe.ARRAY_SHORT_INDEX_SCALE); static final long ARRAY_BASE = From e0445c09f7a967843a56634f72c7545446791e15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Tue, 27 Jan 2026 10:25:58 +0000 Subject: [PATCH 209/328] 8376294: ZipFile.Source.Key should not hold on to its BasicFileAttributes instance Reviewed-by: jpai --- .../share/classes/java/util/zip/ZipFile.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index 7fa507980c2..bf43499e1f9 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2026, 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,6 +37,7 @@ import java.nio.charset.Charset; import java.nio.file.InvalidPathException; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.Files; +import java.nio.file.attribute.FileTime; import java.util.*; import java.util.function.Consumer; import java.util.function.IntFunction; @@ -1444,11 +1445,13 @@ public class ZipFile implements ZipConstants, Closeable { * The unique combination of these components identifies a Source of a ZipFile. */ private static class Key { - private final BasicFileAttributes attrs; private final File file; + private final Object fileKey; + private final FileTime lastModifiedTime; // the Charset that was provided when constructing the ZipFile instance private final Charset charset; + /** * Constructs a {@code Key} to a {@code Source} of a {@code ZipFile} * @@ -1457,7 +1460,8 @@ public class ZipFile implements ZipConstants, Closeable { * @param charset the Charset that was provided when constructing the ZipFile instance */ public Key(File file, BasicFileAttributes attrs, Charset charset) { - this.attrs = attrs; + this.fileKey = attrs.fileKey(); + this.lastModifiedTime = attrs.lastModifiedTime(); this.file = file; this.charset = charset; } @@ -1465,10 +1469,9 @@ public class ZipFile implements ZipConstants, Closeable { @Override public int hashCode() { long t = charset.hashCode(); - t += attrs.lastModifiedTime().toMillis(); - Object fk = attrs.fileKey(); + t += lastModifiedTime.toMillis(); return Long.hashCode(t) + - (fk != null ? fk.hashCode() : file.hashCode()); + (fileKey != null ? fileKey.hashCode() : file.hashCode()); } @Override @@ -1477,12 +1480,12 @@ public class ZipFile implements ZipConstants, Closeable { if (!charset.equals(key.charset)) { return false; } - if (!attrs.lastModifiedTime().equals(key.attrs.lastModifiedTime())) { + if (!lastModifiedTime.equals(key.lastModifiedTime)) { return false; } - Object fk = attrs.fileKey(); - if (fk != null) { - return fk.equals(key.attrs.fileKey()); + + if (fileKey != null) { + return fileKey.equals(key.fileKey); } else { return file.equals(key.file); } From b1aea5520592e835e33762e349615fe616576103 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 27 Jan 2026 10:26:29 +0000 Subject: [PATCH 210/328] 8374695: ZGC: Convert zTLABUsage to use Atomic Reviewed-by: stefank, tschatzl --- src/hotspot/share/gc/z/zTLABUsage.cpp | 11 +++++------ src/hotspot/share/gc/z/zTLABUsage.hpp | 7 ++++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/z/zTLABUsage.cpp b/src/hotspot/share/gc/z/zTLABUsage.cpp index c2e3db6bedf..d3613cf8632 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.cpp +++ b/src/hotspot/share/gc/z/zTLABUsage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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,24 +23,23 @@ #include "gc/z/zTLABUsage.hpp" #include "logging/log.hpp" -#include "runtime/atomicAccess.hpp" ZTLABUsage::ZTLABUsage() : _used(0), _used_history() {} void ZTLABUsage::increase_used(size_t size) { - AtomicAccess::add(&_used, size, memory_order_relaxed); + _used.add_then_fetch(size, memory_order_relaxed); } void ZTLABUsage::decrease_used(size_t size) { - precond(size <= _used); + precond(size <= _used.load_relaxed()); - AtomicAccess::sub(&_used, size, memory_order_relaxed); + _used.sub_then_fetch(size, memory_order_relaxed); } void ZTLABUsage::reset() { - const size_t used = AtomicAccess::xchg(&_used, (size_t) 0); + const size_t used = _used.exchange(0u); // Avoid updates when nothing has been allocated since the last YC if (used == 0) { diff --git a/src/hotspot/share/gc/z/zTLABUsage.hpp b/src/hotspot/share/gc/z/zTLABUsage.hpp index 3d1b084fe16..68c7620c26e 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.hpp +++ b/src/hotspot/share/gc/z/zTLABUsage.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #ifndef SHARE_GC_Z_ZTLABUSAGE_HPP #define SHARE_GC_Z_ZTLABUSAGE_HPP +#include "runtime/atomic.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/numberSeq.hpp" @@ -42,9 +43,9 @@ class ZTLABUsage { private: // Accounting TLAB used until the next GC cycle - volatile size_t _used; + Atomic _used; // Sequence of historic used values - TruncatedSeq _used_history; + TruncatedSeq _used_history; public: ZTLABUsage(); From 4ff5f3a8c0910e9ed9d77586bd692c469bdf3460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Tue, 27 Jan 2026 10:28:54 +0000 Subject: [PATCH 211/328] 8376271: ZipFile comment confusingly refers to "native" ZIP file implementation Reviewed-by: jpai --- src/java.base/share/classes/java/util/zip/ZipFile.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index bf43499e1f9..a198c35c366 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -87,11 +87,11 @@ public class ZipFile implements ZipConstants, Closeable { private final ZipCoder zipCoder; private volatile boolean closeRequested; - // The "resource" used by this ZIP file that needs to be - // cleaned after use. + // An object holding state which needs to be cleaned after + // this ZipFile is closed or becomes unreachable: // a) the input streams that need to be closed // b) the list of cached Inflater objects - // c) the "native" source of this ZIP file. + // c) the Source object providing read access to the actual ZIP file private final @Stable CleanableResource res; private static final int STORED = ZipEntry.STORED; From 5990165d8257f39595b4c38f4e3e8d6ebb3393e8 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Tue, 27 Jan 2026 11:55:25 +0000 Subject: [PATCH 212/328] 8358957: [ubsan]: The assert in layout_helper_boolean_diffbit() in klass.hpp needs UB to fail Reviewed-by: dlong, jsjolen --- src/hotspot/share/oops/klass.hpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index b6974762209..d59db9744cb 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -510,18 +510,20 @@ protected: return (BasicType) btvalue; } - // Want a pattern to quickly diff against layout header in register - // find something less clever! + // Return a value containing a single set bit that is in the bitset difference between the + // layout helpers for array-of-boolean and array-of-byte. static int layout_helper_boolean_diffbit() { - jint zlh = array_layout_helper(T_BOOLEAN); - jint blh = array_layout_helper(T_BYTE); - assert(zlh != blh, "array layout helpers must differ"); - int diffbit = 1; - while ((diffbit & (zlh ^ blh)) == 0 && (diffbit & zlh) == 0) { - diffbit <<= 1; - assert(diffbit != 0, "make sure T_BOOLEAN has a different bit than T_BYTE"); - } - return diffbit; + uint zlh = static_cast(array_layout_helper(T_BOOLEAN)); + uint blh = static_cast(array_layout_helper(T_BYTE)); + // get all the bits that are set in zlh and clear in blh + uint candidates = (zlh & ~blh); + assert(candidates != 0, "must be"); // must be some if there is a solution. + // Use well known bit hack to isolate the low bit of candidates. + uint result = candidates & (-candidates); + assert(is_power_of_2(result), "must be power of 2"); + assert((result & zlh) != 0, "must be set in alh of T_BOOLEAN"); + assert((result & blh) == 0, "must be clear in alh of T_BYTE"); + return static_cast(result); } static int layout_helper_log2_element_size(jint lh) { From 528bbe7919785c50dda583277f4146b25eb4d2a4 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Tue, 27 Jan 2026 12:33:43 +0000 Subject: [PATCH 213/328] 8376302: os::Machine::used_memory reports container used memory when running containerized Reviewed-by: eosterlund, sgehwolf --- src/hotspot/share/runtime/os.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 1c06bf3c521..57971897400 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -2211,8 +2211,8 @@ bool os::used_memory(physical_memory_size_type& value) { bool os::Machine::used_memory(physical_memory_size_type& value) { physical_memory_size_type avail_mem = 0; // Return value ignored - defaulting to 0 on failure. - (void)os::available_memory(avail_mem); - physical_memory_size_type phys_mem = os::physical_memory(); + (void)os::Machine::available_memory(avail_mem); + physical_memory_size_type phys_mem = os::Machine::physical_memory(); value = phys_mem - avail_mem; return true; } From 40d1b642a43fbc5c6ad21417f2f9d62d99db0201 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 27 Jan 2026 12:51:20 +0000 Subject: [PATCH 214/328] 8376191: Remove AtomicAccess include from files that do not use it in gc/shared Reviewed-by: iwalulya, stefank --- src/hotspot/share/gc/shared/oopStorageSetParState.inline.hpp | 1 - src/hotspot/share/gc/shared/partialArrayState.cpp | 1 - src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp | 1 - src/hotspot/share/gc/shared/taskqueue.cpp | 1 - src/hotspot/share/gc/shared/taskqueue.inline.hpp | 1 - src/hotspot/share/gc/shared/workerThread.cpp | 1 - 6 files changed, 6 deletions(-) diff --git a/src/hotspot/share/gc/shared/oopStorageSetParState.inline.hpp b/src/hotspot/share/gc/shared/oopStorageSetParState.inline.hpp index 8e220e745e5..8341a3b20c4 100644 --- a/src/hotspot/share/gc/shared/oopStorageSetParState.inline.hpp +++ b/src/hotspot/share/gc/shared/oopStorageSetParState.inline.hpp @@ -31,7 +31,6 @@ #include "gc/shared/oopStorageSet.hpp" #include "memory/iterator.hpp" #include "oops/access.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/debug.hpp" template diff --git a/src/hotspot/share/gc/shared/partialArrayState.cpp b/src/hotspot/share/gc/shared/partialArrayState.cpp index 6f714d48a35..aadbc46b7c1 100644 --- a/src/hotspot/share/gc/shared/partialArrayState.cpp +++ b/src/hotspot/share/gc/shared/partialArrayState.cpp @@ -28,7 +28,6 @@ #include "memory/arena.hpp" #include "nmt/memTag.hpp" #include "oops/oopsHierarchy.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/orderAccess.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp b/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp index aaa86e2de16..6946f7c69ff 100644 --- a/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp +++ b/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp @@ -28,7 +28,6 @@ #include "gc/shared/partialArrayTaskStepper.hpp" #include "gc/shared/partialArrayState.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/checkedCast.hpp" #include "utilities/debug.hpp" diff --git a/src/hotspot/share/gc/shared/taskqueue.cpp b/src/hotspot/share/gc/shared/taskqueue.cpp index f75dc4c2923..58af1793a48 100644 --- a/src/hotspot/share/gc/shared/taskqueue.cpp +++ b/src/hotspot/share/gc/shared/taskqueue.cpp @@ -25,7 +25,6 @@ #include "gc/shared/taskqueue.hpp" #include "logging/log.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/javaThread.hpp" #include "runtime/os.hpp" #include "utilities/debug.hpp" diff --git a/src/hotspot/share/gc/shared/taskqueue.inline.hpp b/src/hotspot/share/gc/shared/taskqueue.inline.hpp index 55851495a5f..e77645f4fcf 100644 --- a/src/hotspot/share/gc/shared/taskqueue.inline.hpp +++ b/src/hotspot/share/gc/shared/taskqueue.inline.hpp @@ -32,7 +32,6 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/orderAccess.hpp" #include "utilities/debug.hpp" #include "utilities/ostream.hpp" diff --git a/src/hotspot/share/gc/shared/workerThread.cpp b/src/hotspot/share/gc/shared/workerThread.cpp index e4831d25d26..2f6f003608f 100644 --- a/src/hotspot/share/gc/shared/workerThread.cpp +++ b/src/hotspot/share/gc/shared/workerThread.cpp @@ -26,7 +26,6 @@ #include "gc/shared/workerThread.hpp" #include "logging/log.hpp" #include "memory/iterator.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/init.hpp" #include "runtime/java.hpp" #include "runtime/os.hpp" From 992a8ef46bc0a06c70fd5f4f307dbd20e402ed33 Mon Sep 17 00:00:00 2001 From: Daniel Gredler Date: Tue, 27 Jan 2026 13:20:26 +0000 Subject: [PATCH 215/328] 8376226: CharsetEncoder.canEncode(CharSequence) is much slower than necessary Reviewed-by: alanb, naoto --- .../nio/charset/Charset-X-Coder.java.template | 18 +- .../share/classes/sun/nio/cs/DoubleByte.java | 12 +- .../share/classes/sun/nio/cs/ISO_8859_1.java | 12 +- .../share/classes/sun/nio/cs/SingleByte.java | 12 +- .../share/classes/sun/nio/cs/US_ASCII.java | 12 +- .../bench/java/nio/CharsetCanEncode.java | 187 ++++++++++++++++++ 6 files changed, 245 insertions(+), 8 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/nio/CharsetCanEncode.java diff --git a/src/java.base/share/classes/java/nio/charset/Charset-X-Coder.java.template b/src/java.base/share/classes/java/nio/charset/Charset-X-Coder.java.template index e900c2eca0f..aca987ed678 100644 --- a/src/java.base/share/classes/java/nio/charset/Charset-X-Coder.java.template +++ b/src/java.base/share/classes/java/nio/charset/Charset-X-Coder.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -819,6 +819,12 @@ public abstract class Charset$Coder$ { */ public final $Otype$Buffer $code$($Itype$Buffer in) throws CharacterCodingException + { + return $code$(in, true); + } + + private $Otype$Buffer $code$($Itype$Buffer in, boolean throwOnError) + throws CharacterCodingException { int n = Math.min((int)(in.remaining() * average$ItypesPerOtype$()), ArraysSupport.SOFT_MAX_ARRAY_LENGTH); @@ -844,7 +850,11 @@ public abstract class Charset$Coder$ { out = o; continue; } - cr.throwException(); + if (throwOnError) { + cr.throwException(); + } else { + return null; + } } out.flip(); return out; @@ -938,7 +948,8 @@ public abstract class Charset$Coder$ { try { onMalformedInput(CodingErrorAction.REPORT); onUnmappableCharacter(CodingErrorAction.REPORT); - encode(cb); + ByteBuffer bb = encode(cb, false); + return bb != null; } catch (CharacterCodingException x) { return false; } finally { @@ -946,7 +957,6 @@ public abstract class Charset$Coder$ { onUnmappableCharacter(ua); reset(); } - return true; } /** diff --git a/src/java.base/share/classes/sun/nio/cs/DoubleByte.java b/src/java.base/share/classes/sun/nio/cs/DoubleByte.java index 2a4dbdc95ed..0aaae14bbf9 100644 --- a/src/java.base/share/classes/sun/nio/cs/DoubleByte.java +++ b/src/java.base/share/classes/sun/nio/cs/DoubleByte.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, 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 @@ -583,6 +583,16 @@ public class DoubleByte { return encodeChar(c) != UNMAPPABLE_ENCODING; } + public boolean canEncode(CharSequence cs) { + int length = cs.length(); + for (int i = 0; i < length; i++) { + if (!canEncode(cs.charAt(i))) { + return false; + } + } + return true; + } + protected Surrogate.Parser sgp() { if (sgp == null) sgp = new Surrogate.Parser(); diff --git a/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java b/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java index 39215bfa93d..9240ac3f380 100644 --- a/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java +++ b/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -136,6 +136,16 @@ public class ISO_8859_1 return c <= '\u00FF'; } + public boolean canEncode(CharSequence cs) { + int length = cs.length(); + for (int i = 0; i < length; i++) { + if (!canEncode(cs.charAt(i))) { + return false; + } + } + return true; + } + public boolean isLegalReplacement(byte[] repl) { return true; // we accept any byte value } diff --git a/src/java.base/share/classes/sun/nio/cs/SingleByte.java b/src/java.base/share/classes/sun/nio/cs/SingleByte.java index 59887b944d3..d4127b7c043 100644 --- a/src/java.base/share/classes/sun/nio/cs/SingleByte.java +++ b/src/java.base/share/classes/sun/nio/cs/SingleByte.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, 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 @@ -201,6 +201,16 @@ public class SingleByte return encode(c) != UNMAPPABLE_ENCODING; } + public boolean canEncode(CharSequence cs) { + int length = cs.length(); + for (int i = 0; i < length; i++) { + if (!canEncode(cs.charAt(i))) { + return false; + } + } + return true; + } + public boolean isLegalReplacement(byte[] repl) { return ((repl.length == 1 && repl[0] == (byte)'?') || super.isLegalReplacement(repl)); diff --git a/src/java.base/share/classes/sun/nio/cs/US_ASCII.java b/src/java.base/share/classes/sun/nio/cs/US_ASCII.java index bb84ab1bd4b..61c4948e949 100644 --- a/src/java.base/share/classes/sun/nio/cs/US_ASCII.java +++ b/src/java.base/share/classes/sun/nio/cs/US_ASCII.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -139,6 +139,16 @@ public class US_ASCII return c < 0x80; } + public boolean canEncode(CharSequence cs) { + int length = cs.length(); + for (int i = 0; i < length; i++) { + if (!canEncode(cs.charAt(i))) { + return false; + } + } + return true; + } + public boolean isLegalReplacement(byte[] repl) { return (repl.length == 1 && repl[0] >= 0) || super.isLegalReplacement(repl); diff --git a/test/micro/org/openjdk/bench/java/nio/CharsetCanEncode.java b/test/micro/org/openjdk/bench/java/nio/CharsetCanEncode.java new file mode 100644 index 00000000000..ebfbc217a95 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/nio/CharsetCanEncode.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.nio; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Fork(3) +public class CharsetCanEncode { + + private static final char ALEF_CHAR = '\u05d0'; + private static final String ALEF_STRING = "\u05d0"; + + // sun.nio.cs.US_ASCII + private CharsetEncoder ascii = Charset.forName("US-ASCII").newEncoder(); + + // sun.nio.cs.ISO_8859_1 + private CharsetEncoder iso88591 = Charset.forName("ISO-8859-1").newEncoder(); + + // sun.nio.cs.SingleByte + private CharsetEncoder iso88592 = Charset.forName("ISO-8859-2").newEncoder(); + + // sun.nio.cs.DoubleByte + private CharsetEncoder shiftjis = Charset.forName("Shift_JIS").newEncoder(); + + // sun.nio.cs.UTF_8 + private CharsetEncoder utf8 = Charset.forName("UTF-8").newEncoder(); + + // sun.nio.cs.UTF_16LE + private CharsetEncoder utf16le = Charset.forName("UTF-16LE").newEncoder(); + + @Benchmark + public boolean asciiCanEncodeCharYes() { + return ascii.canEncode('D'); + } + + @Benchmark + public boolean asciiCanEncodeStringYes() { + return ascii.canEncode("D"); + } + + @Benchmark + public boolean asciiCanEncodeCharNo() { + return ascii.canEncode(ALEF_CHAR); + } + + @Benchmark + public boolean asciiCanEncodeStringNo() { + return ascii.canEncode(ALEF_STRING); + } + + @Benchmark + public boolean iso88591CanEncodeCharYes() { + return iso88591.canEncode('D'); + } + + @Benchmark + public boolean iso88591CanEncodeStringYes() { + return iso88591.canEncode("D"); + } + + @Benchmark + public boolean iso88591CanEncodeCharNo() { + return iso88591.canEncode(ALEF_CHAR); + } + + @Benchmark + public boolean iso88591CanEncodeStringNo() { + return iso88591.canEncode(ALEF_STRING); + } + + @Benchmark + public boolean iso88592CanEncodeCharYes() { + return iso88592.canEncode('D'); + } + + @Benchmark + public boolean iso88592CanEncodeStringYes() { + return iso88592.canEncode("D"); + } + + @Benchmark + public boolean iso88592CanEncodeCharNo() { + return iso88592.canEncode(ALEF_CHAR); + } + + @Benchmark + public boolean iso88592CanEncodeStringNo() { + return iso88592.canEncode(ALEF_STRING); + } + + @Benchmark + public boolean shiftjisCanEncodeCharYes() { + return shiftjis.canEncode('D'); + } + + @Benchmark + public boolean shiftjisCanEncodeStringYes() { + return shiftjis.canEncode("D"); + } + + @Benchmark + public boolean shiftjisCanEncodeCharNo() { + return shiftjis.canEncode(ALEF_CHAR); + } + + @Benchmark + public boolean shiftjisCanEncodeStringNo() { + return shiftjis.canEncode(ALEF_STRING); + } + + @Benchmark + public boolean utf8CanEncodeCharYes() { + return utf8.canEncode('D'); + } + + @Benchmark + public boolean utf8CanEncodeStringYes() { + return utf8.canEncode("D"); + } + + @Benchmark + public boolean utf8CanEncodeCharNo() { + return utf8.canEncode(Character.MIN_SURROGATE); + } + + @Benchmark + public boolean utf8CanEncodeStringNo() { + return utf8.canEncode(String.valueOf(Character.MIN_SURROGATE)); + } + + @Benchmark + public boolean utf16leCanEncodeCharYes() { + return utf16le.canEncode('D'); + } + + @Benchmark + public boolean utf16leCanEncodeStringYes() { + return utf16le.canEncode("D"); + } + + @Benchmark + public boolean utf16leCanEncodeCharNo() { + return utf16le.canEncode(Character.MIN_SURROGATE); + } + + @Benchmark + public boolean utf16leCanEncodeStringNo() { + return utf16le.canEncode(String.valueOf(Character.MIN_SURROGATE)); + } +} From 479ac8b2fdfbb64d26b34ff72abd61a1ce5f6c87 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 27 Jan 2026 13:30:14 +0000 Subject: [PATCH 216/328] 8376281: Remove USE_XLC_BUILTINS macro usage in AIX code Reviewed-by: mdoerr, clanger --- src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp | 8 ++------ src/hotspot/os_cpu/aix_ppc/prefetch_aix_ppc.inline.hpp | 10 +--------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp index afef21b091a..3ab81697280 100644 --- a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp +++ b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2025 SAP SE. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -412,12 +412,8 @@ run_stub: } void os::Aix::init_thread_fpu_state(void) { -#if !defined(USE_XLC_BUILTINS) // Disable FP exceptions. __asm__ __volatile__ ("mtfsfi 6,0"); -#else - __mtfsfi(6, 0); -#endif } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/hotspot/os_cpu/aix_ppc/prefetch_aix_ppc.inline.hpp b/src/hotspot/os_cpu/aix_ppc/prefetch_aix_ppc.inline.hpp index c741335b5f0..d9dac0e231f 100644 --- a/src/hotspot/os_cpu/aix_ppc/prefetch_aix_ppc.inline.hpp +++ b/src/hotspot/os_cpu/aix_ppc/prefetch_aix_ppc.inline.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2013 SAP SE. All rights reserved. + * Copyright (c) 2012, 2026 SAP SE. 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 @@ -29,29 +29,21 @@ // Included in runtime/prefetch.inline.hpp inline void Prefetch::read(const void *loc, intx interval) { -#if !defined(USE_XLC_BUILTINS) __asm__ __volatile__ ( " dcbt 0, %0 \n" : : /*%0*/"r" ( ((address)loc) +((long)interval) ) //: ); -#else - __dcbt(((address)loc) +((long)interval)); -#endif } inline void Prefetch::write(void *loc, intx interval) { -#if !defined(USE_XLC_BUILTINS) __asm__ __volatile__ ( " dcbtst 0, %0 \n" : : /*%0*/"r" ( ((address)loc) +((long)interval) ) //: ); -#else - __dcbtst( ((address)loc) +((long)interval) ); -#endif } #endif // OS_CPU_AIX_PPC_PREFETCH_AIX_PPC_INLINE_HPP From 64b0ae6be8a7b70ed4cc08333447e9b73bdcbaca Mon Sep 17 00:00:00 2001 From: Wang Haomin Date: Tue, 27 Jan 2026 14:21:44 +0000 Subject: [PATCH 217/328] 8376276: Add javafx to allowed-list of CheckFiles Reviewed-by: erikj, kcr --- test/jdk/build/CheckFiles.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/jdk/build/CheckFiles.java b/test/jdk/build/CheckFiles.java index 5a915e881f0..7ef5b803d2d 100644 --- a/test/jdk/build/CheckFiles.java +++ b/test/jdk/build/CheckFiles.java @@ -106,6 +106,8 @@ public class CheckFiles { allowedEndingsLibDir.add("psfont.properties.ja"); allowedEndingsLibDir.add("src.zip"); allowedEndingsLibDir.add("tzdb.dat"); + allowedEndingsLibDir.add("javafx-swt.jar"); + allowedEndingsLibDir.add("javafx.properties"); if (Platform.isWindows()) { allowedEndingsLibDir.add(".lib"); allowedEndingsLibDir.add("tzmappings"); From bbb4b0d498900f929225233008bbdbafaae5d709 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 27 Jan 2026 14:51:04 +0000 Subject: [PATCH 218/328] 8376277: Migrate java/lang/reflect tests away from TestNG Reviewed-by: alanb --- .../AccessibleObject/CanAccessTest.java | 41 ++--- .../ModuleSetAccessibleTest.java | 75 +++------ .../TrySetAccessibleTest.java | 79 ++++----- .../java/lang/reflect/ChainedReflection.java | 42 +++-- .../FilterNotMostSpecific.java | 22 +-- .../DefaultStaticInvokeTest.java | 70 ++++---- .../DefaultStaticTestData.java | 16 +- .../java/lang/reflect/Field/NegativeTest.java | 159 +++++------------- .../lang/reflect/Generics/ThreadSafety.java | 9 +- .../lang/reflect/IllegalArgumentsTest.java | 8 +- .../lang/reflect/Method/MethodArityLimit.java | 18 +- .../reflect/MethodHandleAccessorsTest.java | 70 ++++---- .../lang/reflect/Proxy/DefaultMethods.java | 127 ++++++-------- .../reflect/Proxy/HiddenProxyInterface.java | 15 +- .../reflect/Proxy/LazyInitializationTest.java | 13 +- .../reflect/Proxy/ProxyClassAccessTest.java | 30 ++-- .../lang/reflect/Proxy/ProxyLayerTest.java | 32 ++-- .../java/lang/reflect/Proxy/ProxyTest.java | 20 +-- .../reflect/Proxy/SealedInterfaceTest.java | 15 +- .../java/lang/reflect/Proxy/TestVarArgs.java | 45 +++-- .../nonPublicProxy/DefaultMethodProxy.java | 40 ++--- .../annotationSharing/AnnotationSharing.java | 6 +- .../reflect/callerCache/CustomLoaderTest.java | 36 ++-- .../ReflectionCallerCacheTest.java | 23 +-- .../records/CheckEqualityIsBasedOnFields.java | 22 ++- .../lang/reflect/records/IsRecordTest.java | 44 ++--- .../reflect/records/RecordReflectionTest.java | 81 +++++---- .../SealedClassesReflectionTest.java | 59 ++++--- 28 files changed, 511 insertions(+), 706 deletions(-) diff --git a/test/jdk/java/lang/reflect/AccessibleObject/CanAccessTest.java b/test/jdk/java/lang/reflect/AccessibleObject/CanAccessTest.java index 45e2502b601..ac7a1bad31b 100644 --- a/test/jdk/java/lang/reflect/AccessibleObject/CanAccessTest.java +++ b/test/jdk/java/lang/reflect/AccessibleObject/CanAccessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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,11 +21,11 @@ * questions. */ -/** +/* * @test * @build CanAccessTest * @modules java.base/jdk.internal.misc:+open - * @run testng/othervm CanAccessTest + * @run junit/othervm CanAccessTest * @summary Test AccessibleObject::canAccess method */ @@ -34,31 +34,29 @@ import java.lang.reflect.Method; import java.security.SecureClassLoader; import jdk.internal.misc.Unsafe; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; -@Test public class CanAccessTest { private static Unsafe INSTANCE = Unsafe.getUnsafe(); /** * null object parameter for Constructor */ + @Test public void testConstructor() throws Exception { Constructor ctor = Unsafe.class.getDeclaredConstructor(); assertFalse(ctor.canAccess(null)); assertTrue(ctor.trySetAccessible()); - try { - // non-null object parameter - ctor.canAccess(INSTANCE); - assertTrue(false); - } catch (IllegalArgumentException expected) {} + // non-null object parameter + assertThrows(IllegalArgumentException.class, () -> ctor.canAccess(INSTANCE)); } /** * Test protected constructors */ + @Test public void testProtectedConstructor() throws Exception { TestLoader.testProtectedConstructorNonOpenedPackage(); @@ -69,21 +67,20 @@ public class CanAccessTest { /** * null object parameter for static members */ + @Test public void testStaticMember() throws Exception { Method m = Unsafe.class.getDeclaredMethod("throwIllegalAccessError"); assertFalse(m.canAccess(null)); assertTrue(m.trySetAccessible()); - try { - // non-null object parameter - m.canAccess(INSTANCE); - assertTrue(false); - } catch (IllegalArgumentException expected) { } + // non-null object parameter + assertThrows(IllegalArgumentException.class, () -> m.canAccess(INSTANCE)); } /** * Test protected static */ + @Test public void testProtectedStatic() throws Exception { Method m = TestLoader.testProtectedStatic(); assertFalse(m.canAccess(null)); @@ -93,28 +90,24 @@ public class CanAccessTest { * the specified object must be an instance of the declaring class * for instance members */ + @Test public void testInstanceMethod() throws Exception { Method m = Unsafe.class.getDeclaredMethod("allocateMemory0", long.class); assertFalse(m.canAccess(INSTANCE)); - try { - m.canAccess(null); - assertTrue(false); - } catch (IllegalArgumentException expected) { } + assertThrows(IllegalArgumentException.class, () -> m.canAccess(null)); } /** * the specified object must be an instance of the declaring class * for instance members */ + @Test public void testInvalidInstanceObject() throws Exception { Class clazz = Class.forName("sun.security.x509.X500Name"); Method m = clazz.getDeclaredMethod("size"); - try { - m.canAccess(INSTANCE); - assertTrue(false); - } catch (IllegalArgumentException expected) { } + assertThrows(IllegalArgumentException.class, () -> m.canAccess(INSTANCE)); } diff --git a/test/jdk/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java b/test/jdk/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java index 45cebdb552b..7d79a1ac49b 100644 --- a/test/jdk/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java +++ b/test/jdk/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, 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,12 +21,12 @@ * questions. */ -/** +/* * @test * @build ModuleSetAccessibleTest * @modules java.base/java.lang:open * java.base/jdk.internal.misc:+open - * @run testng/othervm ModuleSetAccessibleTest + * @run junit/othervm ModuleSetAccessibleTest * @summary Test java.lang.reflect.AccessibleObject with modules */ @@ -40,22 +40,19 @@ import java.security.ProtectionDomain; import jdk.internal.misc.Unsafe; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; -@Test public class ModuleSetAccessibleTest { /** * Invoke a private constructor on a public class in an exported package */ + @Test public void testPrivateConstructorInExportedPackage() throws Exception { Constructor ctor = Unsafe.class.getDeclaredConstructor(); - try { - ctor.newInstance(); - assertTrue(false); - } catch (IllegalAccessException expected) { } + assertThrows(IllegalAccessException.class, () -> ctor.newInstance()); ctor.setAccessible(true); Unsafe unsafe = (Unsafe) ctor.newInstance(); @@ -65,34 +62,26 @@ public class ModuleSetAccessibleTest { /** * Invoke a private method on a public class in an exported package */ + @Test public void testPrivateMethodInExportedPackage() throws Exception { Method m = Unsafe.class.getDeclaredMethod("throwIllegalAccessError"); - try { - m.invoke(null); - assertTrue(false); - } catch (IllegalAccessException expected) { } + assertThrows(IllegalAccessException.class, () -> m.invoke(null)); m.setAccessible(true); - try { - m.invoke(null); - assertTrue(false); - } catch (InvocationTargetException e) { - // thrown by throwIllegalAccessError - assertTrue(e.getCause() instanceof IllegalAccessError); - } + InvocationTargetException e = assertThrows(InvocationTargetException.class, () -> + m.invoke(null)); + // thrown by throwIllegalAccessError + assertInstanceOf(IllegalAccessError.class, e.getCause()); } /** * Access a private field in a public class that is an exported package */ + @Test public void testPrivateFieldInExportedPackage() throws Exception { Field f = Unsafe.class.getDeclaredField("theUnsafe"); - - try { - f.get(null); - assertTrue(false); - } catch (IllegalAccessException expected) { } + assertThrows(IllegalAccessException.class, () -> f.get(null)); f.setAccessible(true); Unsafe unsafe = (Unsafe) f.get(null); @@ -102,19 +91,14 @@ public class ModuleSetAccessibleTest { /** * Invoke a public constructor on a public class in a non-exported package */ + @Test public void testPublicConstructorInNonExportedPackage() throws Exception { Class clazz = Class.forName("sun.security.x509.X500Name"); Constructor ctor = clazz.getConstructor(String.class); - try { - ctor.newInstance("cn=duke"); - assertTrue(false); - } catch (IllegalAccessException expected) { } + assertThrows(IllegalAccessException.class, () -> ctor.newInstance("cn=duke")); - try { - ctor.setAccessible(true); - assertTrue(false); - } catch (InaccessibleObjectException expected) { } + assertThrows(InaccessibleObjectException.class, () -> ctor.setAccessible(true)); ctor.setAccessible(false); // should succeed } @@ -123,19 +107,14 @@ public class ModuleSetAccessibleTest { /** * Access a public field in a public class that in a non-exported package */ + @Test public void testPublicFieldInNonExportedPackage() throws Exception { Class clazz = Class.forName("sun.security.x509.X500Name"); Field f = clazz.getField("SERIALNUMBER_OID"); - try { - f.get(null); - assertTrue(false); - } catch (IllegalAccessException expected) { } + assertThrows(IllegalAccessException.class, () -> f.get(null)); - try { - f.setAccessible(true); - assertTrue(false); - } catch (InaccessibleObjectException expected) { } + assertThrows(InaccessibleObjectException.class, () -> f.setAccessible(true)); f.setAccessible(false); // should succeed } @@ -144,6 +123,7 @@ public class ModuleSetAccessibleTest { /** * Test that the Class constructor cannot be make accessible. */ + @Test public void testJavaLangClass() throws Exception { // non-public constructor @@ -152,15 +132,8 @@ public class ModuleSetAccessibleTest { ProtectionDomain.class, boolean.class, char.class); AccessibleObject[] ctors = { ctor }; - try { - ctor.setAccessible(true); - assertTrue(false); - } catch (SecurityException expected) { } - - try { - AccessibleObject.setAccessible(ctors, true); - assertTrue(false); - } catch (SecurityException expected) { } + assertThrows(SecurityException.class, () -> ctor.setAccessible(true)); + assertThrows(SecurityException.class, () -> AccessibleObject.setAccessible(ctors, true)); // should succeed ctor.setAccessible(false); diff --git a/test/jdk/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java b/test/jdk/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java index 774ee4d1dad..bd4d0fab23f 100644 --- a/test/jdk/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java +++ b/test/jdk/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,14 +21,14 @@ * questions. */ -/** +/* * @test * @build TrySetAccessibleTest * @modules java.base/java.lang:open * java.base/jdk.internal.module * java.base/jdk.internal.perf * java.base/jdk.internal.misc:+open - * @run testng/othervm TrySetAccessibleTest + * @run junit/othervm TrySetAccessibleTest * @summary Test AccessibleObject::trySetAccessible method */ @@ -43,21 +43,18 @@ import jdk.internal.module.ModulePath; import jdk.internal.perf.Perf; import java.security.ProtectionDomain; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; -@Test public class TrySetAccessibleTest { /** * Invoke a private constructor on a public class in an exported package */ + @Test public void testPrivateConstructorInExportedPackage() throws Exception { Constructor ctor = Perf.class.getDeclaredConstructor(); - try { - ctor.newInstance(); - assertTrue(false); - } catch (IllegalAccessException expected) { } + assertThrows(IllegalAccessException.class, () -> ctor.newInstance()); assertFalse(ctor.trySetAccessible()); assertFalse(ctor.canAccess(null)); @@ -66,13 +63,11 @@ public class TrySetAccessibleTest { /** * Invoke a private constructor on a public class in an open package */ + @Test public void testPrivateConstructorInOpenedPackage() throws Exception { Constructor ctor = Unsafe.class.getDeclaredConstructor(); - try { - ctor.newInstance(); - assertTrue(false); - } catch (IllegalAccessException expected) { } + assertThrows(IllegalAccessException.class, () -> ctor.newInstance()); assertTrue(ctor.trySetAccessible()); assertTrue(ctor.canAccess(null)); @@ -82,12 +77,10 @@ public class TrySetAccessibleTest { /** * Invoke a private method on a public class in an exported package */ + @Test public void testPrivateMethodInExportedPackage() throws Exception { Method m = ModulePath.class.getDeclaredMethod("packageName", String.class); - try { - m.invoke(null); - assertTrue(false); - } catch (IllegalAccessException expected) { } + assertThrows(IllegalAccessException.class, () -> m.invoke(null)); assertFalse(m.trySetAccessible()); assertFalse(m.canAccess(null)); @@ -97,54 +90,42 @@ public class TrySetAccessibleTest { /** * Invoke a private method on a public class in an open package */ + @Test public void testPrivateMethodInOpenedPackage() throws Exception { Method m = Unsafe.class.getDeclaredMethod("throwIllegalAccessError"); assertFalse(m.canAccess(null)); - try { - m.invoke(null); - assertTrue(false); - } catch (IllegalAccessException expected) { } + assertThrows(IllegalAccessException.class, () -> m.invoke(null)); assertTrue(m.trySetAccessible()); assertTrue(m.canAccess(null)); - try { - m.invoke(null); - assertTrue(false); - } catch (InvocationTargetException e) { - // thrown by throwIllegalAccessError - assertTrue(e.getCause() instanceof IllegalAccessError); - } + + InvocationTargetException e = assertThrows(InvocationTargetException.class, () -> + m.invoke(null)); + assertInstanceOf(IllegalAccessError.class, e.getCause()); } /** * Invoke a private method on a public class in an exported package */ + @Test public void testPrivateFieldInExportedPackage() throws Exception { Field f = Perf.class.getDeclaredField("instance"); - try { - f.get(null); - assertTrue(false); - } catch (IllegalAccessException expected) { } + assertThrows(IllegalAccessException.class, () -> f.get(null)); assertFalse(f.trySetAccessible()); assertFalse(f.canAccess(null)); - try { - f.get(null); - assertTrue(false); - } catch (IllegalAccessException expected) {} + assertThrows(IllegalAccessException.class, () -> f.get(null)); } /** * Access a private field in a public class that is an exported package */ + @Test public void testPrivateFieldInOpenedPackage() throws Exception { Field f = Unsafe.class.getDeclaredField("theUnsafe"); - try { - f.get(null); - assertTrue(false); - } catch (IllegalAccessException expected) { } + assertThrows(IllegalAccessException.class, () -> f.get(null)); assertTrue(f.trySetAccessible()); assertTrue(f.canAccess(null)); @@ -155,32 +136,29 @@ public class TrySetAccessibleTest { /** * Invoke a public constructor on a public class in a non-exported package */ + @Test public void testPublicConstructorInNonExportedPackage() throws Exception { Class clazz = Class.forName("sun.security.x509.X500Name"); Constructor ctor = clazz.getConstructor(String.class); - try { - ctor.newInstance("cn=duke"); - assertTrue(false); - } catch (IllegalAccessException expected) { } + assertThrows(IllegalAccessException.class, () -> ctor.newInstance("cn=duke")); assertFalse(ctor.trySetAccessible()); assertFalse(ctor.canAccess(null)); - assertTrue(ctor.trySetAccessible() == ctor.isAccessible()); + assertFalse(ctor.trySetAccessible()); + assertFalse(ctor.isAccessible()); // should match trySetAccessible } /** * Access a public field in a public class that in a non-exported package */ + @Test public void testPublicFieldInNonExportedPackage() throws Exception { Class clazz = Class.forName("sun.security.x509.X500Name"); Field f = clazz.getField("SERIALNUMBER_OID"); - try { - f.get(null); - assertTrue(false); - } catch (IllegalAccessException expected) { } + assertThrows(IllegalAccessException.class, () -> f.get(null)); assertFalse(f.trySetAccessible()); assertFalse(f.canAccess(null)); @@ -190,6 +168,7 @@ public class TrySetAccessibleTest { /** * Test that the Class constructor cannot be make accessible. */ + @Test public void testJavaLangClass() throws Exception { // non-public constructor diff --git a/test/jdk/java/lang/reflect/ChainedReflection.java b/test/jdk/java/lang/reflect/ChainedReflection.java index 212a70345cd..bd76cd13fc8 100644 --- a/test/jdk/java/lang/reflect/ChainedReflection.java +++ b/test/jdk/java/lang/reflect/ChainedReflection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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,9 +23,11 @@ /* * @test - * @run testng/othervm ChainedReflection + * @run junit/othervm ChainedReflection * @summary Test Method::invoke and Constructor::newInstance chained calls that * should wrap NPE in InvocationTargetException properly + * @comment This test is not using assertThrows given lambdas may affect the + * exception stack trace and therefore test anticipations */ import java.lang.reflect.Constructor; @@ -33,24 +35,28 @@ import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; import java.util.Optional; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class ChainedReflection { - public ChainedReflection() {} - ChainedReflection(Void dummy) throws ReflectiveOperationException { - Method m = ChainedReflection.class.getMethod("throwNPE"); - try { - m.invoke(null); - } catch (InvocationTargetException e) { - Throwable t = e.getTargetException(); - if (t instanceof NullPointerException npe) { - throw npe; - } else { - throw new RuntimeException("Test failed (InvocationTargetException didn't wrap NullPointerException)"); + // This inner class is declared with a constructor that ctorCallMethodInvoke + // reflects on. Such a constructor cannot be declared in ChainedReflection + // because JUnit does not allow a test class to declare multiple constructors. + class Inner { + Inner() throws ReflectiveOperationException { + Method m = ChainedReflection.class.getMethod("throwNPE"); + try { + m.invoke(null); + } catch (InvocationTargetException e) { + Throwable t = e.getTargetException(); + if (t instanceof NullPointerException npe) { + throw npe; + } else { + throw new RuntimeException("Test failed (InvocationTargetException didn't wrap NullPointerException)"); + } + } catch (Throwable t) { + throw new RuntimeException("Test failed (Unexpected exception)", t); } - } catch (Throwable t) { - throw new RuntimeException("Test failed (Unexpected exception)", t); } } @@ -105,9 +111,9 @@ public class ChainedReflection { */ @Test public void ctorCallMethodInvoke() throws ReflectiveOperationException { - Constructor ctor = ChainedReflection.class.getDeclaredConstructor(Void.class); + Constructor ctor = ChainedReflection.Inner.class.getDeclaredConstructor(ChainedReflection.class); try { - ctor.newInstance((Void)null); + ctor.newInstance(this); } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); if (!(t instanceof NullPointerException)) { diff --git a/test/jdk/java/lang/reflect/DefaultMethodMembers/FilterNotMostSpecific.java b/test/jdk/java/lang/reflect/DefaultMethodMembers/FilterNotMostSpecific.java index 1992f31d5de..b8738a383b0 100644 --- a/test/jdk/java/lang/reflect/DefaultMethodMembers/FilterNotMostSpecific.java +++ b/test/jdk/java/lang/reflect/DefaultMethodMembers/FilterNotMostSpecific.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * @bug 8029674 * @summary Verify that the right interface methods are returned by * Class.getMethod() and Class.getMethods() - * @run testng FilterNotMostSpecific + * @run junit FilterNotMostSpecific */ import java.lang.reflect.*; @@ -39,14 +39,14 @@ import java.util.HashMap; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class FilterNotMostSpecific { - @Test(dataProvider="getCases") + @ParameterizedTest + @MethodSource("getCases") public void testGetMethod(Class iface) { boolean match = false; MethodDesc[] expectedMethods = iface.getAnnotationsByType(MethodDesc.class); @@ -67,7 +67,8 @@ public class FilterNotMostSpecific { assert(match); } - @Test(dataProvider="getCases") + @ParameterizedTest + @MethodSource("getCases") public void testGetMethods(Class iface) { List foundMethods = filterObjectMethods(iface.getMethods()); MethodDesc[] expectedMethods = iface.getAnnotationsByType(MethodDesc.class); @@ -84,7 +85,7 @@ public class FilterNotMostSpecific { fail("On: "+ iface +"\nDid not find " + toMethodString(expected) + " among " + foundMethods); } - assertEquals(foundMethods.size(), expectedMethods.length, + assertEquals(expectedMethods.length, foundMethods.size(), "\non: " + iface + "\nexpected: " + toMethodStrings(expectedMethods) + "\nfound: " + foundMethods + "\n"); @@ -565,8 +566,7 @@ public class FilterNotMostSpecific { @MethodDesc(name="m", declaringClass=F.class, isGetMethodReturn=true) abstract class H extends G implements F {} - @DataProvider - public Object[][] getCases() { return CASES; } + public static Object[][] getCases() { return CASES; } public static final Class[][] CASES = { { K1.class }, { K1M.class }, diff --git a/test/jdk/java/lang/reflect/DefaultStaticTest/DefaultStaticInvokeTest.java b/test/jdk/java/lang/reflect/DefaultStaticTest/DefaultStaticInvokeTest.java index 215ee3dd66a..ff7d12502b3 100644 --- a/test/jdk/java/lang/reflect/DefaultStaticTest/DefaultStaticInvokeTest.java +++ b/test/jdk/java/lang/reflect/DefaultStaticTest/DefaultStaticInvokeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ * in interfaces and/or in inheritance * @bug 7184826 * @build helper.Mod helper.Declared DefaultStaticTestData - * @run testng DefaultStaticInvokeTest + * @run junit DefaultStaticInvokeTest * @author Yong Lu */ @@ -40,23 +40,19 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.fail; -import org.testng.annotations.Test; - import static helper.Mod.*; import static helper.Declared.*; -import helper.Mod; +import static org.junit.jupiter.api.Assertions.*; +import helper.Mod; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class DefaultStaticInvokeTest { // getMethods(): Make sure getMethods returns the expected methods. - @Test(dataProvider = "testCasesAll", - dataProviderClass = DefaultStaticTestData.class) + @ParameterizedTest + @MethodSource({"DefaultStaticTestData#testClasses", "DefaultStaticTestData#testInterfaces"}) public void testGetMethods(String testTarget, Object param) throws Exception { testMethods(ALL_METHODS, testTarget, param); @@ -64,8 +60,8 @@ public class DefaultStaticInvokeTest { // getDeclaredMethods(): Make sure getDeclaredMethods returns the expected methods. - @Test(dataProvider = "testCasesAll", - dataProviderClass = DefaultStaticTestData.class) + @ParameterizedTest + @MethodSource({"DefaultStaticTestData#testClasses", "DefaultStaticTestData#testInterfaces"}) public void testGetDeclaredMethods(String testTarget, Object param) throws Exception { testMethods(DECLARED_ONLY, testTarget, param); @@ -73,8 +69,8 @@ public class DefaultStaticInvokeTest { // getMethod(): Make sure that getMethod finds all methods it should find. - @Test(dataProvider = "testCasesAll", - dataProviderClass = DefaultStaticTestData.class) + @ParameterizedTest + @MethodSource({"DefaultStaticTestData#testClasses", "DefaultStaticTestData#testInterfaces"}) public void testGetMethod(String testTarget, Object param) throws Exception { @@ -91,8 +87,8 @@ public class DefaultStaticInvokeTest { // getMethod(): Make sure that getMethod does *not* find certain methods. - @Test(dataProvider = "testCasesAll", - dataProviderClass = DefaultStaticTestData.class) + @ParameterizedTest + @MethodSource({"DefaultStaticTestData#testClasses", "DefaultStaticTestData#testInterfaces"}) public void testGetMethodSuperInterfaces(String testTarget, Object param) throws Exception { @@ -124,8 +120,8 @@ public class DefaultStaticInvokeTest { // Method.invoke(): Make sure Method.invoke returns the expected value. - @Test(dataProvider = "testCasesAll", - dataProviderClass = DefaultStaticTestData.class) + @ParameterizedTest + @MethodSource({"DefaultStaticTestData#testClasses", "DefaultStaticTestData#testInterfaces"}) public void testMethodInvoke(String testTarget, Object param) throws Exception { Class typeUnderTest = Class.forName(testTarget); @@ -141,8 +137,8 @@ public class DefaultStaticInvokeTest { // MethodHandle.invoke(): Make sure MethodHandle.invoke returns the expected value. - @Test(dataProvider = "testCasesAll", - dataProviderClass = DefaultStaticTestData.class) + @ParameterizedTest + @MethodSource({"DefaultStaticTestData#testClasses", "DefaultStaticTestData#testInterfaces"}) public void testMethodHandleInvoke(String testTarget, Object param) throws Throwable { Class typeUnderTest = Class.forName(testTarget); @@ -169,14 +165,14 @@ public class DefaultStaticInvokeTest { : (String) methodHandle.invoke(typeUnderTest.newInstance(), param); } - assertEquals(result, expectedReturn); + assertEquals(expectedReturn, result); } } // Lookup.findStatic / .findVirtual: Make sure IllegalAccessException is thrown as expected. - @Test(dataProvider = "testClasses", - dataProviderClass = DefaultStaticTestData.class) + @ParameterizedTest + @MethodSource("DefaultStaticTestData#testClasses") public void testIAE(String testTarget, Object param) throws ClassNotFoundException { @@ -189,14 +185,8 @@ public class DefaultStaticInvokeTest { if (mod != STATIC && typeUnderTest.isInterface()) { continue; } - Exception caught = null; - try { - getTestMH(typeUnderTest, mName, param, true); - } catch (Exception e) { - caught = e; - } - assertNotNull(caught); - assertEquals(caught.getClass(), IllegalAccessException.class); + assertThrowsExactly(IllegalAccessException.class, () -> + getTestMH(typeUnderTest, mName, param, true)); } } @@ -254,7 +244,7 @@ public class DefaultStaticInvokeTest { } } - assertEquals(myMethods.size(), expectedMethods.length); + assertEquals(expectedMethods.length, myMethods.size()); for (MethodDesc toTest : expectedMethods) { @@ -284,16 +274,15 @@ public class DefaultStaticInvokeTest { assertFalse(method.isDefault()); // Test invoke it - assertEquals(tryInvoke(method, null, param), expectedReturn); + assertEquals(expectedReturn, tryInvoke(method, null, param)); break; case DEFAULT: // if typeUnderTest is a class then instantiate and invoke if (!typeUnderTest.isInterface()) { - assertEquals(tryInvoke( + assertEquals(expectedReturn, tryInvoke( method, typeUnderTest, - param), - expectedReturn); + param)); } //assert candidate is default @@ -302,11 +291,10 @@ public class DefaultStaticInvokeTest { break; case REGULAR: // if typeUnderTest must be a class - assertEquals(tryInvoke( + assertEquals(expectedReturn, tryInvoke( method, typeUnderTest, - param), - expectedReturn); + param)); //assert candidate is neither default nor static assertFalse(Modifier.isStatic(method.getModifiers())); diff --git a/test/jdk/java/lang/reflect/DefaultStaticTest/DefaultStaticTestData.java b/test/jdk/java/lang/reflect/DefaultStaticTest/DefaultStaticTestData.java index 8049712569b..add991e3493 100644 --- a/test/jdk/java/lang/reflect/DefaultStaticTest/DefaultStaticTestData.java +++ b/test/jdk/java/lang/reflect/DefaultStaticTest/DefaultStaticTestData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, 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,12 +27,10 @@ * @author Yong Lu */ +import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.testng.annotations.DataProvider; -import org.testng.collections.Lists; - import static helper.Mod.*; import static helper.Declared.*; import helper.Mod; @@ -379,7 +377,6 @@ public class DefaultStaticTestData { * data is the name of the class under test Second data used in test as the * arguments used for the method call. */ - @DataProvider static Object[][] testClasses() { return new Object[][]{ {"TestClass1", null}, @@ -408,7 +405,6 @@ public class DefaultStaticTestData { * data is the name of the interface under test Second data used in test as * the arguments used for the method call. */ - @DataProvider static Object[][] testInterfaces() { return new Object[][]{ {"TestIF1", null}, @@ -438,12 +434,4 @@ public class DefaultStaticTestData { {"TestIF21", null}, }; } - - @DataProvider - static Object[][] testCasesAll() { - List result = Lists.newArrayList(); - result.addAll(Arrays.asList(testClasses())); - result.addAll(Arrays.asList(testInterfaces())); - return result.toArray(new Object[result.size()][]); - } } diff --git a/test/jdk/java/lang/reflect/Field/NegativeTest.java b/test/jdk/java/lang/reflect/Field/NegativeTest.java index fe1f2dd7480..186267f4458 100644 --- a/test/jdk/java/lang/reflect/Field/NegativeTest.java +++ b/test/jdk/java/lang/reflect/Field/NegativeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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,20 +21,20 @@ * questions. */ -/** +/* * @test * @bug 8277451 * @summary Test exception thrown due to bad receiver and bad value on * Field with and without setAccessible(true) - * @run testng/othervm --enable-final-field-mutation=ALL-UNNAMED NegativeTest + * @run junit/othervm --enable-final-field-mutation=ALL-UNNAMED NegativeTest */ import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class NegativeTest { static class Fields { @@ -167,8 +167,7 @@ public class NegativeTest { } } - @DataProvider(name = "instanceFields") - private Object[][] instanceFields() { + private static Object[][] instanceFields() { return new Object[][]{ new Object[]{i_field}, new Object[]{c_field}, @@ -217,7 +216,8 @@ public class NegativeTest { * IllegalArgumentException is thrown if the receiver is of * a bad type. NullPointerException is thrown if the receiver is null. */ - @Test(dataProvider = "instanceFields") + @ParameterizedTest + @MethodSource("instanceFields") public void testReceiver(Field f) throws ReflectiveOperationException { f.get(INSTANCE); // good receiver @@ -231,15 +231,10 @@ public class NegativeTest { private void testBadReceiver(Field f) throws ReflectiveOperationException { assertFalse(Modifier.isStatic(f.getModifiers())); // instance field Object badObj = new NegativeTest(); - try { - f.get(badObj); - fail("expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // expected - } + assertThrows(IllegalArgumentException.class, () -> f.get(badObj)); Class fType = f.getType(); if (fType.isPrimitive()) { - try { + assertThrows(IllegalArgumentException.class, () -> { switch (fType.descriptorString()) { case "B" -> f.getByte(badObj); case "C" -> f.getChar(badObj); @@ -250,10 +245,7 @@ public class NegativeTest { case "S" -> f.getShort(badObj); case "Z" -> f.getBoolean(badObj); } - fail("expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // expected - } + }); } } @@ -262,16 +254,11 @@ public class NegativeTest { */ private void testNullReceiver(Field f) throws ReflectiveOperationException { assertFalse(Modifier.isStatic(f.getModifiers())); // instance field - try { - f.get(null); - fail("expected NullPointerException"); - } catch (NullPointerException e) { - // expected - } + assertThrows(NullPointerException.class, () -> f.get(null)); Class fType = f.getType(); if (fType.isPrimitive()) { - try { + assertThrows(NullPointerException.class, () -> { switch (fType.descriptorString()) { case "B" -> f.getByte(null); case "C" -> f.getChar(null); @@ -282,15 +269,11 @@ public class NegativeTest { case "S" -> f.getShort(null); case "Z" -> f.getBoolean(null); } - fail("expected NullPointerException"); - } catch (NullPointerException e) { - // expected - } + }); } } - @DataProvider(name = "writeableFields") - private Object[][] writeableFields() { + private static Object[][] writeableFields() { Fields obj = new Fields(); return new Object[][]{ // instance fields with and without setAccessible(true) @@ -352,7 +335,8 @@ public class NegativeTest { * NullPointerException is thrown if the receiver of an instance field is null. * The receiver is checked */ - @Test(dataProvider = "writeableFields") + @ParameterizedTest + @MethodSource("writeableFields") public void testSetValue(Field f, Object obj, Object value) throws IllegalAccessException { f.set(obj, value); Class fType = f.getType(); @@ -369,25 +353,14 @@ public class NegativeTest { } // test null value only if it's primitive type - try { - f.set(obj, null); - fail("expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // expected - } + assertThrows(IllegalArgumentException.class, () -> f.set(obj, null)); } Object badValue = new NegativeTest(); - try { - f.set(obj, badValue); - fail("expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // expected - } + assertThrows(IllegalArgumentException.class, () -> f.set(obj, badValue)); } - @DataProvider(name = "readOnlyFinalFields") - private Object[][] readOnlyFinalFields() { + private static Object[][] readOnlyFinalFields() { Object obj = INSTANCE; return new Object[][]{ // instance final fields @@ -427,19 +400,15 @@ public class NegativeTest { * IllegalAccessException is thrown regardless of whether the value * is of a bad type or not. */ - @Test(dataProvider = "readOnlyFinalFields") + @ParameterizedTest + @MethodSource("readOnlyFinalFields") public void testSetValueOnFinalField(Field f, Object obj, Object value) { assertTrue(Modifier.isFinal(f.getModifiers())); - try { - f.set(obj, value); - fail("expected IllegalAccessException"); - } catch (IllegalAccessException e) { - // expected - } + assertThrows(IllegalAccessException.class, () -> f.set(obj, value)); Class fType = f.getType(); if (fType.isPrimitive()) { - try { + assertThrows(IllegalAccessException.class, () -> { switch (fType.descriptorString()) { case "B" -> f.setByte(obj, ((Byte)value).byteValue()); case "C" -> f.setChar(obj, ((Character)value).charValue()); @@ -450,33 +419,17 @@ public class NegativeTest { case "S" -> f.setShort(obj, ((Short)value).shortValue()); case "Z" -> f.setBoolean(obj, ((Boolean)value).booleanValue()); } - fail("expected IllegalAccessException"); - } catch (IllegalAccessException e) { - // expected - } + }); // test null value only if it's primitive type - try { - f.set(obj, null); - fail("expected IllegalAccessException"); - } catch (IllegalAccessException e) { - // expected - } + assertThrows(IllegalAccessException.class, () -> f.set(obj, null)); } Object badValue = new NegativeTest(); - try { - f.set(obj, badValue); - fail("expected IllegalAccessException"); - } catch (IllegalAccessException e) { - // expected - } + assertThrows(IllegalAccessException.class, () -> f.set(obj, badValue)); } - - - @DataProvider(name = "finalInstanceFields") - private Object[][] finalInstanceFields() { + private static Object[][] finalInstanceFields() { return new Object[][]{ new Object[]{fi_field, Integer.valueOf(10)}, new Object[]{fc_field, Character.valueOf('c')}, @@ -497,54 +450,27 @@ public class NegativeTest { * The receiver is checked before the access check is performed and * also before the value is checked. */ - @Test(dataProvider = "finalInstanceFields") + @ParameterizedTest + @MethodSource("finalInstanceFields") public void testReceiverOnFinalField(Field f, Object value) { assertTrue(Modifier.isFinal(f.getModifiers())); Object badReceiver = new NegativeTest(); // set the field with a bad receiver with a good value - try { - f.set(badReceiver, value); - fail("expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // expected - } catch (IllegalAccessException e) { - throw new RuntimeException("Expected IllegalArgumentException but got: " + e.getMessage(), e); - } + assertThrows(IllegalArgumentException.class, () -> f.set(badReceiver, value)); // set the field with a bad receiver with a bad value Object badValue = new NegativeTest(); - try { - f.set(badReceiver, badValue); - fail("expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // expected - } catch (IllegalAccessException e) { - throw new RuntimeException("Expected IllegalArgumentException but got: " + e.getMessage(), e); - } + assertThrows(IllegalArgumentException.class, () -> f.set(badReceiver, badValue)); // set the field with a null receiver with a good value - try { - f.set(null, value); - fail("expected NullPointerException"); - } catch (NullPointerException e) { - // expected - } catch (IllegalAccessException e) { - throw new RuntimeException("Expected NullPointerException but got: " + e.getMessage(), e); - } + assertThrows(NullPointerException.class, () -> f.set(null, value)); // set the field with a null receiver with a bad value - try { - f.set(null, badValue); - fail("expected NullPointerException"); - } catch (NullPointerException e) { - // expected - } catch (IllegalAccessException e) { - throw new RuntimeException("Expected NullPointerException but got: " + e.getMessage(), e); - } + assertThrows(NullPointerException.class, () -> f.set(null, badValue)); Class fType = f.getType(); if (fType.isPrimitive()) { // test bad receiver - try { + assertThrows(IllegalArgumentException.class, () -> { switch (fType.descriptorString()) { case "B" -> f.setByte(badReceiver, ((Byte) value).byteValue()); case "C" -> f.setChar(badReceiver, ((Character) value).charValue()); @@ -555,12 +481,9 @@ public class NegativeTest { case "S" -> f.setShort(badReceiver, ((Short) value).shortValue()); case "Z" -> f.setBoolean(badReceiver, ((Boolean) value).booleanValue()); } - } catch (IllegalArgumentException e) { - } catch (IllegalAccessException e) { - throw new RuntimeException("Expected IllegalArgumentException but got: " + e.getMessage(), e); - } + }); // test null receiver - try { + assertThrows(NullPointerException.class, () -> { switch (fType.descriptorString()) { case "B" -> f.setByte(null, ((Byte) value).byteValue()); case "C" -> f.setChar(null, ((Character) value).charValue()); @@ -571,11 +494,7 @@ public class NegativeTest { case "S" -> f.setShort(null, ((Short) value).shortValue()); case "Z" -> f.setBoolean(null, ((Boolean) value).booleanValue()); } - } catch (NullPointerException e) { - // expected - } catch (IllegalAccessException e) { - throw new RuntimeException("Expected NullPointerException but got: " + e.getMessage(), e); - } + }); } } } diff --git a/test/jdk/java/lang/reflect/Generics/ThreadSafety.java b/test/jdk/java/lang/reflect/Generics/ThreadSafety.java index 1aa1a4e9386..81ca2ae488a 100644 --- a/test/jdk/java/lang/reflect/Generics/ThreadSafety.java +++ b/test/jdk/java/lang/reflect/Generics/ThreadSafety.java @@ -21,17 +21,16 @@ * questions. */ -/** +/* * @test * @bug 8062771 8016236 * @summary Test publication of Class objects via a data race - * @run testng ThreadSafety + * @run junit ThreadSafety */ import java.io.File; import java.net.URL; import java.net.URLClassLoader; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; import java.util.concurrent.BrokenBarrierException; @@ -43,8 +42,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeoutException; import static java.util.concurrent.TimeUnit.SECONDS; -import static org.testng.Assert.*; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; /** * A test resulting from an attempt to repro this failure (in guice): diff --git a/test/jdk/java/lang/reflect/IllegalArgumentsTest.java b/test/jdk/java/lang/reflect/IllegalArgumentsTest.java index 7260c04c10a..58115523a3d 100644 --- a/test/jdk/java/lang/reflect/IllegalArgumentsTest.java +++ b/test/jdk/java/lang/reflect/IllegalArgumentsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,14 @@ * @test * @bug 8277964 * @summary Test IllegalArgumentException be thrown when an argument is invalid - * @run testng/othervm/timeout=720 IllegalArgumentsTest + * @comment Avoid using framework utilities; this is effectively a runtime test + * sensitive to stack traces + * @run junit/othervm/timeout=720 IllegalArgumentsTest */ import java.lang.reflect.Constructor; import java.lang.reflect.Method; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class IllegalArgumentsTest { static class T { diff --git a/test/jdk/java/lang/reflect/Method/MethodArityLimit.java b/test/jdk/java/lang/reflect/Method/MethodArityLimit.java index 536b3a5e317..05d4ef609ef 100644 --- a/test/jdk/java/lang/reflect/Method/MethodArityLimit.java +++ b/test/jdk/java/lang/reflect/Method/MethodArityLimit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,18 +24,16 @@ /* * @test * @bug 8271820 - * @run testng/othervm MethodArityLimit + * @run junit/othervm MethodArityLimit * @summary Method exceeds the method handle arity limit (255). */ -import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.reflect.Method; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.*; public class MethodArityLimit { @Test @@ -74,12 +72,10 @@ public class MethodArityLimit { 106L, 107L, 108L, 109L, 110L, 111L, 112L, 113L, 114L, 115L, 116L, 117L, 118L, 119L, 120L, 121L, 122L, 123L, 124L, 125L, 126L, 127); - assertEquals(resultViaMethod, 127); + assertEquals(127, resultViaMethod); - try { - MethodHandle mh = MethodHandles.lookup().unreflect(m); - fail("should fail in creating the method handle"); - } catch (IllegalArgumentException e) {} + var lookup = MethodHandles.lookup(); + assertThrows(IllegalArgumentException.class, () -> lookup.unreflect(m)); } public static long f(long a0, long a1, long a2, long a3, long a4, long a5, diff --git a/test/jdk/java/lang/reflect/MethodHandleAccessorsTest.java b/test/jdk/java/lang/reflect/MethodHandleAccessorsTest.java index b7e6b52b5dc..af72d8dec58 100644 --- a/test/jdk/java/lang/reflect/MethodHandleAccessorsTest.java +++ b/test/jdk/java/lang/reflect/MethodHandleAccessorsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * @bug 8271820 8300924 * @modules java.base/jdk.internal.reflect * @summary Test compliance of ConstructorAccessor, FieldAccessor, MethodAccessor implementations - * @run testng/othervm --add-exports java.base/jdk.internal.reflect=ALL-UNNAMED -XX:-ShowCodeDetailsInExceptionMessages MethodHandleAccessorsTest + * @run junit/othervm -XX:-ShowCodeDetailsInExceptionMessages MethodHandleAccessorsTest */ import jdk.internal.reflect.ConstructorAccessor; @@ -44,8 +44,11 @@ import java.util.Objects; import java.util.function.IntUnaryOperator; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertThrows; public class MethodHandleAccessorsTest { public static void public_static_V() {} @@ -446,9 +449,7 @@ public class MethodHandleAccessorsTest { new InvocationTargetException(new IllegalArgumentException("IAE")) }; - - @DataProvider(name = "testNoArgMethods") - private Object[][] testNoArgMethods() { + private static Object[][] testNoArgMethods() { MethodHandleAccessorsTest inst = new MethodHandleAccessorsTest(); Object[] emptyArgs = new Object[]{}; return new Object[][] { @@ -468,8 +469,7 @@ public class MethodHandleAccessorsTest { }; } - @DataProvider(name = "testOneArgMethods") - private Object[][] testOneArgMethods() { + private static Object[][] testOneArgMethods() { MethodHandleAccessorsTest inst = new MethodHandleAccessorsTest(); Object wrongInst = new Object(); return new Object[][]{ @@ -497,8 +497,7 @@ public class MethodHandleAccessorsTest { }; } - @DataProvider(name = "testMultiArgMethods") - private Object[][] testMultiArgMethods() { + private static Object[][] testMultiArgMethods() { MethodHandleAccessorsTest inst = new MethodHandleAccessorsTest(); Class[] params_L3 = new Class[] { Object.class, Object.class, Object.class}; Class[] params_L4 = new Class[] { Object.class, Object.class, Object.class, Object.class}; @@ -515,8 +514,7 @@ public class MethodHandleAccessorsTest { }; } - @DataProvider(name = "testMethodsWithVarargs") - private Object[][] testMethodsWithVarargs() { + private static Object[][] testMethodsWithVarargs() { Class[] paramTypes = new Class[] { int[].class }; Class[] I_paramTypes = new Class[] { int.class, int[].class }; Class[] L_paramTypes = new Class[] { String.class, String[].class }; @@ -533,32 +531,35 @@ public class MethodHandleAccessorsTest { }; } - @Test(dataProvider = "testNoArgMethods") + @ParameterizedTest + @MethodSource("testNoArgMethods") public void testNoArgMethod(String methodname, Object target, Object[] args, Object expectedReturn, Throwable[] expectedExpections) throws Exception { doTest(MethodHandleAccessorsTest.class.getDeclaredMethod(methodname), target, args, expectedReturn, expectedExpections); } - @Test(dataProvider = "testOneArgMethods") + @ParameterizedTest + @MethodSource("testOneArgMethods") public void testOneArgMethod(String methodname, Class paramType, Object target, Object[] args, Object expectedReturn, Throwable[] expectedExpections) throws Exception { doTest(MethodHandleAccessorsTest.class.getDeclaredMethod(methodname, paramType), target, args, expectedReturn, expectedExpections); } - @Test(dataProvider = "testMultiArgMethods") + @ParameterizedTest + @MethodSource("testMultiArgMethods") public void testMultiArgMethod(String methodname, Class[] paramTypes, Object target, Object[] args, Object expectedReturn, Throwable[] expectedExpections) throws Exception { doTest(MethodHandleAccessorsTest.class.getDeclaredMethod(methodname, paramTypes), target, args, expectedReturn, expectedExpections); } - @Test(dataProvider = "testMethodsWithVarargs") + @ParameterizedTest + @MethodSource("testMethodsWithVarargs") public void testMethodsWithVarargs(String methodname, Class[] paramTypes, Object target, Object[] args, Object expectedReturn, Throwable[] expectedExpections) throws Exception { doTest(MethodHandleAccessorsTest.class.getDeclaredMethod(methodname, paramTypes), target, args, expectedReturn, expectedExpections); } - @DataProvider(name = "testConstructors") - private Object[][] testConstructors() { + private static Object[][] testConstructors() { return new Object[][]{ new Object[]{null, new Object[]{}, new Public(), noException}, new Object[]{null, null, new Public(), noException}, @@ -584,13 +585,13 @@ public class MethodHandleAccessorsTest { }; } - @Test(dataProvider = "testConstructors") + @ParameterizedTest + @MethodSource("testConstructors") public void testPublicConstructors(Class[] paramTypes, Object[] args, Object expectedReturn, Throwable[] expectedExpections) throws Exception { doTest(Public.class.getDeclaredConstructor(paramTypes), args, expectedReturn, expectedExpections); } - @DataProvider(name = "testMultiArgConstructors") - private Object[][] testMultiArgConstructors() { + private static Object[][] testMultiArgConstructors() { Class[] params_L3 = new Class[] { Object.class, Object.class, Object.class}; Class[] params_L4 = new Class[] { Object.class, Object.class, Object.class, Object.class}; Object o = "arg"; @@ -602,7 +603,8 @@ public class MethodHandleAccessorsTest { }; } - @Test(dataProvider = "testMultiArgConstructors") + @ParameterizedTest + @MethodSource("testMultiArgConstructors") public void testMultiArgConstructors(Class[] paramTypes, Object[] args, Object expectedReturn, Throwable[] expectedExpections) throws Exception { doTest(Public.class.getDeclaredConstructor(paramTypes), args, expectedReturn, expectedExpections); } @@ -616,8 +618,7 @@ public class MethodHandleAccessorsTest { doTest(Abstract.class.getDeclaredConstructor(), null, null, new InstantiationException()); } - @DataProvider(name = "throwException") - private Object[][] throwException() { + private static Object[][] throwException() { return new Object[][]{ new Object[] {new NullPointerException("NPE"), wrapped_npe}, new Object[] {new IllegalArgumentException("IAE"), wrapped_iae}, @@ -629,7 +630,8 @@ public class MethodHandleAccessorsTest { * Test Method::invoke and Constructor::newInstance to wrap NPE/CCE/IAE * thrown by the member */ - @Test(dataProvider = "throwException") + @ParameterizedTest + @MethodSource("throwException") public void testInvocationTargetException(Throwable ex, Throwable[] expectedExpections) throws Exception { Object[] args = new Object[] { ex }; // test static method @@ -646,8 +648,7 @@ public class MethodHandleAccessorsTest { doTest(applyAsIntMethod, intUnaryOp, new Object[]{12}, 12); } - @DataProvider(name = "readAccess") - private Object[][] readAccess() { + private static Object[][] readAccess() { String wrongInst = new String(); return new Object[][]{ new Object[]{"i", new Public(100), 100, noException}, @@ -657,8 +658,7 @@ public class MethodHandleAccessorsTest { new Object[]{"b", wrongInst, 0, cannot_get_field}, }; } - @DataProvider(name = "writeAccess") - private Object[][] writeAccess() { + private static Object[][] writeAccess() { Object o = new Object(); byte b = 1; return new Object[][]{ @@ -673,14 +673,16 @@ public class MethodHandleAccessorsTest { }; } - @Test(dataProvider = "readAccess") + @ParameterizedTest + @MethodSource("readAccess") public void testFieldReadAccess(String name, Object target, Object expectedValue, Throwable[] expectedExpections) throws Exception { Field f = Public.class.getDeclaredField(name); f.setAccessible(true); doTest(f, target, expectedValue, expectedExpections); } - @Test(dataProvider = "writeAccess") + @ParameterizedTest + @MethodSource("writeAccess") public void testFieldWriteAccess(String name, Object target, Object oldValue, Object newValue, Throwable[] expectedExpections) throws Exception { Field f = Public.class.getDeclaredField(name); f.setAccessible(true); @@ -693,8 +695,6 @@ public class MethodHandleAccessorsTest { Field f = Public.class.getDeclaredField("STATIC_FINAL"); doTest(f, new Public(), 1, noException); - try { - f.setInt(null, 100); - } catch (IllegalAccessException e) { } + assertThrows(IllegalAccessException.class, () -> f.setInt(null, 100)); } } diff --git a/test/jdk/java/lang/reflect/Proxy/DefaultMethods.java b/test/jdk/java/lang/reflect/Proxy/DefaultMethods.java index 48bb67f405e..e494e623119 100644 --- a/test/jdk/java/lang/reflect/Proxy/DefaultMethods.java +++ b/test/jdk/java/lang/reflect/Proxy/DefaultMethods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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,19 +23,19 @@ import java.io.IOException; import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -/** +/* * @test * @bug 8159746 - * @run testng DefaultMethods + * @run junit DefaultMethods * @summary Basic tests for Proxy::invokeSuper default method */ @@ -96,15 +96,11 @@ public class DefaultMethods { } private static Method findDefaultMethod(Class refc, Method m) { - try { - assertTrue(refc.isInterface()); + assertTrue(refc.isInterface()); - Method method = refc.getMethod(m.getName(), m.getParameterTypes()); - assertTrue(method.isDefault()); - return method; - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } + Method method = assertDoesNotThrow(() -> refc.getMethod(m.getName(), m.getParameterTypes())); + assertTrue(method.isDefault()); + return method; } @Test @@ -115,12 +111,11 @@ public class DefaultMethods { return InvocationHandler.invokeDefault(o, findDefaultMethod(I2.class, method), params); }); I1 i1 = (I1) proxy; - assertEquals(i1.m(), 20); + assertEquals(20, i1.m()); } // a default method is declared in one of the proxy interfaces - @DataProvider(name = "defaultMethods") - private Object[][] defaultMethods() { + private static Object[][] defaultMethods() { return new Object[][]{ new Object[]{new Class[]{I1.class, I2.class}, true, 10}, new Object[]{new Class[]{I1.class, I3.class}, true, 10}, @@ -133,13 +128,14 @@ public class DefaultMethods { }; } - @Test(dataProvider = "defaultMethods") + @ParameterizedTest + @MethodSource("defaultMethods") public void testDefaultMethod(Class[] intfs, boolean isDefault, int expected) throws Throwable { InvocationHandler ih = (proxy, method, params) -> { System.out.format("invoking %s with parameters: %s%n", method, Arrays.toString(params)); switch (method.getName()) { case "m": - assertTrue(method.isDefault() == isDefault); + assertEquals(isDefault, method.isDefault()); assertTrue(Arrays.stream(proxy.getClass().getInterfaces()) .anyMatch(intf -> method.getDeclaringClass() == intf), Arrays.toString(proxy.getClass().getInterfaces())); @@ -156,13 +152,12 @@ public class DefaultMethods { Object proxy = Proxy.newProxyInstance(DefaultMethods.class.getClassLoader(), intfs, ih); Method m = proxy.getClass().getMethod("m"); int result = (int)m.invoke(proxy); - assertEquals(result, expected); + assertEquals(expected, result); } // a default method may be declared in a proxy interface or // inherited from a superinterface of a proxy interface - @DataProvider(name = "supers") - private Object[][] supers() { + private static Object[][] supers() { return new Object[][]{ // invoke "m" implemented in the first proxy interface // same as the method passed to InvocationHandler::invoke @@ -188,7 +183,8 @@ public class DefaultMethods { }; } - @Test(dataProvider = "supers") + @ParameterizedTest + @MethodSource("supers") public void testSuper(Class[] intfs, Class proxyInterface, int expected) throws Throwable { final InvocationHandler ih = (proxy, method, params) -> { switch (method.getName()) { @@ -203,21 +199,21 @@ public class DefaultMethods { Object proxy = Proxy.newProxyInstance(loader, intfs, ih); if (proxyInterface == I1.class) { I1 i1 = (I1) proxy; - assertEquals(i1.m(), expected); + assertEquals(expected, i1.m()); } else if (proxyInterface == I2.class) { I2 i2 = (I2) proxy; - assertEquals(i2.m(), expected); + assertEquals(expected, i2.m()); } else if (proxyInterface == I3.class) { I3 i3 = (I3) proxy; - assertEquals(i3.m(), expected); + assertEquals(expected, i3.m()); } else if (proxyInterface == I4.class) { I4 i4 = (I4) proxy; - assertEquals(i4.m(), expected); + assertEquals(expected, i4.m()); } else { throw new UnsupportedOperationException(proxyInterface.toString()); } // invoke via InvocationHandler.invokeDefaultMethod directly - assertEquals(InvocationHandler.invokeDefault(proxy, proxyInterface.getMethod("m")), expected); + assertEquals(expected, InvocationHandler.invokeDefault(proxy, proxyInterface.getMethod("m"))); } // invoke I12 default methods with parameters and var args @@ -236,12 +232,12 @@ public class DefaultMethods { }; ClassLoader loader = DefaultMethods.class.getClassLoader(); I12 i12 = (I12) Proxy.newProxyInstance(loader, new Class[] { I12.class }, ih); - assertEquals(i12.sum(1, 2), 3); - assertEquals(i12.concat(1, 2, 3, 4), new Object[]{1, 2, 3, 4}); + assertEquals(3, i12.sum(1, 2)); + assertArrayEquals(new Object[]{1, 2, 3, 4}, i12.concat(1, 2, 3, 4)); Method m = I12.class.getMethod("concat", Object.class, Object[].class); assertTrue(m.isDefault()); - assertEquals(InvocationHandler.invokeDefault(i12, m, 100, new Object[] {"foo", true, "bar"}), - new Object[] {100, "foo", true, "bar"}); + assertArrayEquals(new Object[] {100, "foo", true, "bar"}, (Object[]) + InvocationHandler.invokeDefault(i12, m, 100, new Object[] {"foo", true, "bar"})); } // test a no-arg default method with and without arguments passed in the invocation @@ -250,13 +246,13 @@ public class DefaultMethods { ClassLoader loader = DefaultMethods.class.getClassLoader(); Object proxy = Proxy.newProxyInstance(loader, new Class[]{I4.class}, HANDLER); Method m1 = I4.class.getMethod("m"); - assertTrue(m1.getDeclaringClass() == I4.class); + assertSame(I4.class, m1.getDeclaringClass()); assertTrue(m1.isDefault()); InvocationHandler.invokeDefault(proxy, m1); InvocationHandler.invokeDefault(proxy, m1, new Object[0]); Method m2 = I4.class.getMethod("mix", int.class, String.class); - assertTrue(m1.getDeclaringClass() == I4.class); + assertSame(I4.class, m1.getDeclaringClass()); assertTrue(m1.isDefault()); InvocationHandler.invokeDefault(proxy, m2, Integer.valueOf(100), "foo"); } @@ -267,38 +263,37 @@ public class DefaultMethods { I3 proxy = (I3)Proxy.newProxyInstance(loader, new Class[]{I3.class}, HANDLER); Method m = I3.class.getMethod("m3", String[].class); assertTrue(m.isVarArgs() && m.isDefault()); - assertEquals(proxy.m3("a", "b", "cde"), 5); - assertEquals(InvocationHandler.invokeDefault(proxy, m, (Object)new String[] { "a", "bc" }), 3); + assertEquals(5, proxy.m3("a", "b", "cde")); + assertEquals(3, InvocationHandler.invokeDefault(proxy, m, (Object)new String[] { "a", "bc" })); } /* * Invoke I12::m which is an abstract method */ - @Test(expectedExceptions = {IllegalArgumentException.class}) + @Test public void invokeAbstractMethod() throws Exception { ClassLoader loader = DefaultMethods.class.getClassLoader(); I12 proxy = (I12) Proxy.newProxyInstance(loader, new Class[]{I12.class}, HANDLER); Method method = I12.class.getMethod("m"); - assertTrue(method.getDeclaringClass() == I12.class); + assertSame(I12.class, method.getDeclaringClass()); assertFalse(method.isDefault()); - proxy.m(); + assertThrows(IllegalArgumentException.class, () -> proxy.m()); } /* * Invoke a non proxy (default) method with parameters */ - @Test(expectedExceptions = {IllegalArgumentException.class}) + @Test public void invokeNonProxyMethod() throws Throwable { ClassLoader loader = DefaultMethods.class.getClassLoader(); I3 proxy = (I3) Proxy.newProxyInstance(loader, new Class[]{I3.class}, HANDLER); Method m = I4.class.getMethod("mix", int.class, String.class); assertTrue(m.isDefault()); - InvocationHandler.invokeDefault(proxy, m); + assertThrows(IllegalArgumentException.class, () -> InvocationHandler.invokeDefault(proxy, m)); } // negative cases - @DataProvider(name = "negativeCases") - private Object[][] negativeCases() { + private static Object[][] negativeCases() { return new Object[][]{ // I4::m overrides I1::m and I2::m new Object[] { new Class[]{I4.class}, I1.class, "m" }, @@ -315,25 +310,20 @@ public class DefaultMethods { }; } - @Test(dataProvider = "negativeCases", expectedExceptions = {IllegalArgumentException.class}) + @ParameterizedTest + @MethodSource("negativeCases") public void testNegativeCase(Class[] interfaces, Class defc, String name) throws Throwable { ClassLoader loader = DefaultMethods.class.getClassLoader(); Object proxy = Proxy.newProxyInstance(loader, interfaces, HANDLER); - try { - Method method = defc.getDeclaredMethod(name); - InvocationHandler.invokeDefault(proxy, method); - } catch (Throwable e) { - System.out.format("%s method %s::%s exception thrown: %s%n", - Arrays.toString(interfaces), defc.getName(), name, e.getMessage()); - throw e; - } + Method method = defc.getDeclaredMethod(name); + assertThrows(IllegalArgumentException.class, () -> + InvocationHandler.invokeDefault(proxy, method)); } - @DataProvider(name = "illegalArguments") - private Object[][] illegalArguments() { - return new Object[][] { - new Object[] { new Object[0]}, + private static Object[] illegalArguments() { + return new Object[] { + new Object[] { null }, new Object[] { new Object[] { 100 }}, new Object[] { new Object[] { 100, "foo", 100 }}, new Object[] { new Object[] { 100L, "foo" }}, @@ -342,21 +332,18 @@ public class DefaultMethods { }; } - @Test(dataProvider = "illegalArguments", expectedExceptions = {IllegalArgumentException.class}) + @ParameterizedTest + @MethodSource("illegalArguments") public void testIllegalArgument(Object[] args) throws Throwable { ClassLoader loader = DefaultMethods.class.getClassLoader(); I4 proxy = (I4)Proxy.newProxyInstance(loader, new Class[]{I4.class}, HANDLER); Method m = I4.class.getMethod("mix", int.class, String.class); assertTrue(m.isDefault()); - if (args.length == 0) { - // substitute empty args with null since @DataProvider doesn't allow null array - args = null; - } - InvocationHandler.invokeDefault(proxy, m, args); + assertThrows(IllegalArgumentException.class, () -> + InvocationHandler.invokeDefault(proxy, m, args)); } - @DataProvider(name = "throwables") - private Object[][] throwables() { + private static Object[][] throwables() { return new Object[][] { new Object[] { new IOException() }, new Object[] { new IllegalArgumentException() }, @@ -367,16 +354,14 @@ public class DefaultMethods { }; } - @Test(dataProvider = "throwables") + @ParameterizedTest + @MethodSource("throwables") public void testInvocationException(Throwable exception) throws Throwable { ClassLoader loader = DefaultMethods.class.getClassLoader(); IX proxy = (IX)Proxy.newProxyInstance(loader, new Class[]{IX.class}, HANDLER); Method m = IX.class.getMethod("doThrow", Throwable.class); - try { - InvocationHandler.invokeDefault(proxy, m, exception); - } catch (Throwable e) { - assertEquals(e, exception); - } + assertSame(exception, assertThrows(Throwable.class, () -> + InvocationHandler.invokeDefault(proxy, m, exception))); } private static final InvocationHandler HANDLER = (proxy, method, params) -> { diff --git a/test/jdk/java/lang/reflect/Proxy/HiddenProxyInterface.java b/test/jdk/java/lang/reflect/Proxy/HiddenProxyInterface.java index e52d3671ab6..fbaf9db6325 100644 --- a/test/jdk/java/lang/reflect/Proxy/HiddenProxyInterface.java +++ b/test/jdk/java/lang/reflect/Proxy/HiddenProxyInterface.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @bug 8250219 - * @run testng HiddenProxyInterface + * @run junit HiddenProxyInterface */ import java.lang.invoke.MethodHandles; @@ -35,8 +35,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class HiddenProxyInterface { private static final Path CLASSES_DIR = Paths.get(System.getProperty("test.classes")); @@ -45,18 +45,19 @@ public class HiddenProxyInterface { void m(); } - @Test(expectedExceptions = { IllegalArgumentException.class }) + @Test public void testHiddenInterface() throws Exception { Path classFile = CLASSES_DIR.resolve("HiddenProxyInterface$Intf.class"); byte[] bytes = Files.readAllBytes(classFile); Class hiddenIntf = MethodHandles.lookup().defineHiddenClass(bytes, false).lookupClass(); - Proxy.newProxyInstance(HiddenProxyInterface.class.getClassLoader(), + assertThrows(IllegalArgumentException.class, () -> Proxy.newProxyInstance( + HiddenProxyInterface.class.getClassLoader(), new Class[]{ hiddenIntf }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return null; } - }); + })); } } diff --git a/test/jdk/java/lang/reflect/Proxy/LazyInitializationTest.java b/test/jdk/java/lang/reflect/Proxy/LazyInitializationTest.java index cb65904cfdb..2a223873275 100644 --- a/test/jdk/java/lang/reflect/Proxy/LazyInitializationTest.java +++ b/test/jdk/java/lang/reflect/Proxy/LazyInitializationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, 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,14 +23,15 @@ import java.lang.reflect.Proxy; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; /* * @test * @bug 8285401 * @summary Avoid initialization of parameter types in proxy construction - * @run testng LazyInitializationTest + * @run junit LazyInitializationTest */ public final class LazyInitializationTest { private static volatile boolean initialized = false; @@ -50,9 +51,9 @@ public final class LazyInitializationTest { Intf value = (Intf) Proxy.newProxyInstance(LazyInitializationTest.class.getClassLoader(), new Class[]{ Intf.class }, (proxy, method, args) -> null); - Assert.assertFalse(initialized, "parameter type initialized unnecessarily"); + assertFalse(initialized, "parameter type initialized unnecessarily"); value.m(new Parameter()); - Assert.assertTrue(initialized, "parameter type initialized after instantiation"); + assertTrue(initialized, "parameter type initialized after instantiation"); } } diff --git a/test/jdk/java/lang/reflect/Proxy/ProxyClassAccessTest.java b/test/jdk/java/lang/reflect/Proxy/ProxyClassAccessTest.java index 50fbd150ec7..265f9ce7104 100644 --- a/test/jdk/java/lang/reflect/Proxy/ProxyClassAccessTest.java +++ b/test/jdk/java/lang/reflect/Proxy/ProxyClassAccessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,17 +32,17 @@ import java.util.List; import jdk.test.lib.compiler.CompilerUtils; import static jdk.test.lib.process.ProcessTools.executeTestJava; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; -/** +/* * @test * @library /test/lib * @modules jdk.compiler * @build ProxyClassAccessTest q.NP * jdk.test.lib.compiler.CompilerUtils - * @run testng ProxyClassAccessTest + * @run junit ProxyClassAccessTest * @summary Driver for testing proxy class doesn't have access to * types referenced by proxy interfaces */ @@ -61,8 +61,8 @@ public class ProxyClassAccessTest { /** * Compiles all modules used by the test */ - @BeforeTest - public void compileAll() throws Exception { + @BeforeAll + public static void compileAll() throws Exception { for (String mn : modules) { Path msrc = SRC_DIR.resolve(mn); assertTrue(CompilerUtils.compile(msrc, MODS_DIR, "--module-source-path", SRC_DIR.toString())); @@ -80,7 +80,7 @@ public class ProxyClassAccessTest { .errorTo(System.out) .getExitValue(); - assertTrue(exitValue == 0); + assertEquals(0, exitValue); } /** @@ -105,16 +105,10 @@ public class ProxyClassAccessTest { } private void checkIAE(ClassLoader loader, Class[] interfaces) throws Throwable { - try { - Proxy.getProxyClass(loader, interfaces); - throw new RuntimeException("Expected IllegalArgumentException thrown"); - } catch (IllegalArgumentException e) {} + assertThrows(IllegalArgumentException.class, () -> Proxy.getProxyClass(loader, interfaces)); - try { - Proxy.newProxyInstance(loader, interfaces, - (proxy, m, params) -> { throw new RuntimeException(m.toString()); }); - throw new RuntimeException("Expected IllegalArgumentException thrown"); - } catch (IllegalArgumentException e) {} + assertThrows(IllegalArgumentException.class, () -> Proxy.newProxyInstance(loader, interfaces, + (proxy, m, params) -> { throw new RuntimeException(m.toString()); })); } } diff --git a/test/jdk/java/lang/reflect/Proxy/ProxyLayerTest.java b/test/jdk/java/lang/reflect/Proxy/ProxyLayerTest.java index 85ebf922a20..d2708e18c0e 100644 --- a/test/jdk/java/lang/reflect/Proxy/ProxyLayerTest.java +++ b/test/jdk/java/lang/reflect/Proxy/ProxyLayerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,17 +32,18 @@ import java.util.Arrays; import jdk.test.lib.compiler.CompilerUtils; import static jdk.test.lib.process.ProcessTools.executeTestJava; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; -/** +/* * @test * @library /test/lib * @modules jdk.compiler * @build ProxyTest jdk.test.lib.process.ProcessTools * jdk.test.lib.compiler.CompilerUtils - * @run testng ProxyLayerTest + * @run junit ProxyLayerTest * @summary Test proxies to implement interfaces in a layer */ @@ -62,8 +63,8 @@ public class ProxyLayerTest { /** * Compiles all modules used by the test */ - @BeforeTest - public void compileAll() throws Exception { + @BeforeAll + public static void compileAll() throws Exception { for (String mn : modules) { Path msrc = SRC_DIR.resolve(mn); assertTrue(CompilerUtils.compile(msrc, MODS_DIR, "--module-source-path", SRC_DIR.toString())); @@ -102,7 +103,7 @@ public class ProxyLayerTest { assertTrue(proxyClass.getModule().isNamed()); assertTrue(pkg.isSealed()); assertTrue(proxyClass.getModule().isExported(pkg.getName())); - assertEquals(proxyClass.getModule().getLayer(), null); + assertNull(proxyClass.getModule().getLayer()); } /** @@ -134,7 +135,7 @@ public class ProxyLayerTest { assertTrue(proxyClass.getModule().isNamed()); assertTrue(pkg.isSealed()); assertFalse(proxyClass.getModule().isExported(pkg.getName())); - assertEquals(proxyClass.getModule().getLayer(), null); + assertNull(proxyClass.getModule().getLayer()); } /** @@ -164,15 +165,8 @@ public class ProxyLayerTest { } private void checkIAE(ClassLoader loader, Class[] interfaces) { - try { - Proxy.getProxyClass(loader, interfaces); - throw new RuntimeException("Expected IllegalArgumentException thrown"); - } catch (IllegalArgumentException e) {} - - try { - Proxy.newProxyInstance(loader, interfaces, handler); - throw new RuntimeException("Expected IllegalArgumentException thrown"); - } catch (IllegalArgumentException e) {} + assertThrows(IllegalArgumentException.class, () -> Proxy.getProxyClass(loader, interfaces)); + assertThrows(IllegalArgumentException.class, () -> Proxy.newProxyInstance(loader, interfaces, handler)); } private final static InvocationHandler handler = diff --git a/test/jdk/java/lang/reflect/Proxy/ProxyTest.java b/test/jdk/java/lang/reflect/Proxy/ProxyTest.java index 811471585a9..1da6a10260a 100644 --- a/test/jdk/java/lang/reflect/Proxy/ProxyTest.java +++ b/test/jdk/java/lang/reflect/Proxy/ProxyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, 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 @@ -29,17 +29,17 @@ import java.util.List; import jdk.test.lib.compiler.CompilerUtils; import static jdk.test.lib.process.ProcessTools.executeTestJava; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; -/** +/* * @test * @library /test/lib * @modules jdk.compiler * @build ProxyTest q.U * jdk.test.lib.compiler.CompilerUtils - * @run testng ProxyTest + * @run junit ProxyTest * @summary Driver for testing proxies accessing interfaces in named modules */ @@ -59,8 +59,8 @@ public class ProxyTest { /** * Compiles all modules used by the test */ - @BeforeTest - public void compileAll() throws Exception { + @BeforeAll + public static void compileAll() throws Exception { for (String mn : modules) { Path msrc = SRC_DIR.resolve(mn); assertTrue(CompilerUtils.compile(msrc, MODS_DIR, "--module-source-path", SRC_DIR.toString())); @@ -79,7 +79,7 @@ public class ProxyTest { .errorTo(System.out) .getExitValue(); - assertTrue(exitValue == 0); + assertEquals(0, exitValue); } /** @@ -95,6 +95,6 @@ public class ProxyTest { .errorTo(System.out) .getExitValue(); - assertTrue(exitValue == 0); + assertEquals(0, exitValue); } } diff --git a/test/jdk/java/lang/reflect/Proxy/SealedInterfaceTest.java b/test/jdk/java/lang/reflect/Proxy/SealedInterfaceTest.java index 1337248f817..822c5d83319 100644 --- a/test/jdk/java/lang/reflect/Proxy/SealedInterfaceTest.java +++ b/test/jdk/java/lang/reflect/Proxy/SealedInterfaceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,15 +24,15 @@ /* * @test * @bug 8269351 - * @run testng SealedInterfaceTest + * @run junit SealedInterfaceTest */ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class SealedInterfaceTest { sealed interface Intf permits NonSealedInterface { @@ -43,16 +43,17 @@ public class SealedInterfaceTest { void m2(); } - @Test(expectedExceptions = { IllegalArgumentException.class }) + @Test public void testSealedInterface() { - Proxy.newProxyInstance(SealedInterfaceTest.class.getClassLoader(), + assertThrows(IllegalArgumentException.class, () -> Proxy.newProxyInstance( + SealedInterfaceTest.class.getClassLoader(), new Class[]{ Intf.class }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return null; } - }); + })); } @Test diff --git a/test/jdk/java/lang/reflect/Proxy/TestVarArgs.java b/test/jdk/java/lang/reflect/Proxy/TestVarArgs.java index a472f75d4b7..b16831c7867 100644 --- a/test/jdk/java/lang/reflect/Proxy/TestVarArgs.java +++ b/test/jdk/java/lang/reflect/Proxy/TestVarArgs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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,10 +21,10 @@ * questions. */ -/** +/* * @test * @bug 8022795 - * @run testng TestVarArgs + * @run junit TestVarArgs * @summary Verify if a method defined in a proxy interface has ACC_VARARGS set */ @@ -34,11 +34,10 @@ import java.lang.invoke.MethodType; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -import java.util.Arrays; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class TestVarArgs { interface I { @@ -48,8 +47,7 @@ public class TestVarArgs { Object call(Object[] values); } - @DataProvider(name = "proxyInterfaces") - public Object[][] proxyInterfaces() { + public static Object[][] proxyInterfaces() { return new Object[][] { { new Class[] { I.class }, true}, { new Class[] { J.class }, false}, @@ -58,11 +56,12 @@ public class TestVarArgs { }; } - @Test(dataProvider = "proxyInterfaces") + @ParameterizedTest + @MethodSource("proxyInterfaces") public void testMethod(Class[] proxyInterfaces, boolean isVarArgs) throws Throwable { // check if the first proxy interface with the method named "call" declares var result Method m = proxyInterfaces[0].getMethod("call", Object[].class); - assertTrue(m.isVarArgs() == isVarArgs); + assertEquals(isVarArgs, m.isVarArgs()); // the method in the generated proxy class should match the method // declared in the proxy interface @@ -71,19 +70,19 @@ public class TestVarArgs { Class proxyClass = proxy.getClass(); assertTrue(Proxy.isProxyClass(proxyClass)); Method method = proxyClass.getMethod("call", Object[].class); - assertTrue(method.isVarArgs() == isVarArgs); + assertEquals(isVarArgs, method.isVarArgs()); - Object params = new Object[] { "foo", "bar", "goo" }; - Object result; + Object[] params = new Object[] { "foo", "bar", "goo" }; + Object[] result; // test reflection - result = method.invoke(proxy, params); - assertEquals(result, params); + result = (Object[]) method.invoke(proxy, new Object[] {params}); + assertEquals(params, result); // test method handle MethodHandle mh = MethodHandles.lookup().findVirtual(proxyClass, "call", MethodType.methodType(Object.class, Object[].class)); - assertTrue(mh.isVarargsCollector() == isVarArgs); + assertEquals(isVarArgs, mh.isVarargsCollector()); MethodHandle mhVarArity = mh; MethodHandle mhFixedArity = mh; if (isVarArgs) { @@ -91,18 +90,18 @@ public class TestVarArgs { } else { mhVarArity = mh.asVarargsCollector(Object[].class); } - result = mhVarArity.invoke(proxy, "foo", "bar", "goo"); - assertEquals(result, params); + result = (Object[]) mhVarArity.invoke(proxy, "foo", "bar", "goo"); + assertArrayEquals(params, result); - result = mhFixedArity.invoke(proxy, params); - assertEquals(result, params); + result = (Object[]) mhFixedArity.invoke(proxy, params); + assertArrayEquals(params, result); if (!isVarArgs) { MethodType mt = MethodType.methodType(Object.class, Object.class, String.class, String.class, String.class); mh = mh.asVarargsCollector(Object[].class).asType(mt); } - result = mh.invoke(proxy, "foo", "bar", "goo"); - assertEquals(result, params); + result = (Object[]) mh.invoke(proxy, "foo", "bar", "goo"); + assertArrayEquals(params, result); } private static final InvocationHandler IH = new InvocationHandler() { diff --git a/test/jdk/java/lang/reflect/Proxy/nonPublicProxy/DefaultMethodProxy.java b/test/jdk/java/lang/reflect/Proxy/nonPublicProxy/DefaultMethodProxy.java index daf6f656aab..a304063638c 100644 --- a/test/jdk/java/lang/reflect/Proxy/nonPublicProxy/DefaultMethodProxy.java +++ b/test/jdk/java/lang/reflect/Proxy/nonPublicProxy/DefaultMethodProxy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,16 +25,17 @@ import java.lang.reflect.*; import java.util.Arrays; import java.util.stream.Collectors; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /* * @test * @bug 8159746 * @summary Test invoking a default method in a non-public proxy interface * @build p.Foo p.Bar p.ProxyMaker - * @run testng DefaultMethodProxy + * @run junit DefaultMethodProxy */ public class DefaultMethodProxy { public interface I { @@ -42,7 +43,7 @@ public class DefaultMethodProxy { } @Test - public static void publicInterface() throws ReflectiveOperationException { + public void publicInterface() throws ReflectiveOperationException { // create a proxy instance of a public proxy interface should succeed Proxy proxy = (Proxy)Proxy.newProxyInstance(DefaultMethodProxy.class.getClassLoader(), new Class[] { I.class }, IH); @@ -50,11 +51,9 @@ public class DefaultMethodProxy { testDefaultMethod(proxy, "I"); // can get the invocation handler - assertTrue(Proxy.getInvocationHandler(proxy) == IH); + assertSame(IH, Proxy.getInvocationHandler(proxy)); } - - @DataProvider(name = "nonPublicIntfs") private static Object[][] nonPublicIntfs() throws ClassNotFoundException { Class fooClass = Class.forName("p.Foo"); Class barClass = Class.forName("p.Bar"); @@ -65,8 +64,9 @@ public class DefaultMethodProxy { }; } - @Test(dataProvider = "nonPublicIntfs") - public static void hasPackageAccess(Class[] intfs, String expected) throws ReflectiveOperationException { + @ParameterizedTest + @MethodSource("nonPublicIntfs") + public void hasPackageAccess(Class[] intfs, String expected) throws ReflectiveOperationException { Proxy proxy = (Proxy)Proxy.newProxyInstance(DefaultMethodProxy.class.getClassLoader(), intfs, IH); testDefaultMethod(proxy, expected); @@ -75,19 +75,13 @@ public class DefaultMethodProxy { } // IAE thrown at invocation time - @Test(dataProvider = "nonPublicIntfs", expectedExceptions = {IllegalAccessException.class}) - public static void noPackageAccess(Class[] intfs, String ignored) throws Throwable { + @ParameterizedTest + @MethodSource("nonPublicIntfs") + public void noPackageAccess(Class[] intfs, String ignored) throws Throwable { Proxy proxy = (Proxy)Proxy.newProxyInstance(DefaultMethodProxy.class.getClassLoader(), intfs, IH_NO_ACCESS); - try { - testDefaultMethod(proxy, "dummy"); - } catch (InvocationTargetException e) { - // unwrap the exception - if (e.getCause() instanceof UndeclaredThrowableException) { - Throwable cause = e.getCause(); - throw cause.getCause(); - } - throw e; - } + InvocationTargetException ite = assertThrows(InvocationTargetException.class, () -> testDefaultMethod(proxy, "dummy")); + var ute = assertInstanceOf(UndeclaredThrowableException.class, ite.getCause(), "unwrap the InvocationTargetException"); + assertInstanceOf(IllegalAccessException.class, ute.getCause(), "unwrap the UndeclaredThrowableException"); } /* diff --git a/test/jdk/java/lang/reflect/annotationSharing/AnnotationSharing.java b/test/jdk/java/lang/reflect/annotationSharing/AnnotationSharing.java index 98a13d6416c..b29c74637d6 100644 --- a/test/jdk/java/lang/reflect/annotationSharing/AnnotationSharing.java +++ b/test/jdk/java/lang/reflect/annotationSharing/AnnotationSharing.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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,13 +27,13 @@ * @summary Test sharing of annotations between Executable/Field instances. * Sharing should not be noticeable when performing mutating * operations. - * @run testng AnnotationSharing + * @run junit AnnotationSharing */ import java.lang.annotation.*; import java.lang.reflect.*; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class AnnotationSharing { @Test diff --git a/test/jdk/java/lang/reflect/callerCache/CustomLoaderTest.java b/test/jdk/java/lang/reflect/callerCache/CustomLoaderTest.java index f3a429027d9..6951cc0829c 100644 --- a/test/jdk/java/lang/reflect/callerCache/CustomLoaderTest.java +++ b/test/jdk/java/lang/reflect/callerCache/CustomLoaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ * @library /test/lib/ * @modules jdk.compiler * @build CustomLoaderTest jdk.test.lib.compiler.CompilerUtils - * @run testng/othervm CustomLoaderTest + * @run junit/othervm CustomLoaderTest * * @summary Test method whose parameter types and return type are not visible to the caller. */ @@ -42,27 +42,23 @@ import java.nio.file.Paths; import java.util.concurrent.atomic.AtomicInteger; import jdk.test.lib.compiler.CompilerUtils; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; public class CustomLoaderTest { private static final Path CLASSES = Paths.get("classes"); - @BeforeTest - public void setup() throws IOException { + @BeforeAll + public static void setup() throws IOException { String src = System.getProperty("test.src", "."); String classpath = System.getProperty("test.classes", "."); boolean rc = CompilerUtils.compile(Paths.get(src, "ReflectTest.java"), CLASSES, "-cp", classpath); if (!rc) { - throw new RuntimeException("fail compilation"); - } - try { - Class p = Class.forName("ReflectTest$P"); - fail("should not be visible to this loader"); - } catch (ClassNotFoundException e) { - e.printStackTrace(); + fail("fail compilation"); } + assertThrows(ClassNotFoundException.class, () -> Class.forName("ReflectTest$P"), + "should not be visible to this loader"); } @Test @@ -72,17 +68,17 @@ public class CustomLoaderTest { Method m1 = loader1.findMethod(); Method m2 = loader2.findMethod(); - assertTrue(m1.getDeclaringClass() != m2.getDeclaringClass()); + assertNotSame(m1.getDeclaringClass(), m2.getDeclaringClass()); - assertTrue(m1.getDeclaringClass() == loader1.c); - assertTrue(m2.getDeclaringClass() == loader2.c); + assertSame(loader1.c, m1.getDeclaringClass()); + assertSame(loader2.c, m2.getDeclaringClass()); Object o1 = m1.invoke(loader1.c.newInstance(), loader1.p.newInstance(), loader1.q.newInstance()); Object o2 = m2.invoke(loader2.c.newInstance(), loader2.p.newInstance(), loader2.q.newInstance()); - assertTrue(o1.getClass() != o2.getClass()); - assertTrue(o1.getClass() == loader1.r); - assertTrue(o2.getClass() == loader2.r); + assertNotSame(o1.getClass(), o2.getClass()); + assertSame(loader1.r, o1.getClass()); + assertSame(loader2.r, o2.getClass()); } static class TestLoader extends URLClassLoader { diff --git a/test/jdk/java/lang/reflect/callerCache/ReflectionCallerCacheTest.java b/test/jdk/java/lang/reflect/callerCache/ReflectionCallerCacheTest.java index b640a5e2150..4513c698a54 100644 --- a/test/jdk/java/lang/reflect/callerCache/ReflectionCallerCacheTest.java +++ b/test/jdk/java/lang/reflect/callerCache/ReflectionCallerCacheTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -29,7 +29,7 @@ * @library /test/lib/ * @modules jdk.compiler * @build ReflectionCallerCacheTest Members jdk.test.lib.compiler.CompilerUtils - * @run testng/othervm ReflectionCallerCacheTest + * @run junit/othervm ReflectionCallerCacheTest */ import java.io.IOException; @@ -44,16 +44,16 @@ import java.util.concurrent.Callable; import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.util.ForceGC; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class ReflectionCallerCacheTest { private static final Path CLASSES = Paths.get("classes"); private static final ReflectionCallerCacheTest TEST = new ReflectionCallerCacheTest(); - @BeforeTest - public void setup() throws IOException { + @BeforeAll + public static void setup() throws IOException { String src = System.getProperty("test.src", "."); String classpath = System.getProperty("test.classes", "."); boolean rc = CompilerUtils.compile(Paths.get(src, "AccessTest.java"), CLASSES, "-cp", classpath); @@ -61,8 +61,8 @@ public class ReflectionCallerCacheTest { throw new RuntimeException("fail compilation"); } } - @DataProvider(name = "memberAccess") - public Object[][] memberAccess() { + + public static Object[][] memberAccess() { return new Object[][] { { "AccessTest$PublicConstructor" }, { "AccessTest$PublicMethod" }, @@ -102,8 +102,9 @@ public class ReflectionCallerCacheTest { } } - @Test(dataProvider = "memberAccess") - private void load(String classname) throws Exception { + @ParameterizedTest + @MethodSource("memberAccess") + void load(String classname) throws Exception { WeakReference weakLoader = loadAndRunClass(classname); // Force garbage collection to trigger unloading of class loader diff --git a/test/jdk/java/lang/reflect/records/CheckEqualityIsBasedOnFields.java b/test/jdk/java/lang/reflect/records/CheckEqualityIsBasedOnFields.java index b5c438e4f9a..c3e4431bd84 100644 --- a/test/jdk/java/lang/reflect/records/CheckEqualityIsBasedOnFields.java +++ b/test/jdk/java/lang/reflect/records/CheckEqualityIsBasedOnFields.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,17 +25,15 @@ * @test * @bug 8257598 * @summary check that Record::equals uses the fields and not the accessors for the comparison - * @run testng CheckEqualityIsBasedOnFields + * @run junit CheckEqualityIsBasedOnFields */ import java.lang.reflect.Constructor; -import java.lang.reflect.Field; import java.lang.reflect.Method; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class CheckEqualityIsBasedOnFields { public record R01(boolean x) { @@ -91,8 +89,7 @@ public class CheckEqualityIsBasedOnFields { } } - @DataProvider(name = "recordData") - public Object[][] recordTypeAndExpectedValue() { + public static Object[][] recordTypeAndExpectedValue() { return new Object[][] { new Object[] { R01.class, boolean.class, new Object[]{true, false} }, new Object[] { R02.class, byte.class, new Object[]{(byte)0, (byte)1, (byte)2, (byte)3, (byte)4, (byte)5, @@ -112,7 +109,8 @@ public class CheckEqualityIsBasedOnFields { }; } - @Test(dataProvider = "recordData") + @ParameterizedTest + @MethodSource("recordTypeAndExpectedValue") public void testEqualsDoesntUseAccessors(Class clazz, Class componentClass, Object[] expectedXValues) throws Exception { Constructor ctor; Method getter, equalsMethod; @@ -125,8 +123,8 @@ public class CheckEqualityIsBasedOnFields { System.out.println(rec1.toString()); System.out.println(rec2.toString()); assertFalse((boolean) equalsMethod.invoke(rec1, rec2)); - assertNotEquals(expectedXValues[i], expectedXValues[i + expectedXValues.length / 2]); - assertEquals(getter.invoke(rec1), getter.invoke(rec2)); + assertNotEquals(expectedXValues[i + expectedXValues.length / 2], expectedXValues[i]); + assertEquals(getter.invoke(rec2), getter.invoke(rec1)); } } } diff --git a/test/jdk/java/lang/reflect/records/IsRecordTest.java b/test/jdk/java/lang/reflect/records/IsRecordTest.java index 4888e6d506e..153329a7832 100644 --- a/test/jdk/java/lang/reflect/records/IsRecordTest.java +++ b/test/jdk/java/lang/reflect/records/IsRecordTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,32 +26,31 @@ * @bug 8255560 * @summary Class::isRecord should check that the current class is final and not abstract * @library /test/lib - * @run testng/othervm IsRecordTest + * @run junit/othervm IsRecordTest */ import java.lang.classfile.ClassFile; import java.lang.constant.ClassDesc; -import java.lang.reflect.AccessFlag; import java.util.List; import java.util.Map; import java.lang.classfile.attribute.RecordAttribute; import java.lang.classfile.attribute.RecordComponentInfo; import jdk.test.lib.ByteCodeLoader; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.System.out; import static java.lang.classfile.ClassFile.ACC_ABSTRACT; import static java.lang.classfile.ClassFile.ACC_FINAL; import static java.lang.constant.ConstantDescs.CD_int; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.*; public class IsRecordTest { - @DataProvider(name = "scenarios") - public Object[][] scenarios() { + public static Object[][] scenarios() { return new Object[][] { // isFinal, isAbstract, extendJLR, withRecAttr, expectIsRecord { false, false, false, true, false }, @@ -75,7 +74,8 @@ public class IsRecordTest { * iii) direct subclass of j.l.Record (or not), along with the presence or * absence of a record attribute. */ - @Test(dataProvider = "scenarios") + @ParameterizedTest + @MethodSource("scenarios") public void testDirectSubClass(boolean isFinal, boolean isAbstract, boolean extendsJLR, @@ -92,9 +92,8 @@ public class IsRecordTest { Class cls = ByteCodeLoader.load("C", classBytes); out.println("cls=%s, Record::isAssignable=%s, isRecord=%s" .formatted(cls, Record.class.isAssignableFrom(cls), cls.isRecord())); - assertEquals(cls.isRecord(), expectIsRecord); - var getRecordComponents = cls.getRecordComponents(); - assertTrue(expectIsRecord ? getRecordComponents != null : getRecordComponents == null); + assertEquals(expectIsRecord, cls.isRecord()); + assertEquals(expectIsRecord, cls.getRecordComponents() != null); } /** @@ -102,7 +101,8 @@ public class IsRecordTest { * along with the presence or absence of a record attribute, where the class has * a superclass whose superclass is j.l.Record. */ - @Test(dataProvider = "scenarios") + @ParameterizedTest + @MethodSource("scenarios") public void testIndirectSubClass(boolean isFinal, boolean isAbstract, boolean unused1, @@ -127,8 +127,8 @@ public class IsRecordTest { .formatted(cls, Record.class.isAssignableFrom(cls), cls.isRecord())); assertFalse(supFooCls.isRecord()); assertFalse(subFooCls.isRecord()); - assertEquals(supFooCls.getRecordComponents(), null); - assertEquals(subFooCls.getRecordComponents(), null); + assertNull(supFooCls.getRecordComponents()); + assertNull(subFooCls.getRecordComponents()); } /** Tests record-ness properties of traditionally compiled classes. */ @@ -137,23 +137,23 @@ public class IsRecordTest { out.println("\n--- testBasicRecords ---"); record EmptyRecord () { } assertTrue(EmptyRecord.class.isRecord()); - assertEquals(EmptyRecord.class.getRecordComponents().length, 0); + assertEquals(0, EmptyRecord.class.getRecordComponents().length); record FooRecord (int x) { } assertTrue(FooRecord.class.isRecord()); - assertTrue(FooRecord.class.getRecordComponents() != null); + assertNotNull(FooRecord.class.getRecordComponents()); final record FinalFooRecord (int x) { } assertTrue(FinalFooRecord.class.isRecord()); - assertTrue(FinalFooRecord.class.getRecordComponents() != null); + assertNotNull(FinalFooRecord.class.getRecordComponents()); class A { } assertFalse(A.class.isRecord()); - assertFalse(A.class.getRecordComponents() != null); + assertNull(A.class.getRecordComponents()); final class B { } assertFalse(B.class.isRecord()); - assertFalse(B.class.getRecordComponents() != null); + assertNull(B.class.getRecordComponents()); } // -- infra diff --git a/test/jdk/java/lang/reflect/records/RecordReflectionTest.java b/test/jdk/java/lang/reflect/records/RecordReflectionTest.java index 0598e88f0c1..5cc2fd4f8eb 100644 --- a/test/jdk/java/lang/reflect/records/RecordReflectionTest.java +++ b/test/jdk/java/lang/reflect/records/RecordReflectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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,16 +27,17 @@ * @summary reflection test for records * @build R10 * @compile RecordReflectionTest.java - * @run testng/othervm RecordReflectionTest + * @run junit/othervm RecordReflectionTest */ import java.lang.annotation.*; import java.lang.reflect.*; import java.util.List; -import org.testng.annotations.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@Test public class RecordReflectionTest { class NoRecord {} @@ -78,8 +79,7 @@ public class RecordReflectionTest { R13 {} // compact constructor, will contain mandated parameters } - @DataProvider(name = "recordClasses") - public Object[][] recordClassData() { + public static Object[][] recordClassData() { return List.of(R1.class, R2.class, R3.class, @@ -96,17 +96,17 @@ public class RecordReflectionTest { ).stream().map(c -> new Object[] {c}).toArray(Object[][]::new); } - @Test(dataProvider = "recordClasses") + @ParameterizedTest + @MethodSource("recordClassData") public void testIsRecord(Class cls) { String message = cls.toGenericString(); assertTrue(cls.isRecord()); - assertTrue(cls.getSuperclass() == java.lang.Record.class); - assertTrue(cls.getRecordComponents() != null); + assertSame(Record.class, cls.getSuperclass()); + assertNotNull(cls.getRecordComponents()); assertTrue(message.contains("record"), message); } - @DataProvider(name = "notRecordClasses") - public Object[][] notRecordClasses() { + public static List> notRecordClasses() { return List.of(NoRecord.class, NoRecord[].class, Record.class, // java.lang.Record is not itself a record class @@ -116,19 +116,18 @@ public class RecordReflectionTest { int.class, int[].class, long.class, - long[].class) - .stream().map(c -> new Object[] {c}).toArray(Object[][]::new); + long[].class); } - @Test(dataProvider = "notRecordClasses") + @ParameterizedTest + @MethodSource("notRecordClasses") public void testNotARecordClass(Class cls) { assertFalse(cls.isRecord()); - assertFalse(cls.getSuperclass() == java.lang.Record.class); - assertTrue(cls.getRecordComponents() == null); + assertNotSame(Record.class, cls.getSuperclass()); + assertNull(cls.getRecordComponents()); } - @DataProvider(name = "reflectionData") - public Object[][] reflectionData() { + public static Object[][] reflectionData() { return new Object[][] { new Object[] { new R1(), 0, @@ -181,7 +180,8 @@ public class RecordReflectionTest { }; } - @Test(dataProvider = "reflectionData") + @ParameterizedTest + @MethodSource("reflectionData") public void testRecordReflection(Object recordOb, int numberOfComponents, Object[] values, @@ -192,13 +192,13 @@ public class RecordReflectionTest { Class recordClass = recordOb.getClass(); assertTrue(recordClass.isRecord()); RecordComponent[] recordComponents = recordClass.getRecordComponents(); - assertEquals(recordComponents.length, numberOfComponents); + assertEquals(numberOfComponents, recordComponents.length); int i = 0; for (RecordComponent rc : recordComponents) { - assertEquals(rc.getName(), names[i]); - assertEquals(rc.getType(), rc.getAccessor().getReturnType()); - assertEquals(rc.getAccessor().invoke(recordOb), values[i]); - assertEquals(rc.getAccessor().getGenericReturnType().toString(), signatures[i], + assertEquals(names[i], rc.getName()); + assertEquals(rc.getAccessor().getReturnType(), rc.getType()); + assertEquals(values[i], rc.getAccessor().invoke(recordOb)); + assertEquals(signatures[i], rc.getAccessor().getGenericReturnType().toString(), String.format("signature of method \"%s\" different from expected signature \"%s\"", rc.getAccessor().getGenericReturnType(), signatures[i])); i++; @@ -207,7 +207,7 @@ public class RecordReflectionTest { var constructor = recordClass.getDeclaredConstructors()[0]; i = 0; for (var p: constructor.getParameters()) { - assertEquals(p.getParameterizedType().toString(), signatures[i], + assertEquals(signatures[i], p.getParameterizedType().toString(), String.format("signature of method \"%s\" different from expected signature \"%s\"", p.getType().toString(), signatures[i])); i++; @@ -215,7 +215,7 @@ public class RecordReflectionTest { // similar as above but testing another API i = 0; for (var p : constructor.getGenericParameterTypes()) { - assertEquals(p.toString(), signatures[i], + assertEquals(signatures[i], p.toString(), String.format("signature of method \"%s\" different from expected signature \"%s\"", p.toString(), signatures[i])); i++; @@ -228,16 +228,17 @@ public class RecordReflectionTest { record AnnotatedRec(@RCA int i) {} + @Test public void testDeclAnnotationsInRecordComp() throws Throwable { Class recordClass = AnnotatedRec.class; RecordComponent rc = recordClass.getRecordComponents()[0]; Annotation[] annos = rc.getAnnotations(); - assertEquals(annos.length, 1); - assertEquals(annos[0].toString(), "@RecordReflectionTest.RCA()"); + assertEquals(1, annos.length); + assertEquals("@RecordReflectionTest.RCA()", annos[0].toString()); Field f = recordClass.getDeclaredField("i"); - assertEquals(f.getAnnotations().length, 1); - assertEquals(f.getAnnotations()[0].toString(), annos[0].toString()); + assertEquals(1, f.getAnnotations().length); + assertEquals(annos[0].toString(), f.getAnnotations()[0].toString()); } @Retention(RetentionPolicy.RUNTIME) @@ -246,30 +247,28 @@ public class RecordReflectionTest { record TypeAnnotatedRec(@TYPE_USE int i) {} + @Test public void testTypeAnnotationsInRecordComp() throws Throwable { Class recordClass = TypeAnnotatedRec.class; RecordComponent rc = recordClass.getRecordComponents()[0]; AnnotatedType at = rc.getAnnotatedType(); Annotation[] annos = at.getAnnotations(); - assertEquals(annos.length, 1); - assertEquals(annos[0].toString(), "@RecordReflectionTest.TYPE_USE()"); + assertEquals(1, annos.length); + assertEquals("@RecordReflectionTest.TYPE_USE()", annos[0].toString()); Field f = recordClass.getDeclaredField("i"); - assertEquals(f.getAnnotatedType().getAnnotations().length, 1); - assertEquals(f.getAnnotatedType().getAnnotations()[0].toString(), annos[0].toString()); + assertEquals(1, f.getAnnotatedType().getAnnotations().length); + assertEquals(annos[0].toString(), f.getAnnotatedType().getAnnotations()[0].toString()); } + @Test public void testReadOnlyFieldInRecord() throws Throwable { R2 o = new R2(1, 2); Class recordClass = R2.class; String fieldName = "i"; Field f = recordClass.getDeclaredField(fieldName); assertTrue(f.trySetAccessible()); - assertTrue(f.get(o) != null); - try { - f.set(o, null); - assertTrue(false, "should fail to set " + fieldName); - } catch (IllegalAccessException e) { - } + assertNotNull(f.get(o)); + assertThrows(IllegalAccessException.class, () -> f.set(o, null)); } } diff --git a/test/jdk/java/lang/reflect/sealed_classes/SealedClassesReflectionTest.java b/test/jdk/java/lang/reflect/sealed_classes/SealedClassesReflectionTest.java index 03caebb49e8..6e14a5d540e 100644 --- a/test/jdk/java/lang/reflect/sealed_classes/SealedClassesReflectionTest.java +++ b/test/jdk/java/lang/reflect/sealed_classes/SealedClassesReflectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,18 +26,17 @@ * @bug 8227046 * @summary reflection test for sealed classes * @compile SealedClassesReflectionTest.java - * @run testng/othervm SealedClassesReflectionTest + * @run junit/othervm SealedClassesReflectionTest */ import java.lang.annotation.*; -import java.lang.constant.ClassDesc; import java.lang.reflect.*; import java.util.Arrays; import java.util.List; -import org.testng.annotations.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@Test public class SealedClassesReflectionTest { sealed class SealedClass1 permits FinalSubclass1, NonSealedSubclass1 {} @@ -68,8 +67,7 @@ public class SealedClassesReflectionTest { sealed class SealedSubclass2 implements SealedInt3 permits NonSealedSubclass2 {} non-sealed class NonSealedSubclass2 extends SealedSubclass2 {} - @DataProvider(name = "sealedClasses") - public Object[][] sealedClassesData() { + public static List> sealedClassesData() { return List.of( SealedClass1.class, SealedClass2.class, @@ -79,19 +77,19 @@ public class SealedClassesReflectionTest { SealedInt2.class, SealedInt3.class, SealedSubInt1.class - ).stream().map(c -> new Object[] {c}).toArray(Object[][]::new); + ); } - @Test(dataProvider = "sealedClasses") + @ParameterizedTest + @MethodSource("sealedClassesData") public void testSealedClasses(Class cls) { assertTrue(cls.isSealed()); - assertTrue(!Modifier.isFinal(cls.getModifiers())); - assertTrue(cls.getPermittedSubclasses() != null); + assertFalse(Modifier.isFinal(cls.getModifiers())); + assertNotNull(cls.getPermittedSubclasses()); assertTrue(cls.getPermittedSubclasses().length > 0); } - @DataProvider(name = "notSealedClasses") - public Object[][] notSealedClassesData() { + public static List> notSealedClassesData() { return List.of( Object.class, void.class, Void.class, Void[].class, @@ -104,34 +102,34 @@ public class SealedClassesReflectionTest { double.class, double[].class, Double.class, Double[].class, boolean.class, boolean[].class, Boolean.class, Boolean[].class, String.class, String[].class - ).stream().map(c -> new Object[] {c}).toArray(Object[][]::new); + ); } - @Test(dataProvider = "notSealedClasses") + @ParameterizedTest + @MethodSource("notSealedClassesData") public void testNotSealedClasses(Class cls) { - assertTrue(!cls.isSealed()); - assertTrue(cls.getPermittedSubclasses() == null); + assertFalse(cls.isSealed()); + assertNull(cls.getPermittedSubclasses()); } - @DataProvider(name = "non_sealedClasses") - public Object[][] non_sealedClassesData() { + public static List> non_sealedClassesData() { return List.of( NonSealedSubclass1.class, NonSealedSubInt1.class, NonSealedSubclass2.class - ).stream().map(c -> new Object[] {c}).toArray(Object[][]::new); + ); } - @Test(dataProvider = "non_sealedClasses") + @ParameterizedTest + @MethodSource("non_sealedClassesData") public void testnon_sealedClasses(Class cls) { - assertTrue(!cls.isSealed()); - assertTrue(!Modifier.isFinal(cls.getModifiers())); + assertFalse(cls.isSealed()); + assertFalse(Modifier.isFinal(cls.getModifiers())); assertTrue((cls.getSuperclass() != null && cls.getSuperclass().isSealed()) || Arrays.stream(cls.getInterfaces()).anyMatch(Class::isSealed)); - assertTrue(cls.getPermittedSubclasses() == null); + assertNull(cls.getPermittedSubclasses()); } - @DataProvider(name = "reflectionData") - public Object[][] reflectionData() { + public static Object[][] reflectionData() { return new Object[][] { new Object[] { SealedClass1.class, @@ -204,7 +202,8 @@ public class SealedClassesReflectionTest { SEALED, NON_SEALED, FINAL } - @Test(dataProvider = "reflectionData") + @ParameterizedTest + @MethodSource("reflectionData") public void testSealedReflection(Class sealedClass, int numberOfSubclasses, String[] subclassDescriptors, @@ -213,10 +212,10 @@ public class SealedClassesReflectionTest { throws ReflectiveOperationException { assertTrue(sealedClass.isSealed()); - assertTrue(sealedClass.getPermittedSubclasses().length == numberOfSubclasses); + assertEquals(numberOfSubclasses, sealedClass.getPermittedSubclasses().length); int i = 0; for (Class cd : sealedClass.getPermittedSubclasses()) { - assertTrue(cd.getName().equals(subclassDescriptors[i]), "expected: " + subclassDescriptors[i] + " found: " + cd.getName()); + assertEquals(subclassDescriptors[i], cd.getName()); i++; } i = 0; From a5d0b05136e34871366441a8c8e6bda5f20c617c Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 27 Jan 2026 15:04:26 +0000 Subject: [PATCH 219/328] 8376274: JSpec preview support and output enhancement Reviewed-by: hannesw --- .../src/classes/build/tools/taglet/JSpec.java | 69 ++++++++++++++++--- .../lang/runtime/ExactConversionsSupport.java | 11 ++- 2 files changed, 62 insertions(+), 18 deletions(-) diff --git a/make/jdk/src/classes/build/tools/taglet/JSpec.java b/make/jdk/src/classes/build/tools/taglet/JSpec.java index 1c301e94a8a..7e1e0ca215e 100644 --- a/make/jdk/src/classes/build/tools/taglet/JSpec.java +++ b/make/jdk/src/classes/build/tools/taglet/JSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -49,13 +49,15 @@ import static com.sun.source.doctree.DocTree.Kind.*; * The tags can be used as follows: * *

    - * @jls section-number description
    + * @jls chapter.section description
    + * @jls preview-feature-chapter.section description
      * 
    * * For example: * *
      * @jls 3.4 Line Terminators
    + * @jls primitive-types-in-patterns-instanceof-switch-5.7.1 Exact Testing Conversions
      * 
    * * will produce the following HTML, depending on the file containing @@ -64,10 +66,24 @@ import static com.sun.source.doctree.DocTree.Kind.*; *
    {@code
      * 
    See Java Language Specification: *
    3.4 Line terminators + *
    + * 5.7.1 Exact Testing Conversions + * PREVIEW * }
    * - * Copies of JLS and JVMS are expected to have been placed in the {@code specs} - * folder. These documents are not included in open-source repositories. + * In inline tags (note you need manual JLS/JVMS prefix): + *
    + * JLS {@jls 3.4}
    + * 
    + * + * produces (note the section sign and no trailing dot): + *
    + * JLS §3.4
    + * 
    + * + * Copies of JLS, JVMS, and preview JLS and JVMS changes are expected to have + * been placed in the {@code specs} folder. These documents are not included + * in open-source repositories. */ public class JSpec implements Taglet { @@ -87,9 +103,9 @@ public class JSpec implements Taglet { } } - private String tagName; - private String specTitle; - private String idPrefix; + private final String tagName; + private final String specTitle; + private final String idPrefix; JSpec(String tagName, String specTitle, String idPrefix) { this.tagName = tagName; @@ -98,7 +114,7 @@ public class JSpec implements Taglet { } // Note: Matches special cases like @jvms 6.5.checkcast - private static final Pattern TAG_PATTERN = Pattern.compile("(?s)(.+ )?(?[1-9][0-9]*)(?
    [0-9a-z_.]*)( .*)?$"); + private static final Pattern TAG_PATTERN = Pattern.compile("(?s)(.+ )?(?([a-z0-9]+-)+)?(?[1-9][0-9]*)(?
    [0-9a-z_.]*)( .*)?$"); /** * Returns the set of locations in which the tag may be used. @@ -157,19 +173,50 @@ public class JSpec implements Taglet { .trim(); Matcher m = TAG_PATTERN.matcher(tagText); if (m.find()) { + // preview-feature-4.6 is preview-feature-, 4, .6 + String preview = m.group("preview"); // null if no preview feature String chapter = m.group("chapter"); String section = m.group("section"); String rootParent = currentPath().replaceAll("[^/]+", ".."); - String url = String.format("%1$s/specs/%2$s/%2$s-%3$s.html#%2$s-%3$s%4$s", - rootParent, idPrefix, chapter, section); + String url = preview == null ? + String.format("%1$s/specs/%2$s/%2$s-%3$s.html#%2$s-%3$s%4$s", + rootParent, idPrefix, chapter, section) : + String.format("%1$s/specs/%5$s%2$s.html#%2$s-%3$s%4$s", + rootParent, idPrefix, chapter, section, preview); + + var literal = expand(contents).trim(); + var prefix = (preview == null ? "" : preview) + chapter + section; + if (literal.startsWith(prefix)) { + var hasFullTitle = literal.length() > prefix.length(); + if (hasFullTitle) { + // Drop the preview identifier + literal = chapter + section + literal.substring(prefix.length()); + } else { + // No section sign if the tag refers to a chapter, like {@jvms 4} + String sectionSign = section.isEmpty() ? "" : "§"; + // Change whole text to "§chapter.x" in inline tags. + literal = sectionSign + chapter + section; + } + } sb.append("") - .append(expand(contents)) + .append(literal) .append(""); + if (preview != null) { + // Add PREVIEW superscript that links to JLS/JVMS 1.5.1 + // "Restrictions on the Use of Preview Features" + // Similar to how APIs link to the Preview info box warning + var sectionLink = String.format("%1$s/specs/%2$s/%2$s-%3$s.html#%2$s-%3$s%4$s", + rootParent, idPrefix, "1", ".5.1"); + sb.append("PREVIEW"); + } + if (tag.getKind() == DocTree.Kind.UNKNOWN_BLOCK_TAG) { sb.append("
    "); } diff --git a/src/java.base/share/classes/java/lang/runtime/ExactConversionsSupport.java b/src/java.base/share/classes/java/lang/runtime/ExactConversionsSupport.java index a1a93859c42..8d4389f7295 100644 --- a/src/java.base/share/classes/java/lang/runtime/ExactConversionsSupport.java +++ b/src/java.base/share/classes/java/lang/runtime/ExactConversionsSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, 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 @@ -64,12 +64,9 @@ package java.lang.runtime; * floating-point type is considered exact. * * - * @see - * JLS 5.7.1 Exact Testing Conversions - * @see - * JLS 5.7.2 Unconditionally Exact Testing Conversions - * @see - * JLS 15.20.2 The instanceof Operator + * @jls primitive-types-in-patterns-instanceof-switch-5.7.1 Exact Testing Conversions + * @jls primitive-types-in-patterns-instanceof-switch-5.7.2 Unconditionally Exact Testing Conversions + * @jls primitive-types-in-patterns-instanceof-switch-15.20.2 The {@code instanceof} Operator * * @implNote Some exactness checks describe a test which can be redirected * safely through one of the existing methods. Those are omitted too (i.e., From e8048c87bc9c152932ee59cb674bdb6670db2a56 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Tue, 27 Jan 2026 16:07:45 +0000 Subject: [PATCH 220/328] 8376509: [process] Problemlist Test java/lang/ProcessBuilder/PipelineLeaksFD.java Reviewed-by: jpai --- test/jdk/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 291b2163b0d..5e8406b13a6 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -503,6 +503,7 @@ java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java 8151492 generic- java/lang/invoke/LFCaching/LFGarbageCollectedTest.java 8078602 generic-all java/lang/invoke/lambda/LambdaFileEncodingSerialization.java 8249079 linux-all java/lang/invoke/RicochetTest.java 8251969 generic-all +java/lang/ProcessBuilder/PipelineLeaksFD.java 8375585 generic-all ############################################################################ From eb6e74b1fa794bf16f572d5dbce157d1cae4c505 Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Tue, 27 Jan 2026 17:14:40 +0000 Subject: [PATCH 221/328] 8374176: Update --release 26 symbol information for JDK 26 build 32 Reviewed-by: liach, iris, darcy --- src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt index 29ecd9f0304..9166b505c51 100644 --- a/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2025, 2026, 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 @@ -429,6 +429,10 @@ innerclass innerClass java/io/ObjectOutputStream$PutField outerClass java/io/Obj innerclass innerClass java/util/AbstractMap$SimpleImmutableEntry outerClass java/util/AbstractMap innerClassName SimpleImmutableEntry flags 9 innerclass innerClass java/util/concurrent/ConcurrentHashMap$CollectionView outerClass java/util/concurrent/ConcurrentHashMap innerClassName CollectionView flags 408 +class name java/util/concurrent/CopyOnWriteArraySet +header extends java/util/AbstractSet implements java/io/Serializable flags 21 signature Ljava/util/AbstractSet;Ljava/io/Serializable; +innerclass innerClass java/io/ObjectInputStream$GetField outerClass java/io/ObjectInputStream innerClassName GetField flags 409 + class name java/util/concurrent/StructuredTaskScope -method name open descriptor (Ljava/util/concurrent/StructuredTaskScope$Joiner;Ljava/util/function/Function;)Ljava/util/concurrent/StructuredTaskScope; method name open descriptor (Ljava/util/concurrent/StructuredTaskScope$Joiner;Ljava/util/function/UnaryOperator;)Ljava/util/concurrent/StructuredTaskScope; flags 9 signature (Ljava/util/concurrent/StructuredTaskScope$Joiner<-TT;+TR;>;Ljava/util/function/UnaryOperator;)Ljava/util/concurrent/StructuredTaskScope; From fa1b1d677ac492dfdd3110b9303a4c2b009046c8 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Tue, 27 Jan 2026 20:39:35 +0000 Subject: [PATCH 222/328] 8375477: CoreUtils support for SA tests should attempt to locate and unzip core files when they have been zipped Reviewed-by: lmesnik, kevinw --- test/lib/jdk/test/lib/util/CoreUtils.java | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/test/lib/jdk/test/lib/util/CoreUtils.java b/test/lib/jdk/test/lib/util/CoreUtils.java index f7a486def2b..72c1d89af44 100644 --- a/test/lib/jdk/test/lib/util/CoreUtils.java +++ b/test/lib/jdk/test/lib/util/CoreUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -203,6 +203,7 @@ public class CoreUtils { private static final String CORE_PATTERN_FILE_NAME = "/proc/sys/kernel/core_pattern"; private static final String LOCATION_STRING = "location: "; + private static final String ALT_LOCATION_STRING = "alternatively, falling back to"; private static String parseCoreFileLocationFromOutput(String crashOutputString) { System.out.println("crashOutputString = [" + crashOutputString + "]"); @@ -220,12 +221,25 @@ public class CoreUtils { // Find the core file name in the output. String coreWithPid; - if (stringWithLocation.contains("or ") && !Platform.isWindows()) { - Matcher m = Pattern.compile("or.* ([^ ]+[^\\)])\\)?").matcher(stringWithLocation); + if (Platform.isLinux() && stringWithLocation.contains(ALT_LOCATION_STRING)) { + /* + * If hotspot detects that /proc/sys/kernel/core_pattern starts with a "|", + * it generates a messages something like the following: + * # Core dump will be written. Default location: Determined by the following: + * "/var/bin/core.sh %p" (alternatively, falling back to + * /ws/jdk/build/linux-x64/test-support/jtreg_open_test_hotspot_jtreg_serviceability_sa_ClhsdbFindPC_java/scratch/2/core.10353) + * We try to detect this and glean this alternative path from the message. The + * hope here is that either this is where the core file actually ends up, or that + * the script referenced by the core_pattern is just zipping the core file, in + * which case a call to unzipCores() will have already unzipped the core file + * into this path. + */ + Matcher m = Pattern.compile(ALT_LOCATION_STRING + ".* ([^ ]+[^\\)])\\)?").matcher(stringWithLocation); if (!m.find()) { throw new RuntimeException("Couldn't find path to core inside location string"); } coreWithPid = m.group(1); + System.out.println("getCoreFileLocation found alt coreWithPid = " + coreWithPid); } else { coreWithPid = stringWithLocation.trim(); } From 1161a640abe454b47de95ed73452a78535160deb Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 28 Jan 2026 06:58:50 +0000 Subject: [PATCH 223/328] 8373239: Test java/awt/print/PrinterJob/PageRanges.java fails with incorrect selection of printed pages Reviewed-by: prr, aivanov --- .../windows/classes/sun/awt/windows/WPrinterJob.java | 6 +++++- test/jdk/java/awt/print/PrinterJob/PageRanges.java | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java b/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java index 01be8587685..1da9db3a35b 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -1733,6 +1733,10 @@ public final class WPrinterJob extends RasterPrinterJob if (isRangeSet) { attributes.add(new PageRanges(from, to)); setPageRange(from, to); + } else { + attributes.remove(PageRanges.class); + setPageRange(Pageable.UNKNOWN_NUMBER_OF_PAGES, + Pageable.UNKNOWN_NUMBER_OF_PAGES); } defaultCopies = false; attributes.add(new Copies(copies)); diff --git a/test/jdk/java/awt/print/PrinterJob/PageRanges.java b/test/jdk/java/awt/print/PrinterJob/PageRanges.java index aea60516f78..691357d5a3c 100644 --- a/test/jdk/java/awt/print/PrinterJob/PageRanges.java +++ b/test/jdk/java/awt/print/PrinterJob/PageRanges.java @@ -23,7 +23,7 @@ /* * @test - * @bug 6575331 8297191 + * @bug 6575331 8297191 8373239 * @key printer * @summary The specified pages should be printed. * @library /java/awt/regtesthelpers From 88c8a55a4337a857ac17ffff068f730f67cf5763 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 28 Jan 2026 07:44:31 +0000 Subject: [PATCH 224/328] 8373266: Strengthen constant CardTable base accesses Reviewed-by: tschatzl, xpeng --- .../cpu/aarch64/macroAssembler_aarch64.cpp | 7 +++--- .../cardTableBarrierSetAssembler_arm.cpp | 15 +++++------- .../cardTableBarrierSetAssembler_ppc.cpp | 9 ++++---- .../shenandoahBarrierSetAssembler_ppc.cpp | 3 --- .../cpu/riscv/macroAssembler_riscv.cpp | 5 ++-- .../cardTableBarrierSetAssembler_s390.cpp | 10 ++++---- .../cardTableBarrierSetAssembler_x86.cpp | 15 ++++-------- .../os_cpu/linux_arm/javaThread_linux_arm.cpp | 3 ++- src/hotspot/share/ci/ciUtilities.cpp | 9 +++----- src/hotspot/share/ci/ciUtilities.hpp | 4 ++-- src/hotspot/share/compiler/disassembler.cpp | 23 ++++++++++++++++--- .../gc/shared/c1/cardTableBarrierSetC1.cpp | 7 ++---- .../gc/shared/c2/cardTableBarrierSetC2.cpp | 2 +- .../share/gc/shared/cardTableBarrierSet.hpp | 9 ++++++++ .../share/jvmci/jvmciCompilerToVMInit.cpp | 19 ++++++++++----- 15 files changed, 75 insertions(+), 65 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 27428a5c558..e813a70372b 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -5606,12 +5606,11 @@ void MacroAssembler::adrp(Register reg1, const Address &dest, uint64_t &byte_off } void MacroAssembler::load_byte_map_base(Register reg) { - CardTable::CardValue* byte_map_base = - ((CardTableBarrierSet*)(BarrierSet::barrier_set()))->card_table()->byte_map_base(); + CardTableBarrierSet* ctbs = CardTableBarrierSet::barrier_set(); - // Strictly speaking the byte_map_base isn't an address at all, and it might + // Strictly speaking the card table base isn't an address at all, and it might // even be negative. It is thus materialised as a constant. - mov(reg, (uint64_t)byte_map_base); + mov(reg, (uint64_t)ctbs->card_table_base_const()); } void MacroAssembler::build_frame(int framesize) { diff --git a/src/hotspot/cpu/arm/gc/shared/cardTableBarrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/shared/cardTableBarrierSetAssembler_arm.cpp index 2427d46cafa..5d63035ac69 100644 --- a/src/hotspot/cpu/arm/gc/shared/cardTableBarrierSetAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/gc/shared/cardTableBarrierSetAssembler_arm.cpp @@ -67,9 +67,7 @@ void CardTableBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet d void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp) { BLOCK_COMMENT("CardTablePostBarrier"); - BarrierSet* bs = BarrierSet::barrier_set(); - CardTableBarrierSet* ctbs = barrier_set_cast(bs); - CardTable* ct = ctbs->card_table(); + CardTableBarrierSet* ctbs = CardTableBarrierSet::barrier_set(); Label L_cardtable_loop, L_done; @@ -83,7 +81,7 @@ void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembl __ sub(count, count, addr); // nb of cards // warning: Rthread has not been preserved - __ mov_address(tmp, (address) ct->byte_map_base()); + __ mov_address(tmp, (address)ctbs->card_table_base_const()); __ add(addr,tmp, addr); Register zero = __ zero_register(tmp); @@ -122,8 +120,7 @@ void CardTableBarrierSetAssembler::store_check_part1(MacroAssembler* masm, Regis assert(bs->kind() == BarrierSet::CardTableBarrierSet, "Wrong barrier set kind"); - CardTableBarrierSet* ctbs = barrier_set_cast(bs); - CardTable* ct = ctbs->card_table(); + CardTableBarrierSet* ctbs = CardTableBarrierSet::barrier_set(); // Load card table base address. @@ -140,7 +137,7 @@ void CardTableBarrierSetAssembler::store_check_part1(MacroAssembler* masm, Regis Possible cause is a cache miss (card table base address resides in a rarely accessed area of thread descriptor). */ - __ mov_address(card_table_base, (address)ct->byte_map_base()); + __ mov_address(card_table_base, (address)ctbs->card_table_base_const()); } // The 2nd part of the store check. @@ -170,8 +167,8 @@ void CardTableBarrierSetAssembler::store_check_part2(MacroAssembler* masm, Regis void CardTableBarrierSetAssembler::set_card(MacroAssembler* masm, Register card_table_base, Address card_table_addr, Register tmp) { CardTableBarrierSet* ctbs = barrier_set_cast(BarrierSet::barrier_set()); - CardTable* ct = ctbs->card_table(); - if ((((uintptr_t)ct->byte_map_base() & 0xff) == 0)) { + + if ((((uintptr_t)ctbs->card_table_base_const() & 0xff) == 0)) { // Card table is aligned so the lowest byte of the table address base is zero. // This works only if the code is not saved for later use, possibly // in a context where the base would no longer be aligned. diff --git a/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.cpp index 7404f7e2e5c..297ce57a394 100644 --- a/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.cpp @@ -103,8 +103,7 @@ void CardTableBarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Registe void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register preserve) { - CardTableBarrierSet* ctbs = barrier_set_cast(BarrierSet::barrier_set()); - CardTable* ct = ctbs->card_table(); + CardTableBarrierSet* ctbs = CardTableBarrierSet::barrier_set(); assert_different_registers(addr, count, R0); Label Lskip_loop, Lstore_loop; @@ -117,7 +116,7 @@ void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembl __ srdi(addr, addr, CardTable::card_shift()); __ srdi(count, count, CardTable::card_shift()); __ subf(count, addr, count); - __ add_const_optimized(addr, addr, (address)ct->byte_map_base(), R0); + __ add_const_optimized(addr, addr, (address)ctbs->card_table_base_const(), R0); __ addi(count, count, 1); __ li(R0, 0); __ mtctr(count); @@ -140,8 +139,8 @@ void CardTableBarrierSetAssembler::card_table_write(MacroAssembler* masm, } void CardTableBarrierSetAssembler::card_write_barrier_post(MacroAssembler* masm, Register store_addr, Register tmp) { - CardTableBarrierSet* bs = barrier_set_cast(BarrierSet::barrier_set()); - card_table_write(masm, bs->card_table()->byte_map_base(), tmp, store_addr); + CardTableBarrierSet* bs = CardTableBarrierSet::barrier_set(); + card_table_write(masm, bs->card_table_base_const(), tmp, store_addr); } void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp index 1f1bc7622ed..9d143c14d27 100644 --- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp @@ -771,9 +771,6 @@ void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler *masm, Register b void ShenandoahBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register preserve) { assert(ShenandoahCardBarrier, "Should have been checked by caller"); - - ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set(); - CardTable* ct = bs->card_table(); assert_different_registers(addr, count, R0); Label L_skip_loop, L_store_loop; diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 43b17a13c20..fb30f64e9ed 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -5110,9 +5110,8 @@ void MacroAssembler::get_thread(Register thread) { } void MacroAssembler::load_byte_map_base(Register reg) { - CardTable::CardValue* byte_map_base = - ((CardTableBarrierSet*)(BarrierSet::barrier_set()))->card_table()->byte_map_base(); - mv(reg, (uint64_t)byte_map_base); + CardTableBarrierSet* ctbs = CardTableBarrierSet::barrier_set(); + mv(reg, (uint64_t)ctbs->card_table_base_const()); } void MacroAssembler::build_frame(int framesize) { diff --git a/src/hotspot/cpu/s390/gc/shared/cardTableBarrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/shared/cardTableBarrierSetAssembler_s390.cpp index a0da6ebe682..9bb7f63ff31 100644 --- a/src/hotspot/cpu/s390/gc/shared/cardTableBarrierSetAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/gc/shared/cardTableBarrierSetAssembler_s390.cpp @@ -83,8 +83,7 @@ void CardTableBarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Registe void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, bool do_return) { - CardTableBarrierSet* ctbs = barrier_set_cast(BarrierSet::barrier_set()); - CardTable* ct = ctbs->card_table(); + CardTableBarrierSet* ctbs = CardTableBarrierSet::barrier_set(); NearLabel doXC, done; assert_different_registers(Z_R0, Z_R1, addr, count); @@ -105,7 +104,7 @@ void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembl __ add2reg_with_index(count, -BytesPerHeapOop, count, addr); // Get base address of card table. - __ load_const_optimized(Z_R1, (address)ct->byte_map_base()); + __ load_const_optimized(Z_R1, (address)ctbs->card_table_base_const()); // count = (count>>shift) - (addr>>shift) __ z_srlg(addr, addr, CardTable::card_shift()); @@ -179,13 +178,12 @@ void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembl void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register store_addr, Register tmp) { // Does a store check for the oop in register obj. The content of // register obj is destroyed afterwards. - CardTableBarrierSet* ctbs = barrier_set_cast(BarrierSet::barrier_set()); - CardTable* ct = ctbs->card_table(); + CardTableBarrierSet* ctbs = CardTableBarrierSet::barrier_set(); assert_different_registers(store_addr, tmp); __ z_srlg(store_addr, store_addr, CardTable::card_shift()); - __ load_absolute_address(tmp, (address)ct->byte_map_base()); + __ load_absolute_address(tmp, (address)ctbs->card_table_base_const()); __ z_agr(store_addr, tmp); __ z_mvi(0, store_addr, CardTable::dirty_card_val()); } diff --git a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp index 2b91662ddb5..65e6b4e01fc 100644 --- a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp @@ -95,11 +95,7 @@ void CardTableBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet d void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp) { - BarrierSet *bs = BarrierSet::barrier_set(); - CardTableBarrierSet* ctbs = barrier_set_cast(bs); - CardTable* ct = ctbs->card_table(); - intptr_t disp = (intptr_t) ct->byte_map_base(); - SHENANDOAHGC_ONLY(assert(!UseShenandoahGC, "Shenandoah byte_map_base is not constant.");) + CardTableBarrierSet* ctbs = CardTableBarrierSet::barrier_set(); Label L_loop, L_done; const Register end = count; @@ -115,7 +111,7 @@ void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembl __ shrptr(end, CardTable::card_shift()); __ subptr(end, addr); // end --> cards count - __ mov64(tmp, disp); + __ mov64(tmp, (intptr_t)ctbs->card_table_base_const()); __ addptr(addr, tmp); __ BIND(L_loop); __ movb(Address(addr, count, Address::times_1), 0); @@ -128,10 +124,7 @@ __ BIND(L_done); void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Address dst) { // Does a store check for the oop in register obj. The content of // register obj is destroyed afterwards. - BarrierSet* bs = BarrierSet::barrier_set(); - - CardTableBarrierSet* ctbs = barrier_set_cast(bs); - CardTable* ct = ctbs->card_table(); + CardTableBarrierSet* ctbs = CardTableBarrierSet::barrier_set(); __ shrptr(obj, CardTable::card_shift()); @@ -142,7 +135,7 @@ void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register ob // So this essentially converts an address to a displacement and it will // never need to be relocated. On 64bit however the value may be too // large for a 32bit displacement. - intptr_t byte_map_base = (intptr_t)ct->byte_map_base(); + intptr_t byte_map_base = (intptr_t)ctbs->card_table_base_const(); if (__ is_simm32(byte_map_base)) { card_addr = Address(noreg, obj, Address::times_1, byte_map_base); } else { diff --git a/src/hotspot/os_cpu/linux_arm/javaThread_linux_arm.cpp b/src/hotspot/os_cpu/linux_arm/javaThread_linux_arm.cpp index 3dc0035ed87..d82b9d90417 100644 --- a/src/hotspot/os_cpu/linux_arm/javaThread_linux_arm.cpp +++ b/src/hotspot/os_cpu/linux_arm/javaThread_linux_arm.cpp @@ -43,7 +43,8 @@ void JavaThread::cache_global_variables() { BarrierSet* bs = BarrierSet::barrier_set(); if (bs->is_a(BarrierSet::CardTableBarrierSet)) { - _card_table_base = (address) (barrier_set_cast(bs)->card_table()->byte_map_base()); + CardTableBarrierSet* ctbs = CardTableBarrierSet::barrier_set(); + _card_table_base = (address)ctbs->card_table_base_const(); } else { _card_table_base = nullptr; } diff --git a/src/hotspot/share/ci/ciUtilities.cpp b/src/hotspot/share/ci/ciUtilities.cpp index 0c5b4d9824f..011fa049275 100644 --- a/src/hotspot/share/ci/ciUtilities.cpp +++ b/src/hotspot/share/ci/ciUtilities.cpp @@ -42,10 +42,7 @@ const char* basictype_to_str(BasicType t) { // ------------------------------------------------------------------ // card_table_base -CardTable::CardValue* ci_card_table_address() { - BarrierSet* bs = BarrierSet::barrier_set(); - CardTableBarrierSet* ctbs = barrier_set_cast(bs); - CardTable* ct = ctbs->card_table(); - assert(!UseShenandoahGC, "Shenandoah byte_map_base is not constant."); - return ct->byte_map_base(); +CardTable::CardValue* ci_card_table_address_const() { + CardTableBarrierSet* ctbs = CardTableBarrierSet::barrier_set(); + return ctbs->card_table_base_const(); } diff --git a/src/hotspot/share/ci/ciUtilities.hpp b/src/hotspot/share/ci/ciUtilities.hpp index 75dbb03adf4..3333972d57d 100644 --- a/src/hotspot/share/ci/ciUtilities.hpp +++ b/src/hotspot/share/ci/ciUtilities.hpp @@ -51,9 +51,9 @@ inline const char* bool_to_str(bool b) { const char* basictype_to_str(BasicType t); -CardTable::CardValue* ci_card_table_address(); +CardTable::CardValue* ci_card_table_address_const(); template T ci_card_table_address_as() { - return reinterpret_cast(ci_card_table_address()); + return reinterpret_cast(ci_card_table_address_const()); } #endif // SHARE_CI_CIUTILITIES_HPP diff --git a/src/hotspot/share/compiler/disassembler.cpp b/src/hotspot/share/compiler/disassembler.cpp index c79c15e0f32..2c1ef235e07 100644 --- a/src/hotspot/share/compiler/disassembler.cpp +++ b/src/hotspot/share/compiler/disassembler.cpp @@ -607,10 +607,27 @@ void decode_env::print_address(address adr) { return; } + address card_table_base = nullptr; BarrierSet* bs = BarrierSet::barrier_set(); - if (bs->is_a(BarrierSet::CardTableBarrierSet) && - adr == ci_card_table_address_as
    ()) { - st->print("word_map_base"); +#if INCLUDE_G1GC + if (bs->is_a(BarrierSet::G1BarrierSet)) { + G1BarrierSet* g1bs = barrier_set_cast(bs); + card_table_base = g1bs->card_table()->byte_map_base(); + } else +#endif +#if INCLUDE_SHENANDOAHGC + if (bs->is_a(BarrierSet::ShenandoahBarrierSet)) { + ShenandoahBarrierSet* sbs = barrier_set_cast(bs); + if (sbs->card_table() != nullptr) { + card_table_base = sbs->card_table()->byte_map_base(); + } + } else +#endif + if (bs->is_a(BarrierSet::CardTableBarrierSet)) { + card_table_base = ci_card_table_address_as
    (); + } + if (card_table_base != nullptr && adr == card_table_base) { + st->print("card_table_base"); if (WizardMode) st->print(" " INTPTR_FORMAT, p2i(adr)); return; } diff --git a/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp b/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp index ebc1c1c7fb7..914358760aa 100644 --- a/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp +++ b/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp @@ -104,11 +104,8 @@ void CardTableBarrierSetC1::post_barrier(LIRAccess& access, LIR_Opr addr, LIR_Op return; } - BarrierSet* bs = BarrierSet::barrier_set(); - CardTableBarrierSet* ctbs = barrier_set_cast(bs); - CardTable* ct = ctbs->card_table(); - LIR_Const* card_table_base = new LIR_Const(ct->byte_map_base()); - SHENANDOAHGC_ONLY(assert(!UseShenandoahGC, "Shenandoah byte_map_base is not constant.");) + CardTableBarrierSet* ctbs = barrier_set_cast(BarrierSet::barrier_set()); + LIR_Const* card_table_base = new LIR_Const(ctbs->card_table_base_const()); if (addr->is_address()) { LIR_Address* address = addr->as_address_ptr(); diff --git a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp index fada2672e9f..42af77ebdf4 100644 --- a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp @@ -116,7 +116,7 @@ Node* CardTableBarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& access Node* CardTableBarrierSetC2::byte_map_base_node(GraphKit* kit) const { // Get base of card map - CardTable::CardValue* card_table_base = ci_card_table_address(); + CardTable::CardValue* card_table_base = ci_card_table_address_const(); if (card_table_base != nullptr) { return kit->makecon(TypeRawPtr::make((address)card_table_base)); } else { diff --git a/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp b/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp index faeb007c77d..c298bfcd0c2 100644 --- a/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp +++ b/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp @@ -27,6 +27,7 @@ #include "gc/shared/barrierSet.hpp" #include "gc/shared/cardTable.hpp" +#include "gc/shared/gc_globals.hpp" #include "memory/memRegion.hpp" #include "utilities/align.hpp" @@ -60,6 +61,10 @@ public: CardTableBarrierSet(CardTable* card_table); virtual ~CardTableBarrierSet(); + inline static CardTableBarrierSet* barrier_set() { + return barrier_set_cast(BarrierSet::barrier_set()); + } + template inline void write_ref_field_pre(T* addr) {} @@ -86,6 +91,10 @@ public: inline void write_ref_array(HeapWord* start, size_t count); CardTable* card_table() const { return _card_table; } + CardValue* card_table_base_const() const { + assert(UseSerialGC || UseParallelGC, "Only these GCs have constant card table base"); + return _card_table->byte_map_base(); + } virtual void on_slowpath_allocation_exit(JavaThread* thread, oop new_obj); diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index 801a9bf8eb4..3e9d8c97b88 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -236,16 +236,23 @@ void CompilerToVM::Data::initialize(JVMCI_TRAPS) { JVMTI_ONLY( _should_notify_object_alloc = &JvmtiExport::_should_notify_object_alloc; ) BarrierSet* bs = BarrierSet::barrier_set(); +#if INCLUDE_G1GC + if (bs->is_a(BarrierSet::G1BarrierSet)) { + cardtable_start_address = nullptr; + cardtable_shift = CardTable::card_shift(); + } else +#endif +#if INCLUDE_SHENANDOAHGC + if (bs->is_a(BarrierSet::ShenandoahBarrierSet)) { + cardtable_start_address = nullptr; + cardtable_shift = CardTable::card_shift(); + } else +#endif if (bs->is_a(BarrierSet::CardTableBarrierSet)) { - CardTable::CardValue* base = ci_card_table_address(); + CardTable::CardValue* base = ci_card_table_address_const(); assert(base != nullptr, "unexpected byte_map_base"); cardtable_start_address = base; cardtable_shift = CardTable::card_shift(); -#if INCLUDE_SHENANDOAHGC - } else if (bs->is_a(BarrierSet::ShenandoahBarrierSet)) { - cardtable_start_address = nullptr; - cardtable_shift = CardTable::card_shift(); -#endif } else { // No card mark barriers cardtable_start_address = nullptr; From b2cd3b0d48bdabacfd421dee9b9f87a003e0e09d Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Wed, 28 Jan 2026 08:00:11 +0000 Subject: [PATCH 225/328] 8350330: C2: PhaseIdealLoop::add_parse_predicate() should mirror GraphKit::add_parse_predicate() Reviewed-by: chagedorn, qamai --- src/hotspot/share/opto/loopnode.cpp | 44 +++++------ src/hotspot/share/opto/loopnode.hpp | 3 + .../TestLoopNestTooManyTraps.java | 79 +++++++++++++++++++ 3 files changed, 103 insertions(+), 23 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/longcountedloops/TestLoopNestTooManyTraps.java diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 8dc34af9c19..fab354e3e3d 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -590,7 +590,7 @@ Node* PhaseIdealLoop::loop_nest_replace_iv(Node* iv_to_replace, Node* inner_iv, // Add a Parse Predicate with an uncommon trap on the failing/false path. Normal control will continue on the true path. void PhaseIdealLoop::add_parse_predicate(Deoptimization::DeoptReason reason, Node* inner_head, IdealLoopTree* loop, SafePointNode* sfpt) { - if (!C->too_many_traps(reason)) { + if (!C->too_many_traps(sfpt->jvms()->method(), sfpt->jvms()->bci(), reason)) { ParsePredicateNode* parse_predicate = new ParsePredicateNode(inner_head->in(LoopNode::EntryControl), reason, &_igvn); register_control(parse_predicate, loop, inner_head->in(LoopNode::EntryControl)); Node* if_false = new IfFalseNode(parse_predicate); @@ -760,6 +760,24 @@ SafePointNode* PhaseIdealLoop::find_safepoint(Node* back_control, Node* x, Ideal return safepoint; } +void PhaseIdealLoop::add_parse_predicates(IdealLoopTree* outer_ilt, LoopNode* inner_head, SafePointNode* cloned_sfpt) { + if (ShortRunningLongLoop) { + add_parse_predicate(Deoptimization::Reason_short_running_long_loop, inner_head, outer_ilt, cloned_sfpt); + } + if (UseLoopPredicate) { + add_parse_predicate(Deoptimization::Reason_predicate, inner_head, outer_ilt, cloned_sfpt); + if (UseProfiledLoopPredicate) { + add_parse_predicate(Deoptimization::Reason_profile_predicate, inner_head, outer_ilt, cloned_sfpt); + } + } + + if (UseAutoVectorizationPredicate) { + add_parse_predicate(Deoptimization::Reason_auto_vectorization_check, inner_head, outer_ilt, cloned_sfpt); + } + + add_parse_predicate(Deoptimization::Reason_loop_limit_check, inner_head, outer_ilt, cloned_sfpt); +} + // If the loop has the shape of a counted loop but with a long // induction variable, transform the loop in a loop nest: an inner // loop that iterates for at most max int iterations with an integer @@ -1123,26 +1141,7 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { if (safepoint != nullptr) { SafePointNode* cloned_sfpt = old_new[safepoint->_idx]->as_SafePoint(); - if (ShortRunningLongLoop) { - add_parse_predicate(Deoptimization::Reason_short_running_long_loop, inner_head, outer_ilt, cloned_sfpt); - } - if (UseLoopPredicate) { - add_parse_predicate(Deoptimization::Reason_predicate, inner_head, outer_ilt, cloned_sfpt); - if (UseProfiledLoopPredicate) { - add_parse_predicate(Deoptimization::Reason_profile_predicate, inner_head, outer_ilt, cloned_sfpt); - } - } - - if (UseAutoVectorizationPredicate) { - // We only want to use the auto-vectorization check as a trap once per bci. And - // PhaseIdealLoop::add_parse_predicate only checks trap limits per method, so - // we do a custom check here. - if (!C->too_many_traps(cloned_sfpt->jvms()->method(), cloned_sfpt->jvms()->bci(), Deoptimization::Reason_auto_vectorization_check)) { - add_parse_predicate(Deoptimization::Reason_auto_vectorization_check, inner_head, outer_ilt, cloned_sfpt); - } - } - - add_parse_predicate(Deoptimization::Reason_loop_limit_check, inner_head, outer_ilt, cloned_sfpt); + add_parse_predicates(outer_ilt, inner_head, cloned_sfpt); } #ifndef PRODUCT @@ -1893,7 +1892,7 @@ bool PhaseIdealLoop::convert_to_long_loop(Node* cmp, Node* phi, IdealLoopTree* l #endif //------------------------------is_counted_loop-------------------------------- -bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_bt) { +bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*& loop, BasicType iv_bt) { PhaseGVN *gvn = &_igvn; Node* back_control = loop_exit_control(x, loop); @@ -3528,7 +3527,6 @@ void OuterStripMinedLoopNode::transform_to_counted_loop(PhaseIterGVN* igvn, Phas CountedLoopEndNode* cle = inner_cl->loopexit(); Node* inner_test = cle->in(1); IfNode* outer_le = outer_loop_end(); - CountedLoopEndNode* inner_cle = inner_cl->loopexit(); Node* safepoint = outer_safepoint(); fix_sunk_stores_when_back_to_counted_loop(igvn, iloop); diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index ffc283ac941..24976d76a51 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1368,6 +1368,9 @@ public: #endif void add_parse_predicate(Deoptimization::DeoptReason reason, Node* inner_head, IdealLoopTree* loop, SafePointNode* sfpt); SafePointNode* find_safepoint(Node* back_control, Node* x, IdealLoopTree* loop); + + void add_parse_predicates(IdealLoopTree* outer_ilt, LoopNode* inner_head, SafePointNode* cloned_sfpt); + IdealLoopTree* insert_outer_loop(IdealLoopTree* loop, LoopNode* outer_l, Node* outer_ift); IdealLoopTree* create_outer_strip_mined_loop(Node* init_control, IdealLoopTree* loop, float cl_prob, float le_fcnt, diff --git a/test/hotspot/jtreg/compiler/longcountedloops/TestLoopNestTooManyTraps.java b/test/hotspot/jtreg/compiler/longcountedloops/TestLoopNestTooManyTraps.java new file mode 100644 index 00000000000..502afc56548 --- /dev/null +++ b/test/hotspot/jtreg/compiler/longcountedloops/TestLoopNestTooManyTraps.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2026 IBM Corporation. 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 8350330 + * @summary C2: PhaseIdealLoop::add_parse_predicate() should mirror GraphKit::add_parse_predicate() + * @library /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:-BackgroundCompilation -XX:-ShortRunningLongLoop -XX:-UseOnStackReplacement + * -XX:CompileOnly=*TestLoopNestTooManyTraps::test1 -XX:LoopMaxUnroll=0 + * compiler.longcountedloops.TestLoopNestTooManyTraps + */ + +package compiler.longcountedloops; + +import java.lang.reflect.Method; +import java.util.Objects; +import jdk.test.whitebox.WhiteBox; + +public class TestLoopNestTooManyTraps { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + public static void main(String[] args) throws NoSuchMethodException { + Method methodTest1 = TestLoopNestTooManyTraps.class.getDeclaredMethod("test1", int.class, long.class); + + for (int j = 0; j < 10; j++) { + System.out.println("iteration " + j); + for (int i = 0; i < 20_000; i++) { + test1(1000, 1000); + } + if (!WHITE_BOX.isMethodCompiled(methodTest1)) { + throw new RuntimeException("test1 should be compiled"); + } + System.out.println("iteration 2 " + j); + try { + test1(10000, 1000); + } catch (IndexOutOfBoundsException ioobe) { + } + if (j <= 1) { + if (WHITE_BOX.isMethodCompiled(methodTest1)) { + throw new RuntimeException("test1 should have deoptimized at iteration " + j); + } + } else { + if (!WHITE_BOX.isMethodCompiled(methodTest1)) { + throw new RuntimeException("test1 shouldn't have deoptimized"); + } + } + } + } + + private static void test1(int stop, long length) { + for (int i = 0; i < stop; i++) { + Objects.checkIndex(i, length); + } + } +} From 4ae4ffd5a3114aa2a3832818ee30dc38d9aa2b72 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Wed, 28 Jan 2026 08:08:36 +0000 Subject: [PATCH 226/328] 8374513: AArch64: Improve receiver type profiling reliability Reviewed-by: shade, aph --- .../cpu/aarch64/c1_LIRAssembler_aarch64.cpp | 92 ++--------- .../cpu/aarch64/c1_LIRAssembler_aarch64.hpp | 5 +- .../cpu/aarch64/interp_masm_aarch64.cpp | 137 +--------------- .../cpu/aarch64/interp_masm_aarch64.hpp | 12 +- .../cpu/aarch64/macroAssembler_aarch64.cpp | 155 ++++++++++++++++++ .../cpu/aarch64/macroAssembler_aarch64.hpp | 2 + .../cpu/aarch64/templateTable_aarch64.cpp | 4 +- 7 files changed, 179 insertions(+), 228 deletions(-) diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index 37a6a130e0d..c0621cbd5c2 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -1218,43 +1218,11 @@ void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) { __ bind(*op->stub()->continuation()); } -void LIR_Assembler::type_profile_helper(Register mdo, - ciMethodData *md, ciProfileData *data, - Register recv, Label* update_done) { +void LIR_Assembler::type_profile_helper(Register mdo, ciMethodData *md, + ciProfileData *data, Register recv) { - // Given a profile data offset, generate an Address which points to - // the corresponding slot in mdo->data(). - // Clobbers rscratch2. - auto slot_at = [=](ByteSize offset) -> Address { - return __ form_address(rscratch2, mdo, - md->byte_offset_of_slot(data, offset), - LogBytesPerWord); - }; - - for (uint i = 0; i < ReceiverTypeData::row_limit(); i++) { - Label next_test; - // See if the receiver is receiver[n]. - __ ldr(rscratch1, slot_at(ReceiverTypeData::receiver_offset(i))); - __ cmp(recv, rscratch1); - __ br(Assembler::NE, next_test); - __ addptr(slot_at(ReceiverTypeData::receiver_count_offset(i)), - DataLayout::counter_increment); - __ b(*update_done); - __ bind(next_test); - } - - // Didn't find receiver; find next empty slot and fill it in - for (uint i = 0; i < ReceiverTypeData::row_limit(); i++) { - Label next_test; - Address recv_addr(slot_at(ReceiverTypeData::receiver_offset(i))); - __ ldr(rscratch1, recv_addr); - __ cbnz(rscratch1, next_test); - __ str(recv, recv_addr); - __ mov(rscratch1, DataLayout::counter_increment); - __ str(rscratch1, slot_at(ReceiverTypeData::receiver_count_offset(i))); - __ b(*update_done); - __ bind(next_test); - } + int mdp_offset = md->byte_offset_of_slot(data, in_ByteSize(0)); + __ profile_receiver_type(recv, mdo, mdp_offset); } void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null) { @@ -1316,14 +1284,9 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L __ b(*obj_is_null); __ bind(not_null); - Label update_done; Register recv = k_RInfo; __ load_klass(recv, obj); - type_profile_helper(mdo, md, data, recv, &update_done); - Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); - __ addptr(counter_addr, DataLayout::counter_increment); - - __ bind(update_done); + type_profile_helper(mdo, md, data, recv); } else { __ cbz(obj, *obj_is_null); } @@ -1430,13 +1393,9 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { __ b(done); __ bind(not_null); - Label update_done; Register recv = k_RInfo; __ load_klass(recv, value); - type_profile_helper(mdo, md, data, recv, &update_done); - Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); - __ addptr(counter_addr, DataLayout::counter_increment); - __ bind(update_done); + type_profile_helper(mdo, md, data, recv); } else { __ cbz(value, done); } @@ -2540,13 +2499,9 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { if (C1OptimizeVirtualCallProfiling && known_klass != nullptr) { // We know the type that will be seen at this call site; we can // statically update the MethodData* rather than needing to do - // dynamic tests on the receiver type - - // NOTE: we should probably put a lock around this search to - // avoid collisions by concurrent compilations + // dynamic tests on the receiver type. ciVirtualCallData* vc_data = (ciVirtualCallData*) data; - uint i; - for (i = 0; i < VirtualCallData::row_limit(); i++) { + for (uint i = 0; i < VirtualCallData::row_limit(); i++) { ciKlass* receiver = vc_data->receiver(i); if (known_klass->equals(receiver)) { Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i))); @@ -2554,36 +2509,13 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { return; } } - - // Receiver type not found in profile data; select an empty slot - - // Note that this is less efficient than it should be because it - // always does a write to the receiver part of the - // VirtualCallData rather than just the first time - for (i = 0; i < VirtualCallData::row_limit(); i++) { - ciKlass* receiver = vc_data->receiver(i); - if (receiver == nullptr) { - __ mov_metadata(rscratch1, known_klass->constant_encoding()); - Address recv_addr = - __ form_address(rscratch2, mdo, - md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)), - LogBytesPerWord); - __ str(rscratch1, recv_addr); - Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i))); - __ addptr(data_addr, DataLayout::counter_increment); - return; - } - } + // Receiver type is not found in profile data. + // Fall back to runtime helper to handle the rest at runtime. + __ mov_metadata(recv, known_klass->constant_encoding()); } else { __ load_klass(recv, recv); - Label update_done; - type_profile_helper(mdo, md, data, recv, &update_done); - // Receiver did not match any saved receiver and there is no empty row for it. - // Increment total counter to indicate polymorphic case. - __ addptr(counter_addr, DataLayout::counter_increment); - - __ bind(update_done); } + type_profile_helper(mdo, md, data, recv); } else { // Static call __ addptr(counter_addr, DataLayout::counter_increment); diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp index 21916a5f7dd..5af06fc6a1c 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp @@ -50,9 +50,8 @@ friend class ArrayCopyStub; Address stack_slot_address(int index, uint shift, Register tmp, int adjust = 0); // Record the type of the receiver in ReceiverTypeData - void type_profile_helper(Register mdo, - ciMethodData *md, ciProfileData *data, - Register recv, Label* update_done); + void type_profile_helper(Register mdo, ciMethodData *md, + ciProfileData *data, Register recv); void add_debug_info_for_branch(address adr, CodeEmitInfo* info); void casw(Register addr, Register newval, Register cmpval); diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp index 957c2aee1c1..2b506b241e0 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp @@ -240,15 +240,14 @@ void InterpreterMacroAssembler::load_resolved_klass_at_offset( // Rsub_klass: subklass // // Kills: -// r2, r5 +// r2 void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, Label& ok_is_subtype) { assert(Rsub_klass != r0, "r0 holds superklass"); assert(Rsub_klass != r2, "r2 holds 2ndary super array length"); - assert(Rsub_klass != r5, "r5 holds 2ndary super array scan ptr"); // Profile the not-null value's klass. - profile_typecheck(r2, Rsub_klass, r5); // blows r2, reloads r5 + profile_typecheck(r2, Rsub_klass); // blows r2 // Do the check. check_klass_subtype(Rsub_klass, r0, r2, ok_is_subtype); // blows r2 @@ -991,7 +990,6 @@ void InterpreterMacroAssembler::profile_final_call(Register mdp) { void InterpreterMacroAssembler::profile_virtual_call(Register receiver, Register mdp, - Register reg2, bool receiver_can_be_null) { if (ProfileInterpreter) { Label profile_continue; @@ -1009,7 +1007,7 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver, } // Record the receiver type. - record_klass_in_profile(receiver, mdp, reg2); + profile_receiver_type(receiver, mdp, 0); bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. @@ -1018,131 +1016,6 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver, } } -// This routine creates a state machine for updating the multi-row -// type profile at a virtual call site (or other type-sensitive bytecode). -// The machine visits each row (of receiver/count) until the receiver type -// is found, or until it runs out of rows. At the same time, it remembers -// the location of the first empty row. (An empty row records null for its -// receiver, and can be allocated for a newly-observed receiver type.) -// Because there are two degrees of freedom in the state, a simple linear -// search will not work; it must be a decision tree. Hence this helper -// function is recursive, to generate the required tree structured code. -// It's the interpreter, so we are trading off code space for speed. -// See below for example code. -void InterpreterMacroAssembler::record_klass_in_profile_helper( - Register receiver, Register mdp, - Register reg2, int start_row, - Label& done) { - if (TypeProfileWidth == 0) { - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - } else { - record_item_in_profile_helper(receiver, mdp, reg2, 0, done, TypeProfileWidth, - &VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset); - } -} - -void InterpreterMacroAssembler::record_item_in_profile_helper(Register item, Register mdp, - Register reg2, int start_row, Label& done, int total_rows, - OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn) { - int last_row = total_rows - 1; - assert(start_row <= last_row, "must be work left to do"); - // Test this row for both the item and for null. - // Take any of three different outcomes: - // 1. found item => increment count and goto done - // 2. found null => keep looking for case 1, maybe allocate this cell - // 3. found something else => keep looking for cases 1 and 2 - // Case 3 is handled by a recursive call. - for (int row = start_row; row <= last_row; row++) { - Label next_test; - bool test_for_null_also = (row == start_row); - - // See if the item is item[n]. - int item_offset = in_bytes(item_offset_fn(row)); - test_mdp_data_at(mdp, item_offset, item, - (test_for_null_also ? reg2 : noreg), - next_test); - // (Reg2 now contains the item from the CallData.) - - // The item is item[n]. Increment count[n]. - int count_offset = in_bytes(item_count_offset_fn(row)); - increment_mdp_data_at(mdp, count_offset); - b(done); - bind(next_test); - - if (test_for_null_also) { - Label found_null; - // Failed the equality check on item[n]... Test for null. - if (start_row == last_row) { - // The only thing left to do is handle the null case. - cbz(reg2, found_null); - // Item did not match any saved item and there is no empty row for it. - // Increment total counter to indicate polymorphic case. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - b(done); - bind(found_null); - break; - } - // Since null is rare, make it be the branch-taken case. - cbz(reg2, found_null); - - // Put all the "Case 3" tests here. - record_item_in_profile_helper(item, mdp, reg2, start_row + 1, done, total_rows, - item_offset_fn, item_count_offset_fn); - - // Found a null. Keep searching for a matching item, - // but remember that this is an empty (unused) slot. - bind(found_null); - } - } - - // In the fall-through case, we found no matching item, but we - // observed the item[start_row] is null. - - // Fill in the item field and increment the count. - int item_offset = in_bytes(item_offset_fn(start_row)); - set_mdp_data_at(mdp, item_offset, item); - int count_offset = in_bytes(item_count_offset_fn(start_row)); - mov(reg2, DataLayout::counter_increment); - set_mdp_data_at(mdp, count_offset, reg2); - if (start_row > 0) { - b(done); - } -} - -// Example state machine code for three profile rows: -// // main copy of decision tree, rooted at row[1] -// if (row[0].rec == rec) { row[0].incr(); goto done; } -// if (row[0].rec != nullptr) { -// // inner copy of decision tree, rooted at row[1] -// if (row[1].rec == rec) { row[1].incr(); goto done; } -// if (row[1].rec != nullptr) { -// // degenerate decision tree, rooted at row[2] -// if (row[2].rec == rec) { row[2].incr(); goto done; } -// if (row[2].rec != nullptr) { count.incr(); goto done; } // overflow -// row[2].init(rec); goto done; -// } else { -// // remember row[1] is empty -// if (row[2].rec == rec) { row[2].incr(); goto done; } -// row[1].init(rec); goto done; -// } -// } else { -// // remember row[0] is empty -// if (row[1].rec == rec) { row[1].incr(); goto done; } -// if (row[2].rec == rec) { row[2].incr(); goto done; } -// row[0].init(rec); goto done; -// } -// done: - -void InterpreterMacroAssembler::record_klass_in_profile(Register receiver, - Register mdp, Register reg2) { - assert(ProfileInterpreter, "must be profiling"); - Label done; - - record_klass_in_profile_helper(receiver, mdp, reg2, 0, done); - - bind (done); -} - void InterpreterMacroAssembler::profile_ret(Register return_bci, Register mdp) { if (ProfileInterpreter) { @@ -1200,7 +1073,7 @@ void InterpreterMacroAssembler::profile_null_seen(Register mdp) { } } -void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass, Register reg2) { +void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass) { if (ProfileInterpreter) { Label profile_continue; @@ -1213,7 +1086,7 @@ void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass, mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); // Record the object type. - record_klass_in_profile(klass, mdp, reg2); + profile_receiver_type(klass, mdp, 0); } update_mdp_by_constant(mdp, mdp_delta); diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp index 2b230a3b73e..74d4430000d 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp @@ -273,15 +273,6 @@ class InterpreterMacroAssembler: public MacroAssembler { Register test_value_out, Label& not_equal_continue); - void record_klass_in_profile(Register receiver, Register mdp, - Register reg2); - void record_klass_in_profile_helper(Register receiver, Register mdp, - Register reg2, int start_row, - Label& done); - void record_item_in_profile_helper(Register item, Register mdp, - Register reg2, int start_row, Label& done, int total_rows, - OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn); - void update_mdp_by_offset(Register mdp_in, int offset_of_offset); void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp); void update_mdp_by_constant(Register mdp_in, int constant); @@ -295,11 +286,10 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_call(Register mdp); void profile_final_call(Register mdp); void profile_virtual_call(Register receiver, Register mdp, - Register scratch2, bool receiver_can_be_null = false); void profile_ret(Register return_bci, Register mdp); void profile_null_seen(Register mdp); - void profile_typecheck(Register mdp, Register klass, Register scratch); + void profile_typecheck(Register mdp, Register klass); void profile_typecheck_failed(Register mdp); void profile_switch_default(Register mdp); void profile_switch_case(Register index_in_scratch, Register mdp, diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index e813a70372b..f8b5a6f825c 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -2118,6 +2118,161 @@ Address MacroAssembler::argument_address(RegisterOrConstant arg_slot, } } +// Handle the receiver type profile update given the "recv" klass. +// +// Normally updates the ReceiverData (RD) that starts at "mdp" + "mdp_offset". +// If there are no matching or claimable receiver entries in RD, updates +// the polymorphic counter. +// +// This code expected to run by either the interpreter or JIT-ed code, without +// extra synchronization. For safety, receiver cells are claimed atomically, which +// avoids grossly misrepresenting the profiles under concurrent updates. For speed, +// counter updates are not atomic. +// +void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_offset) { + assert_different_registers(recv, mdp, rscratch1, rscratch2); + + int base_receiver_offset = in_bytes(ReceiverTypeData::receiver_offset(0)); + int end_receiver_offset = in_bytes(ReceiverTypeData::receiver_offset(ReceiverTypeData::row_limit())); + int poly_count_offset = in_bytes(CounterData::count_offset()); + int receiver_step = in_bytes(ReceiverTypeData::receiver_offset(1)) - base_receiver_offset; + int receiver_to_count_step = in_bytes(ReceiverTypeData::receiver_count_offset(0)) - base_receiver_offset; + + // Adjust for MDP offsets. + base_receiver_offset += mdp_offset; + end_receiver_offset += mdp_offset; + poly_count_offset += mdp_offset; + +#ifdef ASSERT + // We are about to walk the MDO slots without asking for offsets. + // Check that our math hits all the right spots. + for (uint c = 0; c < ReceiverTypeData::row_limit(); c++) { + int real_recv_offset = mdp_offset + in_bytes(ReceiverTypeData::receiver_offset(c)); + int real_count_offset = mdp_offset + in_bytes(ReceiverTypeData::receiver_count_offset(c)); + int offset = base_receiver_offset + receiver_step*c; + int count_offset = offset + receiver_to_count_step; + assert(offset == real_recv_offset, "receiver slot math"); + assert(count_offset == real_count_offset, "receiver count math"); + } + int real_poly_count_offset = mdp_offset + in_bytes(CounterData::count_offset()); + assert(poly_count_offset == real_poly_count_offset, "poly counter math"); +#endif + + // Corner case: no profile table. Increment poly counter and exit. + if (ReceiverTypeData::row_limit() == 0) { + increment(Address(mdp, poly_count_offset), DataLayout::counter_increment); + return; + } + + Register offset = rscratch2; + + Label L_loop_search_receiver, L_loop_search_empty; + Label L_restart, L_found_recv, L_found_empty, L_polymorphic, L_count_update; + + // The code here recognizes three major cases: + // A. Fastest: receiver found in the table + // B. Fast: no receiver in the table, and the table is full + // C. Slow: no receiver in the table, free slots in the table + // + // The case A performance is most important, as perfectly-behaved code would end up + // there, especially with larger TypeProfileWidth. The case B performance is + // important as well, this is where bulk of code would land for normally megamorphic + // cases. The case C performance is not essential, its job is to deal with installation + // races, we optimize for code density instead. Case C needs to make sure that receiver + // rows are only claimed once. This makes sure we never overwrite a row for another + // receiver and never duplicate the receivers in the list, making profile type-accurate. + // + // It is very tempting to handle these cases in a single loop, and claim the first slot + // without checking the rest of the table. But, profiling code should tolerate free slots + // in the table, as class unloading can clear them. After such cleanup, the receiver + // we need might be _after_ the free slot. Therefore, we need to let at least full scan + // to complete, before trying to install new slots. Splitting the code in several tight + // loops also helpfully optimizes for cases A and B. + // + // This code is effectively: + // + // restart: + // // Fastest: receiver is already installed + // for (i = 0; i < receiver_count(); i++) { + // if (receiver(i) == recv) goto found_recv(i); + // } + // + // // Fast: no receiver, but profile is full + // for (i = 0; i < receiver_count(); i++) { + // if (receiver(i) == null) goto found_null(i); + // } + // goto polymorphic + // + // // Slow: try to install receiver + // found_null(i): + // CAS(&receiver(i), null, recv); + // goto restart + // + // polymorphic: + // count++; + // return + // + // found_recv(i): + // *receiver_count(i)++ + // + + bind(L_restart); + + // Fastest: receiver is already installed + mov(offset, base_receiver_offset); + bind(L_loop_search_receiver); + ldr(rscratch1, Address(mdp, offset)); + cmp(rscratch1, recv); + br(Assembler::EQ, L_found_recv); + add(offset, offset, receiver_step); + sub(rscratch1, offset, end_receiver_offset); + cbnz(rscratch1, L_loop_search_receiver); + + // Fast: no receiver, but profile is full + mov(offset, base_receiver_offset); + bind(L_loop_search_empty); + ldr(rscratch1, Address(mdp, offset)); + cbz(rscratch1, L_found_empty); + add(offset, offset, receiver_step); + sub(rscratch1, offset, end_receiver_offset); + cbnz(rscratch1, L_loop_search_empty); + b(L_polymorphic); + + // Slow: try to install receiver + bind(L_found_empty); + + // Atomically swing receiver slot: null -> recv. + // + // The update uses CAS, which clobbers rscratch1. Therefore, rscratch2 + // is used to hold the destination address. This is safe because the + // offset is no longer needed after the address is computed. + + lea(rscratch2, Address(mdp, offset)); + cmpxchg(/*addr*/ rscratch2, /*expected*/ zr, /*new*/ recv, Assembler::xword, + /*acquire*/ false, /*release*/ false, /*weak*/ true, noreg); + + // CAS success means the slot now has the receiver we want. CAS failure means + // something had claimed the slot concurrently: it can be the same receiver we want, + // or something else. Since this is a slow path, we can optimize for code density, + // and just restart the search from the beginning. + b(L_restart); + + // Counter updates: + + // Increment polymorphic counter instead of receiver slot. + bind(L_polymorphic); + mov(offset, poly_count_offset); + b(L_count_update); + + // Found a receiver, convert its slot offset to corresponding count offset. + bind(L_found_recv); + add(offset, offset, receiver_to_count_step); + + bind(L_count_update); + increment(Address(mdp, offset), DataLayout::counter_increment); +} + + void MacroAssembler::call_VM_leaf_base(address entry_point, int number_of_arguments, Label *retaddr) { diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 4baa07d7d49..7eb6cea0614 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -1122,6 +1122,8 @@ public: Address argument_address(RegisterOrConstant arg_slot, int extra_slot_offset = 0); + void profile_receiver_type(Register recv, Register mdp, int mdp_offset); + void verify_sve_vector_length(Register tmp = rscratch1); void reinitialize_ptrue() { if (UseSVE > 0) { diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp index 07b469650f0..5d4f7103a84 100644 --- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp @@ -3370,7 +3370,7 @@ void TemplateTable::invokevirtual_helper(Register index, __ load_klass(r0, recv); // profile this call - __ profile_virtual_call(r0, rlocals, r3); + __ profile_virtual_call(r0, rlocals); // get target Method & entry point __ lookup_virtual_method(r0, index, method); @@ -3500,7 +3500,7 @@ void TemplateTable::invokeinterface(int byte_no) { /*return_method=*/false); // profile this call - __ profile_virtual_call(r3, r13, r19); + __ profile_virtual_call(r3, r13); // Get declaring interface class from method, and itable index From 6afc0d8f39390d474ce8ba16533c30b4c7770388 Mon Sep 17 00:00:00 2001 From: Saranya Natarajan Date: Wed, 28 Jan 2026 09:38:20 +0000 Subject: [PATCH 227/328] 8366861: Phase AFTER_LOOP_OPTS printed even though the method has no loops Reviewed-by: chagedorn, dfenacci --- src/hotspot/share/opto/compile.cpp | 5 +++-- src/hotspot/share/opto/compile.hpp | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 7d99f4a7336..eaec1605108 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -1876,7 +1876,7 @@ void Compile::process_for_post_loop_opts_igvn(PhaseIterGVN& igvn) { // at least to this point, even if no loop optimizations were done. PhaseIdealLoop::verify(igvn); - if (has_loops() || _loop_opts_cnt > 0) { + if (_print_phase_loop_opts) { print_method(PHASE_AFTER_LOOP_OPTS, 2); } C->set_post_loop_opts_phase(); // no more loop opts allowed @@ -2404,7 +2404,8 @@ void Compile::Optimize() { if (failing()) return; - if (has_loops()) { + _print_phase_loop_opts = has_loops(); + if (_print_phase_loop_opts) { print_method(PHASE_BEFORE_LOOP_OPTS, 2); } diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 12812424f5e..d9a8ea15724 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -355,6 +355,7 @@ class Compile : public Phase { bool _print_assembly; // True if we should dump assembly code for this compilation bool _print_inlining; // True if we should print inlining for this compilation bool _print_intrinsics; // True if we should print intrinsics for this compilation + bool _print_phase_loop_opts; // True if we should print before and after loop opts phase #ifndef PRODUCT uint _phase_counter; // Counter for the number of already printed phases uint _igv_idx; // Counter for IGV node identifiers From 127bfc9b0dd122c78e702867a88e0847ec362e68 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Wed, 28 Jan 2026 11:11:07 +0000 Subject: [PATCH 228/328] 8374926: EnableX86ECoreOpts was not enabled on some hybrid CPU Reviewed-by: vpaprotski, dholmes --- src/hotspot/cpu/x86/vm_version_x86.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 747daefd51d..0fff5b44e00 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -921,8 +921,9 @@ void VM_Version::get_processor_features() { // Check if processor has Intel Ecore if (FLAG_IS_DEFAULT(EnableX86ECoreOpts) && is_intel() && is_intel_server_family() && - (_model == 0x97 || _model == 0xAA || _model == 0xAC || _model == 0xAF || - _model == 0xCC || _model == 0xDD)) { + (supports_hybrid() || + _model == 0xAF /* Xeon 6 E-cores (Sierra Forest) */ || + _model == 0xDD /* Xeon 6+ E-cores (Clearwater Forest) */ )) { FLAG_SET_DEFAULT(EnableX86ECoreOpts, true); } From 2a465cb0eba6ffe397cf3ad8c1def06bf7a1e392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20H=C3=BCbner?= Date: Wed, 28 Jan 2026 13:14:51 +0000 Subject: [PATCH 229/328] 8371777: Clean up preferred address of G1's archive region Reviewed-by: stefank, jsikstro --- src/hotspot/share/cds/aotMappedHeapLoader.cpp | 2 +- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 2 +- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/cds/aotMappedHeapLoader.cpp b/src/hotspot/share/cds/aotMappedHeapLoader.cpp index 84051cbd9e5..a8678ed757f 100644 --- a/src/hotspot/share/cds/aotMappedHeapLoader.cpp +++ b/src/hotspot/share/cds/aotMappedHeapLoader.cpp @@ -619,7 +619,7 @@ bool AOTMappedHeapLoader::map_heap_region_impl(FileMapInfo* info) { aot_log_info(aot)("Preferred address to map heap data (to avoid relocation) is " INTPTR_FORMAT, p2i(requested_start)); // allocate from java heap - HeapWord* start = G1CollectedHeap::heap()->alloc_archive_region(word_size, (HeapWord*)requested_start); + HeapWord* start = G1CollectedHeap::heap()->alloc_archive_region(word_size); if (start == nullptr) { AOTMetaspace::report_loading_error("UseSharedSpaces: Unable to allocate java heap region for archive heap."); return false; diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index b6c3c0b0907..8f83a653885 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -525,7 +525,7 @@ void G1CollectedHeap::iterate_regions_in_range(MemRegion range, const Func& func } } -HeapWord* G1CollectedHeap::alloc_archive_region(size_t word_size, HeapWord* preferred_addr) { +HeapWord* G1CollectedHeap::alloc_archive_region(size_t word_size) { assert(!is_init_completed(), "Expect to be called at JVM init time"); MutexLocker x(Heap_lock); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 8009df1fa6a..1f900c76851 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -736,12 +736,10 @@ public: void iterate_regions_in_range(MemRegion range, const Func& func); // Commit the required number of G1 region(s) according to the size requested - // and mark them as 'old' region(s). Preferred address is treated as a hint for - // the location of the archive space in the heap. The returned address may or may - // not be same as the preferred address. + // and mark them as 'old' region(s). // This API is only used for allocating heap space for the archived heap objects // in the CDS archive. - HeapWord* alloc_archive_region(size_t word_size, HeapWord* preferred_addr); + HeapWord* alloc_archive_region(size_t word_size); // Populate the G1BlockOffsetTable for archived regions with the given // memory range. From 8c86b1bb1054b565cf23156d89ee8925a4e32597 Mon Sep 17 00:00:00 2001 From: Roger Calnan Date: Wed, 28 Jan 2026 14:18:52 +0000 Subject: [PATCH 230/328] 8375325: add anchors to the options in the security man pages Reviewed-by: weijun, hchao --- src/java.base/share/man/keytool.md | 58 ++++++++++----------- src/java.security.jgss/windows/man/kinit.md | 20 +++---- src/java.security.jgss/windows/man/klist.md | 6 +-- src/java.security.jgss/windows/man/ktab.md | 10 ++-- src/jdk.jartool/share/man/jarsigner.md | 54 +++++++++---------- 5 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/java.base/share/man/keytool.md b/src/java.base/share/man/keytool.md index 19ba8c34912..1d70bd2f5f8 100644 --- a/src/java.base/share/man/keytool.md +++ b/src/java.base/share/man/keytool.md @@ -1,5 +1,5 @@ --- -# Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1998, 2026, 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 @@ -211,7 +211,7 @@ perform. ## Commands for Creating or Adding Data to the Keystore -`-gencert` +[`-gencert`]{#command-gencert} : The following are the available options for the `-gencert` command: - {`-rfc`}: Output in RFC (Request For Comment) style @@ -328,7 +328,7 @@ perform. > `keytool -alias e1 -certreq | keytool -alias ca2 -gencert > e1.cert` -`-genkeypair` +[`-genkeypair`]{#option-genkeypair} : The following are the available options for the `-genkeypair` command: - {`-alias` *alias*}: Alias name of the entry to process @@ -478,7 +478,7 @@ perform. specified by `-startdate`, or the current date when `-startdate` isn't specified) for which the certificate should be considered valid. -`-genseckey` +[`-genseckey`]{#command-genseckey} : The following are the available options for the `-genseckey` command: - {`-alias` *alias*}: Alias name of the entry to process @@ -521,7 +521,7 @@ perform. the same password that is used for the `-keystore`. The `-keypass` value must contain at least six characters. -`-importcert` +[`-importcert`]{#command-importcert} : The following are the available options for the `-importcert` command: - {`-noprompt`}: Do not prompt @@ -586,7 +586,7 @@ perform. entry, then the `keytool` command assumes that you're importing a certificate reply. -`-importpass` +[`-importpass`]{#command-importpass} : The following are the available options for the `-importpass` command: - {`-alias` *alias*}: Alias name of the entry to process @@ -629,7 +629,7 @@ perform. ## Commands for Importing Contents from Another Keystore -`-importkeystore` +[`-importkeystore`]{#command-importkeystore} : The following are the available options for the `-importkeystore` command: - `-srckeystore` *keystore*: Source keystore name @@ -724,7 +724,7 @@ perform. ## Commands for Generating a Certificate Request -`-certreq` +[`-certreq`]{#command-certreq} : The following are the available options for the `-certreq` command: - {`-alias` *alias*}: Alias name of the entry to process @@ -786,7 +786,7 @@ perform. ## Commands for Exporting Data -`-exportcert` +[`-exportcert`]{#command-exportcert} : The following are the available options for the `-exportcert` command: - {`-rfc`}: Output in RFC style @@ -834,7 +834,7 @@ perform. ## Commands for Displaying Data -`-list` +[`-list`]{#command-list} : The following are the available options for the `-list` command: - {`-rfc`}: Output in RFC style @@ -881,7 +881,7 @@ perform. You can't specify both `-v` and `-rfc` in the same command. Otherwise, an error is reported. -`-printcert` +[`-printcert`]{#command-printcert} : The following are the available options for the `-printcert` command: - {`-rfc`}: Output in RFC style @@ -946,7 +946,7 @@ perform. trusted certificate in the user keystore (specified by `-keystore`) or in the `cacerts` keystore (if `-trustcacerts` is specified). -`-printcertreq` +[`-printcertreq`]{#command-printcertreq} : The following are the available options for the `-printcertreq` command: - {`-file` *file*}: Input file name @@ -958,7 +958,7 @@ perform. command. The command reads the request from file. If there is no file, then the request is read from the standard input. -`-printcrl` +[`-printcrl`]{#command-printcrl} : The following are the available options for the `-printcrl` command: - {`-file crl`}: Input file name @@ -999,7 +999,7 @@ perform. ## Commands for Managing the Keystore -`-storepasswd` +[`-storepasswd`]{#command-storepasswd} : The following are the available options for the `-storepasswd` command: - \[`-new` *arg*\]: New password @@ -1029,7 +1029,7 @@ perform. integrity of the keystore contents. The new password is set by `-new` *arg* and must contain at least six characters. -`-keypasswd` +[`-keypasswd`]{#command-keypasswd} : The following are the available options for the `-keypasswd` command: - {`-alias` *alias*}: Alias name of the entry to process @@ -1069,7 +1069,7 @@ perform. If the `-new` option isn't provided at the command line, then the user is prompted for it. -`-delete` +[`-delete`]{#command-delete} : The following are the available options for the `-delete` command: - \[`-alias` *alias*\]: Alias name of the entry to process @@ -1101,7 +1101,7 @@ perform. keystore. When not provided at the command line, the user is prompted for the `alias`. -`-changealias` +[`-changealias`]{#command-changealias} : The following are the available options for the `-changealias` command: - {`-alias` *alias*}: Alias name of the entry to process @@ -1143,7 +1143,7 @@ perform. ## Commands for Displaying Security-related Information -`-showinfo` +[`-showinfo`]{#command-showinfo} : The following are the available options for the `-showinfo` command: - {`-tls`}: Displays TLS configuration information @@ -1185,10 +1185,10 @@ environment or memory usage. For a list of possible interpreter options, enter These options can appear for all commands operating on a keystore: -`-storetype` *storetype* +[`-storetype`]{#option-storetype} *storetype* : This qualifier specifies the type of keystore to be instantiated. -`-keystore` *keystore* +[`-keystore`]{#option-keystore} *keystore* : The keystore location. If the JKS `storetype` is used and a keystore file doesn't yet exist, then @@ -1206,13 +1206,13 @@ These options can appear for all commands operating on a keystore: if the keystore isn't file-based. For example, when the keystore resides on a hardware token device. -`-cacerts` *cacerts* +[`-cacerts`]{#option-cacerts} *cacerts* : Operates on the *cacerts* keystore . This option is equivalent to `-keystore` *path\_to\_cacerts* `-storetype` *type\_of\_cacerts*. An error is reported if the `-keystore` or `-storetype` option is used with the `-cacerts` option. -`-storepass` \[`:env` \| `:file` \] *argument* +[`-storepass`]{#option-storepass} \[`:env` \| `:file` \] *argument* : The password that is used to protect the integrity of the keystore. If the modifier `env` or `file` isn't specified, then the password has the @@ -1237,22 +1237,22 @@ These options can appear for all commands operating on a keystore: a password is not specified, then the integrity of the retrieved information can't be verified and a warning is displayed. -`-providername` *name* +[`-providername`]{#option-providername} *name* : Used to identify a cryptographic service provider's name when listed in the security properties file. -`-addprovider` *name* +[`-addprovider`]{#option-addprovider} *name* : Used to add a security provider by name (such as SunPKCS11) . -`-providerclass` *class* +[`-providerclass`]{#option-providerclass} *class* : Used to specify the name of a cryptographic service provider's master class file when the service provider isn't listed in the security properties file. -`-providerpath` *list* +[`-providerpath`]{#option-providerpath} *list* : Used to specify the provider classpath. -`-providerarg` *arg* +[`-providerarg`]{#option-providerarg} *arg* : Used with the `-addprovider` or `-providerclass` option to represent an optional string input argument for the constructor of *class* name. @@ -1263,7 +1263,7 @@ These options can appear for all commands operating on a keystore: following two options, `-srcprotected` and `-destprotected`, are provided for the source keystore and the destination keystore respectively. -`-ext` {*name*{`:critical`} {`=`*value*}} +[`-ext`]{#option-ext} {*name*{`:critical`} {`=`*value*}} : Denotes an X.509 certificate extension. The option can be used in `-genkeypair` and `-gencert` to embed extensions into the generated certificate, or in `-certreq` to show what extensions are requested in the @@ -1276,7 +1276,7 @@ These options can appear for all commands operating on a keystore: `isCritical` attribute is `true`; otherwise, it is `false`. You can use `:c` in place of `:critical`. -`-conf` *file* +[`-conf`]{#option-conf} *file* : Specifies a pre-configured options file. ## Pre-configured options file diff --git a/src/java.security.jgss/windows/man/kinit.md b/src/java.security.jgss/windows/man/kinit.md index 130bf7b007a..a32d6634e74 100644 --- a/src/java.security.jgss/windows/man/kinit.md +++ b/src/java.security.jgss/windows/man/kinit.md @@ -1,5 +1,5 @@ --- -# Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2026, 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 @@ -79,34 +79,34 @@ will compromise your password. You can specify one of the following commands. After the command, specify the options for it. -`-A` +[`-A`]{#option-A} : Doesn't include addresses. -`-f` +[`-f`]{#option-f} : Issues a forwardable ticket. -`-p` +[`-p`]{#option-p} : Issues a proxiable ticket. -`-c` *cache\_name* +[`-c`]{#option-c} *cache\_name* : The cache name (for example, `FILE:D:\temp\mykrb5cc`). -`-l` *lifetime* +[`-l`]{#option-l} *lifetime* : Sets the lifetime of a ticket. The value can be one of "h:m[:s]", "NdNhNmNs", and "N". See the [MIT krb5 Time Duration definition]( http://web.mit.edu/kerberos/krb5-1.17/doc/basic/date_format.html#duration) for more information. -`-r` *renewable\_time* +[`-r`]{#option-r} *renewable\_time* : Sets the total lifetime that a ticket can be renewed. -`-R` +[`-R`]{#option-R} : Renews a ticket. -`-k` +[`-k`]{#option-k} : Uses keytab -`-t` *keytab\_filename* +[`-t`]{#option-t} *keytab\_filename* : The keytab name (for example, `D:\winnt\profiles\duke\krb5.keytab`). *principal* diff --git a/src/java.security.jgss/windows/man/klist.md b/src/java.security.jgss/windows/man/klist.md index 67c84e65dec..c4874f7dc67 100644 --- a/src/java.security.jgss/windows/man/klist.md +++ b/src/java.security.jgss/windows/man/klist.md @@ -1,5 +1,5 @@ --- -# Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2026, 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 @@ -45,7 +45,7 @@ the contents of the credentials cache or keytab using the `klist` tool. The ## Commands -`-c` +[`-c`]{#option-c} : Specifies that the credential cache is to be listed. The following are the options for credential cache entries: @@ -62,7 +62,7 @@ the contents of the credentials cache or keytab using the `klist` tool. The `-n` : If the `-a` option is specified, don't reverse resolve addresses. -`-k` +[`-k`]{#option-k} : Specifies that key tab is to be listed. List the keytab entries. The following are the options for keytab entries: diff --git a/src/java.security.jgss/windows/man/ktab.md b/src/java.security.jgss/windows/man/ktab.md index d6817ab81cf..36e09d56e3e 100644 --- a/src/java.security.jgss/windows/man/ktab.md +++ b/src/java.security.jgss/windows/man/ktab.md @@ -1,5 +1,5 @@ --- -# Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2026, 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 @@ -72,12 +72,12 @@ send a keytab file over a network in the clear. ## Commands and Options -`-l` \[`-e`\] \[`-t`\] +[`-l`]{#command-l} \[`-e`\] \[`-t`\] : Lists the keytab name and entries. When `-e` is specified, the encryption type for each entry is displayed. When `-t` is specified, the timestamp for each entry is displayed. -`-a` *principal\_name* \[*password*\] \[`-n` *kvno*\] \[`-s` *salt* \| `-f`\] \[`-append`\] +[`-a`]{#command-a} *principal\_name* \[*password*\] \[`-n` *kvno*\] \[`-s` *salt* \| `-f`\] \[`-append`\] : Adds new key entries to the keytab for the given principal name with an optional *password*. If a *kvno* is specified, new keys' Key Version Numbers equal to the value, otherwise, automatically incrementing the Key @@ -90,7 +90,7 @@ send a keytab file over a network in the clear. on the command line or in a script.** This tool will prompt for a password if it isn't specified. -`-d` *principal\_name* \[`-f`\] \[`-e` *etype*\] \[*kvno* \| `all`\| `old`\] +[`-d`]{#command-d} *principal\_name* \[`-f`\] \[`-e` *etype*\] \[*kvno* \| `all`\| `old`\] : Deletes key entries from the keytab for the specified principal. No changes are made to the Kerberos database. @@ -115,7 +115,7 @@ send a keytab file over a network in the clear. This option can be used with the `-l`, `-a` or `-d` commands. -`-k` *keytab name* +[`-k`]{#option-k} *keytab name* : Specifies the keytab name and path with the `FILE:` prefix. ## Examples diff --git a/src/jdk.jartool/share/man/jarsigner.md b/src/jdk.jartool/share/man/jarsigner.md index 0ecc159a037..d128b9c11ff 100644 --- a/src/jdk.jartool/share/man/jarsigner.md +++ b/src/jdk.jartool/share/man/jarsigner.md @@ -483,7 +483,7 @@ the following standards: `-keystore` option is relevant for signing and verifying a JAR file. In addition, aliases are specified when signing and verifying a JAR file. -`-keystore` *url* +[`-keystore`]{#option-keystore} *url* : Specifies the URL that tells the keystore location. This defaults to the file `.keystore` in the user's home directory, as determined by the `user.home` system property. @@ -517,7 +517,7 @@ the following standards: > `keytool -keystore NONE -storetype PKCS11 -list` -`-storepass` \[`:env` \| `:file`\] *argument* +[`-storepass`]{#option-storepass} \[`:env` \| `:file`\] *argument* : Specifies the password that is required to access the keystore. This is only needed when signing (not verifying) a JAR file. In that case, if a `-storepass` option isn't provided at the command line, then the user is @@ -536,7 +536,7 @@ the following standards: The password shouldn't be specified on the command line or in a script unless it is for testing purposes, or you are on a secure system. -`-storetype` *storetype* +[`-storetype`]{#option-storetype} *storetype* : Specifies the type of keystore to be instantiated. The default keystore type is the one that is specified as the value of the `keystore.type` property in the security properties file, which is returned by the static @@ -548,7 +548,7 @@ the following standards: (such as a dedicated PIN-pad or a biometric reader), then the `-protected` option must be specified and no password options can be specified. -`-keypass` \[`:env` \| `:file`\] *argument* `-certchain` *file* +[`-keypass`]{#option-keypass} \[`:env` \| `:file`\] *argument* `-certchain` *file* : Specifies the password used to protect the private key of the keystore entry addressed by the alias specified on the command line. The password is required when using `jarsigner` to sign a JAR file. If no password is @@ -568,7 +568,7 @@ the following standards: The password shouldn't be specified on the command line or in a script unless it is for testing purposes, or you are on a secure system. -`-certchain` *file* +[`-certchain`]{#option-certchain} *file* : Specifies the certificate chain to be used when the certificate chain associated with the private key of the keystore entry that is addressed by the alias specified on the command line isn't complete. This can happen @@ -579,7 +579,7 @@ the following standards: (also known as Base64 encoding) as defined by [Internet RFC 1421 Certificate Encoding Standard](http://tools.ietf.org/html/rfc1421). -`-sigfile` *file* +[`-sigfile`]{#option-sigfile} *file* : Specifies the base file name to be used for the generated `.SF` and signature block files. For example, if file is `DUKESIGN`, then the generated `.SF` and signature block files are named `DUKESIGN.SF` and `DUKESIGN.RSA`, and placed in the @@ -598,10 +598,10 @@ the following standards: file name, then each such character is converted to an underscore (\_) character to form the file name. -`-signedjar` *file* +[`-signedjar`]{#option-signedjar} *file* : Specifies the name of signed JAR file. -`-digestalg` *algorithm* +[`-digestalg`]{#option-digestalg} *algorithm* : Specifies the name of the message digest algorithm to use when digesting the entries of a JAR file. @@ -613,7 +613,7 @@ the following standards: specified algorithm or the user must specify one with the `-addprovider` or `-providerClass` options; otherwise, the command will not succeed. -`-sigalg` *algorithm* +[`-sigalg`]{#option-sigalg} *algorithm* : Specifies the name of the signature algorithm to use to sign the JAR file. This algorithm must be compatible with the private key used to sign the @@ -627,10 +627,10 @@ the following standards: For a list of standard signature algorithm names, see the Java Security Standard Algorithm Names Specification. -`-verify` +[`-verify`]{#option-verify} : Verifies a signed JAR file. -`-verbose`\[`:`*suboptions*\] +[`-verbose`]{#option-verbose}\[`:`*suboptions*\] : When the `-verbose` option appears on the command line, it indicates that the `jarsigner` use the verbose mode when signing or verifying with the suboptions determining how much information is shown. This causes the , @@ -654,7 +654,7 @@ the following standards: more)*. See [Example of Verifying a Signed JAR File] and [Example of Verification with Certificate Information]. -`-certs` +[`-certs`]{#option-certs} : If the `-certs` option appears on the command line with the `-verify` and `-verbose` options, then the output includes certificate information for each signer of the JAR file. This information includes the name of the type @@ -669,14 +669,14 @@ the following standards: the alias name for the keystore entry for that signer is displayed in parentheses. -`-revCheck` +[`-revCheck`]{#option-revCheck} : This option enables revocation checking of certificates when signing or verifying a JAR file. The `jarsigner` command attempts to make network connections to fetch OCSP responses and CRLs if the `-revCheck` option is specified on the command line. Note that revocation checks are not enabled unless this option is specified. -`-tsa` *url* +[`-tsa`]{#option-tsa} *url* : If `-tsa http://example.tsa.url` appears on the command line when signing a JAR file then a time stamp is generated for the signature. The URL, `http://example.tsa.url`, identifies the location of the Time Stamping @@ -689,7 +689,7 @@ the following standards: stamp token returned by the TSA is stored with the signature in the signature block file. -`-tsacert` *alias* +[`-tsacert`]{#option-tsacert} *alias* : When `-tsacert` *alias* appears on the command line when signing a JAR file, a time stamp is generated for the signature. The alias identifies the TSA public key certificate in the keystore that is in effect. The entry's @@ -699,7 +699,7 @@ the following standards: The TSA public key certificate must be present in the keystore when using the `-tsacert` option. -`-tsapolicyid` *policyid* +[`-tsapolicyid`]{#option-tsapolicyid} *policyid* : Specifies the object identifier (OID) that identifies the policy ID to be sent to the TSA server. If this option isn't specified, no policy ID is sent and the TSA server will choose a default policy ID. @@ -708,7 +708,7 @@ the following standards: Standardization Sector (ITU-T) standard. These identifiers are typically period-separated sets of non-negative digits like `1.2.3.4`, for example. -`-tsadigestalg` *algorithm* +[`-tsadigestalg`]{#option-tsadigestalg} *algorithm* : Specifies the message digest algorithm that is used to generate the message imprint to be sent to the TSA server. If this option isn't specified, SHA-384 will be used. @@ -718,7 +718,7 @@ the following standards: For a list of standard message digest algorithm names, see the Java Security Standard Algorithm Names Specification. -`-internalsf` +[`-internalsf`]{#option-internalsf} : In the past, the signature block file generated when a JAR file was signed included a complete encoded copy of the `.SF` file (signature file) also generated. This behavior has been changed. To reduce the overall @@ -728,7 +728,7 @@ the following standards: In practice, don't use the `-internalsf` option because it incurs higher overhead. -`-sectionsonly` +[`-sectionsonly`]{#option-sectionsonly} : If the `-sectionsonly` option appears on the command line, then the `.SF` file (signature file) generated when a JAR file is signed doesn't include a header that contains a hash of the whole manifest file. It contains only @@ -747,12 +747,12 @@ the following standards: The `-sectionsonly` option is primarily used for testing. It shouldn't be used other than for testing because using it incurs higher overhead. -`-protected` +[`-protected`]{#option-protected} : Values can be either `true` or `false`. Specify `true` when a password must be specified through a protected authentication path such as a dedicated PIN reader. -`-providerName` *providerName* +[`-providerName`]{#option-providerName} *providerName* : If more than one provider was configured in the `java.security` security properties file, then you can use the `-providerName` option to target a specific provider instance. The argument to this option is the name of the @@ -768,7 +768,7 @@ the following standards: > `jarsigner -keystore NONE -storetype PKCS11 -providerName SunPKCS11-SmartCard -list` -`-addprovider` *name* \[`-providerArg` *arg*\] +[`-addprovider`]{#option-addprovider} *name* \[`-providerArg` *arg*\] : Adds a security provider by name (such as SunPKCS11) and an optional configure argument. The value of the security provider is the name of a security provider that is defined in a module. @@ -782,7 +782,7 @@ the following standards: > `jarsigner -keystore NONE -storetype PKCS11 -addprovider SunPKCS11 -providerArg /mydir1/mydir2/token.config` -`-providerClass` *provider-class-name* \[`-providerArg` *arg*\] +[`-providerClass`]{#option-providerClass} *provider-class-name* \[`-providerArg` *arg*\] : Used to specify the name of cryptographic service provider's master class file when the service provider isn't listed in the `java.security` security properties file. Adds a security provider by fully-qualified class name and @@ -792,7 +792,7 @@ the following standards: The preferred way to load PKCS11 is by using modules. See `-addprovider`. -`-providerPath` *classpath* +[`-providerPath`]{#option-providerPath} *classpath* : Used to specify the classpath for providers specified by the `-providerClass` option. Multiple paths should be separated by the system-dependent path-separator character. @@ -804,13 +804,13 @@ the following standards: execution environment or memory usage. For a list of possible interpreter options, type `java -h` or `java -X` at the command line. -`-strict` +[`-strict`]{#option-strict} : During the signing or verifying process, the command may issue warning messages. If you specify this option, the exit code of the tool reflects the severe warning messages that this command found. See [Errors and Warnings]. -`-conf` *url* +[`-conf`]{#option-conf} *url* : Specifies a pre-configured options file. Read the [keytool documentation](keytool.html#pre-configured-options-file) for details. The property keys supported are "jarsigner.all" for all actions, @@ -818,7 +818,7 @@ the following standards: `jarsigner` arguments including the JAR file name and alias name(s) cannot be set in this file. -`-version` +[`-version`]{#option-version} : Prints the program version. ## Errors and Warnings From 8095e33ee88759cf2fbe61e2284d95f6b7fb9a3a Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Wed, 28 Jan 2026 15:02:21 +0000 Subject: [PATCH 231/328] 8375433: jar should validate automatic module names Reviewed-by: jvernee --- .../classes/sun/tools/jar/Validator.java | 35 +++++++++++- .../sun/tools/jar/resources/jar.properties | 4 ++ test/jdk/tools/jar/ValidatorTest.java | 53 ++++++++++++++++--- 3 files changed, 83 insertions(+), 9 deletions(-) diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java b/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java index be694eeb1bc..c6f6f012543 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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,6 +47,8 @@ import java.util.function.Function; import java.util.function.IntSupplier; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.jar.Attributes; +import java.util.jar.Manifest; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; @@ -100,6 +102,7 @@ final class Validator { this.zf = zf; this.zis = zis; checkModuleDescriptor(MODULE_INFO); + checkAutomaticModuleName(); } static boolean validate(Main main, File zipFile) throws IOException { @@ -453,6 +456,36 @@ final class Validator { }); } + /** + * Checks whether an Automatic-Module-Name entry is valid + * and also verifies it to the name given by a compiled + * module descriptor. + */ + private void checkAutomaticModuleName() { + var entry = zf.getEntry("META-INF/MANIFEST.MF"); + if (entry == null) { + return; + } + try (InputStream jis = zf.getInputStream(entry)) { + Attributes attributes = new Manifest(jis).getMainAttributes(); + String automaticModuleName = attributes.getValue("Automatic-Module-Name"); + if (automaticModuleName == null) { + return; + } + try { + ModuleDescriptor.newAutomaticModule(automaticModuleName); + } catch (IllegalArgumentException e) { + errorAndInvalid(formatMsg("error.validator.manifest.invalid.automatic.module.name", automaticModuleName)); + } + if (md == null || automaticModuleName.equals(md.name())) { + return; + } + errorAndInvalid(formatMsg("error.validator.manifest.inconsistent.automatic.module.name", automaticModuleName, md.name())); + } catch (IOException e) { + errorAndInvalid(e.getMessage()); + } + } + /* * Checks whether or not the given versioned module descriptor's attributes * are valid when compared against the root/base module descriptor. diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties b/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties index c80377e20c1..95c5f80197d 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties +++ b/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties @@ -138,6 +138,10 @@ error.validator.metainf.wrong.position=\ expected entry META-INF/ to be at position 0, but found: {0} error.validator.manifest.wrong.position=\ expected entry META-INF/MANIFEST.MF to be at position 0 or 1, but found it at position: {0} +error.validator.manifest.invalid.automatic.module.name=\ + invalid module name of Automatic-Module-Name entry in manifest: {0} +error.validator.manifest.inconsistent.automatic.module.name=\ + expected Automatic-Module-Name entry in manifest: {0} to match name of compiled module: {1} warn.validator.identical.entry=\ Warning: entry {0} contains a class that\n\ is identical to an entry already in the jar diff --git a/test/jdk/tools/jar/ValidatorTest.java b/test/jdk/tools/jar/ValidatorTest.java index c2dfeae8dec..e3f649a04a2 100644 --- a/test/jdk/tools/jar/ValidatorTest.java +++ b/test/jdk/tools/jar/ValidatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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,12 +23,8 @@ /* * @test - * @bug 8345431 + * @bug 8345431 8375433 * @summary test validator to report malformed jar file - * @library /test/lib - * @modules jdk.jartool - * @build jdk.test.lib.Platform - * jdk.test.lib.util.FileUtils * @run junit/othervm ValidatorTest */ @@ -40,6 +36,7 @@ import org.junit.jupiter.api.TestInstance.Lifecycle; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertLinesMatch; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -59,13 +56,15 @@ import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import jdk.test.lib.util.FileUtils; - class ValidatorTest { private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") .orElseThrow(() -> new RuntimeException("jar tool not found") ); + private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac") + .orElseThrow(() -> + new RuntimeException("javac tool not found") + ); private final String nl = System.lineSeparator(); private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -310,6 +309,44 @@ class ValidatorTest { } } + @Test + public void testInvalidAutomaticModuleName() throws Exception { + System.out.printf("%n%n*****Creating Jar with invalid Automatic-Module-Name in Manifest*****%n%n"); + var file = Path.of("InvalidAutomaticModuleName.jar"); + var manifest = Path.of("MANIFEST.MF"); + Files.writeString(manifest, + """ + Automatic-Module-Name: default + """); + jar("--create --file " + file + " --manifest " + manifest); + var e = assertThrows(IOException.class, () -> jar("--validate --file " + file.toString())); + var err = e.getMessage(); + System.out.println(err); + assertTrue(err.contains("invalid module name of Automatic-Module-Name entry in manifest: default"), "missing warning for: default"); + } + + @Test + public void testWrongAutomaticModuleName() throws Exception { + System.out.printf("%n%n*****Creating Jar with wrong Automatic-Module-Name in Manifest*****%n%n"); + var file = Path.of("WrongAutomaticModuleName.jar"); + var foo = Path.of("module-info.java"); + Files.writeString(foo, + """ + module foo {} + """); + var manifest = Path.of("MANIFEST.MF"); + Files.writeString(manifest, + """ + Automatic-Module-Name: bar + """); + JAVAC_TOOL.run(System.out, System.err, foo.toString()); + jar("--create --file " + file + " --manifest " + manifest + " module-info.class"); + var e = assertThrows(IOException.class, () -> jar("--validate --file " + file.toString())); + var err = e.getMessage(); + System.out.println(err); + assertTrue(err.contains("expected Automatic-Module-Name entry in manifest: bar to match name of compiled module: foo"), "missing warning for: foo/bar"); + } + /** * Validates that base manifest-related entries are at expected LOC positions. *

    From 0e2e66be2423335002a53d887df35d2348a3ec9f Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 28 Jan 2026 16:30:34 +0000 Subject: [PATCH 232/328] 8376402: Dependencies::print_statistics() and AbstractClassHierarchyWalker::print_statistics() are not called from PRODUCT code Reviewed-by: azafari, chagedorn --- src/hotspot/share/code/dependencies.cpp | 6 ++++-- src/hotspot/share/code/dependencies.hpp | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/code/dependencies.cpp b/src/hotspot/share/code/dependencies.cpp index d90695739a1..dbfe1cd884e 100644 --- a/src/hotspot/share/code/dependencies.cpp +++ b/src/hotspot/share/code/dependencies.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, 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 @@ -1124,7 +1124,7 @@ class AbstractClassHierarchyWalker { Klass* find_witness(InstanceKlass* context_type, KlassDepChange* changes = nullptr); static void init(); - static void print_statistics(); + NOT_PRODUCT(static void print_statistics();) }; PerfCounter* AbstractClassHierarchyWalker::_perf_find_witness_anywhere_calls_count = nullptr; @@ -2277,6 +2277,7 @@ bool KlassDepChange::involves_context(Klass* k) { return is_contained; } +#ifndef PRODUCT void Dependencies::print_statistics() { AbstractClassHierarchyWalker::print_statistics(); } @@ -2302,6 +2303,7 @@ void AbstractClassHierarchyWalker::print_statistics() { } } } +#endif CallSiteDepChange::CallSiteDepChange(Handle call_site, Handle method_handle) : _call_site(call_site), diff --git a/src/hotspot/share/code/dependencies.hpp b/src/hotspot/share/code/dependencies.hpp index d11c51a66dc..582a08183f9 100644 --- a/src/hotspot/share/code/dependencies.hpp +++ b/src/hotspot/share/code/dependencies.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, 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 @@ -649,7 +649,7 @@ class Dependencies: public ResourceObj { }; friend class Dependencies::DepStream; - static void print_statistics(); + NOT_PRODUCT(static void print_statistics();) }; From 50d872ad7ac5fa5a3406517eb53d8f61f81706df Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 28 Jan 2026 16:30:56 +0000 Subject: [PATCH 233/328] 8376419: (fs) Minor improvement of java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java Reviewed-by: jpai --- .../UserDefinedFileAttributeView/Basic.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/test/jdk/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java b/test/jdk/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java index 4586c33521f..b729438812f 100644 --- a/test/jdk/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java +++ b/test/jdk/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,9 +24,12 @@ /* @test * @bug 4313887 6838333 8273922 * @summary Unit test for java.nio.file.attribute.UserDefinedFileAttributeView + * (use -Dseed=X to set PRNG seed) * @library ../.. /test/lib * @key randomness * @build jdk.test.lib.Platform + * @build jdk.test.lib.RandomFactory + * @build jtreg.SkippedException * @run main Basic */ @@ -38,17 +41,20 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; -import static java.nio.file.LinkOption.*; -import java.nio.file.attribute.*; +import java.nio.file.attribute.UserDefinedFileAttributeView; import java.util.Arrays; import java.util.Map; import java.util.Random; + import jdk.test.lib.Platform; +import jdk.test.lib.RandomFactory; + +import jtreg.SkippedException; public class Basic { // Must be indeterministic - private static final Random rand = new Random(); + private static final Random rand = RandomFactory.getRandom(); private static final String ATTR_NAME = "mime_type"; private static final String ATTR_VALUE = "text/plain"; @@ -281,10 +287,8 @@ public class Basic { // create temporary directory to run tests Path dir = TestUtil.createTemporaryDirectory(); try { - if (!Files.getFileStore(dir).supportsFileAttributeView("user")) { - System.out.println("UserDefinedFileAttributeView not supported - skip test"); - return; - } + if (!Files.getFileStore(dir).supportsFileAttributeView("user")) + throw new SkippedException("UserDefinedFileAttributeView not supported"); // test access to user defined attributes of regular file Path file = dir.resolve("foo.html"); @@ -310,7 +314,7 @@ public class Basic { Path link = dir.resolve("link"); Files.createSymbolicLink(link, target); try { - test(link, NOFOLLOW_LINKS); + test(link, LinkOption.NOFOLLOW_LINKS); } catch (IOException x) { // access to attributes of sym link may not be supported } finally { From 89a18c0108e10dc4ca4a4fa9e8718d49036f8871 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 28 Jan 2026 17:58:15 +0000 Subject: [PATCH 234/328] 8376432: Remove AppContext from sun/swing/DefaultLookup.java Reviewed-by: psadhukhan, azvegint, aivanov --- .../classes/sun/swing/DefaultLookup.java | 51 +++++-------------- 1 file changed, 12 insertions(+), 39 deletions(-) diff --git a/src/java.desktop/share/classes/sun/swing/DefaultLookup.java b/src/java.desktop/share/classes/sun/swing/DefaultLookup.java index d7a7f22eba3..a2ae0921507 100644 --- a/src/java.desktop/share/classes/sun/swing/DefaultLookup.java +++ b/src/java.desktop/share/classes/sun/swing/DefaultLookup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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 @@ -29,7 +29,6 @@ import java.awt.Insets; import javax.swing.*; import javax.swing.border.Border; import javax.swing.plaf.ComponentUI; -import sun.awt.AppContext; /** * DefaultLookup provides a way to customize the lookup done by the @@ -44,17 +43,9 @@ import sun.awt.AppContext; * @author Scott Violet */ public class DefaultLookup { + /** - * Key used to store DefaultLookup for AppContext. - */ - private static final Object DEFAULT_LOOKUP_KEY = new - StringBuffer("DefaultLookup"); - /** - * Thread that last asked for a default. - */ - private static Thread currentDefaultThread; - /** - * DefaultLookup for last thread. + * DefaultLookup currently set. */ private static DefaultLookup currentDefaultLookup; @@ -63,28 +54,24 @@ public class DefaultLookup { */ private static boolean isLookupSet; - /** - * Sets the DefaultLookup instance to use for the current - * AppContext. Null implies the UIManager should be - * used. + * Sets the DefaultLookup instance to use. + * Null implies the UIManager should be used. */ public static void setDefaultLookup(DefaultLookup lookup) { synchronized(DefaultLookup.class) { if (!isLookupSet && lookup == null) { - // Null was passed in, and no one has invoked setDefaultLookup + // Null was passed in, and no one has previously invoked setDefaultLookup // with a non-null value, we don't need to do anything. return; } else if (lookup == null) { - // null was passed in, but someone has invoked setDefaultLookup + // null was passed in, but someone has previously invoked setDefaultLookup // with a non-null value, use an instance of DefaultLookup // which will fallback to UIManager. lookup = new DefaultLookup(); } isLookupSet = true; - AppContext.getAppContext().put(DEFAULT_LOOKUP_KEY, lookup); - currentDefaultThread = Thread.currentThread(); currentDefaultLookup = lookup; } } @@ -98,27 +85,13 @@ public class DefaultLookup { // No one has set a valid DefaultLookup, use UIManager. return UIManager.get(key, c.getLocale()); } - Thread thisThread = Thread.currentThread(); DefaultLookup lookup; synchronized(DefaultLookup.class) { - // See if we've already cached the DefaultLookup for this thread, - // and use it if we have. - if (thisThread == currentDefaultThread) { - // It is cached, use it. - lookup = currentDefaultLookup; - } - else { - // Not cached, get the DefaultLookup to use from the AppContext - lookup = (DefaultLookup)AppContext.getAppContext().get( - DEFAULT_LOOKUP_KEY); - if (lookup == null) { - // Fallback to DefaultLookup, which will redirect to the - // UIManager. - lookup = new DefaultLookup(); - AppContext.getAppContext().put(DEFAULT_LOOKUP_KEY, lookup); - } - // Cache the values to make the next lookup easier. - currentDefaultThread = thisThread; + lookup = currentDefaultLookup; + if (lookup == null) { + // Fallback to DefaultLookup, which will redirect to the + // UIManager. + lookup = new DefaultLookup(); currentDefaultLookup = lookup; } } From 7efa3168b706c1d061c4ee65574427ef1f50fc7b Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 28 Jan 2026 18:01:10 +0000 Subject: [PATCH 235/328] 8376434: Remove AppContext from awt ImageFetcher implementation Reviewed-by: azvegint, aivanov --- .../classes/sun/awt/image/ImageFetcher.java | 61 ++++++------------- 1 file changed, 18 insertions(+), 43 deletions(-) diff --git a/src/java.desktop/share/classes/sun/awt/image/ImageFetcher.java b/src/java.desktop/share/classes/sun/awt/image/ImageFetcher.java index 74c7c4d2ce2..917378389a4 100644 --- a/src/java.desktop/share/classes/sun/awt/image/ImageFetcher.java +++ b/src/java.desktop/share/classes/sun/awt/image/ImageFetcher.java @@ -26,7 +26,6 @@ package sun.awt.image; import java.util.Vector; -import sun.awt.AppContext; /** * An ImageFetcher is a thread used to fetch ImageFetchable objects. @@ -34,10 +33,6 @@ import sun.awt.AppContext; * thread may also be used to animate it if necessary, via the * startingAnimation() / stoppingAnimation() methods. * - * There can be up to FetcherInfo.MAX_NUM_FETCHERS_PER_APPCONTEXT - * ImageFetcher threads for each AppContext. A per-AppContext queue - * of ImageFetchables is used to track objects to fetch. - * * @author Jim Graham * @author Fred Ecks */ @@ -153,7 +148,6 @@ class ImageFetcher extends Thread { info.numWaiting++; info.waitList.wait(end - now); } catch (InterruptedException e) { - // A normal occurrence as an AppContext is disposed return null; } finally { info.numWaiting--; @@ -280,28 +274,20 @@ class ImageFetcher extends Thread { // We need to instantiate a new ImageFetcher thread. // First, figure out which ThreadGroup we'll put the // new ImageFetcher into - final AppContext appContext = AppContext.getAppContext(); - ThreadGroup threadGroup = appContext.getThreadGroup(); - ThreadGroup fetcherThreadGroup; - if (threadGroup.getParent() != null) { - // threadGroup is not the root, so we proceed - fetcherThreadGroup = threadGroup; - } else { - // threadGroup is the root ("system") ThreadGroup. - // We instead want to use its child: the "main" - // ThreadGroup. Thus, we start with the current - // ThreadGroup, and go up the tree until - // threadGroup.getParent().getParent() == null. - threadGroup = Thread.currentThread().getThreadGroup(); - ThreadGroup parent = threadGroup.getParent(); - while ((parent != null) - && (parent.getParent() != null)) { - threadGroup = parent; - parent = threadGroup.getParent(); - } - fetcherThreadGroup = threadGroup; + // We don't want the root ("system") ThreadGroup. + // We instead want to use its child: the "main" + // ThreadGroup. Thus, we start with the current + // ThreadGroup, and go up the tree until + // threadGroup.getParent().getParent() == null. + ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); + ThreadGroup parent = threadGroup.getParent(); + while ((parent != null) + && (parent.getParent() != null)) { + threadGroup = parent; + parent = threadGroup.getParent(); } - final ThreadGroup fetcherGroup = fetcherThreadGroup; + final ThreadGroup fetcherGroup = threadGroup; + for (int i = 0; i < info.fetchers.length; i++) { if (info.fetchers[i] == null) { @@ -320,12 +306,13 @@ class ImageFetcher extends Thread { } /** - * The FetcherInfo class encapsulates the per-AppContext ImageFetcher + * The FetcherInfo class encapsulates the ImageFetcher * information. This includes the array of ImageFetchers, as well as * the queue of ImageFetchable objects. */ class FetcherInfo { - static final int MAX_NUM_FETCHERS_PER_APPCONTEXT = 4; + static final int MAX_NUM_FETCHERS = 4; + static final FetcherInfo FETCHER_INFO = new FetcherInfo(); Thread[] fetchers; int numFetchers; @@ -333,25 +320,13 @@ class FetcherInfo { Vector waitList; private FetcherInfo() { - fetchers = new Thread[MAX_NUM_FETCHERS_PER_APPCONTEXT]; + fetchers = new Thread[MAX_NUM_FETCHERS]; numFetchers = 0; numWaiting = 0; waitList = new Vector<>(); } - /* The key to put()/get() the FetcherInfo into/from the AppContext. */ - private static final Object FETCHER_INFO_KEY = - new StringBuffer("FetcherInfo"); - static FetcherInfo getFetcherInfo() { - AppContext appContext = AppContext.getAppContext(); - synchronized(appContext) { - FetcherInfo info = (FetcherInfo)appContext.get(FETCHER_INFO_KEY); - if (info == null) { - info = new FetcherInfo(); - appContext.put(FETCHER_INFO_KEY, info); - } - return info; - } + return FETCHER_INFO; } } From 0722ae926ff1327c47a922b1ca0b493a0d06526e Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 28 Jan 2026 19:53:41 +0000 Subject: [PATCH 236/328] 8376433: Remove AppContext from Swing Windows L&F implementation Reviewed-by: serb, aivanov --- .../plaf/windows/AnimationController.java | 19 ++++++------------- .../swing/plaf/windows/WindowsButtonUI.java | 15 +++------------ .../swing/plaf/windows/WindowsCheckBoxUI.java | 15 +++------------ .../swing/plaf/windows/WindowsLabelUI.java | 14 +++----------- .../plaf/windows/WindowsRadioButtonUI.java | 15 +++------------ .../plaf/windows/WindowsToggleButtonUI.java | 15 +++------------ 6 files changed, 21 insertions(+), 72 deletions(-) diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/AnimationController.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/AnimationController.java index 4fb843543e3..06574d17641 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/AnimationController.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/AnimationController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2026, 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 @@ -39,8 +39,6 @@ import com.sun.java.swing.plaf.windows.TMSchema.Part; import com.sun.java.swing.plaf.windows.TMSchema.Prop; import com.sun.java.swing.plaf.windows.XPStyle.Skin; -import sun.awt.AppContext; - /** * A class to help mimic Vista theme animations. The only kind of * animation it handles for now is 'transition' animation (this seems @@ -68,8 +66,7 @@ final class AnimationController implements ActionListener, PropertyChangeListene Boolean.getBoolean("swing.disablevistaanimation"); - private static final Object ANIMATION_CONTROLLER_KEY = - new StringBuilder("ANIMATION_CONTROLLER_KEY"); + private static AnimationController animationController; private final Map> animationStateMap = new WeakHashMap>(); @@ -80,13 +77,10 @@ final class AnimationController implements ActionListener, PropertyChangeListene new javax.swing.Timer(1000/30, this); private static synchronized AnimationController getAnimationController() { - AppContext appContext = AppContext.getAppContext(); - Object obj = appContext.get(ANIMATION_CONTROLLER_KEY); - if (obj == null) { - obj = new AnimationController(); - appContext.put(ANIMATION_CONTROLLER_KEY, obj); + if (animationController == null) { + animationController = new AnimationController(); } - return (AnimationController) obj; + return animationController; } private AnimationController() { @@ -316,8 +310,7 @@ final class AnimationController implements ActionListener, PropertyChangeListene timer.stop(); UIManager.removePropertyChangeListener(this); synchronized (AnimationController.class) { - AppContext.getAppContext() - .put(ANIMATION_CONTROLLER_KEY, null); + animationController = null; } } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java index 0c86bd33e10..ee07276aa30 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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,8 +47,6 @@ import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicButtonUI; import javax.swing.plaf.basic.BasicGraphicsUtils; -import sun.awt.AppContext; - import static com.sun.java.swing.plaf.windows.TMSchema.Part; import static com.sun.java.swing.plaf.windows.TMSchema.State; import static com.sun.java.swing.plaf.windows.XPStyle.Skin; @@ -69,20 +67,13 @@ public final class WindowsButtonUI extends BasicButtonUI private boolean defaults_initialized = false; - private static final Object WINDOWS_BUTTON_UI_KEY = new Object(); + private static final ComponentUI UI = new WindowsButtonUI(); // ******************************** // Create PLAF // ******************************** public static ComponentUI createUI(JComponent c) { - AppContext appContext = AppContext.getAppContext(); - WindowsButtonUI windowsButtonUI = - (WindowsButtonUI) appContext.get(WINDOWS_BUTTON_UI_KEY); - if (windowsButtonUI == null) { - windowsButtonUI = new WindowsButtonUI(); - appContext.put(WINDOWS_BUTTON_UI_KEY, windowsButtonUI); - } - return windowsButtonUI; + return UI; } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java index 3c869efc97b..7cb2490fd76 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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,8 +30,6 @@ import javax.swing.JComponent; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; -import sun.awt.AppContext; - /** * Windows check box. * @@ -43,7 +41,7 @@ public final class WindowsCheckBoxUI extends WindowsRadioButtonUI // of BasicCheckBoxUI because we want to pick up all the // painting changes made in WindowsRadioButtonUI. - private static final Object WINDOWS_CHECK_BOX_UI_KEY = new Object(); + private static final ComponentUI UI = new WindowsCheckBoxUI(); private static final String propertyPrefix = "CheckBox" + "."; @@ -53,14 +51,7 @@ public final class WindowsCheckBoxUI extends WindowsRadioButtonUI // Create PLAF // ******************************** public static ComponentUI createUI(JComponent c) { - AppContext appContext = AppContext.getAppContext(); - WindowsCheckBoxUI windowsCheckBoxUI = - (WindowsCheckBoxUI) appContext.get(WINDOWS_CHECK_BOX_UI_KEY); - if (windowsCheckBoxUI == null) { - windowsCheckBoxUI = new WindowsCheckBoxUI(); - appContext.put(WINDOWS_CHECK_BOX_UI_KEY, windowsCheckBoxUI); - } - return windowsCheckBoxUI; + return UI; } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java index 403468af0af..4283f743b97 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,6 @@ import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicLabelUI; -import sun.awt.AppContext; import sun.swing.MnemonicHandler; import sun.swing.SwingUtilities2; @@ -43,20 +42,13 @@ import sun.swing.SwingUtilities2; */ public final class WindowsLabelUI extends BasicLabelUI { - private static final Object WINDOWS_LABEL_UI_KEY = new Object(); + private static final ComponentUI UI = new WindowsLabelUI(); // ******************************** // Create PLAF // ******************************** public static ComponentUI createUI(JComponent c) { - AppContext appContext = AppContext.getAppContext(); - WindowsLabelUI windowsLabelUI = - (WindowsLabelUI) appContext.get(WINDOWS_LABEL_UI_KEY); - if (windowsLabelUI == null) { - windowsLabelUI = new WindowsLabelUI(); - appContext.put(WINDOWS_LABEL_UI_KEY, windowsLabelUI); - } - return windowsLabelUI; + return UI; } @Override diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java index 2a784a470a4..c62a9ec8586 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -38,14 +38,12 @@ import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicGraphicsUtils; import javax.swing.plaf.basic.BasicRadioButtonUI; -import sun.awt.AppContext; - /** * Windows rendition of the component. */ public class WindowsRadioButtonUI extends BasicRadioButtonUI { - private static final Object WINDOWS_RADIO_BUTTON_UI_KEY = new Object(); + private static final ComponentUI UI = new WindowsRadioButtonUI(); protected int dashedRectGapX; protected int dashedRectGapY; @@ -60,14 +58,7 @@ public class WindowsRadioButtonUI extends BasicRadioButtonUI // Create PLAF // ******************************** public static ComponentUI createUI(JComponent c) { - AppContext appContext = AppContext.getAppContext(); - WindowsRadioButtonUI windowsRadioButtonUI = - (WindowsRadioButtonUI) appContext.get(WINDOWS_RADIO_BUTTON_UI_KEY); - if (windowsRadioButtonUI == null) { - windowsRadioButtonUI = new WindowsRadioButtonUI(); - appContext.put(WINDOWS_RADIO_BUTTON_UI_KEY, windowsRadioButtonUI); - } - return windowsRadioButtonUI; + return UI; } // ******************************** diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java index 5e94ebdb2cc..67eb5c1d6a0 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -38,8 +38,6 @@ import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicGraphicsUtils; import javax.swing.plaf.basic.BasicToggleButtonUI; -import sun.awt.AppContext; - /** * A Windows toggle button. * @@ -54,19 +52,12 @@ public final class WindowsToggleButtonUI extends BasicToggleButtonUI protected Color focusColor; - private static final Object WINDOWS_TOGGLE_BUTTON_UI_KEY = new Object(); + private static final ComponentUI UI = new WindowsToggleButtonUI(); private boolean defaults_initialized = false; public static ComponentUI createUI(JComponent b) { - AppContext appContext = AppContext.getAppContext(); - WindowsToggleButtonUI windowsToggleButtonUI = - (WindowsToggleButtonUI) appContext.get(WINDOWS_TOGGLE_BUTTON_UI_KEY); - if (windowsToggleButtonUI == null) { - windowsToggleButtonUI = new WindowsToggleButtonUI(); - appContext.put(WINDOWS_TOGGLE_BUTTON_UI_KEY, windowsToggleButtonUI); - } - return windowsToggleButtonUI; + return UI; } From 09ed8e66dc7a788763a2c7c24f54e93ec8eafedb Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Wed, 28 Jan 2026 21:28:16 +0000 Subject: [PATCH 237/328] 8376531: Genshen: Convert ShenandoahOldGeneration to use Atomic Reviewed-by: wkemper, shade --- .../gc/shenandoah/shenandoahOldGeneration.cpp | 22 +++++++++---------- .../gc/shenandoah/shenandoahOldGeneration.hpp | 10 ++++----- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index aed768b9db1..d5e34d02b13 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -63,7 +63,7 @@ private: uint _nworkers; ShenandoahHeapRegion** _coalesce_and_fill_region_array; uint _coalesce_and_fill_region_count; - volatile bool _is_preempted; + Atomic _is_preempted; public: ShenandoahConcurrentCoalesceAndFillTask(uint nworkers, @@ -88,7 +88,7 @@ public: if (!r->oop_coalesce_and_fill(true)) { // Coalesce and fill has been preempted - AtomicAccess::store(&_is_preempted, true); + _is_preempted.store_relaxed(true); return; } } @@ -96,7 +96,7 @@ public: // Value returned from is_completed() is only valid after all worker thread have terminated. bool is_completed() { - return !AtomicAccess::load(&_is_preempted); + return !_is_preempted.load_relaxed(); } }; @@ -147,23 +147,23 @@ void ShenandoahOldGeneration::augment_promoted_reserve(size_t increment) { void ShenandoahOldGeneration::reset_promoted_expended() { shenandoah_assert_heaplocked_or_safepoint(); - AtomicAccess::store(&_promoted_expended, static_cast(0)); - AtomicAccess::store(&_promotion_failure_count, static_cast(0)); - AtomicAccess::store(&_promotion_failure_words, static_cast(0)); + _promoted_expended.store_relaxed(0); + _promotion_failure_count.store_relaxed(0); + _promotion_failure_words.store_relaxed(0); } size_t ShenandoahOldGeneration::expend_promoted(size_t increment) { shenandoah_assert_heaplocked_or_safepoint(); assert(get_promoted_expended() + increment <= get_promoted_reserve(), "Do not expend more promotion than budgeted"); - return AtomicAccess::add(&_promoted_expended, increment); + return _promoted_expended.add_then_fetch(increment); } size_t ShenandoahOldGeneration::unexpend_promoted(size_t decrement) { - return AtomicAccess::sub(&_promoted_expended, decrement); + return _promoted_expended.sub_then_fetch(decrement); } size_t ShenandoahOldGeneration::get_promoted_expended() const { - return AtomicAccess::load(&_promoted_expended); + return _promoted_expended.load_relaxed(); } bool ShenandoahOldGeneration::can_allocate(const ShenandoahAllocRequest &req) const { @@ -582,8 +582,8 @@ void ShenandoahOldGeneration::handle_failed_evacuation() { } void ShenandoahOldGeneration::handle_failed_promotion(Thread* thread, size_t size) { - AtomicAccess::inc(&_promotion_failure_count); - AtomicAccess::add(&_promotion_failure_words, size); + _promotion_failure_count.add_then_fetch(1UL); + _promotion_failure_words.and_then_fetch(size); LogTarget(Debug, gc, plab) lt; LogStream ls(lt); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp index 633d2c9f617..5ebad461f3c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp @@ -64,7 +64,7 @@ private: // is therefore always accessed through atomic operations. This is increased when a // PLAB is allocated for promotions. The value is decreased by the amount of memory // remaining in a PLAB when it is retired. - size_t _promoted_expended; + Atomic _promoted_expended; // Represents the quantity of live bytes we expect to promote during the next GC cycle, either by // evacuation or by promote-in-place. This value is used by the young heuristic to trigger mixed collections. @@ -78,8 +78,8 @@ private: // Keep track of the number and size of promotions that failed. Perhaps we should use this to increase // the size of the old generation for the next collection cycle. - size_t _promotion_failure_count; - size_t _promotion_failure_words; + Atomic _promotion_failure_count; + Atomic _promotion_failure_words; // During construction of the collection set, we keep track of regions that are eligible // for promotion in place. These fields track the count of those humongous and regular regions. @@ -126,8 +126,8 @@ public: size_t get_promoted_expended() const; // Return the count and size (in words) of failed promotions since the last reset - size_t get_promotion_failed_count() const { return AtomicAccess::load(&_promotion_failure_count); } - size_t get_promotion_failed_words() const { return AtomicAccess::load(&_promotion_failure_words); } + size_t get_promotion_failed_count() const { return _promotion_failure_count.load_relaxed(); } + size_t get_promotion_failed_words() const { return _promotion_failure_words.load_relaxed(); } // Test if there is enough memory reserved for this promotion bool can_promote(size_t requested_bytes) const { From 2529e2fe8dfe9685033bb0ae558266b8bc3cf95c Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 29 Jan 2026 02:30:41 +0000 Subject: [PATCH 238/328] 8376169: JPopupMenu.setInvoker(null) causes NPE Reviewed-by: aivanov, azvegint, prr, kizune --- .../share/classes/javax/swing/JPopupMenu.java | 6 ++++-- .../jdk/javax/swing/JPopupMenu/TestPopupInvoker.java | 12 ++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/JPopupMenu.java b/src/java.desktop/share/classes/javax/swing/JPopupMenu.java index 38bde1a97fa..1b04e8c6169 100644 --- a/src/java.desktop/share/classes/javax/swing/JPopupMenu.java +++ b/src/java.desktop/share/classes/javax/swing/JPopupMenu.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -960,7 +960,9 @@ public class JPopupMenu extends JComponent implements Accessible,MenuElement { if (oldInvoker != null) { oldInvoker.removePropertyChangeListener("ancestor", propListener); } - invoker.addPropertyChangeListener("ancestor", propListener); + if (invoker != null) { + invoker.addPropertyChangeListener("ancestor", propListener); + } ui.installUI(this); } invalidate(); diff --git a/test/jdk/javax/swing/JPopupMenu/TestPopupInvoker.java b/test/jdk/javax/swing/JPopupMenu/TestPopupInvoker.java index c8ddfe67999..a3dc658df0e 100644 --- a/test/jdk/javax/swing/JPopupMenu/TestPopupInvoker.java +++ b/test/jdk/javax/swing/JPopupMenu/TestPopupInvoker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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,13 +23,14 @@ /* * @test - * @bug 4938801 + * @bug 4938801 8376169 * @key headful * @summary Verifies popup is removed when the component is removed * @run main TestPopupInvoker */ import java.awt.BorderLayout; +import java.awt.Component; import java.awt.Container; import java.awt.Robot; import java.util.concurrent.CountDownLatch; @@ -48,6 +49,7 @@ public class TestPopupInvoker { static JFrame frame; static JLabel label; static Container pane; + static volatile Component invoker; private static final CountDownLatch popupShown = new CountDownLatch(1); private static final CountDownLatch popupHidden = new CountDownLatch(1); @@ -73,6 +75,7 @@ public class TestPopupInvoker { @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { popupHidden.countDown(); + popupMenu.setInvoker(null); } @Override @@ -106,6 +109,11 @@ public class TestPopupInvoker { if (!popupHidden.await(1, SECONDS)) { throw new RuntimeException("Popup is visible after component is removed"); } + + SwingUtilities.invokeAndWait(() -> invoker = popupMenu.getInvoker()); + if (invoker != null) { + throw new RuntimeException("Invoker is not null"); + } } finally { SwingUtilities.invokeAndWait(() -> { if (frame != null) { From 62c7e9aefd4320d9d0cd8fa10610f59abb4de670 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 29 Jan 2026 04:49:56 +0000 Subject: [PATCH 239/328] 8376423: Test javax/swing/plaf/metal/MetalUtils/bug6190373.java failed: ClassCastException: class java.lang.Character cannot be cast to class javax.swing.Painter Reviewed-by: aivanov, tr --- .../share/classes/javax/swing/UIManager.java | 28 ++--- .../swing/plaf/metal/DefaultMetalTheme.java | 7 +- .../classes/sun/swing/SwingAccessor.java | 29 ++++- .../classes/sun/swing/SwingUtilities2.java | 8 +- .../javax/swing/UIManager/Test6657026.java | 60 ---------- .../plaf/metal/MetalUtils/bug6190373.java | 112 ------------------ 6 files changed, 45 insertions(+), 199 deletions(-) delete mode 100644 test/jdk/javax/swing/UIManager/Test6657026.java delete mode 100644 test/jdk/javax/swing/plaf/metal/MetalUtils/bug6190373.java diff --git a/src/java.desktop/share/classes/javax/swing/UIManager.java b/src/java.desktop/share/classes/javax/swing/UIManager.java index 7a2ae226f33..69063c562e6 100644 --- a/src/java.desktop/share/classes/javax/swing/UIManager.java +++ b/src/java.desktop/share/classes/javax/swing/UIManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,6 +59,7 @@ import java.util.Objects; import sun.awt.AppContext; import sun.awt.AWTAccessor; +import sun.swing.SwingAccessor; /** * {@code UIManager} manages the current look and feel, the set of @@ -233,8 +234,9 @@ public class UIManager implements Serializable */ public UIManager() {} + private static final LAFState LAF_STATE = new LAFState(); /** - * Return the LAFState object, lazily create one if necessary. + * Return the LAFState object. * All access to the LAFState fields is done via this method, * for example: *

    @@ -242,22 +244,18 @@ public class UIManager implements Serializable
          * 
    */ private static LAFState getLAFState() { - LAFState rv = (LAFState)SwingUtilities.appContextGet( - SwingUtilities2.LAF_STATE_KEY); - if (rv == null) { - synchronized (classLock) { - rv = (LAFState)SwingUtilities.appContextGet( - SwingUtilities2.LAF_STATE_KEY); - if (rv == null) { - SwingUtilities.appContextPut( - SwingUtilities2.LAF_STATE_KEY, - (rv = new LAFState())); - } - } + synchronized (classLock) { + return LAF_STATE; } - return rv; } + static { + SwingAccessor.setLAFStateAccessor(UIManager::isLafStateInitialized); + } + + private static boolean isLafStateInitialized() { + return LAF_STATE.initialized; + } /* Keys used in the swing.properties properties file. * See loadUserProperties(), initialize(). diff --git a/src/java.desktop/share/classes/javax/swing/plaf/metal/DefaultMetalTheme.java b/src/java.desktop/share/classes/javax/swing/plaf/metal/DefaultMetalTheme.java index 8ee862fb0b3..d64267676c3 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/metal/DefaultMetalTheme.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/metal/DefaultMetalTheme.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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 @@ -29,7 +29,7 @@ import javax.swing.plaf.*; import javax.swing.*; import java.awt.*; -import sun.awt.AppContext; +import sun.swing.SwingAccessor; import sun.swing.SwingUtilities2; /** @@ -153,8 +153,7 @@ public class DefaultMetalTheme extends MetalTheme { static int getDefaultFontStyle(int key) { if (key != WINDOW_TITLE_FONT) { Object boldMetal = null; - if (AppContext.getAppContext().get( - SwingUtilities2.LAF_STATE_KEY) != null) { + if (SwingAccessor.getLAFStateAccessor().lafStateIsInitialized()) { // Only access the boldMetal key if a look and feel has // been loaded, otherwise we'll trigger loading the look // and feel. diff --git a/src/java.desktop/share/classes/sun/swing/SwingAccessor.java b/src/java.desktop/share/classes/sun/swing/SwingAccessor.java index 5c561de4a42..563cc038ae9 100644 --- a/src/java.desktop/share/classes/sun/swing/SwingAccessor.java +++ b/src/java.desktop/share/classes/sun/swing/SwingAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -133,6 +133,33 @@ public final class SwingAccessor { KeyStroke create(); } + /** + * An accessor for the LAFState class state. + */ + public interface LAFStateAccessor { + boolean lafStateIsInitialized(); + } + + private static LAFStateAccessor lafStateAccessor; + /** + * Set an accessor object for the LAFState class. + */ + public static void setLAFStateAccessor(LAFStateAccessor accessor) { + lafStateAccessor = accessor; + } + + /** + * Retrieve the accessor object for the LAFState class. + */ + public static LAFStateAccessor getLAFStateAccessor() { + var access = lafStateAccessor; + if (access == null) { + ensureClassInitialized(UIManager.class); + access = lafStateAccessor; + } + return access; + } + /** * The javax.swing.JComponent class accessor object. */ diff --git a/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java b/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java index 20a07c608a0..faf31e0b426 100644 --- a/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java +++ b/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,12 +120,6 @@ import static java.awt.geom.AffineTransform.TYPE_TRANSLATION; * */ public class SwingUtilities2 { - /** - * The {@code AppContext} key for our one {@code LAFState} - * instance. - */ - public static final Object LAF_STATE_KEY = - new StringBuffer("LookAndFeel State"); public static final Object MENU_SELECTION_MANAGER_LISTENER_KEY = new StringBuffer("MenuSelectionManager listener key"); diff --git a/test/jdk/javax/swing/UIManager/Test6657026.java b/test/jdk/javax/swing/UIManager/Test6657026.java deleted file mode 100644 index 5ce1ea73de4..00000000000 --- a/test/jdk/javax/swing/UIManager/Test6657026.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2009, 2015, 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 6657026 - * @summary Tests shared UIManager in different application contexts - * @author Sergey Malenkov - * @modules java.desktop/sun.awt - */ - -import sun.awt.SunToolkit; - -import javax.swing.UIManager; -import javax.swing.UIManager.LookAndFeelInfo; - -public class Test6657026 implements Runnable { - - public static void main(String[] args) throws Exception { - if (UIManager.getInstalledLookAndFeels().length == 0) { - throw new Error("unexpected amount of look&feels"); - } - UIManager.setInstalledLookAndFeels(new LookAndFeelInfo[0]); - if (UIManager.getInstalledLookAndFeels().length != 0) { - throw new Error("unexpected amount of look&feels"); - } - - ThreadGroup group = new ThreadGroup("$$$"); - Thread thread = new Thread(group, new Test6657026()); - thread.start(); - thread.join(); - } - - public void run() { - SunToolkit.createNewAppContext(); - if (UIManager.getInstalledLookAndFeels().length == 0) { - throw new Error("shared look&feels"); - } - } -} diff --git a/test/jdk/javax/swing/plaf/metal/MetalUtils/bug6190373.java b/test/jdk/javax/swing/plaf/metal/MetalUtils/bug6190373.java deleted file mode 100644 index 07211c7a569..00000000000 --- a/test/jdk/javax/swing/plaf/metal/MetalUtils/bug6190373.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2005, 2018, 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.awt.Graphics; -import java.awt.image.BufferedImage; -import java.util.concurrent.CyclicBarrier; - -import javax.swing.JButton; -import javax.swing.SwingUtilities; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; - -import sun.awt.AppContext; -import sun.awt.SunToolkit; - -import static javax.swing.UIManager.getInstalledLookAndFeels; - -/** - * @test - * @bug 6190373 - * @summary Tests 6190373 - * @author Scott Violet - * @modules java.desktop/sun.awt - */ -public final class bug6190373 { - - private static AppContext app1; - private static AppContext app2; - private static final int LOOP_COUNT = 10000; - private static final CyclicBarrier barrier = new CyclicBarrier(2); - - public static void main(final String[] args) throws Exception { - final Thread t1 = new Thread(new ThreadGroup("firstGroup"), () -> { - app1 = SunToolkit.createNewAppContext(); - test(true); - }); - final Thread t2 = new Thread(new ThreadGroup("secondGroup"), () -> { - app2 = SunToolkit.createNewAppContext(); - test(false); - }); - - t1.start(); - t2.start(); - t1.join(); - t2.join(); - app1.dispose(); - app2.dispose(); - } - - private static void test(final boolean lock) { - for (final UIManager.LookAndFeelInfo laf : getInstalledLookAndFeels()) { - try { - SwingUtilities.invokeAndWait(() -> setLookAndFeel(laf)); - barrier.await(); - SwingUtilities.invokeAndWait(() -> slam(lock)); - barrier.await(); - } catch (final Exception e) { - throw new RuntimeException(e); - } - } - } - - private static void slam(final boolean lock) { - JButton button = new JButton("HI"); - button.setSize(100, 100); - BufferedImage image = new BufferedImage(100, 100, - BufferedImage.TYPE_INT_RGB); - for (int i = 0; i < LOOP_COUNT; i++) { - Graphics g = image.getGraphics(); - if (lock) { - synchronized (button.getTreeLock()) { - button.paint(g); - } - } else { - button.paint(g); - } - g.dispose(); - } - } - - private static void setLookAndFeel(final UIManager.LookAndFeelInfo laf) { - try { - UIManager.setLookAndFeel(laf.getClassName()); - System.out.println("LookAndFeel: " + laf.getClassName()); - } catch (final UnsupportedLookAndFeelException ignored){ - System.out.println("Unsupported LookAndFeel: " + laf.getClassName()); - } catch (ClassNotFoundException | InstantiationException | - IllegalAccessException e) { - throw new RuntimeException(e); - } - } -} From 19c6fdf11b01308e9f99ce5666bfffcfbc453de3 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Thu, 29 Jan 2026 06:34:02 +0000 Subject: [PATCH 240/328] 8376290: SocketChannel.finishConnect() contains confusing "getsockopt" in exception message for a failed connect() on Windows Reviewed-by: alanb --- .../unix/native/libnet/net_util_md.c | 13 +- .../windows/native/libnet/net_util_md.c | 30 ++-- src/java.base/windows/native/libnio/ch/Net.c | 4 +- .../Selector/ConnectionRefusedMessage.java | 128 ++++++++++++++++++ 4 files changed, 153 insertions(+), 22 deletions(-) create mode 100644 test/jdk/java/nio/channels/Selector/ConnectionRefusedMessage.java diff --git a/src/java.base/unix/native/libnet/net_util_md.c b/src/java.base/unix/native/libnet/net_util_md.c index 1496be5f5c6..48cc1a7bb02 100644 --- a/src/java.base/unix/native/libnet/net_util_md.c +++ b/src/java.base/unix/native/libnet/net_util_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -68,13 +68,14 @@ NET_ThrowByNameWithLastError(JNIEnv *env, const char *name, void NET_ThrowNew(JNIEnv *env, int errorNumber, char *msg) { char fullMsg[512]; - if (!msg) { - msg = "no further information"; - } switch(errorNumber) { case EBADF: - jio_snprintf(fullMsg, sizeof(fullMsg), "socket closed: %s", msg); - JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg); + if (msg == NULL) { + JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed"); + } else { + jio_snprintf(fullMsg, sizeof(fullMsg), "socket closed: %s", msg); + JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg); + } break; default: errno = errorNumber; diff --git a/src/java.base/windows/native/libnet/net_util_md.c b/src/java.base/windows/native/libnet/net_util_md.c index bac3d1438ab..5abdd8d4c2e 100644 --- a/src/java.base/windows/native/libnet/net_util_md.c +++ b/src/java.base/windows/native/libnet/net_util_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -139,13 +139,6 @@ NET_ThrowNew(JNIEnv *env, int errorNum, char *msg) return; } - /* - * Default message text if not provided - */ - if (!msg) { - msg = "no further information"; - } - /* * Check table for known winsock errors */ @@ -163,13 +156,22 @@ NET_ThrowNew(JNIEnv *env, int errorNum, char *msg) */ if (i < table_size) { excP = (char *)winsock_errors[i].exc; - jio_snprintf(fullMsg, sizeof(fullMsg), "%s: %s", - (char *)winsock_errors[i].errString, msg); + if (msg == NULL) { + jio_snprintf(fullMsg, sizeof(fullMsg), "%s", + (char *)winsock_errors[i].errString); + } else { + jio_snprintf(fullMsg, sizeof(fullMsg), "%s: %s", + (char *)winsock_errors[i].errString, msg); + } } else { - jio_snprintf(fullMsg, sizeof(fullMsg), - "Unrecognized Windows Sockets error: %d: %s", - errorNum, msg); - + if (msg == NULL) { + jio_snprintf(fullMsg, sizeof(fullMsg), + "Unrecognized Windows Sockets error: %d", errorNum); + } else { + jio_snprintf(fullMsg, sizeof(fullMsg), + "Unrecognized Windows Sockets error: %d: %s", + errorNum, msg); + } } /* diff --git a/src/java.base/windows/native/libnio/ch/Net.c b/src/java.base/windows/native/libnio/ch/Net.c index 814f502c48a..adfd67b5017 100644 --- a/src/java.base/windows/native/libnio/ch/Net.c +++ b/src/java.base/windows/native/libnio/ch/Net.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -733,7 +733,7 @@ Java_sun_nio_ch_Net_pollConnect(JNIEnv* env, jclass this, jobject fdo, jlong tim NET_ThrowNew(env, lastError, "getsockopt"); } } else if (optError != NO_ERROR) { - NET_ThrowNew(env, optError, "getsockopt"); + NET_ThrowNew(env, optError, NULL); } return JNI_FALSE; } diff --git a/test/jdk/java/nio/channels/Selector/ConnectionRefusedMessage.java b/test/jdk/java/nio/channels/Selector/ConnectionRefusedMessage.java new file mode 100644 index 00000000000..5e7b6395a66 --- /dev/null +++ b/test/jdk/java/nio/channels/Selector/ConnectionRefusedMessage.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2026, 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.IOException; +import java.net.ConnectException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.time.Duration; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assumptions.assumeFalse; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +/* + * @test + * @bug 8376290 + * @summary Verify that when a SocketChannel is registered with a Selector + * with an interest in CONNECT operation, then SocketChannel.finishConnect() + * throws the correct exception message, if the connect() fails + * @run junit ${test.main.class} + */ +class ConnectionRefusedMessage { + + /* + * On a non-blocking SocketChannel, registered with a Selector, this test method + * attempts a SocketChannel.connect() against an address that is expected to return + * Connection refused. The test then calls SocketChannel.finishConnect() when the + * Selector makes available the ready key for this connect operation and expects + * that finishConnect() throws a ConnectException with the expected exception message. + */ + @Test + void testFinishConnect() throws Exception { + // find a suitable address against which the connect() attempt + // will result in a Connection refused exception + final InetSocketAddress destAddr = findSuitableRefusedAddress(); + // skip the test if we couldn't find a port which would raise a connection refused error + assumeTrue(destAddr != null, + "couldn't find a suitable port which will generate a connection refused error"); + try (Selector selector = Selector.open(); + SocketChannel sc = SocketChannel.open()) { + + // non-blocking + sc.configureBlocking(false); + sc.register(selector, SelectionKey.OP_CONNECT); + + System.err.println("establishing connection to " + destAddr); + boolean connected = sc.connect(destAddr); + // this test checks the exception message of a ConnectException, so it's + // OK to skip the test if something unexpectedly accepted the connection + assumeFalse(connected, "unexpectedly connected to " + destAddr); + // wait for ready ops + int numReady = selector.select(Duration.ofMinutes(10).toMillis()); + System.err.println("Num ready keys = " + numReady); + for (SelectionKey readyKey : selector.selectedKeys()) { + System.err.println("ready key: " + readyKey); + assertTrue(readyKey.isConnectable(), "unexpected key, readyOps = " + + readyKey.readyOps()); + readyKey.cancel(); + try { + boolean success = sc.finishConnect(); + // this test checks the exception message of a ConnectException, so it's + // OK to skip the test if something unexpectedly accepted the connection + assumeFalse(success, "unexpectedly connected to " + destAddr); + // this test doesn't expect finishConnect() to return normally + // with a return value of false + fail("ConnectException was not thrown"); + } catch (ConnectException ce) { + System.err.println("got (expected) ConnectException - " + ce); + // verify exception message + if (!"Connection refused".equals(ce.getMessage())) { + // propagate the original exception + fail("unexpected exception message: " + ce.getMessage(), ce); + } + } + } + } + } + + // Try to find a suitable port to provoke a "Connection Refused" error. + private static InetSocketAddress findSuitableRefusedAddress() throws IOException { + final InetAddress loopbackAddr = InetAddress.getLoopbackAddress(); + // Ports 47, 51, 61 are in the IANA reserved port list, and + // are currently unassigned to any specific service. + // We use them here on the assumption that there won't be + // any service listening on them. + InetSocketAddress destAddr = new InetSocketAddress(loopbackAddr, 47); + try (SocketChannel sc1 = SocketChannel.open(destAddr)) { + // we managed to connect (unexpectedly), let's try the next reserved port + destAddr = new InetSocketAddress(loopbackAddr, 51); + try (SocketChannel sc2 = SocketChannel.open(destAddr)) { + } + // we managed to connect (unexpectedly again), let's try the next reserved port + // as a last attempt + destAddr = new InetSocketAddress(loopbackAddr, 61); + try (SocketChannel sc3 = SocketChannel.open(destAddr)) { + } + return null; + } catch (ConnectException x) { + } + // the address which will generate a connection refused, when a connection is attempted + return destAddr; + } +} From 06d1345f2913830c273b9546c997e877f7958113 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 29 Jan 2026 08:39:10 +0000 Subject: [PATCH 241/328] 8373026: C2 SuperWord and Vector API: vector algorithms test and benchmark Co-authored-by: Otmar Ertl Reviewed-by: vlivanov, jbhateja, psandoz, xgong --- .../vectorization/TestVectorAlgorithms.java | 556 +++++++++++++ .../vectorization/VectorAlgorithmsImpl.java | 774 +++++++++++++++++ .../bench/vm/compiler/VectorAlgorithms.java | 274 +++++++ .../vm/compiler/VectorAlgorithmsImpl.java | 775 ++++++++++++++++++ 4 files changed, 2379 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java create mode 100644 test/hotspot/jtreg/compiler/vectorization/VectorAlgorithmsImpl.java create mode 100644 test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithms.java create mode 100644 test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithmsImpl.java diff --git a/test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java b/test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java new file mode 100644 index 00000000000..e02563c2fc2 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java @@ -0,0 +1,556 @@ +/* + * Copyright (c) 2026, 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=vanilla + * @bug 8373026 + * @summary Test auto vectorization and Vector API with some vector + * algorithms. Related benchmark: VectorAlgorithms.java + * @library /test/lib / + * @modules jdk.incubator.vector + * @run driver ${test.main.class} + */ + +/* + * @test id=noSuperWord + * @bug 8373026 + * @library /test/lib / + * @modules jdk.incubator.vector + * @run driver ${test.main.class} -XX:-UseSuperWord + */ + +/* + * @test id=noOptimizeFill + * @bug 8373026 + * @library /test/lib / + * @modules jdk.incubator.vector + * @run driver ${test.main.class} -XX:-OptimizeFill + */ + +package compiler.vectorization; + +import java.util.Map; +import java.util.HashMap; +import jdk.test.lib.Utils; +import java.util.Random; +import java.lang.foreign.*; + +import compiler.lib.ir_framework.*; +import compiler.lib.generators.*; +import static compiler.lib.generators.Generators.G; +import compiler.lib.verify.*; + +/** + * The goal of this benchmark is to show the power of auto vectorization + * and the Vector API. + * + * Please only modify this benchark in synchronization with the JMH benchmark: + * micro/org/openjdk/bench/vm/compiler/VectorAlgorithms.java + */ +public class TestVectorAlgorithms { + private static final Random RANDOM = Utils.getRandomInstance(); + private static final RestrictableGenerator INT_GEN = Generators.G.ints(); + + interface TestFunction { + Object run(int i); + } + + Map> testGroups = new HashMap>(); + + VectorAlgorithmsImpl.Data d; + + public static void main(String[] args) { + TestFramework framework = new TestFramework(); + framework.addFlags("--add-modules=jdk.incubator.vector", + "-XX:CompileCommand=inline,*VectorAlgorithmsImpl*::*"); + framework.addFlags(args); + framework.start(); + } + + public TestVectorAlgorithms () { + testGroups.put("fillI", new HashMap()); + testGroups.get("fillI").put("fillI_loop", i -> { return fillI_loop(d.rI1); }); + testGroups.get("fillI").put("fillI_VectorAPI", i -> { return fillI_VectorAPI(d.rI2); }); + testGroups.get("fillI").put("fillI_Arrays", i -> { return fillI_Arrays(d.rI3); }); + + testGroups.put("iotaI", new HashMap()); + testGroups.get("iotaI").put("iotaI_loop", i -> { return iotaI_loop(d.rI1); }); + testGroups.get("iotaI").put("iotaI_VectorAPI", i -> { return iotaI_VectorAPI(d.rI2); }); + + testGroups.put("copyI", new HashMap()); + testGroups.get("copyI").put("copyI_loop", i -> { return copyI_loop(d.aI, d.rI1); }); + testGroups.get("copyI").put("copyI_VectorAPI", i -> { return copyI_VectorAPI(d.aI, d.rI2); }); + testGroups.get("copyI").put("copyI_System_arraycopy", i -> { return copyI_System_arraycopy(d.aI, d.rI3); }); + + testGroups.put("mapI", new HashMap()); + testGroups.get("mapI").put("mapI_loop", i -> { return mapI_loop(d.aI, d.rI1); }); + testGroups.get("mapI").put("mapI_VectorAPI", i -> { return mapI_VectorAPI(d.aI, d.rI2); }); + + testGroups.put("reduceAddI", new HashMap()); + testGroups.get("reduceAddI").put("reduceAddI_loop", i -> { return reduceAddI_loop(d.aI); }); + testGroups.get("reduceAddI").put("reduceAddI_reassociate", i -> { return reduceAddI_reassociate(d.aI); }); + testGroups.get("reduceAddI").put("reduceAddI_VectorAPI_naive", i -> { return reduceAddI_VectorAPI_naive(d.aI); }); + testGroups.get("reduceAddI").put("reduceAddI_VectorAPI_reduction_after_loop", i -> { return reduceAddI_VectorAPI_reduction_after_loop(d.aI); }); + + testGroups.put("dotProductF", new HashMap()); + testGroups.get("dotProductF").put("dotProductF_loop", i -> { return dotProductF_loop(d.aF, d.bF); }); + testGroups.get("dotProductF").put("dotProductF_VectorAPI_naive", i -> { return dotProductF_VectorAPI_naive(d.aF, d.bF); }); + testGroups.get("dotProductF").put("dotProductF_VectorAPI_reduction_after_loop", i -> { return dotProductF_VectorAPI_reduction_after_loop(d.aF, d.bF); }); + + testGroups.put("hashCodeB", new HashMap()); + testGroups.get("hashCodeB").put("hashCodeB_loop", i -> { return hashCodeB_loop(d.aB); }); + testGroups.get("hashCodeB").put("hashCodeB_Arrays", i -> { return hashCodeB_Arrays(d.aB); }); + testGroups.get("hashCodeB").put("hashCodeB_VectorAPI_v1", i -> { return hashCodeB_VectorAPI_v1(d.aB); }); + testGroups.get("hashCodeB").put("hashCodeB_VectorAPI_v2", i -> { return hashCodeB_VectorAPI_v2(d.aB); }); + + testGroups.put("scanAddI", new HashMap()); + testGroups.get("scanAddI").put("scanAddI_loop", i -> { return scanAddI_loop(d.aI, d.rI1); }); + testGroups.get("scanAddI").put("scanAddI_loop_reassociate", i -> { return scanAddI_loop_reassociate(d.aI, d.rI2); }); + testGroups.get("scanAddI").put("scanAddI_VectorAPI_permute_add", i -> { return scanAddI_VectorAPI_permute_add(d.aI, d.rI4); }); + + testGroups.put("findMinIndexI", new HashMap()); + testGroups.get("findMinIndexI").put("findMinIndexI_loop", i -> { return findMinIndexI_loop(d.aI); }); + testGroups.get("findMinIndexI").put("findMinIndexI_VectorAPI", i -> { return findMinIndexI_VectorAPI(d.aI); }); + + testGroups.put("findI", new HashMap()); + testGroups.get("findI").put("findI_loop", i -> { return findI_loop(d.aI, d.eI[i]); }); + testGroups.get("findI").put("findI_VectorAPI", i -> { return findI_VectorAPI(d.aI, d.eI[i]); }); + + testGroups.put("reverseI", new HashMap()); + testGroups.get("reverseI").put("reverseI_loop", i -> { return reverseI_loop(d.aI, d.rI1); }); + testGroups.get("reverseI").put("reverseI_VectorAPI", i -> { return reverseI_VectorAPI(d.aI, d.rI2); }); + + testGroups.put("filterI", new HashMap()); + testGroups.get("filterI").put("filterI_loop", i -> { return filterI_loop(d.aI, d.rI1, d.eI[i]); }); + testGroups.get("filterI").put("filterI_VectorAPI", i -> { return filterI_VectorAPI(d.aI, d.rI2, d.eI[i]); }); + + testGroups.put("reduceAddIFieldsX4", new HashMap()); + testGroups.get("reduceAddIFieldsX4").put("reduceAddIFieldsX4_loop", i -> { return reduceAddIFieldsX4_loop(d.oopsX4, d.memX4); }); + testGroups.get("reduceAddIFieldsX4").put("reduceAddIFieldsX4_VectorAPI", i -> { return reduceAddIFieldsX4_VectorAPI(d.oopsX4, d.memX4); }); + + testGroups.put("lowerCaseB", new HashMap()); + testGroups.get("lowerCaseB").put("lowerCaseB_loop", i -> { return lowerCaseB_loop(d.strB, d.rB1); }); + testGroups.get("lowerCaseB").put("lowerCaseB_VectorAPI_v1", i -> { return lowerCaseB_VectorAPI_v1(d.strB, d.rB2); }); + testGroups.get("lowerCaseB").put("lowerCaseB_VectorAPI_v2", i -> { return lowerCaseB_VectorAPI_v2(d.strB, d.rB3); }); + } + + @Warmup(100) + @Run(test = {"fillI_loop", + "fillI_VectorAPI", + "fillI_Arrays", + "iotaI_loop", + "iotaI_VectorAPI", + "copyI_loop", + "copyI_VectorAPI", + "copyI_System_arraycopy", + "mapI_loop", + "mapI_VectorAPI", + "reduceAddI_loop", + "reduceAddI_reassociate", + "reduceAddI_VectorAPI_naive", + "reduceAddI_VectorAPI_reduction_after_loop", + "dotProductF_loop", + "dotProductF_VectorAPI_naive", + "dotProductF_VectorAPI_reduction_after_loop", + "hashCodeB_loop", + "hashCodeB_Arrays", + "hashCodeB_VectorAPI_v1", + "hashCodeB_VectorAPI_v2", + "scanAddI_loop", + "scanAddI_loop_reassociate", + "scanAddI_VectorAPI_permute_add", + "findMinIndexI_loop", + "findMinIndexI_VectorAPI", + "findI_loop", + "findI_VectorAPI", + "reverseI_loop", + "reverseI_VectorAPI", + "filterI_loop", + "filterI_VectorAPI", + "reduceAddIFieldsX4_loop", + "reduceAddIFieldsX4_VectorAPI", + "lowerCaseB_loop", + "lowerCaseB_VectorAPI_v1", + "lowerCaseB_VectorAPI_v2"}) + public void runTests(RunInfo info) { + // Repeat many times, so that we also have multiple iterations for post-warmup to potentially recompile + int iters = info.isWarmUp() ? 1 : 20; + for (int iter = 0; iter < iters; iter++) { + // Set up random inputs, random size is important to stress tails. + int size = 100_000 + RANDOM.nextInt(10_000); + int seed = RANDOM.nextInt(); + int numXObjects = 10_000; + d = new VectorAlgorithmsImpl.Data(size, seed, numXObjects); + + // Run all tests + for (Map.Entry> group_entry : testGroups.entrySet()) { + String group_name = group_entry.getKey(); + Map group = group_entry.getValue(); + Object gold = null; + String gold_name = "NONE"; + for (Map.Entry entry : group.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + Object result = test.run(iter); + if (gold == null) { + gold = result; + gold_name = name; + } else { + try { + Verify.checkEQ(gold, result); + } catch (VerifyException e) { + throw new RuntimeException("Verify.checkEQ failed for group " + group_name + + ", gold " + gold_name + ", test " + name, e); + } + } + } + } + } + } + + @Test + @IR(counts = {IRNode.REPLICATE_I, "= 1", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfAnd = {"UseSuperWord", "true", "OptimizeFill", "false"}) + @IR(counts = {".*CallLeafNoFP.*jint_fill.*", "= 1"}, + phase = CompilePhase.BEFORE_MATCHING, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIf = {"OptimizeFill", "true"}) + // By default, the fill intrinsic "jint_fill" is used, but we can disable + // the detection of the fill loop, and then we auto vectorize. + public Object fillI_loop(int[] r) { + return VectorAlgorithmsImpl.fillI_loop(r); + } + + @Test + @IR(counts = {IRNode.REPLICATE_I, "= 1", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + public Object fillI_VectorAPI(int[] r) { + return VectorAlgorithmsImpl.fillI_VectorAPI(r); + } + + @Test + // Arrays.fill is not necessarily inlined, so we can't check + // for vectors in the IR. + public Object fillI_Arrays(int[] r) { + return VectorAlgorithmsImpl.fillI_Arrays(r); + } + + @Test + @IR(counts = {IRNode.POPULATE_INDEX, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}, + applyIf = {"UseSuperWord", "true"}) + // Note: the Vector API example below can also vectorize for AVX, + // because it does not use a PopulateIndex. + public Object iotaI_loop(int[] r) { + return VectorAlgorithmsImpl.iotaI_loop(r); + } + + @Test + @IR(counts = {IRNode.ADD_VI, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeature = {"sse4.1", "true"}) + // Note: also works with NEON/asimd, but only with TieredCompilation. + public Object iotaI_VectorAPI(int[] r) { + return VectorAlgorithmsImpl.iotaI_VectorAPI(r); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIf = {"UseSuperWord", "true"}) + public Object copyI_loop(int[] a, int[] r) { + return VectorAlgorithmsImpl.copyI_loop(a, r); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + public Object copyI_VectorAPI(int[] a, int[] r) { + return VectorAlgorithmsImpl.copyI_VectorAPI(a, r); + } + + @Test + @IR(counts = {".*CallLeafNoFP.*jint_disjoint_arraycopy.*", "= 1"}, + phase = CompilePhase.BEFORE_MATCHING, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + public Object copyI_System_arraycopy(int[] a, int[] r) { + return VectorAlgorithmsImpl.copyI_System_arraycopy(a, r); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.MUL_VI, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIf = {"UseSuperWord", "true"}) + public Object mapI_loop(int[] a, int[] r) { + return VectorAlgorithmsImpl.mapI_loop(a, r); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.MUL_VI, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + public Object mapI_VectorAPI(int[] a, int[] r) { + return VectorAlgorithmsImpl.mapI_VectorAPI(a, r); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.ADD_REDUCTION_VI, "> 0", + IRNode.ADD_VI, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIf = {"UseSuperWord", "true"}) + public int reduceAddI_loop(int[] a) { + return VectorAlgorithmsImpl.reduceAddI_loop(a); + } + + @Test + public int reduceAddI_reassociate(int[] a) { + return VectorAlgorithmsImpl.reduceAddI_reassociate(a); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.ADD_REDUCTION_VI, "> 0"}, // reduceLanes inside loop + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + public int reduceAddI_VectorAPI_naive(int[] a) { + return VectorAlgorithmsImpl.reduceAddI_VectorAPI_naive(a); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", + IRNode.ADD_REDUCTION_V, "> 0", + IRNode.MUL_VF, "> 0"}, + applyIfCPUFeature = {"sse4.1", "true"}, + applyIf = {"UseSuperWord", "true"}) + // See also TestReduction.floatAddDotProduct + public float dotProductF_loop(float[] a, float[] b) { + return VectorAlgorithmsImpl.dotProductF_loop(a, b); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", + IRNode.ADD_REDUCTION_V, "> 0", + IRNode.MUL_VF, "> 0"}, + applyIfCPUFeature = {"sse4.1", "true"}, + applyIf = {"UseSuperWord", "true"}) + public float dotProductF_VectorAPI_naive(float[] a, float[] b) { + return VectorAlgorithmsImpl.dotProductF_VectorAPI_naive(a, b); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", + IRNode.ADD_REDUCTION_V, "> 0", + IRNode.MUL_VF, "> 0"}, + applyIfCPUFeature = {"sse4.1", "true"}, + applyIf = {"UseSuperWord", "true"}) + public float dotProductF_VectorAPI_reduction_after_loop(float[] a, float[] b) { + return VectorAlgorithmsImpl.dotProductF_VectorAPI_reduction_after_loop(a, b); + } + + @Test + public int hashCodeB_loop(byte[] a) { + return VectorAlgorithmsImpl.hashCodeB_loop(a); + } + + @Test + public int hashCodeB_Arrays(byte[] a) { + return VectorAlgorithmsImpl.hashCodeB_Arrays(a); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, IRNode.VECTOR_SIZE_8, "> 0", + IRNode.VECTOR_CAST_B2I, IRNode.VECTOR_SIZE_8, "> 0", + IRNode.MUL_VI, IRNode.VECTOR_SIZE_8, "> 0", + IRNode.ADD_VI, IRNode.VECTOR_SIZE_8, "> 0", + IRNode.ADD_REDUCTION_VI, "> 0"}, + applyIfCPUFeature = {"avx2", "true"}) + public int hashCodeB_VectorAPI_v1(byte[] a) { + return VectorAlgorithmsImpl.hashCodeB_VectorAPI_v1(a); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.MUL_VI, "> 0", + IRNode.ADD_VI, "> 0", + IRNode.ADD_REDUCTION_VI, "> 0"}, + applyIfCPUFeature = {"avx2", "true"}) + public int hashCodeB_VectorAPI_v2(byte[] a) { + return VectorAlgorithmsImpl.hashCodeB_VectorAPI_v2(a); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.ADD_REDUCTION_VI, "> 0", + IRNode.ADD_VI, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + public int reduceAddI_VectorAPI_reduction_after_loop(int[] a) { + return VectorAlgorithmsImpl.reduceAddI_VectorAPI_reduction_after_loop(a); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0"}) + // Currently does not vectorize, but might in the future. + public Object scanAddI_loop(int[] a, int[] r) { + return VectorAlgorithmsImpl.scanAddI_loop(a, r); + } + + @Test + public Object scanAddI_loop_reassociate(int[] a, int[] r) { + return VectorAlgorithmsImpl.scanAddI_loop_reassociate(a, r); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.REARRANGE_VI, "> 0", + IRNode.AND_VI, "> 0", + IRNode.ADD_VI, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIf = {"MaxVectorSize", ">=64"}) + public Object scanAddI_VectorAPI_permute_add(int[] a, int[] r) { + return VectorAlgorithmsImpl.scanAddI_VectorAPI_permute_add(a, r); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0"}) + // Currently does not vectorize, but might in the future. + public int findMinIndexI_loop(int[] a) { + return VectorAlgorithmsImpl.findMinIndexI_loop(a); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.VECTOR_MASK_CMP, "> 0", + IRNode.VECTOR_BLEND_I, "> 0", + IRNode.MIN_REDUCTION_V, "> 0", + IRNode.ADD_VI, "> 0"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + public int findMinIndexI_VectorAPI(int[] a) { + return VectorAlgorithmsImpl.findMinIndexI_VectorAPI(a); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0"}) + // Currently does not vectorize, but might in the future. + public int findI_loop(int[] a, int e) { + return VectorAlgorithmsImpl.findI_loop(a, e); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.VECTOR_MASK_CMP, "> 0", + IRNode.VECTOR_TEST, "> 0"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + public int findI_VectorAPI(int[] a, int e) { + return VectorAlgorithmsImpl.findI_VectorAPI(a, e); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0"}) + // Currently does not vectorize, but might in the future. + public Object reverseI_loop(int[] a, int[] r) { + return VectorAlgorithmsImpl.reverseI_loop(a, r); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.REARRANGE_VI, "> 0", + IRNode.AND_VI, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + public Object reverseI_VectorAPI(int[] a, int[] r) { + return VectorAlgorithmsImpl.reverseI_VectorAPI(a, r); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0"}) + public Object filterI_loop(int[] a, int[] r, int threshold) { + return VectorAlgorithmsImpl.filterI_loop(a, r, threshold); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.VECTOR_MASK_CMP, "> 0", + IRNode.VECTOR_TEST, "> 0", + IRNode.COMPRESS_VI, "> 0", + IRNode.STORE_VECTOR_MASKED, "> 0"}, + applyIfCPUFeature = {"avx2", "true"}) + public Object filterI_VectorAPI(int[] a, int[] r, int threshold) { + return VectorAlgorithmsImpl.filterI_VectorAPI(a, r, threshold); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0"}) + // Currently does not vectorize, but might in the future. + public int reduceAddIFieldsX4_loop(int[] oops, int[] mem) { + return VectorAlgorithmsImpl.reduceAddIFieldsX4_loop(oops, mem); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.VECTOR_MASK_CMP, "> 0", + IRNode.VECTOR_TEST, "> 0", + IRNode.LOAD_VECTOR_GATHER_MASKED, "> 0", + IRNode.OR_V_MASK, "> 0", + IRNode.ADD_VI, "> 0", + IRNode.ADD_REDUCTION_VI, "> 0"}, + applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public int reduceAddIFieldsX4_VectorAPI(int[] oops, int[] mem) { + return VectorAlgorithmsImpl.reduceAddIFieldsX4_VectorAPI(oops, mem); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0"}) + // Currently does not vectorize, but might in the future. + public Object lowerCaseB_loop(byte[] a, byte[] r) { + return VectorAlgorithmsImpl.lowerCaseB_loop(a, r); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.ADD_VB, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + public Object lowerCaseB_VectorAPI_v1(byte[] a, byte[] r) { + return VectorAlgorithmsImpl.lowerCaseB_VectorAPI_v1(a, r); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.ADD_VB, "> 0"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + public Object lowerCaseB_VectorAPI_v2(byte[] a, byte[] r) { + return VectorAlgorithmsImpl.lowerCaseB_VectorAPI_v2(a, r); + } +} diff --git a/test/hotspot/jtreg/compiler/vectorization/VectorAlgorithmsImpl.java b/test/hotspot/jtreg/compiler/vectorization/VectorAlgorithmsImpl.java new file mode 100644 index 00000000000..2dfac704069 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorization/VectorAlgorithmsImpl.java @@ -0,0 +1,774 @@ +/* + * Copyright (c) 2026, 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.vectorization; + +import java.util.Arrays; +import java.util.Random; +import jdk.incubator.vector.*; + +/** + * The code below is supposed to be an exact copy of: + * micro/org/openjdk/bench/vm/compiler/VectorAlgorithmsImpl.java + */ +public class VectorAlgorithmsImpl { + private static final VectorSpecies SPECIES_I = IntVector.SPECIES_PREFERRED; + private static final VectorSpecies SPECIES_I512 = IntVector.SPECIES_512; + private static final VectorSpecies SPECIES_I256 = IntVector.SPECIES_256; + private static final VectorSpecies SPECIES_B = ByteVector.SPECIES_PREFERRED; + private static final VectorSpecies SPECIES_B64 = ByteVector.SPECIES_64; + private static final VectorSpecies SPECIES_F = FloatVector.SPECIES_PREFERRED; + + // This class stores the input and output arrays. + // The constructor sets up all the data. + // + // IMPORTANT: + // If you want to use some array but do NOT modify it: just use it. + // If you want to use it and DO want to modify it: clone it. This + // ensures that each test gets a separate copy, and that when we + // capture the modified arrays they are different for every method + // and run. + // An alternative to cloning is to use different return arrays for + // different implementations of the same group, e.g. rI1, rI2, ... + // + public static class Data { + public int[] aI; + public int[] rI1; + public int[] rI2; + public int[] rI3; + public int[] rI4; + public int[] eI; + // The test has to use the same index into eI for all implementations. But in the + // benchmark, we'd like to use random indices, so we use the index to advance through + // the array. + public int eI_idx = 0; + + public float[] aF; + public float[] bF; + + public byte[] aB; + public byte[] strB; + public byte[] rB1; + public byte[] rB2; + public byte[] rB3; + + public int[] oopsX4; + public int[] memX4; + + public Data(int size, int seed, int numX4Objects) { + Random random = new Random(seed); + + // int: one input array and multiple output arrays so different implementations can + // store their results to different arrays. + aI = new int[size]; + rI1 = new int[size]; + rI2 = new int[size]; + rI3 = new int[size]; + rI4 = new int[size]; + Arrays.setAll(aI, i -> random.nextInt()); + + // Populate with some random values from aI, and some totally random values. + eI = new int[0x10000]; + for (int i = 0; i < eI.length; i++) { + eI[i] = (random.nextInt(10) == 0) ? random.nextInt() : aI[random.nextInt(size)]; + } + + // X4 oop setup. + // oopsX4 holds "addresses" (i.e. indices), that point to the 16-byte objects in memX4. + oopsX4 = new int[size]; + memX4 = new int[numX4Objects * 4]; + for (int i = 0; i < size; i++) { + // assign either a zero=null, or assign a random oop. + oopsX4[i] = (random.nextInt(10) == 0) ? 0 : random.nextInt(numX4Objects) * 4; + } + // Just fill the whole array with random values. + // The relevant field is only at every "4 * i + 3" though. + memX4 = new int[4 * numX4Objects]; + for (int i = 0; i < memX4.length; i++) { + memX4[i] = random.nextInt(); + } + + // float inputs. To avoid rounding issues, only use small integers. + aF = new float[size]; + bF = new float[size]; + for (int i = 0; i < size; i++) { + aF[i] = random.nextInt(32) - 16; + bF[i] = random.nextInt(32) - 16; + } + + // byte: just random data. + aB = new byte[size]; + strB = new byte[size]; + rB1 = new byte[size]; + rB2 = new byte[size]; + rB3 = new byte[size]; + random.nextBytes(aB); + random.nextBytes(strB); // TODO: special data! + } + } + + public static Object fillI_loop(int[] r) { + for (int i = 0; i < r.length; i++) { + r[i] = 42; + } + return r; + } + + public static Object fillI_Arrays(int[] r) { + Arrays.fill(r, 42); + return r; + } + + public static Object fillI_VectorAPI(int[] r) { + var v = IntVector.broadcast(SPECIES_I, 42); + int i = 0; + for (; i < SPECIES_I.loopBound(r.length); i += SPECIES_I.length()) { + v.intoArray(r, i); + } + for (; i < r.length; i++) { + r[i] = 42; + } + return r; + } + + public static Object iotaI_loop(int[] r) { + for (int i = 0; i < r.length; i++) { + r[i] = i; + } + return r; + } + + public static Object iotaI_VectorAPI(int[] r) { + var iota = IntVector.broadcast(SPECIES_I, 0).addIndex(1); + int i = 0; + for (; i < SPECIES_I.loopBound(r.length); i += SPECIES_I.length()) { + iota.intoArray(r, i); + iota = iota.add(SPECIES_I.length()); + } + for (; i < r.length; i++) { + r[i] = i; + } + return r; + } + + public static Object copyI_loop(int[] a, int[] r) { + for (int i = 0; i < a.length; i++) { + r[i] = a[i]; + } + return r; + } + + public static Object copyI_System_arraycopy(int[] a, int[] r) { + System.arraycopy(a, 0, r, 0, a.length); + return r; + } + + public static Object copyI_VectorAPI(int[] a, int[] r) { + int i = 0; + for (; i < SPECIES_I.loopBound(r.length); i += SPECIES_I.length()) { + IntVector v = IntVector.fromArray(SPECIES_I, a, i); + v.intoArray(r, i); + } + for (; i < r.length; i++) { + r[i] = a[i]; + } + return r; + } + + public static Object mapI_loop(int[] a, int[] r) { + for (int i = 0; i < a.length; i++) { + r[i] = a[i] * 42; + } + return r; + } + + public static Object mapI_VectorAPI(int[] a, int[] r) { + int i = 0; + for (; i < SPECIES_I.loopBound(r.length); i += SPECIES_I.length()) { + IntVector v = IntVector.fromArray(SPECIES_I, a, i); + v = v.mul(42); + v.intoArray(r, i); + } + for (; i < r.length; i++) { + r[i] = a[i] * 42; + } + return r; + } + + public static int reduceAddI_loop(int[] a) { + int sum = 0; + for (int i = 0; i < a.length; i++) { + // Relying on simple reduction loop should vectorize since JDK26. + sum += a[i]; + } + return sum; + } + + public static int reduceAddI_reassociate(int[] a) { + int sum = 0; + int i; + for (i = 0; i < a.length - 3; i += 4) { + // Unroll 4x, reassociate inside. + sum += a[i] + a[i + 1] + a[i + 2] + a[i + 3]; + } + for (; i < a.length; i++) { + // Tail + sum += a[i]; + } + return sum; + } + + public static int reduceAddI_VectorAPI_naive(int[] a) { + var sum = 0; + int i; + for (i = 0; i < SPECIES_I.loopBound(a.length); i += SPECIES_I.length()) { + IntVector v = IntVector.fromArray(SPECIES_I, a, i); + // reduceLanes in loop is better than scalar performance, but still + // relatively slow. + sum += v.reduceLanes(VectorOperators.ADD); + } + for (; i < a.length; i++) { + sum += a[i]; + } + return sum; + } + + public static int reduceAddI_VectorAPI_reduction_after_loop(int[] a) { + var acc = IntVector.broadcast(SPECIES_I, 0); + int i; + for (i = 0; i < SPECIES_I.loopBound(a.length); i += SPECIES_I.length()) { + IntVector v = IntVector.fromArray(SPECIES_I, a, i); + // Element-wide addition into a vector of partial sums is much faster. + // Now, we only need to do a reduceLanes after the loop. + // This works because int-addition is associative and commutative. + acc = acc.add(v); + } + int sum = acc.reduceLanes(VectorOperators.ADD); + for (; i < a.length; i++) { + sum += a[i]; + } + return sum; + } + + public static float dotProductF_loop(float[] a, float[] b) { + float sum = 0; + for (int i = 0; i < a.length; i++) { + sum += a[i] * b[i]; + } + return sum; + } + + public static float dotProductF_VectorAPI_naive(float[] a, float[] b) { + float sum = 0; + int i; + for (i = 0; i < SPECIES_F.loopBound(a.length); i += SPECIES_F.length()) { + var va = FloatVector.fromArray(SPECIES_F, a, i); + var vb = FloatVector.fromArray(SPECIES_F, b, i); + sum += va.mul(vb).reduceLanes(VectorOperators.ADD); + } + for (; i < a.length; i++) { + sum += a[i] * b[i]; + } + return sum; + } + + public static float dotProductF_VectorAPI_reduction_after_loop(float[] a, float[] b) { + var sums = FloatVector.broadcast(SPECIES_F, 0.0f); + int i; + for (i = 0; i < SPECIES_F.loopBound(a.length); i += SPECIES_F.length()) { + var va = FloatVector.fromArray(SPECIES_F, a, i); + var vb = FloatVector.fromArray(SPECIES_F, b, i); + sums = sums.add(va.mul(vb)); + } + float sum = sums.reduceLanes(VectorOperators.ADD); + for (; i < a.length; i++) { + sum += a[i] * b[i]; + } + return sum; + } + + public static int hashCodeB_loop(byte[] a) { + int h = 1; + for (int i = 0; i < a.length; i++) { + h = 31 * h + a[i]; + } + return h; + } + + public static int hashCodeB_Arrays(byte[] a) { + return Arrays.hashCode(a); + } + + // Simplified intrinsic code from C2_MacroAssembler::arrays_hashcode in c2_MacroAssembler_x86.cpp + // + // Ideas that may help understand the code: + // h(i) = 31 * h(i-1) + a[i] + // "unroll" by factor of L=8: + // h(i+8) = h(i) * 31^8 + a[i+1] * 31^7 + a[i+2] * 31^6 + ... + a[i+8] * 1 + // ----------- ------------------------------------------------ + // scalar vector: notice the powers of 31 in reverse + // + // We notice that we can load a[i+1 .. i+8], then element-wise multiply with + // the vector of reversed powers-of-31, and then do reduceLanes(ADD). + // But we can do even better: By looking at multiple such 8-unrolled iterations. + // Instead of applying the "next" factor of "31^8" to the reduced scalar, we can + // already apply it element-wise. That allows us to move the reduction out + // of the loop. + // + // Note: the intrinsic additionally unrolls the loop by a factor of 4, + // but we want to keep thins simple for demonstration purposes. + // + private static int[] REVERSE_POWERS_OF_31 = new int[9]; + static { + int p = 1; + for (int i = REVERSE_POWERS_OF_31.length - 1; i >= 0; i--) { + REVERSE_POWERS_OF_31[i] = p; + p *= 31; + } + } + public static int hashCodeB_VectorAPI_v1(byte[] a) { + int result = 1; // initialValue + var vresult = IntVector.zero(SPECIES_I256); + int next = REVERSE_POWERS_OF_31[0]; // 31^L + var vcoef = IntVector.fromArray(SPECIES_I256, REVERSE_POWERS_OF_31, 1); // powers of 2 in reverse + int i; + for (i = 0; i < SPECIES_B64.loopBound(a.length); i += SPECIES_B64.length()) { + // scalar part: result *= 31^L + result *= next; + // vector part: element-wise apply the next factor and add in the new values. + var vb = ByteVector.fromArray(SPECIES_B64, a, i); + var vi = vb.castShape(SPECIES_I256, 0); + vresult = vresult.mul(next).add(vi); + } + // reduce the partial hashes in the elements, using the reverse list of powers of 2. + result += vresult.mul(vcoef).reduceLanes(VectorOperators.ADD); + for (; i < a.length; i++) { + result = 31 * result + a[i]; + } + return result; + } + + // This second approach follows the idea from this blog post by Otmar Ertl: + // https://www.dynatrace.com/news/blog/java-arrays-hashcode-byte-efficiency-techniques/ + // + // I simplified the algorithm a little, so that it is a bit closer + // to the solution "v1" above. + // + // The major issue with "v1" is that we cannot load a full vector of bytes, + // because of the cast to ints. So we can only fill 1/4 of the maximal + // vector size. The trick here is to do an unrolling of factor 4, from: + // h(i) = 31 * h(i-1) + a[i] + // to: + // h(i+4) = h(i) * 31^4 + a[i + 1] * 31^3 + // + a[i + 2] * 31^2 + // + a[i + 3] * 31^1 + // + a[i + 4] * 31^0 + // The goal is now to compute this value for 4 bytes within a 4 byte + // lane of the vector. One concern is that we start with byte values, + // but need to do int-multiplication with powers of 31. If we instead + // did a byte-multiplication, we could get overflows that we would not + // have had in the int-multiplication. + // One trick that helps with chaning the size of the lanes from byte + // to short to int is doing all operations with unsigned integers. That + // way, we can zero-extend instead of sign-bit extend. The first step + // is thus to convert the bytes into unsigned values. Since byte is in + // range [-128..128), doing "a[i+j] + 128" makes it a positive value, + // allowing for unsigned multiplication. + // h(i+4) = h(i) * 31^4 + a[i + 1] * 31^3 + // + a[i + 2] * 31^2 + // + a[i + 3] * 31^1 + // + a[i + 4] * 31^0 + // = h(i) * 31^4 + (a[i + 1] + 128 - 128) * 31^3 + // + (a[i + 2] + 128 - 128) * 31^2 + // + (a[i + 3] + 128 - 128) * 31^1 + // + (a[i + 4] + 128 - 128) * 31^0 + // = h(i) * 31^4 + (a[i + 1] + 128 ) * 31^3 + // + (a[i + 2] + 128 ) * 31^2 + // + (a[i + 3] + 128 ) * 31^1 + // + (a[i + 4] + 128 ) * 31^0 + // + -128 * (31^3 + 31^2 + 31^1 + 1) + // = h(i) * 31^4 + ((a[i + 1] + 128) * 31 + // + (a[i + 2] + 128 ) * 31^2 + // + ((a[i + 3] + 128) * 31 + // + (a[i + 4] + 128 ) + // + -128 * (31^3 + 31^2 + 31^1 + 1) + // + // Getting from the signed a[i] value to unsigned with +128, we can + // just xor with 0x80=128. Any numbers there in range [-128..0) are + // now in range [0..128). And any numbers that were in range [0..128) + // are now in unsigned range [128..255). What a neat trick! + // + // We then apply a byte->short transition where we crunch 2 bytes + // into one short, applying a multiplication with 31 to one of the + // two bytes. This multiplication cannot overflow in a short. + // then we apply a short->int transition where we crunch 2 shorts + // into one int, applying a multiplication with 31^2 to one of the + // two shorts. This multiplication cannot overflow in an int. + // + public static int hashCodeB_VectorAPI_v2(byte[] a) { + return HashCodeB_VectorAPI_V2.compute(a); + } + + private static class HashCodeB_VectorAPI_V2 { + private static final int L = Math.min(ByteVector.SPECIES_PREFERRED.length(), + IntVector.SPECIES_PREFERRED.length() * 4); + private static final VectorShape SHAPE = VectorShape.forBitSize(8 * L); + private static final VectorSpecies SPECIES_B = SHAPE.withLanes(byte.class); + private static final VectorSpecies SPECIES_I = SHAPE.withLanes(int.class); + + private static int[] REVERSE_POWERS_OF_31_STEP_4 = new int[L / 4 + 1]; + static { + int p = 1; + int step = 31 * 31 * 31 * 31; // step by 4 + for (int i = REVERSE_POWERS_OF_31_STEP_4.length - 1; i >= 0; i--) { + REVERSE_POWERS_OF_31_STEP_4[i] = p; + p *= step; + } + } + + public static int compute(byte[] a) { + int result = 1; // initialValue + int next = REVERSE_POWERS_OF_31_STEP_4[0]; // 31^L + var vcoef = IntVector.fromArray(SPECIES_I, REVERSE_POWERS_OF_31_STEP_4, 1); // W + var vresult = IntVector.zero(SPECIES_I); + int i; + for (i = 0; i < SPECIES_B.loopBound(a.length); i += SPECIES_B.length()) { + var vb = ByteVector.fromArray(SPECIES_B, a, i); + // Add 128 to each byte. + var vs = vb.lanewise(VectorOperators.XOR, (byte)0x80) + .reinterpretAsShorts(); + // Each short lane contains 2 bytes, crunch them. + var vi = vs.and((short)0xff) // lower byte + .mul((short)31) + .add(vs.lanewise(VectorOperators.LSHR, 8)) // upper byte + .reinterpretAsInts(); + // Each int contains 2 shorts, crunch them. + var v = vi.and(0xffff) // lower short + .mul(31 * 31) + .add(vi.lanewise(VectorOperators.LSHR, 16)); // upper short + // Add the correction for the 128 additions above. + v = v.add(-128 * (31*31*31 + 31*31 + 31 + 1)); + // Every element of v now contains a crunched int-package of 4 bytes. + result *= next; + vresult = vresult.mul(next).add(v); + } + result += vresult.mul(vcoef).reduceLanes(VectorOperators.ADD); + for (; i < a.length; i++) { + result = 31 * result + a[i]; + } + return result; + } + } + + public static Object scanAddI_loop(int[] a, int[] r) { + int sum = 0; + for (int i = 0; i < a.length; i++) { + sum += a[i]; + r[i] = sum; + } + return r; + } + + public static Object scanAddI_loop_reassociate(int[] a, int[] r) { + int sum = 0; + int i = 0; + for (; i < a.length - 3; i += 4) { + // We cut the latency by a factor of 4, but increase the number of additions. + int old_sum = sum; + int v0 = a[i + 0]; + int v1 = a[i + 1]; + int v2 = a[i + 2]; + int v3 = a[i + 3]; + int v01 = v0 + v1; + int v23 = v2 + v3; + int v0123 = v01 + v23; + sum += v0123; + r[i + 0] = old_sum + v0; + r[i + 1] = old_sum + v01; + r[i + 2] = old_sum + v01 + v2; + r[i + 3] = old_sum + v0123; + } + for (; i < a.length; i++) { + sum += a[i]; + r[i] = sum; + } + return r; + } + + public static Object scanAddI_VectorAPI_permute_add(int[] a, int[] r) { + // Using Naive Parallel Algorithm: Hills and Steele + int sum = 0; + int xx = 0; // masked later anyway + var shf1 = VectorShuffle.fromArray(SPECIES_I512, new int[]{xx, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 0); + var shf2 = VectorShuffle.fromArray(SPECIES_I512, new int[]{xx, xx, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 0); + var shf3 = VectorShuffle.fromArray(SPECIES_I512, new int[]{xx, xx, xx, xx, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 0); + var shf4 = VectorShuffle.fromArray(SPECIES_I512, new int[]{xx, xx, xx, xx, xx, xx, xx, xx, 0, 1, 2, 3, 4, 5, 6, 7}, 0); + var mask1 = VectorMask.fromLong(SPECIES_I512, 0b1111111111111110); + var mask2 = VectorMask.fromLong(SPECIES_I512, 0b1111111111111100); + var mask3 = VectorMask.fromLong(SPECIES_I512, 0b1111111111110000); + var mask4 = VectorMask.fromLong(SPECIES_I512, 0b1111111100000000); + int i = 0; + for (; i < SPECIES_I512.loopBound(a.length); i += SPECIES_I512.length()) { + IntVector v = IntVector.fromArray(SPECIES_I512, a, i); + v = v.add(v.rearrange(shf1), mask1); + v = v.add(v.rearrange(shf2), mask2); + v = v.add(v.rearrange(shf3), mask3); + v = v.add(v.rearrange(shf4), mask4); + v = v.add(sum); + v.intoArray(r, i); + sum = v.lane(SPECIES_I512.length() - 1); + } + for (; i < a.length; i++) { + sum += a[i]; + r[i] = sum; + } + return r; + } + + public static int findMinIndexI_loop(int[] a) { + int min = a[0]; + int index = 0; + for (int i = 1; i < a.length; i++) { + int ai = a[i]; + if (ai < min) { + min = ai; + index = i; + } + } + return index; + } + + public static int findMinIndexI_VectorAPI(int[] a) { + // Main approach: have partial results in mins and idxs. + var mins = IntVector.broadcast(SPECIES_I, a[0]); + var idxs = IntVector.broadcast(SPECIES_I, 0); + var iota = IntVector.broadcast(SPECIES_I, 0).addIndex(1); + int i = 0; + for (; i < SPECIES_I.loopBound(a.length); i += SPECIES_I.length()) { + IntVector v = IntVector.fromArray(SPECIES_I, a, i); + var mask = v.compare(VectorOperators.LT, mins); + mins = mins.blend(v, mask); + idxs = idxs.blend(iota, mask); + iota = iota.add(SPECIES_I.length()); + } + // Reduce the vectors down + int min = mins.reduceLanes(VectorOperators.MIN); + var not_min_mask = mins.compare(VectorOperators.NE, min); + int index = idxs.blend(a.length, not_min_mask).reduceLanes(VectorOperators.MIN); + // Tail loop + for (; i < a.length; i++) { + int ai = a[i]; + if (ai < min) { + min = ai; + index = i; + } + } + return index; + } + + public static int findI_loop(int[] a, int e) { + for (int i = 0; i < a.length; i++) { + int ai = a[i]; + if (ai == e) { + return i; + } + } + return -1; + } + + public static int findI_VectorAPI(int[] a, int e) { + var es = IntVector.broadcast(SPECIES_I, e); + int i = 0; + for (; i < SPECIES_I.loopBound(a.length); i += SPECIES_I.length()) { + IntVector v = IntVector.fromArray(SPECIES_I, a, i); + var mask = v.compare(VectorOperators.EQ, es); + if (mask.anyTrue()) { + return i + mask.firstTrue(); + } + } + for (; i < a.length; i++) { + int ai = a[i]; + if (ai == e) { + return i; + } + } + return -1; + } + + public static Object reverseI_loop(int[] a, int[] r) { + for (int i = 0; i < a.length; i++) { + r[a.length - i - 1] = a[i]; + } + return r; + } + + private static final VectorShuffle REVERSE_SHUFFLE_I = SPECIES_I.iotaShuffle(SPECIES_I.length()-1, -1, true); + + public static Object reverseI_VectorAPI(int[] a, int[] r) { + int i = 0; + for (; i < SPECIES_I.loopBound(a.length); i += SPECIES_I.length()) { + IntVector v = IntVector.fromArray(SPECIES_I, a, i); + v = v.rearrange(REVERSE_SHUFFLE_I); + v.intoArray(r, r.length - SPECIES_I.length() - i); + } + for (; i < a.length; i++) { + r[a.length - i - 1] = a[i]; + } + return r; + } + + public static Object filterI_loop(int[] a, int[] r, int threshold) { + int j = 0; + for (int i = 0; i < a.length; i++) { + int ai = a[i]; + if (ai >= threshold) { + r[j++] = ai; + } + } + // Just force the resulting length onto the same array. + r[r.length - 1] = j; + return r; + } + + public static Object filterI_VectorAPI(int[] a, int[] r, int threshold) { + var thresholds = IntVector.broadcast(SPECIES_I, threshold); + int j = 0; + int i = 0; + for (; i < SPECIES_I.loopBound(a.length); i += SPECIES_I.length()) { + IntVector v = IntVector.fromArray(SPECIES_I, a, i); + var mask = v.compare(VectorOperators.GE, thresholds); + v = v.compress(mask); + int trueCount = mask.trueCount(); + var prefixMask = mask.compress(); + v.intoArray(r, j, prefixMask); + j += trueCount; + } + + for (; i < a.length; i++) { + int ai = a[i]; + if (ai >= threshold) { + r[j++] = ai; + } + } + // Just force the resulting length onto the same array. + r[r.length - 1] = j; + return r; + } + + // X4: ints simulate 4-byte oops. + // oops: if non-zero (= non-null), every entry simulates a 4-byte oop, pointing into mem. + // mem: an int array that simulates the memory. + // + // Task: Find all non-null oops, and dereference them, get the relevant field. + // Objects have 16 bytes, and the relevant field is at bytes 12-16. + // That maps to 4 ints, and the relevant field is the 4th element of 4. + // Sum up all the field values. + public static int reduceAddIFieldsX4_loop(int[] oops, int[] mem) { + int sum = 0; + for (int i = 0; i < oops.length; i++) { + int oop = oops[i]; + if (oop != 0) { + int fieldValue = mem[oop + 3]; // oop+12 + sum += fieldValue; + } + } + return sum; + } + + public static int reduceAddIFieldsX4_VectorAPI(int[] oops, int[] mem) { + var acc = IntVector.broadcast(SPECIES_I, 0); + int i = 0; + for (; i < SPECIES_I.loopBound(oops.length); i += SPECIES_I.length()) { + var oopv = IntVector.fromArray(SPECIES_I, oops, i); + var mask = oopv.compare(VectorOperators.NE, /* null */0); + // We are lucky today: we need to access mem[oop + 3] + var fieldValues = IntVector.fromArray(SPECIES_I, mem, 3, oops, i, mask); + acc = acc.add(fieldValues); + } + int sum = acc.reduceLanes(VectorOperators.ADD); + for (; i < oops.length; i++) { + int oop = oops[i]; + if (oop != 0) { + int fieldValue = mem[oop + 3]; // oop+12 + sum += fieldValue; + } + } + return sum; + } + + // The lowerCase example demonstrates a lane-wise control-flow diamond. + public static Object lowerCaseB_loop(byte[] a, byte[] r) { + for (int i = 0; i < a.length; i++) { + byte c = a[i]; + if (c >= 'A' && c <= 'Z') { + c += ('a' - 'A'); // c += 32 + } + r[i] = c; + } + return r; + } + + // Control-flow diamonds can easily be simulated by "if-conversion", i.e. + // by using masked operations. An alternative would be to use blend. + public static Object lowerCaseB_VectorAPI_v1(byte[] a, byte[] r) { + int i; + for (i = 0; i < SPECIES_B.loopBound(a.length); i += SPECIES_B.length()) { + var vc = ByteVector.fromArray(SPECIES_B, a, i); + var maskA = vc.compare(VectorOperators.GE, (byte)'A'); + var maskZ = vc.compare(VectorOperators.LE, (byte)'Z'); + var mask = maskA.and(maskZ); + vc = vc.add((byte)32, mask); + vc.intoArray(r, i); + } + for (; i < a.length; i++) { + byte c = a[i]; + if (c >= 'A' && c <= 'Z') { + c += ('a' - 'A'); + } + r[i] = c; + } + return r; + } + + public static Object lowerCaseB_VectorAPI_v2(byte[] a, byte[] r) { + int i; + for (i = 0; i < SPECIES_B.loopBound(a.length); i += SPECIES_B.length()) { + var vc = ByteVector.fromArray(SPECIES_B, a, i); + // We can convert the range 65..90 (represents ascii A..Z) into a range 0..25. + // This allows us to only use a single unsigned comparison. + var vt = vc.add((byte)-'A'); + var mask = vt.compare(VectorOperators.ULE, (byte)25); + vc = vc.add((byte)32, mask); + vc.intoArray(r, i); + } + for (; i < a.length; i++) { + byte c = a[i]; + if (c >= 'A' && c <= 'Z') { + c += ('a' - 'A'); + } + r[i] = c; + } + return r; + } +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithms.java b/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithms.java new file mode 100644 index 00000000000..911494cb022 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithms.java @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.bench.vm.compiler; + +import java.util.Arrays; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.*; + +/** + * The goal of this benchmark is to show the power of auto vectorization + * and the Vector API. + * + * Please only modify this benchark in synchronization with the IR test: + * test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java + * + * You may want to play with the following VM flags: + * - Disable auto vectorization: + * -XX:+UnlockDiagnosticVMOptions -XX:AutoVectorizationOverrideProfitability=0 + * - Smaller vector size: + * -XX:MaxVectorSize=16 + * - Disable fill loop detection, so we don't use intrinsic but auto vectorization: + * -XX:-OptimizeFill + * - Lilliput can also have an effect, because it can change alignment and have + * an impact on which exact intrinsic is chosen (e.g. fill and copy): + * -XX:+UseCompactObjectHeaders + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 3, time = 1) +@Fork(value = 5, jvmArgs = {"--add-modules=jdk.incubator.vector", "-XX:CompileCommand=inline,*VectorAlgorithmsImpl*::*"}) +public class VectorAlgorithms { + @Param({"640000"}) + public int SIZE; + + @Param({"10000"}) + public int NUM_X_OBJECTS; + + @Param({"0"}) + public int SEED; + + VectorAlgorithmsImpl.Data d; + + @Setup + public void init() { + d = new VectorAlgorithmsImpl.Data(SIZE, SEED, NUM_X_OBJECTS); + } + + // ------------------------------------------------------------------------------------------ + // Benchmarks just forward arguments and returns. + // ------------------------------------------------------------------------------------------ + + @Benchmark + public Object fillI_loop() { + return VectorAlgorithmsImpl.fillI_loop(d.rI1); + } + + @Benchmark + public Object fillI_VectorAPI() { + return VectorAlgorithmsImpl.fillI_VectorAPI(d.rI1); + } + + @Benchmark + public Object fillI_Arrays() { + return VectorAlgorithmsImpl.fillI_Arrays(d.rI1); + } + + @Benchmark + public Object iotaI_loop() { + return VectorAlgorithmsImpl.iotaI_loop(d.rI1); + } + + @Benchmark + public Object iotaI_VectorAPI() { + return VectorAlgorithmsImpl.iotaI_VectorAPI(d.rI1); + } + + @Benchmark + public Object copyI_loop() { + return VectorAlgorithmsImpl.copyI_loop(d.aI, d.rI1); + } + + @Benchmark + public Object copyI_VectorAPI() { + return VectorAlgorithmsImpl.copyI_VectorAPI(d.aI, d.rI1); + } + + @Benchmark + public Object copyI_System_arraycopy() { + return VectorAlgorithmsImpl.copyI_System_arraycopy(d.aI, d.rI1); + } + + @Benchmark + public Object mapI_loop() { + return VectorAlgorithmsImpl.mapI_loop(d.aI, d.rI1); + } + + @Benchmark + public Object mapI_VectorAPI() { + return VectorAlgorithmsImpl.mapI_VectorAPI(d.aI, d.rI1); + } + + @Benchmark + public int reduceAddI_loop() { + return VectorAlgorithmsImpl.reduceAddI_loop(d.aI); + } + + @Benchmark + public int reduceAddI_reassociate() { + return VectorAlgorithmsImpl.reduceAddI_reassociate(d.aI); + } + + @Benchmark + public int reduceAddI_VectorAPI_naive() { + return VectorAlgorithmsImpl.reduceAddI_VectorAPI_naive(d.aI); + } + + @Benchmark + public int reduceAddI_VectorAPI_reduction_after_loop() { + return VectorAlgorithmsImpl.reduceAddI_VectorAPI_reduction_after_loop(d.aI); + } + + @Benchmark + public float dotProductF_loop() { + return VectorAlgorithmsImpl.dotProductF_loop(d.aF, d.bF); + } + + @Benchmark + public float dotProductF_VectorAPI_naive() { + return VectorAlgorithmsImpl.dotProductF_VectorAPI_naive(d.aF, d.bF); + } + + @Benchmark + public float dotProductF_VectorAPI_reduction_after_loop() { + return VectorAlgorithmsImpl.dotProductF_VectorAPI_reduction_after_loop(d.aF, d.bF); + } + + @Benchmark + public int hashCodeB_loop() { + return VectorAlgorithmsImpl.hashCodeB_loop(d.aB); + } + + @Benchmark + public int hashCodeB_Arrays() { + return VectorAlgorithmsImpl.hashCodeB_Arrays(d.aB); + } + + @Benchmark + public int hashCodeB_VectorAPI_v1() { + return VectorAlgorithmsImpl.hashCodeB_VectorAPI_v1(d.aB); + } + + @Benchmark + public int hashCodeB_VectorAPI_v2() { + return VectorAlgorithmsImpl.hashCodeB_VectorAPI_v2(d.aB); + } + + @Benchmark + public Object scanAddI_loop() { + return VectorAlgorithmsImpl.scanAddI_loop(d.aI, d.rI1); + } + + @Benchmark + public Object scanAddI_loop_reassociate() { + return VectorAlgorithmsImpl.scanAddI_loop_reassociate(d.aI, d.rI1); + } + + @Benchmark + public Object scanAddI_VectorAPI_permute_add() { + return VectorAlgorithmsImpl.scanAddI_VectorAPI_permute_add(d.aI, d.rI1); + } + + @Benchmark + public int findMinIndexI_loop() { + return VectorAlgorithmsImpl.findMinIndexI_loop(d.aI); + } + + @Benchmark + public int findMinIndexI_VectorAPI() { + return VectorAlgorithmsImpl.findMinIndexI_VectorAPI(d.aI); + } + + @Benchmark + public int findI_loop() { + // Every invocation should have a different value for e, so that + // we don't get branch-prediction that is too good. And also so + // that the position where we exit is more evenly distributed. + d.eI_idx = (d.eI_idx + 1) & 0xffff; + int e = d.eI[d.eI_idx]; + return VectorAlgorithmsImpl.findI_loop(d.aI, e); + } + + @Benchmark + public int findI_VectorAPI() { + d.eI_idx = (d.eI_idx + 1) & 0xffff; + int e = d.eI[d.eI_idx]; + return VectorAlgorithmsImpl.findI_VectorAPI(d.aI, e); + } + + @Benchmark + public Object reverseI_loop() { + return VectorAlgorithmsImpl.reverseI_loop(d.aI, d.rI1); + } + + @Benchmark + public Object reverseI_VectorAPI() { + return VectorAlgorithmsImpl.reverseI_VectorAPI(d.aI, d.rI1); + } + + @Benchmark + public Object filterI_loop() { + // Every invocation should have a different value for e, so that + // we don't get branch-prediction that is too good. And also so + // That the length of the resulting data is more evenly distributed. + d.eI_idx = (d.eI_idx + 1) & 0xffff; + int e = d.eI[d.eI_idx]; + return VectorAlgorithmsImpl.filterI_loop(d.aI, d.rI1, e); + } + + @Benchmark + public Object filterI_VectorAPI() { + d.eI_idx = (d.eI_idx + 1) & 0xffff; + int e = d.eI[d.eI_idx]; + return VectorAlgorithmsImpl.filterI_VectorAPI(d.aI, d.rI1, e); + } + + @Benchmark + public int reduceAddIFieldsX4_loop() { + return VectorAlgorithmsImpl.reduceAddIFieldsX4_loop(d.oopsX4, d.memX4); + } + + @Benchmark + public int reduceAddIFieldsX4_VectorAPI() { + return VectorAlgorithmsImpl.reduceAddIFieldsX4_VectorAPI(d.oopsX4, d.memX4); + } + + @Benchmark + public Object lowerCaseB_loop() { + return VectorAlgorithmsImpl.lowerCaseB_loop(d.strB, d.rB1); + } + + @Benchmark + public Object lowerCaseB_VectorAPI_v1() { + return VectorAlgorithmsImpl.lowerCaseB_VectorAPI_v1(d.strB, d.rB1); + } + + @Benchmark + public Object lowerCaseB_VectorAPI_v2() { + return VectorAlgorithmsImpl.lowerCaseB_VectorAPI_v2(d.strB, d.rB1); + } +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithmsImpl.java b/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithmsImpl.java new file mode 100644 index 00000000000..5ab057329d3 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithmsImpl.java @@ -0,0 +1,775 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.bench.vm.compiler; + +import java.util.Arrays; +import java.util.Random; +import jdk.incubator.vector.*; + +/** + * The code below is supposed to be an exact copy of: + * test/hotspot/jtreg/compiler/vectorization/VectorAlgorithmsImpl.java + */ +public class VectorAlgorithmsImpl { + private static final VectorSpecies SPECIES_I = IntVector.SPECIES_PREFERRED; + private static final VectorSpecies SPECIES_I512 = IntVector.SPECIES_512; + private static final VectorSpecies SPECIES_I256 = IntVector.SPECIES_256; + private static final VectorSpecies SPECIES_B = ByteVector.SPECIES_PREFERRED; + private static final VectorSpecies SPECIES_B64 = ByteVector.SPECIES_64; + private static final VectorSpecies SPECIES_F = FloatVector.SPECIES_PREFERRED; + + // This class stores the input and output arrays. + // The constructor sets up all the data. + // + // IMPORTANT: + // If you want to use some array but do NOT modify it: just use it. + // If you want to use it and DO want to modify it: clone it. This + // ensures that each test gets a separate copy, and that when we + // capture the modified arrays they are different for every method + // and run. + // An alternative to cloning is to use different return arrays for + // different implementations of the same group, e.g. rI1, rI2, ... + // + public static class Data { + public int[] aI; + public int[] rI1; + public int[] rI2; + public int[] rI3; + public int[] rI4; + public int[] eI; + // The test has to use the same index into eI for all implementations. But in the + // benchmark, we'd like to use random indices, so we use the index to advance through + // the array. + public int eI_idx = 0; + + public float[] aF; + public float[] bF; + + public byte[] aB; + public byte[] strB; + public byte[] rB1; + public byte[] rB2; + public byte[] rB3; + + public int[] oopsX4; + public int[] memX4; + + public Data(int size, int seed, int numX4Objects) { + Random random = new Random(seed); + + // int: one input array and multiple output arrays so different implementations can + // store their results to different arrays. + aI = new int[size]; + rI1 = new int[size]; + rI2 = new int[size]; + rI3 = new int[size]; + rI4 = new int[size]; + Arrays.setAll(aI, i -> random.nextInt()); + + // Populate with some random values from aI, and some totally random values. + eI = new int[0x10000]; + for (int i = 0; i < eI.length; i++) { + eI[i] = (random.nextInt(10) == 0) ? random.nextInt() : aI[random.nextInt(size)]; + } + + // X4 oop setup. + // oopsX4 holds "addresses" (i.e. indices), that point to the 16-byte objects in memX4. + oopsX4 = new int[size]; + memX4 = new int[numX4Objects * 4]; + for (int i = 0; i < size; i++) { + // assign either a zero=null, or assign a random oop. + oopsX4[i] = (random.nextInt(10) == 0) ? 0 : random.nextInt(numX4Objects) * 4; + } + // Just fill the whole array with random values. + // The relevant field is only at every "4 * i + 3" though. + memX4 = new int[4 * numX4Objects]; + for (int i = 0; i < memX4.length; i++) { + memX4[i] = random.nextInt(); + } + + // float inputs. To avoid rounding issues, only use small integers. + aF = new float[size]; + bF = new float[size]; + for (int i = 0; i < size; i++) { + aF[i] = random.nextInt(32) - 16; + bF[i] = random.nextInt(32) - 16; + } + + // byte: just random data. + aB = new byte[size]; + strB = new byte[size]; + rB1 = new byte[size]; + rB2 = new byte[size]; + rB3 = new byte[size]; + random.nextBytes(aB); + random.nextBytes(strB); // TODO: special data! + } + } + + public static Object fillI_loop(int[] r) { + for (int i = 0; i < r.length; i++) { + r[i] = 42; + } + return r; + } + + public static Object fillI_Arrays(int[] r) { + Arrays.fill(r, 42); + return r; + } + + public static Object fillI_VectorAPI(int[] r) { + var v = IntVector.broadcast(SPECIES_I, 42); + int i = 0; + for (; i < SPECIES_I.loopBound(r.length); i += SPECIES_I.length()) { + v.intoArray(r, i); + } + for (; i < r.length; i++) { + r[i] = 42; + } + return r; + } + + public static Object iotaI_loop(int[] r) { + for (int i = 0; i < r.length; i++) { + r[i] = i; + } + return r; + } + + public static Object iotaI_VectorAPI(int[] r) { + var iota = IntVector.broadcast(SPECIES_I, 0).addIndex(1); + int i = 0; + for (; i < SPECIES_I.loopBound(r.length); i += SPECIES_I.length()) { + iota.intoArray(r, i); + iota = iota.add(SPECIES_I.length()); + } + for (; i < r.length; i++) { + r[i] = i; + } + return r; + } + + public static Object copyI_loop(int[] a, int[] r) { + for (int i = 0; i < a.length; i++) { + r[i] = a[i]; + } + return r; + } + + public static Object copyI_System_arraycopy(int[] a, int[] r) { + System.arraycopy(a, 0, r, 0, a.length); + return r; + } + + public static Object copyI_VectorAPI(int[] a, int[] r) { + int i = 0; + for (; i < SPECIES_I.loopBound(r.length); i += SPECIES_I.length()) { + IntVector v = IntVector.fromArray(SPECIES_I, a, i); + v.intoArray(r, i); + } + for (; i < r.length; i++) { + r[i] = a[i]; + } + return r; + } + + public static Object mapI_loop(int[] a, int[] r) { + for (int i = 0; i < a.length; i++) { + r[i] = a[i] * 42; + } + return r; + } + + public static Object mapI_VectorAPI(int[] a, int[] r) { + int i = 0; + for (; i < SPECIES_I.loopBound(r.length); i += SPECIES_I.length()) { + IntVector v = IntVector.fromArray(SPECIES_I, a, i); + v = v.mul(42); + v.intoArray(r, i); + } + for (; i < r.length; i++) { + r[i] = a[i] * 42; + } + return r; + } + + public static int reduceAddI_loop(int[] a) { + int sum = 0; + for (int i = 0; i < a.length; i++) { + // Relying on simple reduction loop should vectorize since JDK26. + sum += a[i]; + } + return sum; + } + + public static int reduceAddI_reassociate(int[] a) { + int sum = 0; + int i; + for (i = 0; i < a.length - 3; i += 4) { + // Unroll 4x, reassociate inside. + sum += a[i] + a[i + 1] + a[i + 2] + a[i + 3]; + } + for (; i < a.length; i++) { + // Tail + sum += a[i]; + } + return sum; + } + + public static int reduceAddI_VectorAPI_naive(int[] a) { + var sum = 0; + int i; + for (i = 0; i < SPECIES_I.loopBound(a.length); i += SPECIES_I.length()) { + IntVector v = IntVector.fromArray(SPECIES_I, a, i); + // reduceLanes in loop is better than scalar performance, but still + // relatively slow. + sum += v.reduceLanes(VectorOperators.ADD); + } + for (; i < a.length; i++) { + sum += a[i]; + } + return sum; + } + + public static int reduceAddI_VectorAPI_reduction_after_loop(int[] a) { + var acc = IntVector.broadcast(SPECIES_I, 0); + int i; + for (i = 0; i < SPECIES_I.loopBound(a.length); i += SPECIES_I.length()) { + IntVector v = IntVector.fromArray(SPECIES_I, a, i); + // Element-wide addition into a vector of partial sums is much faster. + // Now, we only need to do a reduceLanes after the loop. + // This works because int-addition is associative and commutative. + acc = acc.add(v); + } + int sum = acc.reduceLanes(VectorOperators.ADD); + for (; i < a.length; i++) { + sum += a[i]; + } + return sum; + } + + public static float dotProductF_loop(float[] a, float[] b) { + float sum = 0; + for (int i = 0; i < a.length; i++) { + sum += a[i] * b[i]; + } + return sum; + } + + public static float dotProductF_VectorAPI_naive(float[] a, float[] b) { + float sum = 0; + int i; + for (i = 0; i < SPECIES_F.loopBound(a.length); i += SPECIES_F.length()) { + var va = FloatVector.fromArray(SPECIES_F, a, i); + var vb = FloatVector.fromArray(SPECIES_F, b, i); + sum += va.mul(vb).reduceLanes(VectorOperators.ADD); + } + for (; i < a.length; i++) { + sum += a[i] * b[i]; + } + return sum; + } + + public static float dotProductF_VectorAPI_reduction_after_loop(float[] a, float[] b) { + var sums = FloatVector.broadcast(SPECIES_F, 0.0f); + int i; + for (i = 0; i < SPECIES_F.loopBound(a.length); i += SPECIES_F.length()) { + var va = FloatVector.fromArray(SPECIES_F, a, i); + var vb = FloatVector.fromArray(SPECIES_F, b, i); + sums = sums.add(va.mul(vb)); + } + float sum = sums.reduceLanes(VectorOperators.ADD); + for (; i < a.length; i++) { + sum += a[i] * b[i]; + } + return sum; + } + + public static int hashCodeB_loop(byte[] a) { + int h = 1; + for (int i = 0; i < a.length; i++) { + h = 31 * h + a[i]; + } + return h; + } + + public static int hashCodeB_Arrays(byte[] a) { + return Arrays.hashCode(a); + } + + // Simplified intrinsic code from C2_MacroAssembler::arrays_hashcode in c2_MacroAssembler_x86.cpp + // + // Ideas that may help understand the code: + // h(i) = 31 * h(i-1) + a[i] + // "unroll" by factor of L=8: + // h(i+8) = h(i) * 31^8 + a[i+1] * 31^7 + a[i+2] * 31^6 + ... + a[i+8] * 1 + // ----------- ------------------------------------------------ + // scalar vector: notice the powers of 31 in reverse + // + // We notice that we can load a[i+1 .. i+8], then element-wise multiply with + // the vector of reversed powers-of-31, and then do reduceLanes(ADD). + // But we can do even better: By looking at multiple such 8-unrolled iterations. + // Instead of applying the "next" factor of "31^8" to the reduced scalar, we can + // already apply it element-wise. That allows us to move the reduction out + // of the loop. + // + // Note: the intrinsic additionally unrolls the loop by a factor of 4, + // but we want to keep thins simple for demonstration purposes. + // + private static int[] REVERSE_POWERS_OF_31 = new int[9]; + static { + int p = 1; + for (int i = REVERSE_POWERS_OF_31.length - 1; i >= 0; i--) { + REVERSE_POWERS_OF_31[i] = p; + p *= 31; + } + } + public static int hashCodeB_VectorAPI_v1(byte[] a) { + int result = 1; // initialValue + var vresult = IntVector.zero(SPECIES_I256); + int next = REVERSE_POWERS_OF_31[0]; // 31^L + var vcoef = IntVector.fromArray(SPECIES_I256, REVERSE_POWERS_OF_31, 1); // powers of 2 in reverse + int i; + for (i = 0; i < SPECIES_B64.loopBound(a.length); i += SPECIES_B64.length()) { + // scalar part: result *= 31^L + result *= next; + // vector part: element-wise apply the next factor and add in the new values. + var vb = ByteVector.fromArray(SPECIES_B64, a, i); + var vi = vb.castShape(SPECIES_I256, 0); + vresult = vresult.mul(next).add(vi); + } + // reduce the partial hashes in the elements, using the reverse list of powers of 2. + result += vresult.mul(vcoef).reduceLanes(VectorOperators.ADD); + for (; i < a.length; i++) { + result = 31 * result + a[i]; + } + return result; + } + + // This second approach follows the idea from this blog post by Otmar Ertl: + // https://www.dynatrace.com/news/blog/java-arrays-hashcode-byte-efficiency-techniques/ + // + // I simplified the algorithm a little, so that it is a bit closer + // to the solution "v1" above. + // + // The major issue with "v1" is that we cannot load a full vector of bytes, + // because of the cast to ints. So we can only fill 1/4 of the maximal + // vector size. The trick here is to do an unrolling of factor 4, from: + // h(i) = 31 * h(i-1) + a[i] + // to: + // h(i+4) = h(i) * 31^4 + a[i + 1] * 31^3 + // + a[i + 2] * 31^2 + // + a[i + 3] * 31^1 + // + a[i + 4] * 31^0 + // The goal is now to compute this value for 4 bytes within a 4 byte + // lane of the vector. One concern is that we start with byte values, + // but need to do int-multiplication with powers of 31. If we instead + // did a byte-multiplication, we could get overflows that we would not + // have had in the int-multiplication. + // One trick that helps with chaning the size of the lanes from byte + // to short to int is doing all operations with unsigned integers. That + // way, we can zero-extend instead of sign-bit extend. The first step + // is thus to convert the bytes into unsigned values. Since byte is in + // range [-128..128), doing "a[i+j] + 128" makes it a positive value, + // allowing for unsigned multiplication. + // h(i+4) = h(i) * 31^4 + a[i + 1] * 31^3 + // + a[i + 2] * 31^2 + // + a[i + 3] * 31^1 + // + a[i + 4] * 31^0 + // = h(i) * 31^4 + (a[i + 1] + 128 - 128) * 31^3 + // + (a[i + 2] + 128 - 128) * 31^2 + // + (a[i + 3] + 128 - 128) * 31^1 + // + (a[i + 4] + 128 - 128) * 31^0 + // = h(i) * 31^4 + (a[i + 1] + 128 ) * 31^3 + // + (a[i + 2] + 128 ) * 31^2 + // + (a[i + 3] + 128 ) * 31^1 + // + (a[i + 4] + 128 ) * 31^0 + // + -128 * (31^3 + 31^2 + 31^1 + 1) + // = h(i) * 31^4 + ((a[i + 1] + 128) * 31 + // + (a[i + 2] + 128 ) * 31^2 + // + ((a[i + 3] + 128) * 31 + // + (a[i + 4] + 128 ) + // + -128 * (31^3 + 31^2 + 31^1 + 1) + // + // Getting from the signed a[i] value to unsigned with +128, we can + // just xor with 0x80=128. Any numbers there in range [-128..0) are + // now in range [0..128). And any numbers that were in range [0..128) + // are now in unsigned range [128..255). What a neat trick! + // + // We then apply a byte->short transition where we crunch 2 bytes + // into one short, applying a multiplication with 31 to one of the + // two bytes. This multiplication cannot overflow in a short. + // then we apply a short->int transition where we crunch 2 shorts + // into one int, applying a multiplication with 31^2 to one of the + // two shorts. This multiplication cannot overflow in an int. + // + public static int hashCodeB_VectorAPI_v2(byte[] a) { + return HashCodeB_VectorAPI_V2.compute(a); + } + + private static class HashCodeB_VectorAPI_V2 { + private static final int L = Math.min(ByteVector.SPECIES_PREFERRED.length(), + IntVector.SPECIES_PREFERRED.length() * 4); + private static final VectorShape SHAPE = VectorShape.forBitSize(8 * L); + private static final VectorSpecies SPECIES_B = SHAPE.withLanes(byte.class); + private static final VectorSpecies SPECIES_I = SHAPE.withLanes(int.class); + + private static int[] REVERSE_POWERS_OF_31_STEP_4 = new int[L / 4 + 1]; + static { + int p = 1; + int step = 31 * 31 * 31 * 31; // step by 4 + for (int i = REVERSE_POWERS_OF_31_STEP_4.length - 1; i >= 0; i--) { + REVERSE_POWERS_OF_31_STEP_4[i] = p; + p *= step; + } + } + + public static int compute(byte[] a) { + int result = 1; // initialValue + int next = REVERSE_POWERS_OF_31_STEP_4[0]; // 31^L + var vcoef = IntVector.fromArray(SPECIES_I, REVERSE_POWERS_OF_31_STEP_4, 1); // W + var vresult = IntVector.zero(SPECIES_I); + int i; + for (i = 0; i < SPECIES_B.loopBound(a.length); i += SPECIES_B.length()) { + var vb = ByteVector.fromArray(SPECIES_B, a, i); + // Add 128 to each byte. + var vs = vb.lanewise(VectorOperators.XOR, (byte)0x80) + .reinterpretAsShorts(); + // Each short lane contains 2 bytes, crunch them. + var vi = vs.and((short)0xff) // lower byte + .mul((short)31) + .add(vs.lanewise(VectorOperators.LSHR, 8)) // upper byte + .reinterpretAsInts(); + // Each int contains 2 shorts, crunch them. + var v = vi.and(0xffff) // lower short + .mul(31 * 31) + .add(vi.lanewise(VectorOperators.LSHR, 16)); // upper short + // Add the correction for the 128 additions above. + v = v.add(-128 * (31*31*31 + 31*31 + 31 + 1)); + // Every element of v now contains a crunched int-package of 4 bytes. + result *= next; + vresult = vresult.mul(next).add(v); + } + result += vresult.mul(vcoef).reduceLanes(VectorOperators.ADD); + for (; i < a.length; i++) { + result = 31 * result + a[i]; + } + return result; + } + } + + public static Object scanAddI_loop(int[] a, int[] r) { + int sum = 0; + for (int i = 0; i < a.length; i++) { + sum += a[i]; + r[i] = sum; + } + return r; + } + + public static Object scanAddI_loop_reassociate(int[] a, int[] r) { + int sum = 0; + int i = 0; + for (; i < a.length - 3; i += 4) { + // We cut the latency by a factor of 4, but increase the number of additions. + int old_sum = sum; + int v0 = a[i + 0]; + int v1 = a[i + 1]; + int v2 = a[i + 2]; + int v3 = a[i + 3]; + int v01 = v0 + v1; + int v23 = v2 + v3; + int v0123 = v01 + v23; + sum += v0123; + r[i + 0] = old_sum + v0; + r[i + 1] = old_sum + v01; + r[i + 2] = old_sum + v01 + v2; + r[i + 3] = old_sum + v0123; + } + for (; i < a.length; i++) { + sum += a[i]; + r[i] = sum; + } + return r; + } + + public static Object scanAddI_VectorAPI_permute_add(int[] a, int[] r) { + // Using Naive Parallel Algorithm: Hills and Steele + int sum = 0; + int xx = 0; // masked later anyway + var shf1 = VectorShuffle.fromArray(SPECIES_I512, new int[]{xx, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 0); + var shf2 = VectorShuffle.fromArray(SPECIES_I512, new int[]{xx, xx, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 0); + var shf3 = VectorShuffle.fromArray(SPECIES_I512, new int[]{xx, xx, xx, xx, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 0); + var shf4 = VectorShuffle.fromArray(SPECIES_I512, new int[]{xx, xx, xx, xx, xx, xx, xx, xx, 0, 1, 2, 3, 4, 5, 6, 7}, 0); + var mask1 = VectorMask.fromLong(SPECIES_I512, 0b1111111111111110); + var mask2 = VectorMask.fromLong(SPECIES_I512, 0b1111111111111100); + var mask3 = VectorMask.fromLong(SPECIES_I512, 0b1111111111110000); + var mask4 = VectorMask.fromLong(SPECIES_I512, 0b1111111100000000); + int i = 0; + for (; i < SPECIES_I512.loopBound(a.length); i += SPECIES_I512.length()) { + IntVector v = IntVector.fromArray(SPECIES_I512, a, i); + v = v.add(v.rearrange(shf1), mask1); + v = v.add(v.rearrange(shf2), mask2); + v = v.add(v.rearrange(shf3), mask3); + v = v.add(v.rearrange(shf4), mask4); + v = v.add(sum); + v.intoArray(r, i); + sum = v.lane(SPECIES_I512.length() - 1); + } + for (; i < a.length; i++) { + sum += a[i]; + r[i] = sum; + } + return r; + } + + public static int findMinIndexI_loop(int[] a) { + int min = a[0]; + int index = 0; + for (int i = 1; i < a.length; i++) { + int ai = a[i]; + if (ai < min) { + min = ai; + index = i; + } + } + return index; + } + + public static int findMinIndexI_VectorAPI(int[] a) { + // Main approach: have partial results in mins and idxs. + var mins = IntVector.broadcast(SPECIES_I, a[0]); + var idxs = IntVector.broadcast(SPECIES_I, 0); + var iota = IntVector.broadcast(SPECIES_I, 0).addIndex(1); + int i = 0; + for (; i < SPECIES_I.loopBound(a.length); i += SPECIES_I.length()) { + IntVector v = IntVector.fromArray(SPECIES_I, a, i); + var mask = v.compare(VectorOperators.LT, mins); + mins = mins.blend(v, mask); + idxs = idxs.blend(iota, mask); + iota = iota.add(SPECIES_I.length()); + } + // Reduce the vectors down + int min = mins.reduceLanes(VectorOperators.MIN); + var not_min_mask = mins.compare(VectorOperators.NE, min); + int index = idxs.blend(a.length, not_min_mask).reduceLanes(VectorOperators.MIN); + // Tail loop + for (; i < a.length; i++) { + int ai = a[i]; + if (ai < min) { + min = ai; + index = i; + } + } + return index; + } + + public static int findI_loop(int[] a, int e) { + for (int i = 0; i < a.length; i++) { + int ai = a[i]; + if (ai == e) { + return i; + } + } + return -1; + } + + public static int findI_VectorAPI(int[] a, int e) { + var es = IntVector.broadcast(SPECIES_I, e); + int i = 0; + for (; i < SPECIES_I.loopBound(a.length); i += SPECIES_I.length()) { + IntVector v = IntVector.fromArray(SPECIES_I, a, i); + var mask = v.compare(VectorOperators.EQ, es); + if (mask.anyTrue()) { + return i + mask.firstTrue(); + } + } + for (; i < a.length; i++) { + int ai = a[i]; + if (ai == e) { + return i; + } + } + return -1; + } + + public static Object reverseI_loop(int[] a, int[] r) { + for (int i = 0; i < a.length; i++) { + r[a.length - i - 1] = a[i]; + } + return r; + } + + private static final VectorShuffle REVERSE_SHUFFLE_I = SPECIES_I.iotaShuffle(SPECIES_I.length()-1, -1, true); + + public static Object reverseI_VectorAPI(int[] a, int[] r) { + int i = 0; + for (; i < SPECIES_I.loopBound(a.length); i += SPECIES_I.length()) { + IntVector v = IntVector.fromArray(SPECIES_I, a, i); + v = v.rearrange(REVERSE_SHUFFLE_I); + v.intoArray(r, r.length - SPECIES_I.length() - i); + } + for (; i < a.length; i++) { + r[a.length - i - 1] = a[i]; + } + return r; + } + + public static Object filterI_loop(int[] a, int[] r, int threshold) { + int j = 0; + for (int i = 0; i < a.length; i++) { + int ai = a[i]; + if (ai >= threshold) { + r[j++] = ai; + } + } + // Just force the resulting length onto the same array. + r[r.length - 1] = j; + return r; + } + + public static Object filterI_VectorAPI(int[] a, int[] r, int threshold) { + var thresholds = IntVector.broadcast(SPECIES_I, threshold); + int j = 0; + int i = 0; + for (; i < SPECIES_I.loopBound(a.length); i += SPECIES_I.length()) { + IntVector v = IntVector.fromArray(SPECIES_I, a, i); + var mask = v.compare(VectorOperators.GE, thresholds); + v = v.compress(mask); + int trueCount = mask.trueCount(); + var prefixMask = mask.compress(); + v.intoArray(r, j, prefixMask); + j += trueCount; + } + + for (; i < a.length; i++) { + int ai = a[i]; + if (ai >= threshold) { + r[j++] = ai; + } + } + // Just force the resulting length onto the same array. + r[r.length - 1] = j; + return r; + } + + // X4: ints simulate 4-byte oops. + // oops: if non-zero (= non-null), every entry simulates a 4-byte oop, pointing into mem. + // mem: an int array that simulates the memory. + // + // Task: Find all non-null oops, and dereference them, get the relevant field. + // Objects have 16 bytes, and the relevant field is at bytes 12-16. + // That maps to 4 ints, and the relevant field is the 4th element of 4. + // Sum up all the field values. + public static int reduceAddIFieldsX4_loop(int[] oops, int[] mem) { + int sum = 0; + for (int i = 0; i < oops.length; i++) { + int oop = oops[i]; + if (oop != 0) { + int fieldValue = mem[oop + 3]; // oop+12 + sum += fieldValue; + } + } + return sum; + } + + public static int reduceAddIFieldsX4_VectorAPI(int[] oops, int[] mem) { + var acc = IntVector.broadcast(SPECIES_I, 0); + int i = 0; + for (; i < SPECIES_I.loopBound(oops.length); i += SPECIES_I.length()) { + var oopv = IntVector.fromArray(SPECIES_I, oops, i); + var mask = oopv.compare(VectorOperators.NE, /* null */0); + // We are lucky today: we need to access mem[oop + 3] + var fieldValues = IntVector.fromArray(SPECIES_I, mem, 3, oops, i, mask); + acc = acc.add(fieldValues); + } + int sum = acc.reduceLanes(VectorOperators.ADD); + for (; i < oops.length; i++) { + int oop = oops[i]; + if (oop != 0) { + int fieldValue = mem[oop + 3]; // oop+12 + sum += fieldValue; + } + } + return sum; + } + + // The lowerCase example demonstrates a lane-wise control-flow diamond. + public static Object lowerCaseB_loop(byte[] a, byte[] r) { + for (int i = 0; i < a.length; i++) { + byte c = a[i]; + if (c >= 'A' && c <= 'Z') { + c += ('a' - 'A'); // c += 32 + } + r[i] = c; + } + return r; + } + + // Control-flow diamonds can easily be simulated by "if-conversion", i.e. + // by using masked operations. An alternative would be to use blend. + public static Object lowerCaseB_VectorAPI_v1(byte[] a, byte[] r) { + int i; + for (i = 0; i < SPECIES_B.loopBound(a.length); i += SPECIES_B.length()) { + var vc = ByteVector.fromArray(SPECIES_B, a, i); + var maskA = vc.compare(VectorOperators.GE, (byte)'A'); + var maskZ = vc.compare(VectorOperators.LE, (byte)'Z'); + var mask = maskA.and(maskZ); + vc = vc.add((byte)32, mask); + vc.intoArray(r, i); + } + for (; i < a.length; i++) { + byte c = a[i]; + if (c >= 'A' && c <= 'Z') { + c += ('a' - 'A'); + } + r[i] = c; + } + return r; + } + + public static Object lowerCaseB_VectorAPI_v2(byte[] a, byte[] r) { + int i; + for (i = 0; i < SPECIES_B.loopBound(a.length); i += SPECIES_B.length()) { + var vc = ByteVector.fromArray(SPECIES_B, a, i); + // We can convert the range 65..90 (represents ascii A..Z) into a range 0..25. + // This allows us to only use a single unsigned comparison. + var vt = vc.add((byte)-'A'); + var mask = vt.compare(VectorOperators.ULE, (byte)25); + vc = vc.add((byte)32, mask); + vc.intoArray(r, i); + } + for (; i < a.length; i++) { + byte c = a[i]; + if (c >= 'A' && c <= 'Z') { + c += ('a' - 'A'); + } + r[i] = c; + } + return r; + } +} + From 92072a93bfeb83186df15032d425ed984d24fc52 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Thu, 29 Jan 2026 08:39:32 +0000 Subject: [PATCH 242/328] 8375747: ZGC: ZForwardingTest is unable to commit memory on Windows Reviewed-by: jsikstro, eosterlund --- src/hotspot/share/gc/z/zAddress.inline.hpp | 8 ++-- test/hotspot/gtest/gc/z/test_zForwarding.cpp | 29 ++++++++---- test/hotspot/gtest/gc/z/zunittest.hpp | 49 ++++++++++++++++++++ 3 files changed, 73 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/gc/z/zAddress.inline.hpp b/src/hotspot/share/gc/z/zAddress.inline.hpp index c8c8ec7ae3a..0b99802729b 100644 --- a/src/hotspot/share/gc/z/zAddress.inline.hpp +++ b/src/hotspot/share/gc/z/zAddress.inline.hpp @@ -199,18 +199,18 @@ CREATE_ZOFFSET_OPERATORS(zoffset) inline uintptr_t untype(zbacking_offset offset) { const uintptr_t value = static_cast(offset); - assert(value < ZBackingOffsetMax, "Offset out of bounds (" PTR_FORMAT " < " PTR_FORMAT ")", value, ZAddressOffsetMax); + assert(value < ZBackingOffsetMax, "Offset out of bounds (" PTR_FORMAT " < " PTR_FORMAT ")", value, ZBackingOffsetMax); return value; } inline uintptr_t untype(zbacking_offset_end offset) { const uintptr_t value = static_cast(offset); - assert(value <= ZBackingOffsetMax, "Offset out of bounds (" PTR_FORMAT " <= " PTR_FORMAT ")", value, ZAddressOffsetMax); + assert(value <= ZBackingOffsetMax, "Offset out of bounds (" PTR_FORMAT " <= " PTR_FORMAT ")", value, ZBackingOffsetMax); return value; } inline zbacking_offset to_zbacking_offset(uintptr_t value) { - assert(value < ZBackingOffsetMax, "Value out of bounds (" PTR_FORMAT " < " PTR_FORMAT ")", value, ZAddressOffsetMax); + assert(value < ZBackingOffsetMax, "Value out of bounds (" PTR_FORMAT " < " PTR_FORMAT ")", value, ZBackingOffsetMax); return zbacking_offset(value); } @@ -227,7 +227,7 @@ inline zbacking_offset_end to_zbacking_offset_end(zbacking_offset start, size_t } inline zbacking_offset_end to_zbacking_offset_end(uintptr_t value) { - assert(value <= ZBackingOffsetMax, "Value out of bounds (" PTR_FORMAT " <= " PTR_FORMAT ")", value, ZAddressOffsetMax); + assert(value <= ZBackingOffsetMax, "Value out of bounds (" PTR_FORMAT " <= " PTR_FORMAT ")", value, ZBackingOffsetMax); return zbacking_offset_end(value); } diff --git a/test/hotspot/gtest/gc/z/test_zForwarding.cpp b/test/hotspot/gtest/gc/z/test_zForwarding.cpp index 5275b78fb82..6b66d43ae7f 100644 --- a/test/hotspot/gtest/gc/z/test_zForwarding.cpp +++ b/test/hotspot/gtest/gc/z/test_zForwarding.cpp @@ -44,11 +44,12 @@ using namespace testing; class ZForwardingTest : public ZTest { public: // Setup and tear down - ZHeap* _old_heap; - ZGenerationOld* _old_old; - ZGenerationYoung* _old_young; - ZAddressReserver _zaddress_reserver; - zoffset _page_offset; + ZHeap* _old_heap; + ZGenerationOld* _old_old; + ZGenerationYoung* _old_young; + ZAddressReserver _zaddress_reserver; + ZPhysicalMemoryBackingMocker _physical_backing; + zoffset _page_offset; virtual void SetUp() { _old_heap = ZHeap::_heap; @@ -73,8 +74,16 @@ public: GTEST_SKIP() << "Unable to reserve memory"; } - char* const addr = (char*)untype(ZOffset::address_unsafe(_page_offset)); - os::commit_memory(addr, ZGranuleSize, /* executable */ false); + // Setup backing storage + _physical_backing.SetUp(ZGranuleSize); + + size_t committed = _physical_backing()->commit(zbacking_offset(0), ZGranuleSize, 0); + + if (committed != ZGranuleSize) { + GTEST_SKIP() << "Unable to commit memory"; + } + + _physical_backing()->map(ZOffset::address_unsafe(_page_offset), ZGranuleSize, zbacking_offset(0)); } virtual void TearDown() { @@ -84,10 +93,12 @@ public: ZGeneration::_young = _old_young; if (_page_offset != zoffset::invalid) { - char* const addr = (char*)untype(ZOffset::address_unsafe(_page_offset)); - os::uncommit_memory(addr, ZGranuleSize, false /* executable */); + _physical_backing()->unmap(ZOffset::address_unsafe(_page_offset), ZGranuleSize); + _physical_backing()->uncommit(zbacking_offset(0), ZGranuleSize); } + _physical_backing.TearDown(); + _zaddress_reserver.TearDown(); } diff --git a/test/hotspot/gtest/gc/z/zunittest.hpp b/test/hotspot/gtest/gc/z/zunittest.hpp index 2464f821380..13a8eb10f8a 100644 --- a/test/hotspot/gtest/gc/z/zunittest.hpp +++ b/test/hotspot/gtest/gc/z/zunittest.hpp @@ -28,6 +28,7 @@ #include "gc/z/zArguments.hpp" #include "gc/z/zInitialize.hpp" #include "gc/z/zNUMA.hpp" +#include "gc/z/zPhysicalMemoryManager.hpp" #include "gc/z/zRangeRegistry.hpp" #include "gc/z/zVirtualMemory.inline.hpp" #include "gc/z/zVirtualMemoryManager.hpp" @@ -104,6 +105,54 @@ public: } }; + class ZPhysicalMemoryBackingMocker { + size_t _old_max; + ZPhysicalMemoryBacking* _backing; + bool _active; + + static size_t set_max(size_t max_capacity) { + size_t old_max = ZBackingOffsetMax; + + ZBackingOffsetMax = max_capacity; + ZBackingIndexMax = checked_cast(ZBackingOffsetMax >> ZGranuleSizeShift); + + return old_max; + } + + public: + ZPhysicalMemoryBackingMocker() + : _old_max(0), + _backing(nullptr), + _active(false) {} + + void SetUp(size_t max_capacity) { + GTEST_EXPECT_FALSE(_active) << "SetUp called twice without a TearDown"; + + _old_max = set_max(max_capacity); + + char* const mem = (char*)os::malloc(sizeof(ZPhysicalMemoryBacking), mtTest); + _backing = new (mem) ZPhysicalMemoryBacking(ZGranuleSize); + + _active = true; + } + + void TearDown() { + GTEST_EXPECT_TRUE(_active) << "TearDown called without a preceding SetUp"; + + _active = false; + + _backing->~ZPhysicalMemoryBacking(); + os::free(_backing); + _backing = nullptr; + + set_max(_old_max); + } + + ZPhysicalMemoryBacking* operator()() { + return _backing; + } + }; + private: ZAddressOffsetMaxSetter _zaddress_offset_max_setter; unsigned int _rand_seed; From f9cc104249433eec179c98cb3fb44546254bf588 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 29 Jan 2026 08:54:37 +0000 Subject: [PATCH 243/328] 8376335: Convert PreservedMarks classes to use Atomic Reviewed-by: stefank, iwalulya --- .../share/gc/shared/preservedMarks.cpp | 30 +++++++++---------- .../share/gc/shared/preservedMarks.hpp | 7 ++--- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/hotspot/share/gc/shared/preservedMarks.cpp b/src/hotspot/share/gc/shared/preservedMarks.cpp index 1c9f1c82e6f..605b7afe072 100644 --- a/src/hotspot/share/gc/shared/preservedMarks.cpp +++ b/src/hotspot/share/gc/shared/preservedMarks.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -29,7 +29,7 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" +#include "runtime/atomic.hpp" #include "utilities/macros.hpp" void PreservedMarks::restore() { @@ -55,15 +55,6 @@ void PreservedMarks::adjust_during_full_gc() { } } -void PreservedMarks::restore_and_increment(volatile size_t* const total_size_addr) { - const size_t stack_size = size(); - restore(); - // Only do the atomic add if the size is > 0. - if (stack_size > 0) { - AtomicAccess::add(total_size_addr, stack_size); - } -} - #ifndef PRODUCT void PreservedMarks::assert_empty() { assert(_stack.is_empty(), "stack expected to be empty, size = %zu", @@ -93,7 +84,7 @@ void PreservedMarksSet::init(uint num) { class RestorePreservedMarksTask : public WorkerTask { PreservedMarksSet* const _preserved_marks_set; SequentialSubTasksDone _sub_tasks; - volatile size_t _total_size; + Atomic _total_size; #ifdef ASSERT size_t _total_size_before; #endif // ASSERT @@ -102,7 +93,12 @@ public: void work(uint worker_id) override { uint task_id = 0; while (_sub_tasks.try_claim_task(task_id)) { - _preserved_marks_set->get(task_id)->restore_and_increment(&_total_size); + PreservedMarks* next = _preserved_marks_set->get(task_id); + size_t num_restored = next->size(); + next->restore(); + if (num_restored > 0) { + _total_size.add_then_fetch(num_restored); + } } } @@ -121,9 +117,11 @@ public: } ~RestorePreservedMarksTask() { - assert(_total_size == _total_size_before, "total_size = %zu before = %zu", _total_size, _total_size_before); - size_t mem_size = _total_size * (sizeof(oop) + sizeof(markWord)); - log_trace(gc)("Restored %zu marks, occupying %zu %s", _total_size, + size_t local_total_size = _total_size.load_relaxed(); + + assert(local_total_size == _total_size_before, "total_size = %zu before = %zu", local_total_size, _total_size_before); + size_t mem_size = local_total_size * (sizeof(oop) + sizeof(markWord)); + log_trace(gc)("Restored %zu marks, occupying %zu %s", local_total_size, byte_size_in_proper_unit(mem_size), proper_unit_for_byte_size(mem_size)); } diff --git a/src/hotspot/share/gc/shared/preservedMarks.hpp b/src/hotspot/share/gc/shared/preservedMarks.hpp index 10f75116524..3bbbd335011 100644 --- a/src/hotspot/share/gc/shared/preservedMarks.hpp +++ b/src/hotspot/share/gc/shared/preservedMarks.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,8 +59,7 @@ public: size_t size() const { return _stack.size(); } inline void push_if_necessary(oop obj, markWord m); inline void push_always(oop obj, markWord m); - // Iterate over the stack, restore all preserved marks, and - // reclaim the memory taken up by the stack segments. + // Restore all preserved marks, and reclaim the memory taken up by the stack segments. void restore(); // Adjust the preserved mark according to its @@ -71,8 +70,6 @@ public: // to their forwarding location stored in the mark. void adjust_during_full_gc(); - void restore_and_increment(volatile size_t* const _total_size_addr); - // Assert the stack is empty and has no cached segments. void assert_empty() PRODUCT_RETURN; From 681e4ec8d37f4e30462b43e1c789d53525211b0a Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 29 Jan 2026 08:54:59 +0000 Subject: [PATCH 244/328] 8376350: Convert ReferenceProcessorPhaseTimes to use Atomic Reviewed-by: stefank, iwalulya --- .../share/gc/shared/referenceProcessorPhaseTimes.cpp | 9 ++++----- .../share/gc/shared/referenceProcessorPhaseTimes.hpp | 5 +++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp b/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp index df7d8f7b38d..0371ed2c73b 100644 --- a/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp +++ b/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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,6 @@ #include "logging/logStream.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" -#include "runtime/atomicAccess.hpp" #define ASSERT_REF_TYPE(ref_type) assert((ref_type) >= REF_SOFT && (ref_type) <= REF_PHANTOM, \ "Invariant (%d)", (int)ref_type) @@ -196,7 +195,7 @@ void ReferenceProcessorPhaseTimes::reset() { _soft_weak_final_refs_phase_worker_time_sec->reset(); for (int i = 0; i < number_of_subclasses_of_ref; i++) { - _ref_dropped[i] = 0; + _ref_dropped[i].store_relaxed(0); _ref_discovered[i] = 0; } @@ -214,7 +213,7 @@ ReferenceProcessorPhaseTimes::~ReferenceProcessorPhaseTimes() { void ReferenceProcessorPhaseTimes::add_ref_dropped(ReferenceType ref_type, size_t count) { ASSERT_REF_TYPE(ref_type); - AtomicAccess::add(&_ref_dropped[ref_type_2_index(ref_type)], count, memory_order_relaxed); + _ref_dropped[ref_type_2_index(ref_type)].add_then_fetch(count, memory_order_relaxed); } void ReferenceProcessorPhaseTimes::set_ref_discovered(ReferenceType ref_type, size_t count) { @@ -271,7 +270,7 @@ void ReferenceProcessorPhaseTimes::print_reference(ReferenceType ref_type, uint int const ref_type_index = ref_type_2_index(ref_type); size_t discovered = _ref_discovered[ref_type_index]; - size_t dropped = _ref_dropped[ref_type_index]; + size_t dropped = _ref_dropped[ref_type_index].load_relaxed(); assert(discovered >= dropped, "invariant"); size_t processed = discovered - dropped; diff --git a/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.hpp b/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.hpp index 16691452ef4..82d26902bce 100644 --- a/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.hpp +++ b/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ #include "gc/shared/workerDataArray.hpp" #include "memory/allocation.hpp" #include "memory/referenceType.hpp" +#include "runtime/atomic.hpp" #include "utilities/ticks.hpp" class DiscoveredList; @@ -52,7 +53,7 @@ class ReferenceProcessorPhaseTimes : public CHeapObj { // Total spent time for reference processing. double _total_time_ms; - size_t _ref_dropped[number_of_subclasses_of_ref]; + Atomic _ref_dropped[number_of_subclasses_of_ref]; size_t _ref_discovered[number_of_subclasses_of_ref]; bool _processing_is_mt; From f96974dbbd824db8d7b2bbf28f5d3b49bb005fb3 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 29 Jan 2026 11:30:42 +0000 Subject: [PATCH 245/328] 8373898: RepeatCompilation does not repeat compilation after bailout Reviewed-by: chagedorn, bmaillard --- src/hotspot/share/compiler/compileBroker.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 574f4d6543b..7b236ed3589 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, 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 @@ -2346,12 +2346,18 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { /* Repeat compilation without installing code for profiling purposes */ int repeat_compilation_count = directive->RepeatCompilationOption; - while (repeat_compilation_count > 0) { - ResourceMark rm(thread); - task->print_ul("NO CODE INSTALLED"); - thread->timeout()->reset(); - comp->compile_method(&ci_env, target, osr_bci, false, directive); - repeat_compilation_count--; + if (repeat_compilation_count > 0) { + CHeapStringHolder failure_reason; + failure_reason.set(ci_env._failure_reason.get()); + while (repeat_compilation_count > 0) { + ResourceMark rm(thread); + task->print_ul("NO CODE INSTALLED"); + thread->timeout()->reset(); + ci_env._failure_reason.clear(); + comp->compile_method(&ci_env, target, osr_bci, false, directive); + repeat_compilation_count--; + } + ci_env._failure_reason.set(failure_reason.get()); } } From 48846744ca96ce3c6464a1a440b9e46119dfbb88 Mon Sep 17 00:00:00 2001 From: Boris Ulasevich Date: Thu, 29 Jan 2026 12:37:51 +0000 Subject: [PATCH 246/328] 8374343: Fix SIGSEGV when lib/modules is unreadable Reviewed-by: iklam, dholmes --- src/hotspot/share/classfile/classLoader.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index d9a63cd154b..f631bfaa102 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -1418,6 +1418,10 @@ char* ClassLoader::lookup_vm_options() { jio_snprintf(modules_path, JVM_MAXPATHLEN, "%s%slib%smodules", Arguments::get_java_home(), fileSep, fileSep); JImage_file =(*JImageOpen)(modules_path, &error); if (JImage_file == nullptr) { + if (Arguments::has_jimage()) { + // The modules file exists but is unreadable or corrupt + vm_exit_during_initialization(err_msg("Unable to load %s", modules_path)); + } return nullptr; } From e85d5d7a16024f6a3eda14f1e08f72e07ae38dd0 Mon Sep 17 00:00:00 2001 From: Kerem Kat Date: Thu, 29 Jan 2026 12:43:48 +0000 Subject: [PATCH 247/328] 8375010: C2 VectorAPI: assert(vbox->is_CheckCastPP()) failed: should be expanded 8374903: C2 VectorAPI: assert(vbox->as_Phi()->region() == vect->as_Phi()->region()) failed Reviewed-by: qamai, vlivanov --- src/hotspot/share/opto/vector.cpp | 38 +++---------- .../vectorapi/VectorBoxExpandPhi.java | 50 +++++++++++++++++ .../vectorapi/VectorBoxExpandProj.java | 54 +++++++++++++++++++ 3 files changed, 112 insertions(+), 30 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/VectorBoxExpandPhi.java create mode 100644 test/hotspot/jtreg/compiler/vectorapi/VectorBoxExpandProj.java diff --git a/src/hotspot/share/opto/vector.cpp b/src/hotspot/share/opto/vector.cpp index cf01b2442e6..f44df7e6da2 100644 --- a/src/hotspot/share/opto/vector.cpp +++ b/src/hotspot/share/opto/vector.cpp @@ -326,37 +326,15 @@ Node* PhaseVector::expand_vbox_node_helper(Node* vbox, return expand_vbox_alloc_node(vbox_alloc, vect, box_type, vect_type); } - // Handle the case when both the allocation input and vector input to - // VectorBoxNode are Phi. This case is generated after the transformation of - // Phi: Phi (VectorBox1 VectorBox2) => VectorBox (Phi1 Phi2). - // With this optimization, the relative two allocation inputs of VectorBox1 and - // VectorBox2 are gathered into Phi1 now. Similarly, the original vector - // inputs of two VectorBox nodes are in Phi2. - // - // See PhiNode::merge_through_phi in cfg.cpp for more details. - if (vbox->is_Phi() && vect->is_Phi()) { - assert(vbox->as_Phi()->region() == vect->as_Phi()->region(), ""); + // Handle the case when the allocation input to VectorBoxNode is a Phi. + // This is generated after the transformation in PhiNode::merge_through_phi: + // Phi (VectorBox1 VectorBox2) => VectorBox (Phi1 Phi2) + // The vector input may also be a Phi (Phi2 above), or it may have been + // value-numbered to a single node if all inputs were identical. + if (vbox->is_Phi()) { + bool same_region = vect->is_Phi() && vbox->as_Phi()->region() == vect->as_Phi()->region(); for (uint i = 1; i < vbox->req(); i++) { - Node* new_box = expand_vbox_node_helper(vbox->in(i), vect->in(i), - box_type, vect_type, visited); - if (!new_box->is_Phi()) { - C->initial_gvn()->hash_delete(vbox); - vbox->set_req(i, new_box); - } - } - return C->initial_gvn()->transform(vbox); - } - - // Handle the case when the allocation input to VectorBoxNode is a phi - // but the vector input is not, which can definitely be the case if the - // vector input has been value-numbered. It seems to be safe to do by - // construction because VectorBoxNode and VectorBoxAllocate come in a - // specific order as a result of expanding an intrinsic call. After that, if - // any of the inputs to VectorBoxNode are value-numbered they can only - // move up and are guaranteed to dominate. - if (vbox->is_Phi() && (vect->is_Vector() || vect->is_LoadVector())) { - for (uint i = 1; i < vbox->req(); i++) { - Node* new_box = expand_vbox_node_helper(vbox->in(i), vect, + Node* new_box = expand_vbox_node_helper(vbox->in(i), same_region ? vect->in(i) : vect, box_type, vect_type, visited); if (!new_box->is_Phi()) { C->initial_gvn()->hash_delete(vbox); diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorBoxExpandPhi.java b/test/hotspot/jtreg/compiler/vectorapi/VectorBoxExpandPhi.java new file mode 100644 index 00000000000..936d24e4767 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorBoxExpandPhi.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2026, 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.vectorapi; + +import jdk.incubator.vector.*; + +/* + * @test + * @bug 8374903 + * @summary C2 crashes when VectorBox Phi and vector Phi have different regions + * @modules jdk.incubator.vector + * @library /test/lib + * + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,compiler.vectorapi.VectorBoxExpandPhi::test compiler.vectorapi.VectorBoxExpandPhi + */ +public class VectorBoxExpandPhi { + public static void main(String[] args) { + for (int i = 0; i < 10_000; i++) { + test(); + } + } + + public static Object test() { + var v0 = DoubleVector.broadcast(DoubleVector.SPECIES_128, 1.0); + var v1 = (FloatVector)v0.convertShape(VectorOperators.Conversion.ofCast(double.class, float.class), FloatVector.SPECIES_64, 0); + var v2 = (FloatVector)v1.convertShape(VectorOperators.Conversion.ofReinterpret(float.class, float.class), FloatVector.SPECIES_64, 0); + return v2; + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorBoxExpandProj.java b/test/hotspot/jtreg/compiler/vectorapi/VectorBoxExpandProj.java new file mode 100644 index 00000000000..5d152834b17 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorBoxExpandProj.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2026, 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.vectorapi; + +import jdk.incubator.vector.*; + +/* + * @test + * @bug 8375010 + * @summary C2 crashes when expanding VectorBox with Proj input from vector math call + * @modules jdk.incubator.vector + * @library /test/lib + * + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,compiler.vectorapi.VectorBoxExpandProj::test compiler.vectorapi.VectorBoxExpandProj + */ +public class VectorBoxExpandProj { + static boolean b; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + b = !b; + test(); + } + System.out.println("PASS"); + } + + // TAN returns Proj (not VectorNode). Phi merging creates VectorBox(Phi, Proj). + // expand_vbox_node_helper must handle Proj inputs with vector type. + static Object test() { + var t = DoubleVector.broadcast(DoubleVector.SPECIES_128, 1.0).lanewise(VectorOperators.TAN); + return b ? t.convertShape(VectorOperators.Conversion.ofCast(double.class, double.class), DoubleVector.SPECIES_128, 0) : t; + } +} From 99119597aa95c1139ae2259bed5ec885a7c01269 Mon Sep 17 00:00:00 2001 From: Ferenc Rakoczi Date: Thu, 29 Jan 2026 12:52:23 +0000 Subject: [PATCH 248/328] 8374755: ML-KEM's 12-bit decompression can be simplified on aarch64 Reviewed-by: adinn --- .../cpu/aarch64/stubGenerator_aarch64.cpp | 83 +++---------------- .../com/sun/crypto/provider/ML_KEM.java | 22 ++--- 2 files changed, 18 insertions(+), 87 deletions(-) diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 7e2f333ba40..db653bcf236 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -6081,14 +6081,18 @@ class StubGenerator: public StubCodeGenerator { // static int implKyber12To16( // byte[] condensed, int index, short[] parsed, int parsedLength) {} // - // (parsedLength or (parsedLength - 48) must be divisible by 64.) + // we assume that parsed and condensed are allocated such that for + // n = (parsedLength + 63) / 64 + // n blocks of 96 bytes of input can be processed, i.e. + // index + n * 96 <= condensed.length and + // n * 64 <= parsed.length // // condensed (byte[]) = c_rarg0 // condensedIndex = c_rarg1 - // parsed (short[112 or 256]) = c_rarg2 - // parsedLength (112 or 256) = c_rarg3 + // parsed (short[]) = c_rarg2 + // parsedLength = c_rarg3 address generate_kyber12To16() { - Label L_F00, L_loop, L_end; + Label L_F00, L_loop; __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_kyber12To16_id; @@ -6209,75 +6213,8 @@ class StubGenerator: public StubCodeGenerator { vs_st2_post(vs_front(vb), __ T8H, parsed); __ sub(parsedLength, parsedLength, 64); - __ cmp(parsedLength, (u1)64); - __ br(Assembler::GE, L_loop); - __ cbz(parsedLength, L_end); - - // if anything is left it should be a final 72 bytes of input - // i.e. a final 48 12-bit values. so we handle this by loading - // 48 bytes into all 16B lanes of front(vin) and only 24 - // bytes into the lower 8B lane of back(vin) - vs_ld3_post(vs_front(vin), __ T16B, condensed); - vs_ld3(vs_back(vin), __ T8B, condensed); - - // Expand vin[0] into va[0:1], and vin[1] into va[2:3] and va[4:5] - // n.b. target elements 2 and 3 of va duplicate elements 4 and - // 5 and target element 2 of vb duplicates element 4. - __ ushll(va[0], __ T8H, vin[0], __ T8B, 0); - __ ushll2(va[1], __ T8H, vin[0], __ T16B, 0); - __ ushll(va[2], __ T8H, vin[1], __ T8B, 0); - __ ushll2(va[3], __ T8H, vin[1], __ T16B, 0); - __ ushll(va[4], __ T8H, vin[1], __ T8B, 0); - __ ushll2(va[5], __ T8H, vin[1], __ T16B, 0); - - // This time expand just the lower 8 lanes - __ ushll(vb[0], __ T8H, vin[3], __ T8B, 0); - __ ushll(vb[2], __ T8H, vin[4], __ T8B, 0); - __ ushll(vb[4], __ T8H, vin[4], __ T8B, 0); - - // shift lo byte of copy 1 of the middle stripe into the high byte - __ shl(va[2], __ T8H, va[2], 8); - __ shl(va[3], __ T8H, va[3], 8); - __ shl(vb[2], __ T8H, vb[2], 8); - - // expand vin[2] into va[6:7] and lower 8 lanes of vin[5] into - // vb[6] pre-shifted by 4 to ensure top bits of the input 12-bit - // int are in bit positions [4..11]. - __ ushll(va[6], __ T8H, vin[2], __ T8B, 4); - __ ushll2(va[7], __ T8H, vin[2], __ T16B, 4); - __ ushll(vb[6], __ T8H, vin[5], __ T8B, 4); - - // mask hi 4 bits of each 1st 12-bit int in pair from copy1 and - // shift lo 4 bits of each 2nd 12-bit int in pair to bottom of - // copy2 - __ andr(va[2], __ T16B, va[2], v31); - __ andr(va[3], __ T16B, va[3], v31); - __ ushr(va[4], __ T8H, va[4], 4); - __ ushr(va[5], __ T8H, va[5], 4); - __ andr(vb[2], __ T16B, vb[2], v31); - __ ushr(vb[4], __ T8H, vb[4], 4); - - - - // sum hi 4 bits and lo 8 bits of each 1st 12-bit int in pair and - // hi 8 bits plus lo 4 bits of each 2nd 12-bit int in pair - - // n.b. ordering ensures: i) inputs are consumed before they are - // overwritten ii) order of 16-bit results across succsessive - // pairs of vectors in va and then lower half of vb reflects order - // of corresponding 12-bit inputs - __ addv(va[0], __ T8H, va[0], va[2]); - __ addv(va[2], __ T8H, va[1], va[3]); - __ addv(va[1], __ T8H, va[4], va[6]); - __ addv(va[3], __ T8H, va[5], va[7]); - __ addv(vb[0], __ T8H, vb[0], vb[2]); - __ addv(vb[1], __ T8H, vb[4], vb[6]); - - // store 48 results interleaved as shorts - vs_st2_post(vs_front(va), __ T8H, parsed); - vs_st2_post(vs_front(vs_front(vb)), __ T8H, parsed); - - __ BIND(L_end); + __ cmp(parsedLength, (u1)0); + __ br(Assembler::GT, L_loop); __ leave(); // required for proper stackwalking of RuntimeStub frame __ mov(r0, zr); // return 0 diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java b/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java index 1280ccdad74..bf6576f4d93 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java @@ -1353,22 +1353,16 @@ public final class ML_KEM { } } - // The intrinsic implementations assume that the input and output buffers - // are such that condensed can be read in 96-byte chunks and - // parsed can be written in 64 shorts chunks except for the last chunk - // that can be either 48 or 64 shorts. In other words, - // if (i - 1) * 64 < parsedLengths <= i * 64 then - // parsed.length should be either i * 64 or (i-1) * 64 + 48 and - // condensed.length should be at least index + i * 96. + // An intrinsic implementation assumes that the input and output buffers + // are such that condensed can be read in chunks of 192 bytes and + // parsed can be written in chunks of 128 shorts, so callers should allocate + // the condensed and parsed arrays accordingly, see the assert() private void twelve2Sixteen(byte[] condensed, int index, short[] parsed, int parsedLength) { - int i = parsedLength / 64; - int remainder = parsedLength - i * 64; - if (remainder != 0) { - i++; - } - assert ((remainder == 0) || (remainder == 48)) && - (index + i * 96 <= condensed.length); + int n = (parsedLength + 127) / 128; + assert ((parsed.length >= n * 128) && + (condensed.length >= index + n * 192)); + implKyber12To16(condensed, index, parsed, parsedLength); } From 7c6c34e150cf01cec5d166f6cbb8a649c75b0627 Mon Sep 17 00:00:00 2001 From: Kerem Kat Date: Thu, 29 Jan 2026 13:11:47 +0000 Subject: [PATCH 249/328] 8370502: C2: segfault while adding node to IGVN worklist Reviewed-by: mhaessig, dlong --- src/hotspot/share/opto/macro.cpp | 22 ++++---- .../c2/TestUnlockNodeNullMemprof.java | 53 +++++++++++++++++++ 2 files changed, 63 insertions(+), 12 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/TestUnlockNodeNullMemprof.java diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 56262d226fc..9470001b2d2 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -2322,12 +2322,7 @@ void PhaseMacroExpand::expand_unlock_node(UnlockNode *unlock) { // No need for a null check on unlock // Make the merge point - Node *region; - Node *mem_phi; - - region = new RegionNode(3); - // create a Phi for the memory state - mem_phi = new PhiNode( region, Type::MEMORY, TypeRawPtr::BOTTOM); + Node* region = new RegionNode(3); FastUnlockNode *funlock = new FastUnlockNode( ctrl, obj, box ); funlock = transform_later( funlock )->as_FastUnlock(); @@ -2356,12 +2351,15 @@ void PhaseMacroExpand::expand_unlock_node(UnlockNode *unlock) { transform_later(region); _igvn.replace_node(_callprojs.fallthrough_proj, region); - Node *memproj = transform_later(new ProjNode(call, TypeFunc::Memory) ); - mem_phi->init_req(1, memproj ); - mem_phi->init_req(2, mem); - transform_later(mem_phi); - - _igvn.replace_node(_callprojs.fallthrough_memproj, mem_phi); + if (_callprojs.fallthrough_memproj != nullptr) { + // create a Phi for the memory state + Node* mem_phi = new PhiNode( region, Type::MEMORY, TypeRawPtr::BOTTOM); + Node* memproj = transform_later(new ProjNode(call, TypeFunc::Memory)); + mem_phi->init_req(1, memproj); + mem_phi->init_req(2, mem); + transform_later(mem_phi); + _igvn.replace_node(_callprojs.fallthrough_memproj, mem_phi); + } } void PhaseMacroExpand::expand_subtypecheck_node(SubTypeCheckNode *check) { diff --git a/test/hotspot/jtreg/compiler/c2/TestUnlockNodeNullMemprof.java b/test/hotspot/jtreg/compiler/c2/TestUnlockNodeNullMemprof.java new file mode 100644 index 00000000000..f86dc495fd2 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestUnlockNodeNullMemprof.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8370502 + * @summary Do not segfault while adding node to IGVN worklist + * + * @run main/othervm -Xbatch ${test.main.class} + */ + +package compiler.c2; + +public class TestUnlockNodeNullMemprof { + public static void main(String[] args) { + int[] a = new int[0]; // test only valid when size is 0. + for (int i = 0; i < Integer.valueOf(10000); i++) // test only valid with boxed loop limit + try { + test(a); + } catch (ArrayIndexOutOfBoundsException e) { + } + } + + static void test(int[] a) { + for (int i = 0; i < 1;) { + a[i] = 0; + synchronized (TestUnlockNodeNullMemprof.class) { + } + for (int j = 0; Integer.valueOf(j) < 1;) + j = 0; + } + } +} From a54ff1bff45e1cb30100cbaa253494c3462f7abd Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 29 Jan 2026 16:29:34 +0000 Subject: [PATCH 250/328] 8376523: Move interned strings into AOT heap roots array Reviewed-by: kvn, shade --- src/hotspot/share/cds/aotMappedHeapLoader.cpp | 4 +- src/hotspot/share/cds/aotMetaspace.cpp | 6 - src/hotspot/share/cds/heapShared.cpp | 12 +- src/hotspot/share/cds/heapShared.hpp | 3 +- src/hotspot/share/classfile/stringTable.cpp | 184 ++---------------- src/hotspot/share/classfile/stringTable.hpp | 43 +--- .../sharedStrings/SharedStringsStress.java | 4 +- 7 files changed, 27 insertions(+), 229 deletions(-) diff --git a/src/hotspot/share/cds/aotMappedHeapLoader.cpp b/src/hotspot/share/cds/aotMappedHeapLoader.cpp index a8678ed757f..146228436f4 100644 --- a/src/hotspot/share/cds/aotMappedHeapLoader.cpp +++ b/src/hotspot/share/cds/aotMappedHeapLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -465,8 +465,6 @@ void AOTMappedHeapLoader::finish_initialization(FileMapInfo* info) { assert(segment_oop->is_objArray(), "Must be"); add_root_segment((objArrayOop)segment_oop); } - - StringTable::load_shared_strings_array(); } } diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index 683c897d855..62d76957c0a 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -1162,12 +1162,6 @@ void AOTMetaspace::dump_static_archive_impl(StaticArchiveBuilder& builder, TRAPS // Perhaps there is a way to avoid hard-coding these names here. // See discussion in JDK-8342481. } - - if (HeapShared::is_writing_mapping_mode()) { - // Do this at the very end, when no Java code will be executed. Otherwise - // some new strings may be added to the intern table. - StringTable::allocate_shared_strings_array(CHECK); - } } else { log_info(aot)("Not dumping heap, reset CDSConfig::_is_using_optimized_module_handling"); CDSConfig::stop_using_optimized_module_handling(); diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 89694c6780e..42129011612 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -413,6 +413,8 @@ void HeapShared::materialize_thread_object() { void HeapShared::add_to_dumped_interned_strings(oop string) { assert(HeapShared::is_writing_mapping_mode(), "Only used by this mode"); AOTMappedHeapWriter::add_to_dumped_interned_strings(string); + bool success = archive_reachable_objects_from(1, _dump_time_special_subgraph, string); + assert(success, "shared strings array must not point to arrays or strings that are too large to archive"); } void HeapShared::finalize_initialization(FileMapInfo* static_mapinfo) { @@ -831,14 +833,6 @@ static objArrayOop get_archived_resolved_references(InstanceKlass* src_ik) { return nullptr; } -void HeapShared::archive_strings() { - assert(HeapShared::is_writing_mapping_mode(), "should not reach here"); - oop shared_strings_array = StringTable::init_shared_strings_array(); - bool success = archive_reachable_objects_from(1, _dump_time_special_subgraph, shared_strings_array); - assert(success, "shared strings array must not point to arrays or strings that are too large to archive"); - StringTable::set_shared_strings_array_index(append_root(shared_strings_array)); -} - int HeapShared::archive_exception_instance(oop exception) { bool success = archive_reachable_objects_from(1, _dump_time_special_subgraph, exception); assert(success, "sanity"); @@ -890,7 +884,7 @@ void HeapShared::start_scanning_for_oops() { void HeapShared::end_scanning_for_oops() { if (is_writing_mapping_mode()) { - archive_strings(); + StringTable::init_shared_table(); } delete_seen_objects_table(); } diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index 118c60faa60..3c7068e96ab 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -478,7 +478,6 @@ private: static bool has_been_archived(oop orig_obj); static void prepare_resolved_references(); - static void archive_strings(); static void archive_subgraphs(); static void copy_java_mirror(oop orig_mirror, oop scratch_m); diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index 20dfad0d980..bbc12c8dcab 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -74,24 +74,9 @@ const size_t REHASH_LEN = 100; const double CLEAN_DEAD_HIGH_WATER_MARK = 0.5; #if INCLUDE_CDS_JAVA_HEAP -bool StringTable::_is_two_dimensional_shared_strings_array = false; -OopHandle StringTable::_shared_strings_array; -int StringTable::_shared_strings_array_root_index; - inline oop StringTable::read_string_from_compact_hashtable(address base_address, u4 index) { assert(AOTMappedHeapLoader::is_in_use(), "sanity"); - objArrayOop array = (objArrayOop)(_shared_strings_array.resolve()); - oop s; - - if (!_is_two_dimensional_shared_strings_array) { - s = array->obj_at((int)index); - } else { - int primary_index = index >> _secondary_array_index_bits; - int secondary_index = index & _secondary_array_index_mask; - objArrayOop secondary = (objArrayOop)array->obj_at(primary_index); - s = secondary->obj_at(secondary_index); - } - + oop s = HeapShared::get_root((int)index, false); assert(java_lang_String::is_instance(s), "must be"); return s; } @@ -115,7 +100,6 @@ OopStorage* StringTable::_oop_storage; static size_t _current_size = 0; static volatile size_t _items_count = 0; -DEBUG_ONLY(static bool _disable_interning_during_cds_dump = false); volatile bool _alt_hash = false; @@ -317,12 +301,6 @@ void StringTable::create_table() { _oop_storage->register_num_dead_callback(&gc_notification); } -#if INCLUDE_CDS_JAVA_HEAP -void StringTable::load_shared_strings_array() { - _shared_strings_array = OopHandle(Universe::vm_global(), HeapShared::get_root(_shared_strings_array_root_index)); -} -#endif - void StringTable::item_added() { AtomicAccess::inc(&_items_count); } @@ -509,9 +487,6 @@ oop StringTable::intern(const char* utf8_string, TRAPS) { } oop StringTable::intern(const StringWrapper& name, TRAPS) { - assert(!AtomicAccess::load_acquire(&_disable_interning_during_cds_dump), - "All threads that may intern strings should have been stopped before CDS starts copying the interned string table"); - // shared table always uses java_lang_String::hash_code unsigned int hash = hash_wrapped_string(name); oop found_string = lookup_shared(name, hash); @@ -957,118 +932,13 @@ oop StringTable::lookup_shared(const jchar* name, int len) { return _shared_table.lookup(wrapped_name, java_lang_String::hash_code(name, len), 0); } -// This is called BEFORE we enter the CDS safepoint. We can still allocate Java object arrays to -// be used by the shared strings table. -void StringTable::allocate_shared_strings_array(TRAPS) { - if (!CDSConfig::is_dumping_heap()) { - return; - } +void StringTable::init_shared_table() { + assert(SafepointSynchronize::is_at_safepoint(), "inside AOT safepoint"); + precond(CDSConfig::is_dumping_heap()); + assert(HeapShared::is_writing_mapping_mode(), "not used for streamed oops"); - assert(HeapShared::is_writing_mapping_mode(), "should not reach here"); - - CompileBroker::wait_for_no_active_tasks(); - - precond(CDSConfig::allow_only_single_java_thread()); - - // At this point, no more strings will be added: - // - There's only a single Java thread (this thread). It no longer executes Java bytecodes - // so JIT compilation will eventually stop. - // - CompileBroker has no more active tasks, so all JIT requests have been processed. - - // This flag will be cleared after intern table dumping has completed, so we can run the - // compiler again (for future AOT method compilation, etc). - DEBUG_ONLY(AtomicAccess::release_store(&_disable_interning_during_cds_dump, true)); - - if (items_count_acquire() > (size_t)max_jint) { - fatal("Too many strings to be archived: %zu", items_count_acquire()); - } - - int total = (int)items_count_acquire(); - size_t single_array_size = objArrayOopDesc::object_size(total); - - log_info(aot)("allocated string table for %d strings", total); - - if (!HeapShared::is_too_large_to_archive(single_array_size)) { - // The entire table can fit in a single array - objArrayOop array = oopFactory::new_objArray(vmClasses::Object_klass(), total, CHECK); - _shared_strings_array = OopHandle(Universe::vm_global(), array); - log_info(aot)("string table array (single level) length = %d", total); - } else { - // Split the table in two levels of arrays. - int primary_array_length = (total + _secondary_array_max_length - 1) / _secondary_array_max_length; - size_t primary_array_size = objArrayOopDesc::object_size(primary_array_length); - size_t secondary_array_size = objArrayOopDesc::object_size(_secondary_array_max_length); - - if (HeapShared::is_too_large_to_archive(secondary_array_size)) { - // This can only happen if you have an extremely large number of classes that - // refer to more than 16384 * 16384 = 26M interned strings! Not a practical concern - // but bail out for safety. - log_error(aot)("Too many strings to be archived: %zu", items_count_acquire()); - AOTMetaspace::unrecoverable_writing_error(); - } - - objArrayOop primary = oopFactory::new_objArray(vmClasses::Object_klass(), primary_array_length, CHECK); - objArrayHandle primaryHandle(THREAD, primary); - _shared_strings_array = OopHandle(Universe::vm_global(), primary); - - log_info(aot)("string table array (primary) length = %d", primary_array_length); - for (int i = 0; i < primary_array_length; i++) { - int len; - if (total > _secondary_array_max_length) { - len = _secondary_array_max_length; - } else { - len = total; - } - total -= len; - - objArrayOop secondary = oopFactory::new_objArray(vmClasses::Object_klass(), len, CHECK); - primaryHandle()->obj_at_put(i, secondary); - - log_info(aot)("string table array (secondary)[%d] length = %d", i, len); - assert(!HeapShared::is_too_large_to_archive(secondary), "sanity"); - } - - assert(total == 0, "must be"); - _is_two_dimensional_shared_strings_array = true; - } -} - -#ifndef PRODUCT -void StringTable::verify_secondary_array_index_bits() { - assert(HeapShared::is_writing_mapping_mode(), "should not reach here"); - int max; - for (max = 1; ; max++) { - size_t next_size = objArrayOopDesc::object_size(1 << (max + 1)); - if (HeapShared::is_too_large_to_archive(next_size)) { - break; - } - } - // Currently max is 17 for +UseCompressedOops, 16 for -UseCompressedOops. - // When we add support for Shenandoah (which has a smaller mininum region size than G1), - // max will become 15/14. - // - // We use _secondary_array_index_bits==14 as that will be the eventual value, and will - // make testing easier. - assert(_secondary_array_index_bits <= max, - "_secondary_array_index_bits (%d) must be smaller than max possible value (%d)", - _secondary_array_index_bits, max); -} -#endif // PRODUCT - -// This is called AFTER we enter the CDS safepoint. -// -// For each shared string: -// [1] Store it into _shared_strings_array. Encode its position as a 32-bit index. -// [2] Store the index and hashcode into _shared_table. -oop StringTable::init_shared_strings_array() { - assert(CDSConfig::is_dumping_heap(), "must be"); - assert(HeapShared::is_writing_mapping_mode(), "should not reach here"); - objArrayOop array = (objArrayOop)(_shared_strings_array.resolve()); - - verify_secondary_array_index_bits(); - - int index = 0; - auto copy_into_array = [&] (WeakHandle* val) { + int n = 0; + auto copy_into_aot_heap = [&] (WeakHandle* val) { oop string = val->peek(); if (string != nullptr && !HeapShared::is_string_too_large_to_archive(string)) { // If string is too large, don't put it into the string table. @@ -1077,53 +947,34 @@ oop StringTable::init_shared_strings_array() { // - If there's a reference to it, we will report an error inside HeapShared.cpp and // dumping will fail. HeapShared::add_to_dumped_interned_strings(string); - if (!_is_two_dimensional_shared_strings_array) { - assert(index < array->length(), "no strings should have been added"); - array->obj_at_put(index, string); - } else { - int primary_index = index >> _secondary_array_index_bits; - int secondary_index = index & _secondary_array_index_mask; - - assert(primary_index < array->length(), "no strings should have been added"); - objArrayOop secondary = (objArrayOop)array->obj_at(primary_index); - - assert(secondary != nullptr && secondary->is_objArray(), "must be"); - assert(secondary_index < secondary->length(), "no strings should have been added"); - secondary->obj_at_put(secondary_index, string); - } - index ++; } + n++; return true; }; - _local_table->do_safepoint_scan(copy_into_array); - log_info(aot)("Archived %d interned strings", index); - return array; + _local_table->do_safepoint_scan(copy_into_aot_heap); + log_info(aot)("Archived %d interned strings", n); }; void StringTable::write_shared_table() { + assert(SafepointSynchronize::is_at_safepoint(), "inside AOT safepoint"); + precond(CDSConfig::is_dumping_heap()); + assert(HeapShared::is_writing_mapping_mode(), "not used for streamed oops"); + _shared_table.reset(); CompactHashtableWriter writer((int)items_count_acquire(), ArchiveBuilder::string_stats()); - int index = 0; auto copy_into_shared_table = [&] (WeakHandle* val) { oop string = val->peek(); if (string != nullptr && !HeapShared::is_string_too_large_to_archive(string)) { unsigned int hash = java_lang_String::hash_code(string); - writer.add(hash, index); - index ++; + int root_id = HeapShared::append_root(string); + writer.add(hash, root_id); } return true; }; _local_table->do_safepoint_scan(copy_into_shared_table); writer.dump(&_shared_table, "string"); - - DEBUG_ONLY(AtomicAccess::release_store(&_disable_interning_during_cds_dump, false)); -} - -void StringTable::set_shared_strings_array_index(int root_index) { - assert(HeapShared::is_writing_mapping_mode(), "should not reach here"); - _shared_strings_array_root_index = root_index; } void StringTable::serialize_shared_table_header(SerializeClosure* soc) { @@ -1135,8 +986,5 @@ void StringTable::serialize_shared_table_header(SerializeClosure* soc) { } else if (!AOTMappedHeapLoader::is_in_use()) { _shared_table.reset(); } - - soc->do_bool(&_is_two_dimensional_shared_strings_array); - soc->do_int(&_shared_strings_array_root_index); } #endif //INCLUDE_CDS_JAVA_HEAP diff --git a/src/hotspot/share/classfile/stringTable.hpp b/src/hotspot/share/classfile/stringTable.hpp index 839e9d9053d..94a0db5b5a5 100644 --- a/src/hotspot/share/classfile/stringTable.hpp +++ b/src/hotspot/share/classfile/stringTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -109,48 +109,15 @@ public: static bool needs_rehashing() { return _needs_rehashing; } static inline void update_needs_rehash(bool rehash); - // Sharing -#if INCLUDE_CDS_JAVA_HEAP - static inline oop read_string_from_compact_hashtable(address base_address, u4 index); - + // AOT support + static inline oop read_string_from_compact_hashtable(address base_address, u4 index) NOT_CDS_JAVA_HEAP_RETURN_(nullptr); private: - static bool _is_two_dimensional_shared_strings_array; - static OopHandle _shared_strings_array; - static int _shared_strings_array_root_index; - - // All the shared strings are referenced through _shared_strings_array to keep them alive. - // Each shared string is stored as a 32-bit index in ::_shared_table. The index - // is interpreted in two ways: - // - // [1] _is_two_dimensional_shared_strings_array = false: _shared_strings_array is an Object[]. - // Each shared string is stored as _shared_strings_array[index] - // - // [2] _is_two_dimensional_shared_strings_array = true: _shared_strings_array is an Object[][] - // This happens when there are too many elements in the shared table. We store them - // using two levels of objArrays, such that none of the arrays are too big for - // AOTMappedHeapWriter::is_too_large_to_archive(). In this case, the index is splited into two - // parts. Each shared string is stored as _shared_strings_array[primary_index][secondary_index]: - // - // [bits 31 .. 14][ bits 13 .. 0 ] - // primary_index secondary_index - const static int _secondary_array_index_bits = 14; - const static int _secondary_array_max_length = 1 << _secondary_array_index_bits; - const static int _secondary_array_index_mask = _secondary_array_max_length - 1; - - // make sure _secondary_array_index_bits is not too big - static void verify_secondary_array_index_bits() PRODUCT_RETURN; -#endif // INCLUDE_CDS_JAVA_HEAP - - private: static oop lookup_shared(const StringWrapper& name, unsigned int hash) NOT_CDS_JAVA_HEAP_RETURN_(nullptr); - public: +public: static oop lookup_shared(const jchar* name, int len) NOT_CDS_JAVA_HEAP_RETURN_(nullptr); static size_t shared_entry_count() NOT_CDS_JAVA_HEAP_RETURN_(0); - static void allocate_shared_strings_array(TRAPS) NOT_CDS_JAVA_HEAP_RETURN; - static void load_shared_strings_array() NOT_CDS_JAVA_HEAP_RETURN; - static oop init_shared_strings_array() NOT_CDS_JAVA_HEAP_RETURN_(nullptr); + static void init_shared_table() NOT_CDS_JAVA_HEAP_RETURN; static void write_shared_table() NOT_CDS_JAVA_HEAP_RETURN; - static void set_shared_strings_array_index(int root_index) NOT_CDS_JAVA_HEAP_RETURN; static void serialize_shared_table_header(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN; // Jcmd diff --git a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsStress.java b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsStress.java index 4d176c949c6..dc677756ffa 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsStress.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsStress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -80,8 +80,6 @@ public class SharedStringsStress { "-Xlog:gc+region+cds", "-Xlog:gc+region=trace")); TestCommon.checkDump(dumpOutput); - dumpOutput.shouldContain("string table array (primary)"); - dumpOutput.shouldContain("string table array (secondary)"); // We could create up to 26MB of archived heap objects. Run with enough Xms to ensure // SerialGC can accommodate the archived objects during VM start up. From 847b5166ea6322f9ff3effa62ed6d1e73a8b1122 Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Thu, 29 Jan 2026 16:44:24 +0000 Subject: [PATCH 251/328] 8373018: Update OpenSSL version to 3.5.4 Reviewed-by: abarashev, weijun --- test/lib/jdk/test/lib/security/OpensslArtifactFetcher.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/lib/jdk/test/lib/security/OpensslArtifactFetcher.java b/test/lib/jdk/test/lib/security/OpensslArtifactFetcher.java index 6fa8cb2e408..f66ad542e47 100644 --- a/test/lib/jdk/test/lib/security/OpensslArtifactFetcher.java +++ b/test/lib/jdk/test/lib/security/OpensslArtifactFetcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -33,7 +33,7 @@ import jtreg.SkippedException; public class OpensslArtifactFetcher { - private static final String OPENSSL_BUNDLE_VERSION = "3.5.1"; + private static final String OPENSSL_BUNDLE_VERSION = "3.5.4"; private static final String OPENSSL_ORG = "jpg.tests.jdk.openssl"; /** From 69c868d5b7fdeaf38d6a45b75d68bf51b6ee7188 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 29 Jan 2026 18:54:39 +0000 Subject: [PATCH 252/328] 8376510: Raster.createBandedRaster(int, int, int, int, int[], int[], Point) does not check for negative scanlineStride Reviewed-by: serb, azvegint --- src/java.desktop/share/classes/java/awt/image/Raster.java | 5 ++++- .../java/awt/image/Raster/CreateRasterExceptionTest.java | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/java.desktop/share/classes/java/awt/image/Raster.java b/src/java.desktop/share/classes/java/awt/image/Raster.java index 053e7c1eec5..3312a39b693 100644 --- a/src/java.desktop/share/classes/java/awt/image/Raster.java +++ b/src/java.desktop/share/classes/java/awt/image/Raster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -452,6 +452,9 @@ public class Raster { throw new IllegalArgumentException("Dimensions (width="+w+ " height="+h+") are too large"); } + if (scanlineStride < 0) { + throw new IllegalArgumentException("Scanline stride must be >= 0"); + } if (bankIndices == null) { throw new ArrayIndexOutOfBoundsException("Bank indices array is null"); diff --git a/test/jdk/java/awt/image/Raster/CreateRasterExceptionTest.java b/test/jdk/java/awt/image/Raster/CreateRasterExceptionTest.java index d89de44401b..13a88e8c590 100644 --- a/test/jdk/java/awt/image/Raster/CreateRasterExceptionTest.java +++ b/test/jdk/java/awt/image/Raster/CreateRasterExceptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8255800 8369129 + * @bug 8255800 8369129 8376297 * @summary verify Raster + SampleModel creation vs spec. */ @@ -739,7 +739,7 @@ public class CreateRasterExceptionTest { /* @throws IllegalArgumentException if * {@code scanlineStride} is less than 0 */ - Raster.createBandedRaster(DataBuffer.TYPE_INT, 1, 1, -3, + Raster.createBandedRaster(DataBuffer.TYPE_INT, 10, 10, -1000, bankIndices, bandOffsets, null); noException(); } catch (IllegalArgumentException t) { From 9470aa31175b504fcef15a932825dbc9e0532234 Mon Sep 17 00:00:00 2001 From: Anupam Dev Date: Thu, 29 Jan 2026 18:59:11 +0000 Subject: [PATCH 253/328] 8375011: OldJTable.java - NullPointerException when columnData is null Reviewed-by: prr, psadhukhan, tr --- .../share/jfc/TableExample/OldJTable.java | 264 ------------------ 1 file changed, 264 deletions(-) delete mode 100644 src/demo/share/jfc/TableExample/OldJTable.java diff --git a/src/demo/share/jfc/TableExample/OldJTable.java b/src/demo/share/jfc/TableExample/OldJTable.java deleted file mode 100644 index 8c77978fe8a..00000000000 --- a/src/demo/share/jfc/TableExample/OldJTable.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - - -import java.util.EventObject; -import java.util.List; -import javax.swing.JTable; -import javax.swing.table.DefaultTableModel; -import javax.swing.table.TableCellEditor; -import javax.swing.table.TableCellRenderer; -import javax.swing.table.TableColumn; - - -/** - * The OldJTable is an unsupported class containing some methods that were - * deleted from the JTable between releases 0.6 and 0.7 - */ -@SuppressWarnings("serial") -public class OldJTable extends JTable -{ - /* - * A new convenience method returning the index of the column in the - * co-ordinate space of the view. - */ - public int getColumnIndex(Object identifier) { - return getColumnModel().getColumnIndex(identifier); - } - -// -// Methods deleted from the JTable because they only work with the -// DefaultTableModel. -// - - public TableColumn addColumn(Object columnIdentifier, int width) { - return addColumn(columnIdentifier, width, null, null, null); - } - - public TableColumn addColumn(Object columnIdentifier, List columnData) { - return addColumn(columnIdentifier, -1, null, null, columnData); - } - - // Override the new JTable implementation - it will not add a column to the - // DefaultTableModel. - public TableColumn addColumn(Object columnIdentifier, int width, - TableCellRenderer renderer, - TableCellEditor editor) { - return addColumn(columnIdentifier, width, renderer, editor, null); - } - - public TableColumn addColumn(Object columnIdentifier, int width, - TableCellRenderer renderer, - TableCellEditor editor, List columnData) { - checkDefaultTableModel(); - - // Set up the model side first - DefaultTableModel m = (DefaultTableModel)getModel(); - m.addColumn(columnIdentifier, columnData.toArray()); - - // The column will have been added to the end, so the index of the - // column in the model is the last element. - TableColumn newColumn = new TableColumn( - m.getColumnCount()-1, width, renderer, editor); - super.addColumn(newColumn); - return newColumn; - } - - // Not possilble to make this work the same way ... change it so that - // it does not delete columns from the model. - public void removeColumn(Object columnIdentifier) { - super.removeColumn(getColumn(columnIdentifier)); - } - - public void addRow(Object[] rowData) { - checkDefaultTableModel(); - ((DefaultTableModel)getModel()).addRow(rowData); - } - - public void addRow(List rowData) { - checkDefaultTableModel(); - ((DefaultTableModel)getModel()).addRow(rowData.toArray()); - } - - public void removeRow(int rowIndex) { - checkDefaultTableModel(); - ((DefaultTableModel)getModel()).removeRow(rowIndex); - } - - public void moveRow(int startIndex, int endIndex, int toIndex) { - checkDefaultTableModel(); - ((DefaultTableModel)getModel()).moveRow(startIndex, endIndex, toIndex); - } - - public void insertRow(int rowIndex, Object[] rowData) { - checkDefaultTableModel(); - ((DefaultTableModel)getModel()).insertRow(rowIndex, rowData); - } - - public void insertRow(int rowIndex, List rowData) { - checkDefaultTableModel(); - ((DefaultTableModel)getModel()).insertRow(rowIndex, rowData.toArray()); - } - - public void setNumRows(int newSize) { - checkDefaultTableModel(); - ((DefaultTableModel)getModel()).setNumRows(newSize); - } - - public void setDataVector(Object[][] newData, List columnIds) { - checkDefaultTableModel(); - ((DefaultTableModel)getModel()).setDataVector( - newData, columnIds.toArray()); - } - - public void setDataVector(Object[][] newData, Object[] columnIds) { - checkDefaultTableModel(); - ((DefaultTableModel)getModel()).setDataVector(newData, columnIds); - } - - protected void checkDefaultTableModel() { - if(!(dataModel instanceof DefaultTableModel)) - throw new InternalError("In order to use this method, the data model must be an instance of DefaultTableModel."); - } - -// -// Methods removed from JTable in the move from identifiers to ints. -// - - public Object getValueAt(Object columnIdentifier, int rowIndex) { - return super.getValueAt(rowIndex, getColumnIndex(columnIdentifier)); - } - - public boolean isCellEditable(Object columnIdentifier, int rowIndex) { - return super.isCellEditable(rowIndex, getColumnIndex(columnIdentifier)); - } - - public void setValueAt(Object aValue, Object columnIdentifier, int rowIndex) { - super.setValueAt(aValue, rowIndex, getColumnIndex(columnIdentifier)); - } - - public boolean editColumnRow(Object identifier, int row) { - return super.editCellAt(row, getColumnIndex(identifier)); - } - - public void moveColumn(Object columnIdentifier, Object targetColumnIdentifier) { - moveColumn(getColumnIndex(columnIdentifier), - getColumnIndex(targetColumnIdentifier)); - } - - public boolean isColumnSelected(Object identifier) { - return isColumnSelected(getColumnIndex(identifier)); - } - - public TableColumn addColumn(int modelColumn, int width) { - return addColumn(modelColumn, width, null, null); - } - - public TableColumn addColumn(int modelColumn) { - return addColumn(modelColumn, 75, null, null); - } - - /** - * Creates a new column with modelColumn, width, - * renderer, and editor and adds it to the end of - * the JTable's array of columns. This method also retrieves the - * name of the column using the model's getColumnName(modelColumn) - * method, and sets the both the header value and the identifier - * for this TableColumn accordingly. - *

    - * The modelColumn is the index of the column in the model which - * will supply the data for this column in the table. This, like the - * columnIdentifier in previous releases, does not change as the - * columns are moved in the view. - *

    - * For the rest of the JTable API, and all of its associated classes, - * columns are referred to in the co-ordinate system of the view, the - * index of the column in the model is kept inside the TableColumn - * and is used only to retrieve the information from the appropraite - * column in the model. - *

    - * - * @param modelColumn The index of the column in the model - * @param width The new column's width. Or -1 to use - * the default width - * @param renderer The renderer used with the new column. - * Or null to use the default renderer. - * @param editor The editor used with the new column. - * Or null to use the default editor. - */ - public TableColumn addColumn(int modelColumn, int width, - TableCellRenderer renderer, - TableCellEditor editor) { - TableColumn newColumn = new TableColumn( - modelColumn, width, renderer, editor); - addColumn(newColumn); - return newColumn; - } - -// -// Methods that had their arguments switched. -// - -// These won't work with the new table package. - -/* - public Object getValueAt(int columnIndex, int rowIndex) { - return super.getValueAt(rowIndex, columnIndex); - } - - public boolean isCellEditable(int columnIndex, int rowIndex) { - return super.isCellEditable(rowIndex, columnIndex); - } - - public void setValueAt(Object aValue, int columnIndex, int rowIndex) { - super.setValueAt(aValue, rowIndex, columnIndex); - } -*/ - - public boolean editColumnRow(int columnIndex, int rowIndex) { - return super.editCellAt(rowIndex, columnIndex); - } - - public boolean editColumnRow(int columnIndex, int rowIndex, EventObject e){ - return super.editCellAt(rowIndex, columnIndex, e); - } - - -} // End Of Class OldJTable From 175bbb143e9fd2e596eb234d46ef9259f2bc4c1a Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 29 Jan 2026 22:39:32 +0000 Subject: [PATCH 254/328] 8375569: Store Java mirrors in AOT configuration file Reviewed-by: iveresov, kvn, asmehra --- src/hotspot/share/cds/aotMappedHeapLoader.cpp | 10 +++--- src/hotspot/share/cds/aotMetaspace.cpp | 7 ++++- .../share/cds/aotReferenceObjSupport.cpp | 13 +++++--- src/hotspot/share/cds/cdsConfig.cpp | 31 +++++++++++++++++-- src/hotspot/share/cds/cdsConfig.hpp | 5 ++- src/hotspot/share/cds/heapShared.cpp | 26 ++++++++-------- src/hotspot/share/classfile/javaClasses.cpp | 4 +++ src/hotspot/share/classfile/stringTable.cpp | 22 +++++++++++++ src/hotspot/share/classfile/stringTable.hpp | 1 + .../cds/appcds/aotCache/AOTMapTest.java | 5 +-- 10 files changed, 96 insertions(+), 28 deletions(-) diff --git a/src/hotspot/share/cds/aotMappedHeapLoader.cpp b/src/hotspot/share/cds/aotMappedHeapLoader.cpp index 146228436f4..210867be70c 100644 --- a/src/hotspot/share/cds/aotMappedHeapLoader.cpp +++ b/src/hotspot/share/cds/aotMappedHeapLoader.cpp @@ -360,10 +360,8 @@ bool AOTMappedHeapLoader::load_heap_region(FileMapInfo* mapinfo) { } objArrayOop AOTMappedHeapLoader::root_segment(int segment_idx) { - if (CDSConfig::is_dumping_heap()) { - assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); - } else { - assert(CDSConfig::is_using_archive(), "must be"); + if (!CDSConfig::is_using_archive()) { + assert(CDSConfig::is_dumping_heap() && Thread::current() == (Thread*)VMThread::vm_thread(), "sanity"); } objArrayOop segment = (objArrayOop)_root_segments->at(segment_idx).resolve(); @@ -465,6 +463,10 @@ void AOTMappedHeapLoader::finish_initialization(FileMapInfo* info) { assert(segment_oop->is_objArray(), "Must be"); add_root_segment((objArrayOop)segment_oop); } + + if (CDSConfig::is_dumping_final_static_archive()) { + StringTable::move_shared_strings_into_runtime_table(); + } } } diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index 62d76957c0a..894a35183ca 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -1104,7 +1104,12 @@ void AOTMetaspace::dump_static_archive_impl(StaticArchiveBuilder& builder, TRAPS #if INCLUDE_CDS_JAVA_HEAP if (CDSConfig::is_dumping_heap()) { - assert(CDSConfig::allow_only_single_java_thread(), "Required"); + if (!CDSConfig::is_dumping_preimage_static_archive()) { + // A single thread is required for Reference handling and deterministic CDS archive. + // Its's not required for dumping preimage, where References won't be archived and + // determinism is not needed. + assert(CDSConfig::allow_only_single_java_thread(), "Required"); + } if (!HeapShared::is_archived_boot_layer_available(THREAD)) { report_loading_error("archivedBootLayer not available, disabling full module graph"); CDSConfig::stop_dumping_full_module_graph(); diff --git a/src/hotspot/share/cds/aotReferenceObjSupport.cpp b/src/hotspot/share/cds/aotReferenceObjSupport.cpp index aa7cc875533..0c27c8ce5f0 100644 --- a/src/hotspot/share/cds/aotReferenceObjSupport.cpp +++ b/src/hotspot/share/cds/aotReferenceObjSupport.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -177,12 +177,17 @@ void AOTReferenceObjSupport::init_keep_alive_objs_table() { // Returns true IFF obj is an instance of java.lang.ref.Reference. If so, perform extra eligibility checks. bool AOTReferenceObjSupport::check_if_ref_obj(oop obj) { - // We have a single Java thread. This means java.lang.ref.Reference$ReferenceHandler thread - // is not running. Otherwise the checks for next/discovered may not work. - precond(CDSConfig::allow_only_single_java_thread()); assert_at_safepoint(); // _keep_alive_objs_table uses raw oops if (obj->klass()->is_subclass_of(vmClasses::Reference_klass())) { + // The following check works only if the java.lang.ref.Reference$ReferenceHandler thread + // is not running. + // + // This code is called on every object found by AOTArtifactFinder. When dumping the + // preimage archive, AOTArtifactFinder should not find any Reference objects. + precond(!CDSConfig::is_dumping_preimage_static_archive()); + precond(CDSConfig::allow_only_single_java_thread()); + precond(AOTReferenceObjSupport::is_enabled()); precond(JavaClasses::is_supported_for_archiving(obj)); precond(_keep_alive_objs_table != nullptr); diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index 5f6b568dd6e..f4ef3c66f7a 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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 @@ -556,7 +556,9 @@ void CDSConfig::check_aotmode_record() { // At VM exit, the module graph may be contaminated with program states. // We will rebuild the module graph when dumping the CDS final image. - disable_heap_dumping(); + _is_using_optimized_module_handling = false; + _is_using_full_module_graph = false; + _is_dumping_full_module_graph = false; } void CDSConfig::check_aotmode_create() { @@ -582,6 +584,7 @@ void CDSConfig::check_aotmode_create() { substitute_aot_filename(FLAG_MEMBER_ENUM(AOTCache)); _is_dumping_final_static_archive = true; + _is_using_full_module_graph = false; UseSharedSpaces = true; RequireSharedSpaces = true; @@ -954,7 +957,9 @@ bool CDSConfig::are_vm_options_incompatible_with_dumping_heap() { } bool CDSConfig::is_dumping_heap() { - if (!(is_dumping_classic_static_archive() || is_dumping_final_static_archive()) + // Note: when dumping preimage static archive, only a very limited set of oops + // are dumped. + if (!is_dumping_static_archive() || are_vm_options_incompatible_with_dumping_heap() || _disable_heap_dumping) { return false; @@ -966,6 +971,26 @@ bool CDSConfig::is_loading_heap() { return HeapShared::is_archived_heap_in_use(); } +bool CDSConfig::is_dumping_klass_subgraphs() { + if (is_dumping_classic_static_archive() || is_dumping_final_static_archive()) { + // KlassSubGraphs (see heapShared.cpp) is a legacy mechanism for archiving oops. It + // has been superceded by AOT class linking. This feature is used only when + // AOT class linking is disabled. + // + // KlassSubGraphs are disabled in the preimage static archive, which contains a very + // limited set of oops. + return is_dumping_heap() && !is_dumping_aot_linked_classes(); + } else { + return false; + } +} + +bool CDSConfig::is_using_klass_subgraphs() { + return (is_loading_heap() && + !CDSConfig::is_using_aot_linked_classes() && + !CDSConfig::is_dumping_final_static_archive()); +} + bool CDSConfig::is_using_full_module_graph() { if (ClassLoaderDataShared::is_full_module_graph_loaded()) { return true; diff --git a/src/hotspot/share/cds/cdsConfig.hpp b/src/hotspot/share/cds/cdsConfig.hpp index 202904e8231..739dbb4937b 100644 --- a/src/hotspot/share/cds/cdsConfig.hpp +++ b/src/hotspot/share/cds/cdsConfig.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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 @@ -188,6 +188,9 @@ public: static bool is_dumping_heap() NOT_CDS_JAVA_HEAP_RETURN_(false); static bool is_loading_heap() NOT_CDS_JAVA_HEAP_RETURN_(false); + static bool is_dumping_klass_subgraphs() NOT_CDS_JAVA_HEAP_RETURN_(false); + static bool is_using_klass_subgraphs() NOT_CDS_JAVA_HEAP_RETURN_(false); + static bool is_dumping_invokedynamic() NOT_CDS_JAVA_HEAP_RETURN_(false); static bool is_dumping_method_handles() NOT_CDS_JAVA_HEAP_RETURN_(false); diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 42129011612..143f9147853 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -210,7 +210,7 @@ static bool is_subgraph_root_class_of(ArchivableStaticFieldInfo fields[], Instan bool HeapShared::is_subgraph_root_class(InstanceKlass* ik) { assert(CDSConfig::is_dumping_heap(), "dump-time only"); - if (!CDSConfig::is_dumping_aot_linked_classes()) { + if (CDSConfig::is_dumping_klass_subgraphs()) { // Legacy CDS archive support (to be deprecated) return is_subgraph_root_class_of(archive_subgraph_entry_fields, ik) || is_subgraph_root_class_of(fmg_archive_subgraph_entry_fields, ik); @@ -455,7 +455,6 @@ int HeapShared::append_root(oop obj) { oop HeapShared::get_root(int index, bool clear) { assert(index >= 0, "sanity"); - assert(!CDSConfig::is_dumping_heap() && CDSConfig::is_using_archive(), "runtime only"); assert(is_archived_heap_in_use(), "getting roots into heap that is not used"); oop result; @@ -600,8 +599,7 @@ public: void set_oop(MetaspaceObj* ptr, oop o) { MutexLocker ml(ScratchObjects_lock, Mutex::_no_safepoint_check_flag); OopHandle handle(Universe::vm_global(), o); - bool is_new = put(ptr, handle); - assert(is_new, "cannot set twice"); + put_when_absent(ptr, handle); } void remove_oop(MetaspaceObj* ptr) { MutexLocker ml(ScratchObjects_lock, Mutex::_no_safepoint_check_flag); @@ -614,6 +612,11 @@ public: }; void HeapShared::add_scratch_resolved_references(ConstantPool* src, objArrayOop dest) { + if (CDSConfig::is_dumping_preimage_static_archive() && scratch_resolved_references(src) != nullptr) { + // We are in AOT training run. The class has been redefined and we are giving it a new resolved_reference. + // Ignore it, as this class will be excluded from the AOT config. + return; + } if (SystemDictionaryShared::is_builtin_loader(src->pool_holder()->class_loader_data())) { _scratch_objects_table->set_oop(src, dest); } @@ -934,7 +937,7 @@ void HeapShared::scan_java_class(Klass* orig_k) { void HeapShared::archive_subgraphs() { assert(CDSConfig::is_dumping_heap(), "must be"); - if (!CDSConfig::is_dumping_aot_linked_classes()) { + if (CDSConfig::is_dumping_klass_subgraphs()) { archive_object_subgraphs(archive_subgraph_entry_fields, false /* is_full_module_graph */); if (CDSConfig::is_dumping_full_module_graph()) { @@ -1292,10 +1295,7 @@ static void verify_the_heap(Klass* k, const char* which) { // this case, we will not load the ArchivedKlassSubGraphInfoRecord and will clear its roots. void HeapShared::resolve_classes(JavaThread* current) { assert(CDSConfig::is_using_archive(), "runtime only!"); - if (!is_archived_heap_in_use()) { - return; // nothing to do - } - if (!CDSConfig::is_using_aot_linked_classes()) { + if (CDSConfig::is_using_klass_subgraphs()) { resolve_classes_for_subgraphs(current, archive_subgraph_entry_fields); resolve_classes_for_subgraphs(current, fmg_archive_subgraph_entry_fields); } @@ -1385,7 +1385,7 @@ void HeapShared::init_classes_for_special_subgraph(Handle class_loader, TRAPS) { void HeapShared::initialize_from_archived_subgraph(JavaThread* current, Klass* k) { JavaThread* THREAD = current; - if (!is_archived_heap_in_use()) { + if (!CDSConfig::is_using_klass_subgraphs()) { return; // nothing to do } @@ -1861,7 +1861,7 @@ void HeapShared::archive_reachable_objects_from_static_field(InstanceKlass *k, const char* klass_name, int field_offset, const char* field_name) { - assert(CDSConfig::is_dumping_heap(), "dump time only"); + precond(CDSConfig::is_dumping_klass_subgraphs()); assert(k->defined_by_boot_loader(), "must be boot class"); oop m = k->java_mirror(); @@ -1912,7 +1912,7 @@ class VerifySharedOopClosure: public BasicOopIterateClosure { }; void HeapShared::verify_subgraph_from_static_field(InstanceKlass* k, int field_offset) { - assert(CDSConfig::is_dumping_heap(), "dump time only"); + precond(CDSConfig::is_dumping_klass_subgraphs()); assert(k->defined_by_boot_loader(), "must be boot class"); oop m = k->java_mirror(); @@ -2138,7 +2138,7 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[], void HeapShared::init_subgraph_entry_fields(TRAPS) { assert(CDSConfig::is_dumping_heap(), "must be"); _dump_time_subgraph_info_table = new (mtClass)DumpTimeKlassSubGraphInfoTable(); - if (!CDSConfig::is_dumping_aot_linked_classes()) { + if (CDSConfig::is_dumping_klass_subgraphs()) { init_subgraph_entry_fields(archive_subgraph_entry_fields, CHECK); if (CDSConfig::is_dumping_full_module_graph()) { init_subgraph_entry_fields(fmg_archive_subgraph_entry_fields, CHECK); diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index dd70d7b49ab..b650bf8cfb8 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1263,6 +1263,10 @@ bool java_lang_Class::restore_archived_mirror(Klass *k, "Restored %s archived mirror " PTR_FORMAT, k->external_name(), p2i(mirror())); } + if (CDSConfig::is_dumping_heap()) { + create_scratch_mirror(k, CHECK_(false)); + } + return true; } #endif // INCLUDE_CDS_JAVA_HEAP diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index bbc12c8dcab..2b8b7780a41 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -987,4 +987,26 @@ void StringTable::serialize_shared_table_header(SerializeClosure* soc) { _shared_table.reset(); } } + +void StringTable::move_shared_strings_into_runtime_table() { + precond(CDSConfig::is_dumping_final_static_archive()); + JavaThread* THREAD = JavaThread::current(); + HandleMark hm(THREAD); + + int n = 0; + _shared_table.iterate_all([&](oop string) { + int length = java_lang_String::length(string); + Handle h_string (THREAD, string); + StringWrapper name(h_string, length); + unsigned int hash = hash_wrapped_string(name); + + assert(!_alt_hash, "too early"); + oop interned = do_intern(name, hash, THREAD); + assert(string == interned, "must be"); + n++; + }); + + _shared_table.reset(); + log_info(aot)("Moved %d interned strings to runtime table", n); +} #endif //INCLUDE_CDS_JAVA_HEAP diff --git a/src/hotspot/share/classfile/stringTable.hpp b/src/hotspot/share/classfile/stringTable.hpp index 94a0db5b5a5..0024a45a2f2 100644 --- a/src/hotspot/share/classfile/stringTable.hpp +++ b/src/hotspot/share/classfile/stringTable.hpp @@ -119,6 +119,7 @@ public: static void init_shared_table() NOT_CDS_JAVA_HEAP_RETURN; static void write_shared_table() NOT_CDS_JAVA_HEAP_RETURN; static void serialize_shared_table_header(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN; + static void move_shared_strings_into_runtime_table(); // Jcmd static void dump(outputStream* st, bool verbose=false); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java index 6cbfcbbd3c3..209eb064945 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -136,6 +136,7 @@ public class AOTMapTest { } class AOTMapTestApp { + static URLClassLoader loader; // keep Hello class alive public static void main(String[] args) throws Exception { System.out.println("Hello AOTMapTestApp"); testCustomLoader(); @@ -144,7 +145,7 @@ class AOTMapTestApp { static void testCustomLoader() throws Exception { File custJar = new File("cust.jar"); URL[] urls = new URL[] {custJar.toURI().toURL()}; - URLClassLoader loader = new URLClassLoader(urls, AOTMapTestApp.class.getClassLoader()); + loader = new URLClassLoader(urls, AOTMapTestApp.class.getClassLoader()); Class c = loader.loadClass("Hello"); System.out.println(c); } From 379dcb0266bc90fac740eaa56b8027c7273e6d76 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Fri, 30 Jan 2026 02:43:57 +0000 Subject: [PATCH 255/328] 8365313: GTK LaF does not respect system color scheme with Gnome Reviewed-by: prr, mkartashev, kizune --- .../java/swing/plaf/gtk/GTKLookAndFeel.java | 17 +++++++++ .../native/libawt_xawt/awt/gtk3_interface.c | 36 +++++++++++++++++++ .../native/libawt_xawt/awt/gtk3_interface.h | 5 +++ .../native/libawt_xawt/awt/gtk_interface.h | 2 ++ .../native/libawt_xawt/awt/swing_GTKEngine.c | 14 ++++++++ 5 files changed, 74 insertions(+) diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java index 24a1997bdc1..5145779a493 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java @@ -1421,6 +1421,8 @@ public class GTKLookAndFeel extends SynthLookAndFeel { return c.getComponentOrientation().isLeftToRight(); } + private native boolean applyThemeIfNeeded(); + /** * {@inheritDoc} */ @@ -1463,6 +1465,21 @@ public class GTKLookAndFeel extends SynthLookAndFeel { // By default mnemonics are hidden for GTK L&F MnemonicHandler.setMnemonicHidden(true); + + if (IS_3) { + boolean shouldApplyTheme = false; + if (toolkit instanceof UNIXToolkit unixToolkit) { + if ("gnome".equals(unixToolkit.getDesktop())) { + int gnomeShellVersion = unixToolkit.getGnomeShellMajorVersion(); + shouldApplyTheme = gnomeShellVersion >= 47; + } + } + + if (shouldApplyTheme && applyThemeIfNeeded()) { + GTKEngine.INSTANCE.themeChanged(); + GTKIconFactory.resetIcons(); + } + } } /** diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c index 03dba969e8d..6ed23ca7541 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c +++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c @@ -602,6 +602,9 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name) fp_g_uuid_string_is_valid = //since: 2.52 dl_symbol("g_uuid_string_is_valid"); fp_g_variant_print = dl_symbol("g_variant_print"); // since 2.24 + + fp_g_settings_new = dl_symbol("g_settings_new"); // since 2.26 + fp_g_settings_get_string = dl_symbol("g_settings_get_string"); // since 2.26 } fp_g_string_printf = dl_symbol("g_string_printf"); fp_g_strconcat = dl_symbol("g_strconcat"); @@ -2987,6 +2990,37 @@ static GdkWindow* gtk3_get_window(void *widget) { return fp_gtk_widget_get_window((GtkWidget*)widget); } +static gboolean apply_theme_if_needed() { + if (!glib_version_2_68) { + return FALSE; + } + + GSettings *settings = fp_g_settings_new("org.gnome.desktop.interface"); + if (!settings) { + return FALSE; + } + + static gboolean wasDark = FALSE; + + gchar *scheme = fp_g_settings_get_string(settings, "color-scheme"); + const gboolean isDark = strcmp(scheme, "prefer-dark") == 0; + + fp_g_free(scheme); + fp_g_object_unref(settings); + + if (wasDark ^ isDark) { + GtkSettings* gtkSettings = fp_gtk_settings_get_default(); + if (!gtkSettings) { + return FALSE; + } + fp_g_object_set(gtkSettings, "gtk-application-prefer-dark-theme", isDark, NULL); + wasDark = isDark; + return TRUE; + } + + return FALSE; +} + static void gtk3_init(GtkApi* gtk) { gtk->version = GTK_3; @@ -2996,6 +3030,8 @@ static void gtk3_init(GtkApi* gtk) { gtk->gtk_check_version = fp_gtk_check_version; gtk->get_setting = >k3_get_setting; + gtk->apply_theme_if_needed = &apply_theme_if_needed; + gtk->paint_arrow = >k3_paint_arrow; gtk->paint_box = >k3_paint_box; gtk->paint_box_gap = >k3_paint_box_gap; diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h index d3a83677dd6..637a3198e43 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h +++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h @@ -193,6 +193,7 @@ typedef void GtkMenuShell; typedef void GtkWidgetClass; typedef void PangoFontDescription; typedef void GtkSettings; +typedef void GSettings; typedef void GtkStyleProvider; typedef void cairo_pattern_t; typedef void cairo_t; @@ -633,6 +634,10 @@ static char* (*fp_pango_font_description_to_string)( const PangoFontDescription* fd); static GtkSettings* (*fp_gtk_settings_get_default)(); static GtkSettings* (*fp_gtk_widget_get_settings)(GtkWidget *widget); + +static GSettings *(*fp_g_settings_new)(const gchar *schema_id); +static gchar *(*fp_g_settings_get_string)(GSettings *settings, const gchar *key); + static GType (*fp_gtk_border_get_type)(); static void (*fp_gtk_arrow_set)(GtkWidget* arrow, GtkArrowType arrow_type, diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h b/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h index 39be6a735d7..37422094202 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h +++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h @@ -541,6 +541,8 @@ typedef struct GtkApi { guint required_micro); jobject (*get_setting)(JNIEnv *env, Setting property); + gboolean (*apply_theme_if_needed)(); + void (*paint_arrow)(WidgetType widget_type, GtkStateType state_type, GtkShadowType shadow_type, const gchar *detail, gint x, gint y, gint width, gint height, diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/swing_GTKEngine.c b/src/java.desktop/unix/native/libawt_xawt/awt/swing_GTKEngine.c index bb5c799f008..3b7b2880316 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/swing_GTKEngine.c +++ b/src/java.desktop/unix/native/libawt_xawt/awt/swing_GTKEngine.c @@ -388,3 +388,17 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_nativeSetRangeValue( gtk->set_range_value(widget_type, value, min, max, visible); gtk->gdk_threads_leave(); } + +/* + * Class: com_sun_java_swing_plaf_gtk_GTKLookAndFeel + * Method: applyThemeIfNeeded + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL +Java_com_sun_java_swing_plaf_gtk_GTKLookAndFeel_applyThemeIfNeeded(JNIEnv *env, jobject this) { + gtk->gdk_threads_enter(); + const gboolean result = gtk->apply_theme_if_needed(); + gtk->gdk_threads_leave(); + + return result; +} From 9a10cceeafa5d332aa571f0d62acf50032a597d4 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 30 Jan 2026 03:19:49 +0000 Subject: [PATCH 256/328] 8374506: Incorrect positioning of arrow icon in parent JMenu in Windows L&F Reviewed-by: aivanov, kizune --- .../swing/plaf/windows/WindowsMenuItemUI.java | 11 ++- .../LargeMenuTextArrowIconPosition.java | 92 +++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 test/jdk/javax/swing/JMenuItem/LargeMenuTextArrowIconPosition.java diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java index 61f760d63c4..d15bc93a628 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -238,6 +238,15 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { SwingUtilities3.paintAccText(g, lh, lr, disabledForeground, acceleratorSelectionForeground, acceleratorForeground); + if (lh.getCheckIcon() != null && lh.useCheckAndArrow()) { + Rectangle rect = lr.getArrowRect(); + if (menuItem.getComponentOrientation().isLeftToRight()) { + rect.x += lh.getAfterCheckIconGap(); + } else { + rect.x -= lh.getAfterCheckIconGap(); + } + lr.setArrowRect(rect); + } SwingUtilities3.paintArrowIcon(g, lh, lr, foreground); // Restore original graphics font and color diff --git a/test/jdk/javax/swing/JMenuItem/LargeMenuTextArrowIconPosition.java b/test/jdk/javax/swing/JMenuItem/LargeMenuTextArrowIconPosition.java new file mode 100644 index 00000000000..72512560cff --- /dev/null +++ b/test/jdk/javax/swing/JMenuItem/LargeMenuTextArrowIconPosition.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2026, 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 8374506 + * @summary Verify if arrow icon positioning is correct in + * parent JMenu in Windows L&F + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual LargeMenuTextArrowIconPosition + */ + +import java.awt.BorderLayout; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.UIManager; + +public class LargeMenuTextArrowIconPosition { + + private static final String INSTRUCTIONS = """ + A frame will be shown with a label. + Right click on the label. + + Check the arrow icon at the end of + "Really long Menu-Text" text. + If it overlaps with the menu text, + press Fail else press Pass."""; + + public static void main(String[] args) throws Throwable { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(LargeMenuTextArrowIconPosition::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + + JFrame frame = new JFrame("LargeMenuTextArrowIcon"); + frame.setSize(300, 150); + frame.setLayout(new BorderLayout()); + + JPopupMenu popupMenu = new JPopupMenu(); + popupMenu.add(new JCheckBoxMenuItem("CheckBox On", true)); + popupMenu.add(new JCheckBoxMenuItem("CheckBox Icon On", + UIManager.getIcon("FileView.floppyDriveIcon"), true)); + popupMenu.add(new JCheckBoxMenuItem("CheckBox Icon Off", + UIManager.getIcon("FileView.floppyDriveIcon"), false)); + + JMenu menu = new JMenu("Really long Menu-Text"); + menu.add(new JMenuItem("Sub-MenuItem")); + menu.add(new JCheckBoxMenuItem("Sub-CheckBox On", true)); + + popupMenu.add(menu); + + JLabel lbl = new JLabel("Right click to invoke popupMenu"); + lbl.setComponentPopupMenu(popupMenu); + frame.add(lbl, BorderLayout.CENTER); + + return frame; + } + +} From 2953e0f445e147d778d4e765be0301cda6557ed5 Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Fri, 30 Jan 2026 03:43:46 +0000 Subject: [PATCH 257/328] 8371162: Compiler warns about implicit cast from long to int in shift operation Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Attr.java | 7 ++-- .../tools/javac/lint/AssignShift64Bits.java | 36 +++++++++++++++++++ .../tools/javac/lint/ShiftOutOfRange.out | 6 +--- 3 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 test/langtools/tools/javac/lint/AssignShift64Bits.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index cc21113882f..f2f9ea24ad7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, 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 @@ -4000,7 +4000,10 @@ public class Attr extends JCTree.Visitor { chk.checkCastable(tree.rhs.pos(), operator.type.getReturnType(), owntype); - chk.checkLossOfPrecision(tree.rhs.pos(), operand, owntype); + switch (tree.getTag()) { + case SL_ASG, SR_ASG, USR_ASG -> { } // we only use (at most) the lower 6 bits, so any integral type is OK + default -> chk.checkLossOfPrecision(tree.rhs.pos(), operand, owntype); + } chk.checkOutOfRangeShift(tree.rhs.pos(), operator, operand); } result = check(tree, owntype, KindSelector.VAL, resultInfo); diff --git a/test/langtools/tools/javac/lint/AssignShift64Bits.java b/test/langtools/tools/javac/lint/AssignShift64Bits.java new file mode 100644 index 00000000000..bb889d09022 --- /dev/null +++ b/test/langtools/tools/javac/lint/AssignShift64Bits.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2026, 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 8371162 + * @summary Verify no lossy conversion warning for 64 bit shift amount + * @compile -Xlint:lossy-conversions -Werror AssignShift64Bits.java + */ + +public class AssignShift64Bits { + void m() { + int a = 1 << 1L; + a <<= 1L; + long b = 1 << 1L; + b <<= 1L; + } +} diff --git a/test/langtools/tools/javac/lint/ShiftOutOfRange.out b/test/langtools/tools/javac/lint/ShiftOutOfRange.out index 7aee0b014af..6942e7e6809 100644 --- a/test/langtools/tools/javac/lint/ShiftOutOfRange.out +++ b/test/langtools/tools/javac/lint/ShiftOutOfRange.out @@ -1,17 +1,13 @@ ShiftOutOfRange.java:14:18: compiler.warn.bit.shift.out.of.range: int, -32, 0 ShiftOutOfRange.java:15:18: compiler.warn.bit.shift.out.of.range: int, -32, 0 ShiftOutOfRange.java:16:19: compiler.warn.bit.shift.out.of.range: int, -32, 0 -ShiftOutOfRange.java:17:15: compiler.warn.possible.loss.of.precision: long, int ShiftOutOfRange.java:17:15: compiler.warn.bit.shift.out.of.range: int, -32, 0 ShiftOutOfRange.java:18:15: compiler.warn.bit.shift.out.of.range: int, -32, 0 ShiftOutOfRange.java:19:16: compiler.warn.bit.shift.out.of.range: int, -32, 0 -ShiftOutOfRange.java:25:15: compiler.warn.possible.loss.of.precision: long, int -ShiftOutOfRange.java:32:15: compiler.warn.possible.loss.of.precision: long, int ShiftOutOfRange.java:39:18: compiler.warn.bit.shift.out.of.range: int, 32, 0 ShiftOutOfRange.java:40:18: compiler.warn.bit.shift.out.of.range: int, 32, 0 ShiftOutOfRange.java:41:19: compiler.warn.bit.shift.out.of.range: int, 32, 0 ShiftOutOfRange.java:42:15: compiler.warn.bit.shift.out.of.range: int, 32, 0 -ShiftOutOfRange.java:43:15: compiler.warn.possible.loss.of.precision: long, int ShiftOutOfRange.java:43:15: compiler.warn.bit.shift.out.of.range: int, 32, 0 ShiftOutOfRange.java:44:16: compiler.warn.bit.shift.out.of.range: int, 32, 0 ShiftOutOfRange.java:51:18: compiler.warn.bit.shift.out.of.range: long, -64, 0 @@ -26,4 +22,4 @@ ShiftOutOfRange.java:78:19: compiler.warn.bit.shift.out.of.range: long, 64, 0 ShiftOutOfRange.java:79:15: compiler.warn.bit.shift.out.of.range: long, 64, 0 ShiftOutOfRange.java:80:15: compiler.warn.bit.shift.out.of.range: long, 64, 0 ShiftOutOfRange.java:81:16: compiler.warn.bit.shift.out.of.range: long, 64, 0 -28 warnings +24 warnings From 9fef14a6d3124fae3ad8b24dac5103aa611d4edb Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 30 Jan 2026 06:15:19 +0000 Subject: [PATCH 258/328] 8375571: Compiler crash when using record pattern matching with a generic type parameter shadowing a record class Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Attr.java | 2 +- .../patterns/DeconstructionPatternErrors.java | 5 +++ .../patterns/DeconstructionPatternErrors.out | 45 ++++++++++--------- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index f2f9ea24ad7..5109dfed22e 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -4269,7 +4269,7 @@ public class Attr extends JCTree.Visitor { } List expectedRecordTypes; - if (site.tsym.kind == Kind.TYP && ((ClassSymbol) site.tsym).isRecord()) { + if (site.tsym instanceof ClassSymbol clazz && clazz.isRecord()) { ClassSymbol record = (ClassSymbol) site.tsym; expectedRecordTypes = record.getRecordComponents() .stream() diff --git a/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.java b/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.java index 4e1a7d7f669..804c2a3f622 100644 --- a/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.java +++ b/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.java @@ -1,5 +1,6 @@ /** * @test /nodynamiccopyright/ + * @bug 8375571 * @summary Verify error reports for erroneous deconstruction patterns are sensible * @compile/fail/ref=DeconstructionPatternErrors.out -XDrawDiagnostics -XDshould-stop.at=FLOW -XDdev DeconstructionPatternErrors.java */ @@ -39,6 +40,10 @@ public class DeconstructionPatternErrors { boolean b = p instanceof P(int i) p; //introducing a variable for the record pattern } + void typeVarTest(T p) { + if (p instanceof T(int i) && i == 0); //T is a type variable + } + public record P(int i) { } diff --git a/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.out b/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.out index f947142cd66..4d21d6069d8 100644 --- a/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.out +++ b/test/langtools/tools/javac/patterns/DeconstructionPatternErrors.out @@ -1,23 +1,24 @@ -DeconstructionPatternErrors.java:35:37: compiler.err.illegal.start.of.type -DeconstructionPatternErrors.java:37:28: compiler.err.illegal.start.of.type -DeconstructionPatternErrors.java:39:42: compiler.err.expected: ';' -DeconstructionPatternErrors.java:39:43: compiler.err.not.stmt -DeconstructionPatternErrors.java:15:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.util.List, java.util.ArrayList) -DeconstructionPatternErrors.java:16:29: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, java.util.ArrayList -DeconstructionPatternErrors.java:17:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, int) -DeconstructionPatternErrors.java:18:28: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: int, java.lang.String) -DeconstructionPatternErrors.java:19:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, DeconstructionPatternErrors.P) -DeconstructionPatternErrors.java:20:26: compiler.err.incorrect.number.of.nested.patterns: java.lang.Runnable,java.lang.Runnable, java.lang.Runnable +DeconstructionPatternErrors.java:36:37: compiler.err.illegal.start.of.type +DeconstructionPatternErrors.java:38:28: compiler.err.illegal.start.of.type +DeconstructionPatternErrors.java:40:42: compiler.err.expected: ';' +DeconstructionPatternErrors.java:40:43: compiler.err.not.stmt +DeconstructionPatternErrors.java:16:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.util.List, java.util.ArrayList) +DeconstructionPatternErrors.java:17:29: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, java.util.ArrayList +DeconstructionPatternErrors.java:18:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, int) +DeconstructionPatternErrors.java:19:28: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: int, java.lang.String) +DeconstructionPatternErrors.java:20:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, DeconstructionPatternErrors.P) DeconstructionPatternErrors.java:21:26: compiler.err.incorrect.number.of.nested.patterns: java.lang.Runnable,java.lang.Runnable, java.lang.Runnable -DeconstructionPatternErrors.java:22:26: compiler.err.incorrect.number.of.nested.patterns: int, int,compiler.misc.type.none -DeconstructionPatternErrors.java:23:26: compiler.err.incorrect.number.of.nested.patterns: int, int,int -DeconstructionPatternErrors.java:24:36: compiler.err.cant.resolve.location: kindname.class, Unresolvable, , , (compiler.misc.location: kindname.class, DeconstructionPatternErrors, null) -DeconstructionPatternErrors.java:24:26: compiler.err.incorrect.number.of.nested.patterns: int, int,Unresolvable -DeconstructionPatternErrors.java:25:13: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord -DeconstructionPatternErrors.java:26:29: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord -DeconstructionPatternErrors.java:27:44: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer) -DeconstructionPatternErrors.java:27:13: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord -DeconstructionPatternErrors.java:28:40: compiler.err.match.binding.exists -DeconstructionPatternErrors.java:29:56: compiler.err.already.defined: kindname.variable, v1, kindname.method, meth() -DeconstructionPatternErrors.java:29:64: compiler.err.already.defined: kindname.variable, v2, kindname.method, meth() -22 errors \ No newline at end of file +DeconstructionPatternErrors.java:22:26: compiler.err.incorrect.number.of.nested.patterns: java.lang.Runnable,java.lang.Runnable, java.lang.Runnable +DeconstructionPatternErrors.java:23:26: compiler.err.incorrect.number.of.nested.patterns: int, int,compiler.misc.type.none +DeconstructionPatternErrors.java:24:26: compiler.err.incorrect.number.of.nested.patterns: int, int,int +DeconstructionPatternErrors.java:25:36: compiler.err.cant.resolve.location: kindname.class, Unresolvable, , , (compiler.misc.location: kindname.class, DeconstructionPatternErrors, null) +DeconstructionPatternErrors.java:25:26: compiler.err.incorrect.number.of.nested.patterns: int, int,Unresolvable +DeconstructionPatternErrors.java:26:13: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord +DeconstructionPatternErrors.java:27:29: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord +DeconstructionPatternErrors.java:28:44: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer) +DeconstructionPatternErrors.java:28:13: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord +DeconstructionPatternErrors.java:29:40: compiler.err.match.binding.exists +DeconstructionPatternErrors.java:30:56: compiler.err.already.defined: kindname.variable, v1, kindname.method, meth() +DeconstructionPatternErrors.java:30:64: compiler.err.already.defined: kindname.variable, v2, kindname.method, meth() +DeconstructionPatternErrors.java:44:26: compiler.err.deconstruction.pattern.only.records: T +23 errors From 55375e98ae1672badeacaaf2f8b6f2f21ad03437 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 30 Jan 2026 08:31:27 +0000 Subject: [PATCH 259/328] 8375573: JTable ignores setPreferredWidth during initial layout when AUTO_RESIZE_LAST_COLUMN is enabled Reviewed-by: tr --- .../share/classes/javax/swing/JTable.java | 18 +++- .../swing/JTable/TestJTableColWidth.java | 87 +++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 test/jdk/javax/swing/JTable/TestJTableColWidth.java diff --git a/src/java.desktop/share/classes/javax/swing/JTable.java b/src/java.desktop/share/classes/javax/swing/JTable.java index 6e64b216d58..f5c914135d1 100644 --- a/src/java.desktop/share/classes/javax/swing/JTable.java +++ b/src/java.desktop/share/classes/javax/swing/JTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -3191,9 +3191,23 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * (maximum or minimum). * */ + public void doLayout() { + boolean prefWidthSet = false; TableColumn resizingColumn = getResizingColumn(); - if (resizingColumn == null) { + // doLayout is called for both pack and show + // so if initial preferred width is set by user then + // it needs to be honoured even if resizingColumn + // is set to last column on account of + // AUTO_RESIZE_LAST_COLUMN autoResizeMode + for (int i = 0; i < columnModel.getColumnCount(); i++) { + if (columnModel.getColumn(i).getPreferredWidth() != 75 + && columnModel.getColumn(i).getWidth() == 75) { + prefWidthSet = true; + break; + } + } + if (resizingColumn == null || prefWidthSet) { setWidthsFromPreferredWidths(false); } else { diff --git a/test/jdk/javax/swing/JTable/TestJTableColWidth.java b/test/jdk/javax/swing/JTable/TestJTableColWidth.java new file mode 100644 index 00000000000..542c4d0ffa1 --- /dev/null +++ b/test/jdk/javax/swing/JTable/TestJTableColWidth.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2026, 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 8192888 + * @key headful + * @summary Verifies JTable doesn't ignore setPreferredWidth during + * initial layout when AUTO_RESIZE_LAST_COLUMN is enabled + * @run main TestJTableColWidth + */ + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableColumnModel; +import javax.swing.SwingUtilities; + +public class TestJTableColWidth { + static JFrame frame; + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> { + try { + frame = new JFrame("JTable colwidth"); + + String[] cols = {"ID", "Name", "Description", "Status"}; + Object[][] data = {{1, "Mimi", "Testing Java 25 Regression", "Pending"}}; + + DefaultTableModel model = new DefaultTableModel(data, cols); + final JTable tab = new JTable(model); + + tab.getTableHeader().setReorderingAllowed(false); + tab.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); + + TableColumnModel columnModel = tab.getColumnModel(); + // Defined widths + int[] widths = {30, 200, 100, 50}; + + for (int i = 0; i < widths.length; i++) { + columnModel.getColumn(i).setPreferredWidth(widths[i]); + } + + frame.add(new JScrollPane(tab)); + frame.setSize(600, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + + System.out.println("Actual column widths on screen:"); + for (int i = 0; i < columnModel.getColumnCount(); i++) { + System.out.println("Column " + i + ": " + + columnModel.getColumn(i).getWidth() + "px"); + } + if (columnModel.getColumn(0).getWidth() + == columnModel.getColumn(1).getWidth()) { + throw new RuntimeException("JTable ignores setPreferredWidth during" + + " initial layout when AUTO_RESIZE_LAST_COLUMN is enabled"); + } + } finally { + if (frame != null) { + frame.dispose(); + } + } + }); + } +} From e6437264d5e6d4aad23430b7dbdf574a12b8f57b Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 30 Jan 2026 08:31:51 +0000 Subject: [PATCH 260/328] 8376604: C2: EA should assert is_oop_field for AddP with oop outs Reviewed-by: qamai, kvn --- src/hotspot/share/opto/escape.cpp | 21 ++++++++++++--------- src/hotspot/share/opto/escape.hpp | 3 ++- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 357c91e8eb5..b46a12fcf89 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -3511,10 +3511,7 @@ bool ConnectionGraph::is_oop_field(Node* n, int offset, bool* unsafe) { bt = field->layout_type(); } else { // Check for unsafe oop field access - if (n->has_out_with(Op_StoreP, Op_LoadP, Op_StoreN, Op_LoadN) || - n->has_out_with(Op_GetAndSetP, Op_GetAndSetN, Op_CompareAndExchangeP, Op_CompareAndExchangeN) || - n->has_out_with(Op_CompareAndSwapP, Op_CompareAndSwapN, Op_WeakCompareAndSwapP, Op_WeakCompareAndSwapN) || - BarrierSet::barrier_set()->barrier_set_c2()->escape_has_out_with_unsafe_object(n)) { + if (has_oop_node_outs(n)) { bt = T_OBJECT; (*unsafe) = true; } @@ -3530,16 +3527,22 @@ bool ConnectionGraph::is_oop_field(Node* n, int offset, bool* unsafe) { } } else if (adr_type->isa_rawptr() || adr_type->isa_klassptr()) { // Allocation initialization, ThreadLocal field access, unsafe access - if (n->has_out_with(Op_StoreP, Op_LoadP, Op_StoreN, Op_LoadN) || - n->has_out_with(Op_GetAndSetP, Op_GetAndSetN, Op_CompareAndExchangeP, Op_CompareAndExchangeN) || - n->has_out_with(Op_CompareAndSwapP, Op_CompareAndSwapN, Op_WeakCompareAndSwapP, Op_WeakCompareAndSwapN) || - BarrierSet::barrier_set()->barrier_set_c2()->escape_has_out_with_unsafe_object(n)) { + if (has_oop_node_outs(n)) { bt = T_OBJECT; } } } // Note: T_NARROWOOP is not classed as a real reference type - return (is_reference_type(bt) || bt == T_NARROWOOP); + bool res = (is_reference_type(bt) || bt == T_NARROWOOP); + assert(!has_oop_node_outs(n) || res, "sanity: AddP has oop outs, needs to be treated as oop field"); + return res; +} + +bool ConnectionGraph::has_oop_node_outs(Node* n) { + return n->has_out_with(Op_StoreP, Op_LoadP, Op_StoreN, Op_LoadN) || + n->has_out_with(Op_GetAndSetP, Op_GetAndSetN, Op_CompareAndExchangeP, Op_CompareAndExchangeN) || + n->has_out_with(Op_CompareAndSwapP, Op_CompareAndSwapN, Op_WeakCompareAndSwapP, Op_WeakCompareAndSwapN) || + BarrierSet::barrier_set()->barrier_set_c2()->escape_has_out_with_unsafe_object(n); } // Returns unique pointed java object or null. diff --git a/src/hotspot/share/opto/escape.hpp b/src/hotspot/share/opto/escape.hpp index 04a9dc82982..dcb832889ec 100644 --- a/src/hotspot/share/opto/escape.hpp +++ b/src/hotspot/share/opto/escape.hpp @@ -539,7 +539,8 @@ private: } // Helper functions - bool is_oop_field(Node* n, int offset, bool* unsafe); + bool is_oop_field(Node* n, int offset, bool* unsafe); + bool has_oop_node_outs(Node* n); static Node* find_second_addp(Node* addp, Node* n); // offset of a field reference int address_offset(Node* adr, PhaseValues* phase); From 42370e22c5bc4ebd40fd500a2e6e9e07f0b8bcd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Fri, 30 Jan 2026 09:01:00 +0000 Subject: [PATCH 261/328] 8376781: Problemlist compiler/longcountedloops/TestLoopNestTooManyTraps.java Reviewed-by: thartmann, chagedorn --- test/hotspot/jtreg/ProblemList.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 84520b00056..7e521279a4c 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -77,6 +77,8 @@ compiler/interpreter/Test6833129.java 8335266 generic-i586 compiler/c2/aarch64/TestStaticCallStub.java 8359963 linux-aarch64,macosx-aarch64 +compiler/longcountedloops/TestLoopNestTooManyTraps.java 8376591 generic-all + ############################################################################# # :hotspot_gc From e3b5b261af6acbe7ab074f301c70283b06c17d39 Mon Sep 17 00:00:00 2001 From: Guanqiang Han Date: Fri, 30 Jan 2026 09:35:32 +0000 Subject: [PATCH 262/328] 8376287: Crashes when using -XX:ObjArrayMarkingStride=0 Reviewed-by: tschatzl, shade --- src/hotspot/share/gc/shared/gc_globals.hpp | 1 + src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index d08e95378f7..6aa1fcf066b 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -261,6 +261,7 @@ develop(uintx, ObjArrayMarkingStride, 2048, \ "Number of object array elements to push onto the marking stack " \ "before pushing a continuation entry") \ + range(1, INT_MAX/2) \ \ product_pd(bool, NeverActAsServerClassMachine, \ "(Deprecated) Never act like a server-class machine") \ diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index 849459157b5..ba24e890769 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -226,8 +226,6 @@ inline void ShenandoahMark::do_chunked_array(ShenandoahObjToScanQueue* q, T* cl, assert(obj->is_objArray(), "expect object array"); objArrayOop array = objArrayOop(obj); - assert (ObjArrayMarkingStride > 0, "sanity"); - // Split out tasks, as suggested in ShenandoahMarkTask docs. Avoid pushing tasks that // are known to start beyond the array. while ((1 << pow) > (int)ObjArrayMarkingStride && (chunk*2 < ShenandoahMarkTask::chunk_size())) { From 0a3809d380bcae8cb24d50886057d8586fa77f7c Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 30 Jan 2026 11:33:03 +0000 Subject: [PATCH 263/328] 8375046: C2: Incremental inlining step asserts when processing empty late inlines list Reviewed-by: vlivanov, thartmann, kbarrett --- src/hotspot/share/opto/compile.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index eaec1605108..c4c9445b61a 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -2098,6 +2098,7 @@ void Compile::inline_boxing_calls(PhaseIterGVN& igvn) { bool Compile::inline_incrementally_one() { assert(IncrementalInline, "incremental inlining should be on"); + assert(_late_inlines.length() > 0, "should have been checked by caller"); TracePhase tp(_t_incrInline_inline); @@ -2209,6 +2210,10 @@ void Compile::inline_incrementally(PhaseIterGVN& igvn) { igvn_worklist()->ensure_empty(); // should be done with igvn + if (_late_inlines.length() == 0) { + break; // no more progress + } + while (inline_incrementally_one()) { assert(!failing_internal() || failure_is_artificial(), "inconsistent"); } @@ -2219,10 +2224,6 @@ void Compile::inline_incrementally(PhaseIterGVN& igvn) { print_method(PHASE_INCREMENTAL_INLINE_STEP, 3); if (failing()) return; - - if (_late_inlines.length() == 0) { - break; // no more progress - } } igvn_worklist()->ensure_empty(); // should be done with igvn From df8c4d6d12dacd0adfcf8c711c8671913d805309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Fri, 30 Jan 2026 13:44:48 +0000 Subject: [PATCH 264/328] 8373604: Operations on peer reset tokens are slow Reviewed-by: dfuchs --- .../net/http/quic/PeerConnIdManager.java | 25 ++++++++++- .../net/http/quic/QuicConnectionImpl.java | 11 +++-- .../internal/net/http/quic/QuicEndpoint.java | 41 +++++++++++-------- .../net/http/quic/QuicPacketReceiver.java | 7 +++- 4 files changed, 63 insertions(+), 21 deletions(-) diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/PeerConnIdManager.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/PeerConnIdManager.java index 065d045b57c..2bc759a920a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/PeerConnIdManager.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/PeerConnIdManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ import java.nio.ByteBuffer; import java.util.ArrayDeque; import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.NavigableMap; import java.util.NavigableSet; @@ -276,6 +277,28 @@ final class PeerConnIdManager { } } + /** + * {@return the list of stateless reset tokens associated with active peer connection IDs} + */ + public List activeResetTokens() { + lock.lock(); + try { + // we only support one active connection ID at the time + PeerConnectionId cid = peerConnectionIds.get(activeConnIdSeq); + byte[] statelessResetToken = null; + if (cid != null) { + statelessResetToken = cid.getStatelessResetToken(); + } + if (statelessResetToken != null) { + return List.of(statelessResetToken); + } else { + return List.of(); + } + } finally { + lock.unlock(); + } + } + /** * {@return the active peer connection ID} */ diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java index 580bbe23d31..edb94d5929a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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 @@ -1246,7 +1246,7 @@ public class QuicConnectionImpl extends QuicConnection implements QuicPacketRece final PacketSpace space = packetSpace(PacketNumberSpace.APPLICATION); final int maxDatagramSize = getMaxDatagramSize(); final QuicConnectionId peerConnectionId = peerConnectionId(); - final int dstIdLength = peerConnectionId().length(); + final int dstIdLength = peerConnectionId.length(); if (!canSend()) { return false; } @@ -1747,6 +1747,11 @@ public class QuicConnectionImpl extends QuicConnection implements QuicPacketRece return localConnIdManager.connectionIds(); } + @Override + public List activeResetTokens() { + return peerConnIdManager.activeResetTokens(); + } + LocalConnIdManager localConnectionIdManager() { return localConnIdManager; } @@ -2453,7 +2458,7 @@ public class QuicConnectionImpl extends QuicConnection implements QuicPacketRece } return; } - final QuicConnectionId currentPeerConnId = this.peerConnIdManager.getPeerConnId(); + final QuicConnectionId currentPeerConnId = peerConnectionId(); if (rt.sourceId().equals(currentPeerConnId)) { if (debug.on()) { debug.log("Invalid retry, same connection ID"); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicEndpoint.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicEndpoint.java index 91b4a678a23..ef342d4cb56 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicEndpoint.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -1572,14 +1572,14 @@ public abstract sealed class QuicEndpoint implements AutoCloseable private void dropPeerIssuedResetTokensFor(QuicPacketReceiver connection) { // remove references to this connection from the map which holds the peer issued // reset tokens - peerIssuedResetTokens.values().removeIf(conn -> connection == conn); + connection.activeResetTokens().forEach(this::forgetStatelessResetToken); } - // remap peer issued stateless token from connection `from` to connection `to` - private void remapPeerIssuedResetToken(QuicPacketReceiver from, QuicPacketReceiver to) { - assert from != null; - assert to != null; - peerIssuedResetTokens.replaceAll((tok, c) -> c == from ? to : c); + // remap peer issued stateless tokens to connection `newReceiver` + private void remapPeerIssuedResetToken(QuicPacketReceiver newReceiver) { + assert newReceiver != null; + newReceiver.activeResetTokens().forEach(resetToken -> + associateStatelessResetToken(resetToken, newReceiver)); } public void draining(final QuicConnectionImpl connection) { @@ -1588,9 +1588,10 @@ public abstract sealed class QuicEndpoint implements AutoCloseable final long idleTimeout = connection.peerPtoMs() * 3; // 3 PTO connection.localConnectionIdManager().close(); - DrainingConnection draining = new DrainingConnection(connection.connectionIds(), idleTimeout); + DrainingConnection draining = new DrainingConnection(connection.connectionIds(), + connection.activeResetTokens(), idleTimeout); // we can ignore stateless reset in the draining state. - remapPeerIssuedResetToken(connection, draining); + remapPeerIssuedResetToken(draining); connection.connectionIds().forEach((id) -> connections.compute(id, (i, r) -> remapDraining(i, r, draining))); @@ -1626,8 +1627,9 @@ public abstract sealed class QuicEndpoint implements AutoCloseable final long idleTimeout = connection.peerPtoMs() * 3; // 3 PTO connection.localConnectionIdManager().close(); - var closingConnection = new ClosingConnection(connection.connectionIds(), idleTimeout, datagram); - remapPeerIssuedResetToken(connection, closingConnection); + var closingConnection = new ClosingConnection(connection.connectionIds(), + connection.activeResetTokens(), idleTimeout, datagram); + remapPeerIssuedResetToken(closingConnection); connection.connectionIds().forEach((id) -> connections.compute(id, (i, r) -> remapClosing(i, r, closingConnection))); @@ -1745,6 +1747,7 @@ public abstract sealed class QuicEndpoint implements AutoCloseable // an instance of this class) final static long NO_IDLE_TIMEOUT = 2000; final List localConnectionIds; + private final List activeResetTokens; final long maxIdleTimeMs; final long id; int more = 1; @@ -1752,7 +1755,8 @@ public abstract sealed class QuicEndpoint implements AutoCloseable volatile Deadline deadline; volatile Deadline updatedDeadline; - ClosedConnection(List localConnectionIds, long maxIdleTimeMs) { + ClosedConnection(List localConnectionIds, List activeResetTokens, long maxIdleTimeMs) { + this.activeResetTokens = activeResetTokens; this.id = QuicTimerQueue.newEventId(); this.maxIdleTimeMs = maxIdleTimeMs == 0 ? NO_IDLE_TIMEOUT : maxIdleTimeMs; this.deadline = Deadline.MAX; @@ -1765,6 +1769,11 @@ public abstract sealed class QuicEndpoint implements AutoCloseable return localConnectionIds; } + @Override + public List activeResetTokens() { + return activeResetTokens; + } + @Override public final void processIncoming(SocketAddress source, ByteBuffer destConnId, HeadersType headersType, ByteBuffer buffer) { Deadline updated = updatedDeadline; @@ -1868,9 +1877,9 @@ public abstract sealed class QuicEndpoint implements AutoCloseable final ByteBuffer closePacket; - ClosingConnection(List localConnIdManager, long maxIdleTimeMs, + ClosingConnection(List localConnectionIds, List activeResetTokens, long maxIdleTimeMs, ByteBuffer closePacket) { - super(localConnIdManager, maxIdleTimeMs); + super(localConnectionIds, activeResetTokens, maxIdleTimeMs); this.closePacket = Objects.requireNonNull(closePacket); } @@ -1903,8 +1912,8 @@ public abstract sealed class QuicEndpoint implements AutoCloseable */ final class DrainingConnection extends ClosedConnection { - DrainingConnection(List localConnIdManager, long maxIdleTimeMs) { - super(localConnIdManager, maxIdleTimeMs); + DrainingConnection(List localConnectionIds, List activeResetTokens, long maxIdleTimeMs) { + super(localConnectionIds, activeResetTokens, maxIdleTimeMs); } @Override diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicPacketReceiver.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicPacketReceiver.java index 6652b44de3a..72f622731f3 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicPacketReceiver.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicPacketReceiver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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 @@ -51,6 +51,11 @@ public interface QuicPacketReceiver { */ List connectionIds(); + /** + * {@return a list of active peer stateless reset tokens for this connection) + */ + List activeResetTokens(); + /** * {@return the initial connection id assigned by the peer} * On the client side, this is always {@link Optional#empty()}. From 96180b9c56a03f6d7cb22c0618ed7d946beae6bf Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Fri, 30 Jan 2026 15:44:51 +0000 Subject: [PATCH 265/328] 8376308: java/net/httpclient/CancelRequestTest.java fails intermittently with "Expected CancellationException not received" Reviewed-by: djelinski, vyazici --- .../net/httpclient/CancelRequestTest.java | 131 ++++++++++++------ 1 file changed, 91 insertions(+), 40 deletions(-) diff --git a/test/jdk/java/net/httpclient/CancelRequestTest.java b/test/jdk/java/net/httpclient/CancelRequestTest.java index 86e06bb78f7..2a0ec19a0ed 100644 --- a/test/jdk/java/net/httpclient/CancelRequestTest.java +++ b/test/jdk/java/net/httpclient/CancelRequestTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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 @@ -49,7 +49,6 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLHandshakeException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -65,6 +64,7 @@ import java.net.http.HttpResponse.BodyHandlers; import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.Random; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; @@ -87,11 +87,14 @@ import static java.net.http.HttpOption.H3_DISCOVERY; import static java.nio.charset.StandardCharsets.UTF_8; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotEquals; import static org.testng.Assert.assertTrue; public class CancelRequestTest implements HttpServerAdapters { private static final Random random = RandomFactory.getRandom(); + private static final ConcurrentHashMap latches + = new ConcurrentHashMap<>(); private static final SSLContext sslContext = SimpleSSLContext.findSSLContext(); HttpTestServer httpTestServer; // HTTP/1.1 [ 4 servers ] @@ -117,6 +120,7 @@ public class CancelRequestTest implements HttpServerAdapters { static volatile boolean tasksFailed; static final AtomicLong serverCount = new AtomicLong(); static final AtomicLong clientCount = new AtomicLong(); + static final AtomicLong requestCount = new AtomicLong(); static final long start = System.nanoTime(); public static String now() { long now = System.nanoTime() - start; @@ -278,10 +282,12 @@ public class CancelRequestTest implements HttpServerAdapters { // set HTTP/3 version on the request when targeting // an HTTP/3 server private HttpRequest.Builder requestBuilder(String uri) { - var builder = HttpRequest.newBuilder(URI.create(uri)); + var u = URI.create(uri+"?req="+requestCount.incrementAndGet()); + var builder = HttpRequest.newBuilder(u); if (uri.contains("h3")) { builder.version(HTTP_3); } + builder.setHeader("X-expect-exception", "true"); return builder; } @@ -324,6 +330,24 @@ public class CancelRequestTest implements HttpServerAdapters { assertEquals(resp.statusCode(), 200); } + private static void releaseLatches() { + // release left over latches + for (var latch : latches.values()) { + latch.countDown(); + } + latches.clear(); + } + + private static CountDownLatch addLatchFor(HttpRequest req) { + // release left over latches + releaseLatches(); + String key = Objects.requireNonNull(req.uri().getRawQuery(), "query"); + var latch = new CountDownLatch(1); + latches.put(key, latch); + out.println(now() + "CountDownLatch " + latch + " added for " + req.uri()); + return latch; + } + @Test(dataProvider = "asyncurls") public void testGetSendAsync(String uri, boolean sameClient, boolean mayInterruptIfRunning) throws Exception { @@ -343,18 +367,21 @@ public class CancelRequestTest implements HttpServerAdapters { .GET() .setOption(H3_DISCOVERY, config) .build(); + var requestLatch = addLatchFor(req); + BodyHandler handler = BodyHandlers.ofString(); CountDownLatch latch = new CountDownLatch(1); + out.println(now() + "Sending (async): " + req.uri()); CompletableFuture> response = client.sendAsync(req, handler); var cf1 = response.whenComplete((r,t) -> System.out.println(t)); CompletableFuture> cf2 = cf1.whenComplete((r,t) -> latch.countDown()); - out.println("iteration: " + i + ", req: " + req.uri()); + out.println(now() + "iteration: " + i + ", req sent: " + req.uri()); out.println("response: " + response); out.println("cf1: " + cf1); out.println("cf2: " + cf2); delay(); cf1.cancel(mayInterruptIfRunning); - out.println("response after cancel: " + response); + out.println(now() + "response after cancel: " + response); out.println("cf1 after cancel: " + cf1); out.println("cf2 after cancel: " + cf2); try { @@ -362,8 +389,10 @@ public class CancelRequestTest implements HttpServerAdapters { assertEquals(body, String.join("", BODY.split("\\|"))); throw new AssertionError("Expected CancellationException not received"); } catch (ExecutionException x) { - out.println("Got expected exception: " + x); + out.println(now() + "Got expected exception: " + x); assertTrue(isCancelled(x)); + } finally { + requestLatch.countDown(); } // Cancelling the request may cause an IOException instead... @@ -371,7 +400,7 @@ public class CancelRequestTest implements HttpServerAdapters { try { cf1.get(); } catch (CancellationException | ExecutionException x) { - out.println("Got expected exception: " + x); + out.println(now() + "Got expected exception: " + x); assertTrue(isCancelled(x)); hasCancellationException = x instanceof CancellationException; } @@ -393,7 +422,7 @@ public class CancelRequestTest implements HttpServerAdapters { if (mayInterruptIfRunning) { if (CancellationException.class.isAssignableFrom(wrapped.getClass())) { cause = wrapped.getCause(); - out.println("CancellationException cause: " + x); + out.println(now() + "CancellationException cause: " + x); } else if (!isCancelled(cause)) { throw new RuntimeException("Unexpected cause: " + cause); } @@ -403,15 +432,15 @@ public class CancelRequestTest implements HttpServerAdapters { } } if (!IOException.class.isInstance(cause)) { - out.println("Unexpected cause: " + cause.getClass()); + out.println(now() + "Unexpected cause: " + cause.getClass()); cause.printStackTrace(out); } assertTrue(IOException.class.isAssignableFrom(cause.getClass())); if (mayInterruptIfRunning) { - out.println("Got expected exception: " + wrapped); + out.println(now() + "Got expected exception: " + wrapped); out.println("\tcause: " + cause); } else { - out.println("Unexpected exception: " + wrapped); + out.println(now() + "Unexpected exception: " + wrapped); wrapped.printStackTrace(out); throw x; } @@ -453,13 +482,13 @@ public class CancelRequestTest implements HttpServerAdapters { @Override public Iterator iterator() { // this is dangerous - out.println("waiting for completion on: " + cancelFuture); + out.println(now() + "waiting for completion on: " + cancelFuture); boolean async = random.nextBoolean(); Runnable cancel = () -> { - out.println("Cancelling from " + Thread.currentThread()); + out.println(now() + "Cancelling from " + Thread.currentThread()); var cf1 = cancelFuture.join(); cf1.cancel(mayInterruptIfRunning); - out.println("cancelled " + cf1); + out.println(now() + "cancelled " + cf1); }; if (async) executor.execute(cancel); else cancel.run(); @@ -474,16 +503,20 @@ public class CancelRequestTest implements HttpServerAdapters { .POST(HttpRequest.BodyPublishers.ofByteArrays(iterable)) .setOption(H3_DISCOVERY, config) .build(); + var requestLatch = addLatchFor(req); + BodyHandler handler = BodyHandlers.ofString(); CountDownLatch latch = new CountDownLatch(1); + out.println(now() + "Sending (async): " + req.uri()); CompletableFuture> response = client.sendAsync(req, handler); - var cf1 = response.whenComplete((r,t) -> System.out.println(t)); + var cf1 = response.whenComplete((r,t) -> System.out.println(now() + t)); CompletableFuture> cf2 = cf1.whenComplete((r,t) -> latch.countDown()); + out.println(now() + "iteration: " + i + ", req sent: " + req.uri()); out.println("response: " + response); out.println("cf1: " + cf1); out.println("cf2: " + cf2); cancelFuture.complete(cf1); - out.println("response after cancel: " + response); + out.println(now() + "response after cancel: " + response); out.println("cf1 after cancel: " + cf1); out.println("cf2 after cancel: " + cf2); try { @@ -491,8 +524,10 @@ public class CancelRequestTest implements HttpServerAdapters { assertEquals(body, String.join("", BODY.split("\\|"))); throw new AssertionError("Expected CancellationException not received"); } catch (ExecutionException x) { - out.println("Got expected exception: " + x); + out.println(now() + "Got expected exception: " + x); assertTrue(isCancelled(x)); + } finally { + requestLatch.countDown(); } // Cancelling the request may cause an IOException instead... @@ -500,7 +535,7 @@ public class CancelRequestTest implements HttpServerAdapters { try { cf1.get(); } catch (CancellationException | ExecutionException x) { - out.println("Got expected exception: " + x); + out.println(now() + "Got expected exception: " + x); assertTrue(isCancelled(x)); hasCancellationException = x instanceof CancellationException; } @@ -521,7 +556,7 @@ public class CancelRequestTest implements HttpServerAdapters { Throwable cause = wrapped; if (CancellationException.class.isAssignableFrom(wrapped.getClass())) { cause = wrapped.getCause(); - out.println("CancellationException cause: " + x); + out.println(now() + "CancellationException cause: " + x); } else if (!isCancelled(cause)) { throw new RuntimeException("Unexpected cause: " + cause); } @@ -531,10 +566,10 @@ public class CancelRequestTest implements HttpServerAdapters { throw new RuntimeException("Unexpected timeout exception", cause); } if (mayInterruptIfRunning) { - out.println("Got expected exception: " + wrapped); + out.println(now() + "Got expected exception: " + wrapped); out.println("\tcause: " + cause); } else { - out.println("Unexpected exception: " + wrapped); + out.println(now() + "Unexpected exception: " + wrapped); wrapped.printStackTrace(out); throw x; } @@ -571,7 +606,7 @@ public class CancelRequestTest implements HttpServerAdapters { Thread main = Thread.currentThread(); CompletableFuture interruptingThread = new CompletableFuture<>(); - var uriStr = uri + "/post/req=" + i; + var uriStr = uri + "/post/i=" + i; Runnable interrupt = () -> { Thread current = Thread.currentThread(); out.printf("%s Interrupting main from: %s (%s)%n", now(), current, uriStr); @@ -593,39 +628,42 @@ public class CancelRequestTest implements HttpServerAdapters { .POST(HttpRequest.BodyPublishers.ofByteArrays(iterable)) .setOption(H3_DISCOVERY, config) .build(); + var requestLatch = addLatchFor(req); + String body = null; Exception failed = null; try { - out.println("Sending: " + uriStr); + out.println(now() + "Sending: " + req.uri()); body = client.send(req, BodyHandlers.ofString()).body(); } catch (Exception x) { failed = x; } - out.println(uriStr + ": got result or exception"); + requestLatch.countDown(); + out.println(now() + req.uri() + ": got result or exception"); if (failed instanceof InterruptedException) { - out.println(uriStr + ": Got expected exception: " + failed); + out.println(now() + req.uri() + ": Got expected exception: " + failed); } else if (failed instanceof IOException) { - out.println(uriStr + ": got IOException: " + failed); + out.println(now() + req.uri() + ": got IOException: " + failed); // that could be OK if the main thread was interrupted // from the main thread: the interrupted status could have // been caught by writing to the socket from the main // thread. if (interruptingThread.isDone() && interruptingThread.get() == main) { - out.println(uriStr + ": Accepting IOException: " + failed); + out.println(now() + req.uri() + ": Accepting IOException: " + failed); failed.printStackTrace(out); } else { - out.println(uriStr + ": unexpected exception: " + failed); + out.println(now() + req.uri() + ": unexpected exception: " + failed); throw failed; } } else if (failed != null) { - out.println(uriStr + ": unexpected exception: " + failed); + out.println(now() + req.uri() + ": unexpected exception: " + failed); throw failed; } else { assert failed == null; - out.println(uriStr + ": got body: " + body); + out.println(now() + req.uri() + ": got body: " + body); assertEquals(body, String.join("", BODY.split("\\|"))); } - out.println("next iteration"); + out.println(now() + "next iteration"); var error = TRACKER.check(tracker, 2000, (t) -> t.getOutstandingOperations() > 0 || t.getOutstandingSubscribers() > 0, @@ -700,7 +738,7 @@ public class CancelRequestTest implements HttpServerAdapters { } finally { if (fail != null) { if (sharedClientName != null) { - System.err.println("Shared client name is: " + sharedClientName); + System.err.println(now() + "Shared client name is: " + sharedClientName); } throw fail; } @@ -719,9 +757,9 @@ public class CancelRequestTest implements HttpServerAdapters { @Override public void handle(HttpTestExchange t) throws IOException { try { - out.println("HTTPSlowHandler received request to " + t.getRequestURI()); - System.err.println("HTTPSlowHandler received request to " + t.getRequestURI()); - + out.println(now() + "HTTPSlowHandler received request to " + t.getRequestURI()); + System.err.println(now() + "HTTPSlowHandler received request to " + t.getRequestURI()); + var requestLatch = latches.get(t.getRequestURI().getRawQuery()); boolean isThreadInterrupt = isThreadInterrupt(t); byte[] req; try (InputStream is = t.getRequestBody()) { @@ -729,7 +767,7 @@ public class CancelRequestTest implements HttpServerAdapters { } t.sendResponseHeaders(200, -1); // chunked/variable try (OutputStream os = t.getResponseBody()) { - // lets split the response in several chunks... + // let's split the response in several chunks... String msg = (req != null && req.length != 0) ? new String(req, UTF_8) : BODY; @@ -743,16 +781,29 @@ public class CancelRequestTest implements HttpServerAdapters { } catch (InterruptedException x) { // OK } - out.printf("Server wrote %d bytes%n", req.length); + out.printf(now() + "Server wrote %d bytes%n", req.length); + } + if (requestLatch != null) { + out.printf(now() + "Server awaiting latch %s for %s%n", + requestLatch, t.getRequestURI()); + try { + requestLatch.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + out.printf(now() + " ...latch released%n"); } } + } catch (IOException io) { + out.println(now() + "HTTPSlowHandler: IOexception is not unexpected: " + io); + throw io; } catch (Throwable e) { - out.println("HTTPSlowHandler: unexpected exception: " + e); + out.println(now() + "HTTPSlowHandler: unexpected exception: " + e); e.printStackTrace(); throw e; } finally { - out.printf("HTTPSlowHandler reply sent: %s%n", t.getRequestURI()); - System.err.printf("HTTPSlowHandler reply sent: %s%n", t.getRequestURI()); + out.printf(now() + "HTTPSlowHandler reply sent: %s%n", t.getRequestURI()); + System.err.printf(now() + "HTTPSlowHandler reply sent: %s%n", t.getRequestURI()); } } } From c1c543cc81b4b73ebf228fb817227309b0cff990 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Fri, 30 Jan 2026 16:10:11 +0000 Subject: [PATCH 266/328] 8210336: DateTimeFormatter predefined formatters should support short time zone offsets Reviewed-by: jlu, rriggs --- .../java/time/format/DateTimeFormatter.java | 23 +++++++- .../time/tck/java/time/TCKOffsetTime.java | 6 ++- .../time/format/TestDateTimeFormatter.java | 54 ++++++++++++++++++- 3 files changed, 79 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatter.java b/src/java.base/share/classes/java/time/format/DateTimeFormatter.java index 16d7193c556..9368cf54afd 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatter.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, 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 @@ -817,6 +817,7 @@ public final class DateTimeFormatter { *

  • The {@link #ISO_LOCAL_DATE} *
  • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then * they will be handled even though this is not part of the ISO-8601 standard. + * The offset parsing is lenient, which allows the minutes and seconds to be optional. * Parsing is case insensitive. * *

    @@ -829,7 +830,9 @@ public final class DateTimeFormatter { ISO_OFFSET_DATE = new DateTimeFormatterBuilder() .parseCaseInsensitive() .append(ISO_LOCAL_DATE) + .parseLenient() .appendOffsetId() + .parseStrict() .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE); } @@ -846,6 +849,7 @@ public final class DateTimeFormatter { *

  • If the offset is not available then the format is complete. *
  • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then * they will be handled even though this is not part of the ISO-8601 standard. + * The offset parsing is lenient, which allows the minutes and seconds to be optional. * Parsing is case insensitive. * *

    @@ -862,7 +866,9 @@ public final class DateTimeFormatter { .parseCaseInsensitive() .append(ISO_LOCAL_DATE) .optionalStart() + .parseLenient() .appendOffsetId() + .parseStrict() .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE); } @@ -919,6 +925,7 @@ public final class DateTimeFormatter { *

  • The {@link #ISO_LOCAL_TIME} *
  • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then * they will be handled even though this is not part of the ISO-8601 standard. + * The offset parsing is lenient, which allows the minutes and seconds to be optional. * Parsing is case insensitive. * *

    @@ -930,7 +937,9 @@ public final class DateTimeFormatter { ISO_OFFSET_TIME = new DateTimeFormatterBuilder() .parseCaseInsensitive() .append(ISO_LOCAL_TIME) + .parseLenient() .appendOffsetId() + .parseStrict() .toFormatter(ResolverStyle.STRICT, null); } @@ -947,6 +956,7 @@ public final class DateTimeFormatter { *

  • If the offset is not available then the format is complete. *
  • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then * they will be handled even though this is not part of the ISO-8601 standard. + * The offset parsing is lenient, which allows the minutes and seconds to be optional. * Parsing is case insensitive. * *

    @@ -962,7 +972,9 @@ public final class DateTimeFormatter { .parseCaseInsensitive() .append(ISO_LOCAL_TIME) .optionalStart() + .parseLenient() .appendOffsetId() + .parseStrict() .toFormatter(ResolverStyle.STRICT, null); } @@ -1075,6 +1087,7 @@ public final class DateTimeFormatter { *

  • If the offset is not available to format or parse then the format is complete. *
  • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then * they will be handled even though this is not part of the ISO-8601 standard. + * The offset parsing is lenient, which allows the minutes and seconds to be optional. *
  • If the zone ID is not available or is a {@code ZoneOffset} then the format is complete. *
  • An open square bracket '['. *
  • The {@link ZoneId#getId() zone ID}. This is not part of the ISO-8601 standard. @@ -1094,7 +1107,9 @@ public final class DateTimeFormatter { ISO_DATE_TIME = new DateTimeFormatterBuilder() .append(ISO_LOCAL_DATE_TIME) .optionalStart() + .parseLenient() .appendOffsetId() + .parseStrict() .optionalStart() .appendLiteral('[') .parseCaseSensitive() @@ -1121,6 +1136,7 @@ public final class DateTimeFormatter { *
  • If the offset is not available to format or parse then the format is complete. *
  • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then * they will be handled even though this is not part of the ISO-8601 standard. + * The offset parsing is lenient, which allows the minutes and seconds to be optional. * Parsing is case insensitive. * *

    @@ -1139,7 +1155,9 @@ public final class DateTimeFormatter { .appendLiteral('-') .appendValue(DAY_OF_YEAR, 3) .optionalStart() + .parseLenient() .appendOffsetId() + .parseStrict() .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE); } @@ -1165,6 +1183,7 @@ public final class DateTimeFormatter { *

  • If the offset is not available to format or parse then the format is complete. *
  • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then * they will be handled even though this is not part of the ISO-8601 standard. + * The offset parsing is lenient, which allows the minutes and seconds to be optional. * Parsing is case insensitive. * *

    @@ -1185,7 +1204,9 @@ public final class DateTimeFormatter { .appendLiteral('-') .appendValue(DAY_OF_WEEK, 1) .optionalStart() + .parseLenient() .appendOffsetId() + .parseStrict() .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE); } diff --git a/test/jdk/java/time/tck/java/time/TCKOffsetTime.java b/test/jdk/java/time/tck/java/time/TCKOffsetTime.java index 7ea9504edbc..8aab9f53977 100644 --- a/test/jdk/java/time/tck/java/time/TCKOffsetTime.java +++ b/test/jdk/java/time/tck/java/time/TCKOffsetTime.java @@ -421,7 +421,6 @@ public class TCKOffsetTime extends AbstractDateTimeTest { {"00;00"}, {"12-00"}, {"-01:00"}, - {"00:00:00-09"}, {"00:00:00,09"}, {"00:00:abs"}, {"11"}, @@ -436,6 +435,11 @@ public class TCKOffsetTime extends AbstractDateTimeTest { Assertions.assertThrows(DateTimeParseException.class, () -> OffsetTime.parse(unparsable)); } + @Test + public void factory_parse_hourOnlyOffset() { + Assertions.assertDoesNotThrow(() -> OffsetTime.parse("00:00:00-09")); + } + //-----------------------------------------------------------------------s @Test public void factory_parse_illegalHour() { diff --git a/test/jdk/java/time/test/java/time/format/TestDateTimeFormatter.java b/test/jdk/java/time/test/java/time/format/TestDateTimeFormatter.java index 2ccc0da8f58..d6c73f6bc74 100644 --- a/test/jdk/java/time/test/java/time/format/TestDateTimeFormatter.java +++ b/test/jdk/java/time/test/java/time/format/TestDateTimeFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,6 +59,7 @@ */ package test.java.time.format; +import static java.time.format.DateTimeFormatter.*; import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -93,15 +94,19 @@ import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.util.Locale; import java.util.function.Function; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * Test DateTimeFormatter. - * @bug 8085887 8293146 + * @bug 8085887 8293146 8210336 */ @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestDateTimeFormatter { @@ -333,4 +338,49 @@ public class TestDateTimeFormatter { assertThrows(DateTimeException.class, () -> LocalDate.parse(weekDate, f)); } } + + private static Stream data_iso_short_offset_parse() { + return Stream.of( + Arguments.of("20260123-01", BASIC_ISO_DATE, "20260123-0100"), + Arguments.of("20260123+00", BASIC_ISO_DATE, "20260123Z"), + Arguments.of("20260123-00", BASIC_ISO_DATE, "20260123Z"), + Arguments.of("2026-01-23-01", ISO_DATE, "2026-01-23-01:00"), + Arguments.of("2026-01-23+00", ISO_DATE, "2026-01-23Z"), + Arguments.of("2026-01-23-00", ISO_DATE, "2026-01-23Z"), + Arguments.of("2026-01-23T11:30:59-01", ISO_DATE_TIME, "2026-01-23T11:30:59-01:00"), + Arguments.of("2026-01-23T11:30:59+00", ISO_DATE_TIME, "2026-01-23T11:30:59Z"), + Arguments.of("2026-01-23T11:30:59-00", ISO_DATE_TIME, "2026-01-23T11:30:59Z"), + Arguments.of("11:30:59-01", ISO_TIME, "11:30:59-01:00"), + Arguments.of("11:30:59+00", ISO_TIME, "11:30:59Z"), + Arguments.of("11:30:59-00", ISO_TIME, "11:30:59Z"), + Arguments.of("2026-01-23-01", ISO_OFFSET_DATE, "2026-01-23-01:00"), + Arguments.of("2026-01-23+00", ISO_OFFSET_DATE, "2026-01-23Z"), + Arguments.of("2026-01-23-00", ISO_OFFSET_DATE, "2026-01-23Z"), + Arguments.of("2026-01-23T11:30:59-01", ISO_OFFSET_DATE_TIME, "2026-01-23T11:30:59-01:00"), + Arguments.of("2026-01-23T11:30:59+00", ISO_OFFSET_DATE_TIME, "2026-01-23T11:30:59Z"), + Arguments.of("2026-01-23T11:30:59-00", ISO_OFFSET_DATE_TIME, "2026-01-23T11:30:59Z"), + Arguments.of("11:30:59-01", ISO_OFFSET_TIME, "11:30:59-01:00"), + Arguments.of("11:30:59+00", ISO_OFFSET_TIME, "11:30:59Z"), + Arguments.of("11:30:59-00", ISO_OFFSET_TIME, "11:30:59Z"), + Arguments.of("2026-023-01", ISO_ORDINAL_DATE, "2026-023-01:00"), + Arguments.of("2026-023+00", ISO_ORDINAL_DATE, "2026-023Z"), + Arguments.of("2026-023-00", ISO_ORDINAL_DATE, "2026-023Z"), + Arguments.of("2026-W04-5-01", ISO_WEEK_DATE, "2026-W04-5-01:00"), + Arguments.of("2026-W04-5+00", ISO_WEEK_DATE, "2026-W04-5Z"), + Arguments.of("2026-W04-5-00", ISO_WEEK_DATE, "2026-W04-5Z"), + Arguments.of("2026-01-23T11:30:59-01", ISO_ZONED_DATE_TIME, "2026-01-23T11:30:59-01:00"), + Arguments.of("2026-01-23T11:30:59+00", ISO_ZONED_DATE_TIME, "2026-01-23T11:30:59Z"), + Arguments.of("2026-01-23T11:30:59-00", ISO_ZONED_DATE_TIME, "2026-01-23T11:30:59Z"), + Arguments.of("2026-01-23T11:30:59-01", ISO_INSTANT, "2026-01-23T12:30:59Z"), + Arguments.of("2026-01-23T11:30:59+00", ISO_INSTANT, "2026-01-23T11:30:59Z"), + Arguments.of("2026-01-23T11:30:59-00", ISO_INSTANT, "2026-01-23T11:30:59Z") + ); + } + + // Checks if predefined ISO formatters can parse hour-only offsets + @ParameterizedTest + @MethodSource("data_iso_short_offset_parse") + public void test_iso_short_offset_parse(String text, DateTimeFormatter formatter, String expected) { + assertEquals(expected, formatter.format(formatter.parse(text))); + } } From 673cd6ed0c4ebbb301346e8e251d1674f363c0d8 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Fri, 30 Jan 2026 16:54:47 +0000 Subject: [PATCH 267/328] 8374449: Shenandoah: Leaf locks used by Shenandoah need lower ranks Reviewed-by: ysr --- .../share/gc/shenandoah/shenandoahControlThread.cpp | 2 +- src/hotspot/share/gc/shenandoah/shenandoahController.hpp | 7 +++++-- .../gc/shenandoah/shenandoahGenerationalControlThread.cpp | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 590e7831f07..bc11659c5e5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -44,7 +44,7 @@ ShenandoahControlThread::ShenandoahControlThread() : ShenandoahController(), _requested_gc_cause(GCCause::_no_gc), _degen_point(ShenandoahGC::_degenerated_outside_cycle), - _control_lock(Mutex::nosafepoint - 2, "ShenandoahGCRequest_lock", true) { + _control_lock(CONTROL_LOCK_RANK, "ShenandoahControl_lock", true) { set_name("Shenandoah Control Thread"); create_and_start(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahController.hpp b/src/hotspot/share/gc/shenandoah/shenandoahController.hpp index a6a699fac3b..b8ff4df4771 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahController.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahController.hpp @@ -42,6 +42,9 @@ private: shenandoah_padding(1); protected: + const Mutex::Rank WAITERS_LOCK_RANK = Mutex::safepoint - 5; + const Mutex::Rank CONTROL_LOCK_RANK = Mutex::nosafepoint - 2; + // While we could have a single lock for these, it may risk unblocking // GC waiters when alloc failure GC cycle finishes. We want instead // to make complete explicit cycle for demanding customers. @@ -54,8 +57,8 @@ protected: public: ShenandoahController(): _gc_id(0), - _alloc_failure_waiters_lock(Mutex::safepoint-2, "ShenandoahAllocFailureGC_lock", true), - _gc_waiters_lock(Mutex::safepoint-2, "ShenandoahRequestedGC_lock", true) + _alloc_failure_waiters_lock(WAITERS_LOCK_RANK, "ShenandoahAllocFailureWaiters_lock", true), + _gc_waiters_lock(WAITERS_LOCK_RANK, "ShenandoahGCWaiters_lock", true) { } // Request a collection cycle. This handles "explicit" gc requests diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index 018b4898a19..3b57190cc75 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -47,7 +47,7 @@ #include "utilities/events.hpp" ShenandoahGenerationalControlThread::ShenandoahGenerationalControlThread() : - _control_lock(Mutex::nosafepoint - 2, "ShenandoahGCRequest_lock", true), + _control_lock(CONTROL_LOCK_RANK, "ShenandoahGCRequest_lock", true), _requested_gc_cause(GCCause::_no_gc), _requested_generation(nullptr), _gc_mode(none), From ee60eff1ec9eddcdedc12c1707fbcca0025e71d6 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Fri, 30 Jan 2026 17:41:50 +0000 Subject: [PATCH 268/328] 8376038: Refactor java/sql tests to use JUnit 8376629: Refactor javax/sql tests to use JUnit Reviewed-by: lancea --- test/jdk/java/sql/JavatimeTest.java | 173 ----- test/jdk/java/sql/test/TEST.properties | 3 + .../test/sql/BatchUpdateExceptionTests.java | 10 +- .../test/sql/CallableStatementTests.java | 65 +- .../test/sql/ConnectionTests.java | 59 +- .../test/sql/DataTruncationTests.java | 10 +- .../sql/{testng => }/test/sql/DateTests.java | 124 ++-- .../test/sql/DriverManagerTests.java | 80 +-- test/jdk/java/sql/test/sql/JavatimeTest.java | 184 +++++ .../test/sql/PreparedStatementTests.java | 65 +- .../test/sql/SQLClientInfoExceptionTests.java | 10 +- .../test/sql/SQLDataExceptionTests.java | 10 +- .../test/sql/SQLExceptionTests.java | 10 +- .../SQLFeatureNotSupportedExceptionTests.java | 10 +- ...rityConstraintViolationExceptionTests.java | 10 +- ...nvalidAuthorizationSpecExceptionTests.java | 10 +- ...LNonTransientConnectionExceptionTests.java | 10 +- .../sql/SQLNonTransientExceptionTests.java | 10 +- .../sql/SQLRecoverableExceptionTests.java | 10 +- .../sql/SQLSyntaxErrorExceptionTests.java | 10 +- .../test/sql/SQLTimeoutExceptionTests.java | 10 +- .../SQLTransactionRollbackExceptionTests.java | 10 +- .../SQLTransientConnectionExceptionTests.java | 10 +- .../test/sql/SQLTransientExceptionTests.java | 10 +- .../test/sql/SQLWarningTests.java | 10 +- .../{testng => }/test/sql/StatementTests.java | 63 +- .../sql/{testng => }/test/sql/TimeTests.java | 136 ++-- .../{testng => }/test/sql/TimestampTests.java | 296 ++++---- .../DriverManagerInitTests.java | 8 +- .../DriverManagerModuleTests.java | 34 +- .../test/sql/drivermanager/TEST.properties | 4 + test/jdk/java/sql/testng/TEST.properties | 4 - .../java/sql/{testng => }/util/BaseTest.java | 146 ++-- .../{testng => }/util/DriverActionImpl.java | 2 +- .../util/SerializedBatchUpdateException.java | 2 +- .../util/StubCallableStatement.java | 2 +- .../sql/{testng => }/util/StubConnection.java | 2 +- .../util/StubDatabaseMetaData.java | 2 +- .../sql/{testng => }/util/StubDriver.java | 2 +- .../sql/{testng => }/util/StubDriverDA.java | 2 +- .../util/StubPreparedStatement.java | 2 +- .../sql/{testng => }/util/StubStatement.java | 2 +- .../javax/sql/{testng => }/TEST.properties | 6 +- .../services/javax.sql.rowset.RowSetFactory | 0 .../services/javax.sql.rowset.RowSetFactory | 0 test/jdk/javax/sql/rowset/TEST.properties | 1 - .../serial/SerialBlob/SetBinaryStream.java | 42 -- .../serial/SerialClob/SetAsciiStream.java | 42 -- .../serial/SerialClob/SetCharacterStream.java | 42 -- .../test/rowset/BaseRowSetTests.java | 124 ++-- .../test/rowset/CommonRowSetTests.java | 637 ++++++++++-------- .../test/rowset/RowSetFactoryTests.java | 43 +- .../test/rowset/RowSetMetaDataTests.java | 339 +++++----- .../test/rowset/RowSetProviderTests.java | 69 +- .../test/rowset/RowSetWarningTests.java | 8 +- .../cachedrowset/CachedRowSetTests.java | 2 +- .../cachedrowset/CommonCachedRowSetTests.java | 544 +++++++++------ .../rowset/filteredrowset/CityFilter.java | 2 +- .../filteredrowset/FilteredRowSetTests.java | 36 +- .../filteredrowset/PrimaryKeyFilter.java | 2 +- .../JdbcRowSetDriverManagerTest.java | 8 +- .../rowset/joinrowset/JoinRowSetTests.java | 76 ++- .../rowset/resourcebundle/TEST.properties | 2 + .../resourcebundle}/ValidateGetBundle.java | 5 +- .../ValidateResourceBundleAccess.java | 16 +- .../test/rowset/serial/SQLInputImplTests.java | 34 +- .../rowset/serial/SQLOutputImplTests.java | 38 +- .../test/rowset/serial/SerialArrayTests.java | 110 +-- .../test/rowset/serial/SerialBlobTests.java | 233 ++++--- .../test/rowset/serial/SerialClobTests.java | 251 ++++--- .../rowset/serial/SerialDataLinkTests.java | 18 +- .../rowset/serial/SerialExceptionTests.java | 8 +- .../rowset/serial/SerialJavaObjectTests.java | 22 +- .../test/rowset/serial/SerialRefTests.java | 30 +- .../test/rowset/serial/SerialStructTests.java | 16 +- .../rowset/spi/SyncFactoryExceptionTests.java | 8 +- .../test/rowset/spi/SyncFactoryTests.java | 30 +- .../spi/SyncProviderExceptionTests.java | 19 +- .../webrowset/CommonWebRowSetTests.java | 103 +-- .../test/rowset/webrowset/WebRowSetTests.java | 2 +- .../util/PropertyStubProvider.java | 2 +- .../sql/{testng => }/util/StubArray.java | 2 +- .../sql/{testng => }/util/StubBaseRowSet.java | 2 +- .../javax/sql/{testng => }/util/StubBlob.java | 2 +- .../util/StubCachedRowSetImpl.java | 2 +- .../javax/sql/{testng => }/util/StubClob.java | 2 +- .../sql/{testng => }/util/StubContext.java | 2 +- .../util/StubFilteredRowSetImpl.java | 2 +- .../{testng => }/util/StubJdbcRowSetImpl.java | 2 +- .../{testng => }/util/StubJoinRowSetImpl.java | 2 +- .../sql/{testng => }/util/StubNClob.java | 2 +- .../javax/sql/{testng => }/util/StubRef.java | 2 +- .../sql/{testng => }/util/StubRowId.java | 2 +- .../{testng => }/util/StubRowSetFactory.java | 2 +- .../sql/{testng => }/util/StubSQLXML.java | 2 +- .../sql/{testng => }/util/StubStruct.java | 2 +- .../{testng => }/util/StubSyncProvider.java | 2 +- .../{testng => }/util/StubSyncResolver.java | 2 +- .../{testng => }/util/StubWebRowSetImpl.java | 2 +- .../sql/{testng => }/util/SuperHero.java | 2 +- .../{testng => }/util/TestRowSetListener.java | 2 +- .../{testng => }/util/TestSQLDataImpl.java | 2 +- .../sql/{testng => }/xml/COFFEE_ROWS.xml | 0 .../{testng => }/xml/DELETED_COFFEE_ROWS.xml | 0 .../{testng => }/xml/INSERTED_COFFEE_ROWS.xml | 0 .../xml/MODFIED_DELETED_COFFEE_ROWS.xml | 0 .../{testng => }/xml/UPDATED_COFFEE_ROWS.xml | 0 .../xml/UPDATED_INSERTED_COFFEE_ROWS.xml | 0 108 files changed, 2511 insertions(+), 2133 deletions(-) delete mode 100644 test/jdk/java/sql/JavatimeTest.java create mode 100644 test/jdk/java/sql/test/TEST.properties rename test/jdk/java/sql/{testng => }/test/sql/BatchUpdateExceptionTests.java (98%) rename test/jdk/java/sql/{testng => }/test/sql/CallableStatementTests.java (62%) rename test/jdk/java/sql/{testng => }/test/sql/ConnectionTests.java (63%) rename test/jdk/java/sql/{testng => }/test/sql/DataTruncationTests.java (97%) rename test/jdk/java/sql/{testng => }/test/sql/DateTests.java (80%) rename test/jdk/java/sql/{testng => }/test/sql/DriverManagerTests.java (84%) create mode 100644 test/jdk/java/sql/test/sql/JavatimeTest.java rename test/jdk/java/sql/{testng => }/test/sql/PreparedStatementTests.java (62%) rename test/jdk/java/sql/{testng => }/test/sql/SQLClientInfoExceptionTests.java (97%) rename test/jdk/java/sql/{testng => }/test/sql/SQLDataExceptionTests.java (97%) rename test/jdk/java/sql/{testng => }/test/sql/SQLExceptionTests.java (97%) rename test/jdk/java/sql/{testng => }/test/sql/SQLFeatureNotSupportedExceptionTests.java (97%) rename test/jdk/java/sql/{testng => }/test/sql/SQLIntegrityConstraintViolationExceptionTests.java (97%) rename test/jdk/java/sql/{testng => }/test/sql/SQLInvalidAuthorizationSpecExceptionTests.java (97%) rename test/jdk/java/sql/{testng => }/test/sql/SQLNonTransientConnectionExceptionTests.java (97%) rename test/jdk/java/sql/{testng => }/test/sql/SQLNonTransientExceptionTests.java (97%) rename test/jdk/java/sql/{testng => }/test/sql/SQLRecoverableExceptionTests.java (97%) rename test/jdk/java/sql/{testng => }/test/sql/SQLSyntaxErrorExceptionTests.java (97%) rename test/jdk/java/sql/{testng => }/test/sql/SQLTimeoutExceptionTests.java (97%) rename test/jdk/java/sql/{testng => }/test/sql/SQLTransactionRollbackExceptionTests.java (97%) rename test/jdk/java/sql/{testng => }/test/sql/SQLTransientConnectionExceptionTests.java (97%) rename test/jdk/java/sql/{testng => }/test/sql/SQLTransientExceptionTests.java (97%) rename test/jdk/java/sql/{testng => }/test/sql/SQLWarningTests.java (97%) rename test/jdk/java/sql/{testng => }/test/sql/StatementTests.java (62%) rename test/jdk/java/sql/{testng => }/test/sql/TimeTests.java (76%) rename test/jdk/java/sql/{testng => }/test/sql/TimestampTests.java (73%) rename test/jdk/java/sql/{testng/test/sql/othervm => test/sql/drivermanager}/DriverManagerInitTests.java (93%) rename test/jdk/java/sql/{driverModuleTests => test/sql/drivermanager}/DriverManagerModuleTests.java (84%) create mode 100644 test/jdk/java/sql/test/sql/drivermanager/TEST.properties delete mode 100644 test/jdk/java/sql/testng/TEST.properties rename test/jdk/java/sql/{testng => }/util/BaseTest.java (54%) rename test/jdk/java/sql/{testng => }/util/DriverActionImpl.java (94%) rename test/jdk/java/sql/{testng => }/util/SerializedBatchUpdateException.java (99%) rename test/jdk/java/sql/{testng => }/util/StubCallableStatement.java (99%) rename test/jdk/java/sql/{testng => }/util/StubConnection.java (99%) rename test/jdk/java/sql/{testng => }/util/StubDatabaseMetaData.java (99%) rename test/jdk/java/sql/{testng => }/util/StubDriver.java (96%) rename test/jdk/java/sql/{testng => }/util/StubDriverDA.java (96%) rename test/jdk/java/sql/{testng => }/util/StubPreparedStatement.java (99%) rename test/jdk/java/sql/{testng => }/util/StubStatement.java (99%) rename test/jdk/javax/sql/{testng => }/TEST.properties (68%) rename test/jdk/javax/sql/{testng => }/jars/badFactory/META-INF/services/javax.sql.rowset.RowSetFactory (100%) rename test/jdk/javax/sql/{testng => }/jars/goodFactory/META-INF/services/javax.sql.rowset.RowSetFactory (100%) delete mode 100644 test/jdk/javax/sql/rowset/TEST.properties delete mode 100644 test/jdk/javax/sql/rowset/serial/SerialBlob/SetBinaryStream.java delete mode 100644 test/jdk/javax/sql/rowset/serial/SerialClob/SetAsciiStream.java delete mode 100644 test/jdk/javax/sql/rowset/serial/SerialClob/SetCharacterStream.java rename test/jdk/javax/sql/{testng => }/test/rowset/BaseRowSetTests.java (83%) rename test/jdk/javax/sql/{testng => }/test/rowset/CommonRowSetTests.java (67%) rename test/jdk/javax/sql/{testng => }/test/rowset/RowSetFactoryTests.java (80%) rename test/jdk/javax/sql/{testng => }/test/rowset/RowSetMetaDataTests.java (55%) rename test/jdk/javax/sql/{testng => }/test/rowset/RowSetProviderTests.java (79%) rename test/jdk/javax/sql/{testng => }/test/rowset/RowSetWarningTests.java (97%) rename test/jdk/javax/sql/{testng => }/test/rowset/cachedrowset/CachedRowSetTests.java (94%) rename test/jdk/javax/sql/{testng => }/test/rowset/cachedrowset/CommonCachedRowSetTests.java (79%) rename test/jdk/javax/sql/{testng => }/test/rowset/filteredrowset/CityFilter.java (97%) rename test/jdk/javax/sql/{testng => }/test/rowset/filteredrowset/FilteredRowSetTests.java (81%) rename test/jdk/javax/sql/{testng => }/test/rowset/filteredrowset/PrimaryKeyFilter.java (97%) rename test/jdk/javax/sql/{testng => }/test/rowset/jdbcrowset/JdbcRowSetDriverManagerTest.java (95%) rename test/jdk/javax/sql/{testng => }/test/rowset/joinrowset/JoinRowSetTests.java (83%) create mode 100644 test/jdk/javax/sql/test/rowset/resourcebundle/TEST.properties rename test/jdk/javax/sql/{resourceBundleTests => test/rowset/resourcebundle}/ValidateGetBundle.java (94%) rename test/jdk/javax/sql/{testng/test/rowset => test/rowset/resourcebundle}/ValidateResourceBundleAccess.java (89%) rename test/jdk/javax/sql/{testng => }/test/rowset/serial/SQLInputImplTests.java (92%) rename test/jdk/javax/sql/{testng => }/test/rowset/serial/SQLOutputImplTests.java (91%) rename test/jdk/javax/sql/{testng => }/test/rowset/serial/SerialArrayTests.java (72%) rename test/jdk/javax/sql/{testng => }/test/rowset/serial/SerialBlobTests.java (69%) rename test/jdk/javax/sql/{testng => }/test/rowset/serial/SerialClobTests.java (72%) rename test/jdk/javax/sql/{testng => }/test/rowset/serial/SerialDataLinkTests.java (90%) rename test/jdk/javax/sql/{testng => }/test/rowset/serial/SerialExceptionTests.java (95%) rename test/jdk/javax/sql/{testng => }/test/rowset/serial/SerialJavaObjectTests.java (86%) rename test/jdk/javax/sql/{testng => }/test/rowset/serial/SerialRefTests.java (86%) rename test/jdk/javax/sql/{testng => }/test/rowset/serial/SerialStructTests.java (92%) rename test/jdk/javax/sql/{testng => }/test/rowset/spi/SyncFactoryExceptionTests.java (95%) rename test/jdk/javax/sql/{testng => }/test/rowset/spi/SyncFactoryTests.java (92%) rename test/jdk/javax/sql/{testng => }/test/rowset/spi/SyncProviderExceptionTests.java (96%) rename test/jdk/javax/sql/{testng => }/test/rowset/webrowset/CommonWebRowSetTests.java (81%) rename test/jdk/javax/sql/{testng => }/test/rowset/webrowset/WebRowSetTests.java (94%) rename test/jdk/javax/sql/{testng => }/util/PropertyStubProvider.java (92%) rename test/jdk/javax/sql/{testng => }/util/StubArray.java (97%) rename test/jdk/javax/sql/{testng => }/util/StubBaseRowSet.java (99%) rename test/jdk/javax/sql/{testng => }/util/StubBlob.java (97%) rename test/jdk/javax/sql/{testng => }/util/StubCachedRowSetImpl.java (99%) rename test/jdk/javax/sql/{testng => }/util/StubClob.java (97%) rename test/jdk/javax/sql/{testng => }/util/StubContext.java (98%) rename test/jdk/javax/sql/{testng => }/util/StubFilteredRowSetImpl.java (99%) rename test/jdk/javax/sql/{testng => }/util/StubJdbcRowSetImpl.java (99%) rename test/jdk/javax/sql/{testng => }/util/StubJoinRowSetImpl.java (99%) rename test/jdk/javax/sql/{testng => }/util/StubNClob.java (93%) rename test/jdk/javax/sql/{testng => }/util/StubRef.java (95%) rename test/jdk/javax/sql/{testng => }/util/StubRowId.java (93%) rename test/jdk/javax/sql/{testng => }/util/StubRowSetFactory.java (96%) rename test/jdk/javax/sql/{testng => }/util/StubSQLXML.java (97%) rename test/jdk/javax/sql/{testng => }/util/StubStruct.java (95%) rename test/jdk/javax/sql/{testng => }/util/StubSyncProvider.java (97%) rename test/jdk/javax/sql/{testng => }/util/StubSyncResolver.java (99%) rename test/jdk/javax/sql/{testng => }/util/StubWebRowSetImpl.java (99%) rename test/jdk/javax/sql/{testng => }/util/SuperHero.java (97%) rename test/jdk/javax/sql/{testng => }/util/TestRowSetListener.java (96%) rename test/jdk/javax/sql/{testng => }/util/TestSQLDataImpl.java (98%) rename test/jdk/javax/sql/{testng => }/xml/COFFEE_ROWS.xml (100%) rename test/jdk/javax/sql/{testng => }/xml/DELETED_COFFEE_ROWS.xml (100%) rename test/jdk/javax/sql/{testng => }/xml/INSERTED_COFFEE_ROWS.xml (100%) rename test/jdk/javax/sql/{testng => }/xml/MODFIED_DELETED_COFFEE_ROWS.xml (100%) rename test/jdk/javax/sql/{testng => }/xml/UPDATED_COFFEE_ROWS.xml (100%) rename test/jdk/javax/sql/{testng => }/xml/UPDATED_INSERTED_COFFEE_ROWS.xml (100%) diff --git a/test/jdk/java/sql/JavatimeTest.java b/test/jdk/java/sql/JavatimeTest.java deleted file mode 100644 index 89344d7cdc6..00000000000 --- a/test/jdk/java/sql/JavatimeTest.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2013, 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 8007520 - *@summary Test those bridge methods to/from java.time date/time classes - * @key randomness - */ - -import java.util.Random; -import java.sql.Date; -import java.sql.Time; -import java.sql.Timestamp; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.LocalDate; -import java.time.LocalTime; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; - -public class JavatimeTest { - - static final int NANOS_PER_SECOND = 1000000000; - - public static void main(String[] args) throws Throwable { - int N = 10000; - long t1970 = new java.util.Date(70, 0, 01).getTime(); - Random r = new Random(); - for (int i = 0; i < N; i++) { - int days = r.nextInt(50) * 365 + r.nextInt(365); - long secs = t1970 + days * 86400 + r.nextInt(86400); - int nanos = r.nextInt(NANOS_PER_SECOND); - int nanos_ms = nanos / 1000000 * 1000000; // millis precision - long millis = secs * 1000 + r.nextInt(1000); - - LocalDateTime ldt = LocalDateTime.ofEpochSecond(secs, nanos, ZoneOffset.UTC); - LocalDateTime ldt_ms = LocalDateTime.ofEpochSecond(secs, nanos_ms, ZoneOffset.UTC); - Instant inst = Instant.ofEpochSecond(secs, nanos); - Instant inst_ms = Instant.ofEpochSecond(secs, nanos_ms); - //System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); - - /////////// Timestamp //////////////////////////////// - Timestamp ta = new Timestamp(millis); - ta.setNanos(nanos); - if (!isEqual(ta.toLocalDateTime(), ta)) { - System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); - print(ta.toLocalDateTime(), ta); - throw new RuntimeException("FAILED: j.s.ts -> ldt"); - } - if (!isEqual(ldt, Timestamp.valueOf(ldt))) { - System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); - print(ldt, Timestamp.valueOf(ldt)); - throw new RuntimeException("FAILED: ldt -> j.s.ts"); - } - Instant inst0 = ta.toInstant(); - if (ta.getTime() != inst0.toEpochMilli() || - ta.getNanos() != inst0.getNano() || - !ta.equals(Timestamp.from(inst0))) { - System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); - throw new RuntimeException("FAILED: j.s.ts -> instant -> j.s.ts"); - } - inst = Instant.ofEpochSecond(secs, nanos); - Timestamp ta0 = Timestamp.from(inst); - if (ta0.getTime() != inst.toEpochMilli() || - ta0.getNanos() != inst.getNano() || - !inst.equals(ta0.toInstant())) { - System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); - throw new RuntimeException("FAILED: instant -> timestamp -> instant"); - } - - ////////// java.sql.Date ///////////////////////////// - // j.s.d/t uses j.u.d.equals() !!!!!!!! - java.sql.Date jsd = new java.sql.Date(millis); - if (!isEqual(jsd.toLocalDate(), jsd)) { - System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); - print(jsd.toLocalDate(), jsd); - throw new RuntimeException("FAILED: j.s.d -> ld"); - } - LocalDate ld = ldt.toLocalDate(); - if (!isEqual(ld, java.sql.Date.valueOf(ld))) { - System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); - print(ld, java.sql.Date.valueOf(ld)); - throw new RuntimeException("FAILED: ld -> j.s.d"); - } - ////////// java.sql.Time ///////////////////////////// - java.sql.Time jst = new java.sql.Time(millis); - if (!isEqual(jst.toLocalTime(), jst)) { - System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); - print(jst.toLocalTime(), jst); - throw new RuntimeException("FAILED: j.s.t -> lt"); - } - // millis precision - LocalTime lt = ldt_ms.toLocalTime(); - if (!isEqual(lt, java.sql.Time.valueOf(lt))) { - System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); - print(lt, java.sql.Time.valueOf(lt)); - throw new RuntimeException("FAILED: lt -> j.s.t"); - } - } - System.out.println("Passed!"); - } - - private static boolean isEqual(LocalDateTime ldt, Timestamp ts) { - ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault()); - return zdt.getYear() == ts.getYear() + 1900 && - zdt.getMonthValue() == ts.getMonth() + 1 && - zdt.getDayOfMonth() == ts.getDate() && - zdt.getHour() == ts.getHours() && - zdt.getMinute() == ts.getMinutes() && - zdt.getSecond() == ts.getSeconds() && - zdt.getNano() == ts.getNanos(); - } - - private static void print(LocalDateTime ldt, Timestamp ts) { - ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault()); - System.out.printf("ldt:ts %d/%d, %d/%d, %d/%d, %d/%d, %d/%d, %d/%d, nano:[%d/%d]%n", - zdt.getYear(), ts.getYear() + 1900, - zdt.getMonthValue(), ts.getMonth() + 1, - zdt.getDayOfMonth(), ts.getDate(), - zdt.getHour(), ts.getHours(), - zdt.getMinute(), ts.getMinutes(), - zdt.getSecond(), ts.getSeconds(), - zdt.getNano(), ts.getNanos()); - } - - private static boolean isEqual(LocalDate ld, java.sql.Date d) { - return ld.getYear() == d.getYear() + 1900 && - ld.getMonthValue() == d.getMonth() + 1 && - ld.getDayOfMonth() == d.getDate(); - } - - private static void print(LocalDate ld, java.sql.Date d) { - System.out.printf("%d/%d, %d/%d, %d/%d%n", - ld.getYear(), d.getYear() + 1900, - ld.getMonthValue(), d.getMonth() + 1, - ld.getDayOfMonth(), d.getDate()); - } - - private static boolean isEqual(LocalTime lt, java.sql.Time t) { - return lt.getHour() == t.getHours() && - lt.getMinute() == t.getMinutes() && - lt.getSecond() == t.getSeconds(); - } - - private static void print(LocalTime lt, java.sql.Time t) { - System.out.printf("%d/%d, %d/%d, %d/%d%n", - lt.getHour(), t.getHours(), - lt.getMinute(), t.getMinutes(), - lt.getSecond(), t.getSeconds()); - } -} diff --git a/test/jdk/java/sql/test/TEST.properties b/test/jdk/java/sql/test/TEST.properties new file mode 100644 index 00000000000..97c9e7bbe18 --- /dev/null +++ b/test/jdk/java/sql/test/TEST.properties @@ -0,0 +1,3 @@ +# JDBC unit tests uses JUnit +JUnit.dirs= . +lib.dirs = /java/sql/util diff --git a/test/jdk/java/sql/testng/test/sql/BatchUpdateExceptionTests.java b/test/jdk/java/sql/test/sql/BatchUpdateExceptionTests.java similarity index 98% rename from test/jdk/java/sql/testng/test/sql/BatchUpdateExceptionTests.java rename to test/jdk/java/sql/test/sql/BatchUpdateExceptionTests.java index 2b1111b7526..2d010b50e41 100644 --- a/test/jdk/java/sql/testng/test/sql/BatchUpdateExceptionTests.java +++ b/test/jdk/java/sql/test/sql/BatchUpdateExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.io.ByteArrayInputStream; import java.io.File; @@ -28,8 +28,10 @@ import java.io.ObjectInputStream; import java.sql.BatchUpdateException; import java.sql.SQLException; import java.util.Arrays; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.SerializedBatchUpdateException; import util.BaseTest; diff --git a/test/jdk/java/sql/testng/test/sql/CallableStatementTests.java b/test/jdk/java/sql/test/sql/CallableStatementTests.java similarity index 62% rename from test/jdk/java/sql/testng/test/sql/CallableStatementTests.java rename to test/jdk/java/sql/test/sql/CallableStatementTests.java index 7a4fe15ecac..dc5c347ef50 100644 --- a/test/jdk/java/sql/testng/test/sql/CallableStatementTests.java +++ b/test/jdk/java/sql/test/sql/CallableStatementTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,28 +20,33 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import org.junit.jupiter.params.provider.ValueSource; import util.BaseTest; import util.StubConnection; import java.sql.CallableStatement; import java.sql.SQLException; -import static org.testng.Assert.assertEquals; +import org.junit.jupiter.api.AfterEach; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class CallableStatementTests extends BaseTest { private CallableStatement cstmt; - @BeforeMethod + @BeforeEach public void setUpMethod() throws Exception { cstmt = new StubConnection().prepareCall("{call SuperHero_Proc(?)}"); } - @AfterMethod + @AfterEach public void tearDownMethod() throws Exception { cstmt.close(); } @@ -50,80 +55,84 @@ public class CallableStatementTests extends BaseTest { * Verify that enquoteLiteral creates a valid literal and converts every * single quote to two single quotes */ - @Test(dataProvider = "validEnquotedLiteralValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validEnquotedLiteralValues") public void test00(String s, String expected) throws SQLException { - assertEquals(cstmt.enquoteLiteral(s), expected); + assertEquals(expected, cstmt.enquoteLiteral(s)); } /* * Validate a NullPointerException is thrown if the string passed to * enquoteLiteral is null */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test01() throws SQLException { - cstmt.enquoteLiteral(null); + assertThrows(NullPointerException.class, () -> cstmt.enquoteLiteral(null)); } /* * Validate that enquoteIdentifier returns the expected value */ - @Test(dataProvider = "validIdentifierValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validEnquotedIdentifierValues") public void test02(String s, boolean alwaysQuote, String expected) throws SQLException { - assertEquals(cstmt.enquoteIdentifier(s, alwaysQuote), expected); + assertEquals(expected, cstmt.enquoteIdentifier(s, alwaysQuote)); } /* * Validate that a SQLException is thrown for values that are not valid * for a SQL identifier */ - @Test(dataProvider = "invalidIdentifierValues", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidEnquotedIdentifierValues") public void test03(String s, boolean alwaysQuote) throws SQLException { - cstmt.enquoteIdentifier(s, alwaysQuote); + assertThrows(SQLException.class, () -> cstmt.enquoteIdentifier(s, alwaysQuote)); } /* * Validate a NullPointerException is thrown is the string passed to * enquoteIdentiifer is null */ - @Test(dataProvider = "trueFalse", - expectedExceptions = NullPointerException.class) + @ParameterizedTest(autoCloseArguments = false) + @ValueSource(booleans = {true, false}) public void test04(boolean alwaysQuote) throws SQLException { - cstmt.enquoteIdentifier(null, alwaysQuote); + assertThrows(NullPointerException.class, () -> cstmt.enquoteIdentifier(null, alwaysQuote)); } /* * Validate that isSimpleIdentifier returns the expected value */ - @Test(dataProvider = "simpleIdentifierValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("simpleIdentifierValues") public void test05(String s, boolean expected) throws SQLException { - assertEquals(cstmt.isSimpleIdentifier(s), expected); + assertEquals(expected, cstmt.isSimpleIdentifier(s)); } /* * Validate a NullPointerException is thrown if the string passed to * isSimpleIdentifier is null */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test06() throws SQLException { - cstmt.isSimpleIdentifier(null); + assertThrows(NullPointerException.class, () -> cstmt.isSimpleIdentifier(null)); } /* * Verify that enquoteLiteral creates a valid literal and converts every * single quote to two single quotes */ - @Test(dataProvider = "validEnquotedNCharLiteralValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validEnquotedNCharLiteralValues") public void test07(String s, String expected) throws SQLException { - assertEquals(cstmt.enquoteNCharLiteral(s), expected); + assertEquals(expected, cstmt.enquoteNCharLiteral(s)); } /* * Validate a NullPointerException is thrown if the string passed to * enquoteNCharLiteral is null */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test08() throws SQLException { - cstmt.enquoteNCharLiteral(null); + assertThrows(NullPointerException.class, () -> cstmt.enquoteNCharLiteral(null)); } } diff --git a/test/jdk/java/sql/testng/test/sql/ConnectionTests.java b/test/jdk/java/sql/test/sql/ConnectionTests.java similarity index 63% rename from test/jdk/java/sql/testng/test/sql/ConnectionTests.java rename to test/jdk/java/sql/test/sql/ConnectionTests.java index f40c2784e4a..534b5d7d96a 100644 --- a/test/jdk/java/sql/testng/test/sql/ConnectionTests.java +++ b/test/jdk/java/sql/test/sql/ConnectionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,22 +20,25 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import org.junit.jupiter.params.provider.ValueSource; import util.BaseTest; import util.StubConnection; import java.sql.SQLException; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class ConnectionTests extends BaseTest { protected StubConnection conn; - @BeforeMethod + @BeforeEach public void setUpMethod() throws Exception { conn = new StubConnection(); } @@ -44,80 +47,84 @@ public class ConnectionTests extends BaseTest { * Verify that enquoteLiteral creates a valid literal and converts every * single quote to two single quotes */ - @Test(dataProvider = "validEnquotedLiteralValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validEnquotedLiteralValues") public void test00(String s, String expected) throws SQLException { - assertEquals(conn.enquoteLiteral(s), expected); + assertEquals(expected, conn.enquoteLiteral(s)); } /* * Validate a NullPointerException is thrown if the string passed to * enquoteLiteral is null */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test01() throws SQLException { - conn.enquoteLiteral(null); + assertThrows(NullPointerException.class, () -> conn.enquoteLiteral(null)); } /* * Validate that enquoteIdentifier returns the expected value */ - @Test(dataProvider = "validIdentifierValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validEnquotedIdentifierValues") public void test02(String s, boolean alwaysQuote, String expected) throws SQLException { - assertEquals(conn.enquoteIdentifier(s, alwaysQuote), expected); + assertEquals(expected, conn.enquoteIdentifier(s, alwaysQuote)); } /* * Validate that a SQLException is thrown for values that are not valid * for a SQL identifier */ - @Test(dataProvider = "invalidIdentifierValues", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidEnquotedIdentifierValues") public void test03(String s, boolean alwaysQuote) throws SQLException { - conn.enquoteIdentifier(s, alwaysQuote); + assertThrows(SQLException.class, () -> conn.enquoteIdentifier(s, alwaysQuote)); } /* * Validate a NullPointerException is thrown is the string passed to * enquoteIdentiifer is null */ - @Test(dataProvider = "trueFalse", - expectedExceptions = NullPointerException.class) + @ParameterizedTest(autoCloseArguments = false) + @ValueSource(booleans = {true, false}) public void test04(boolean alwaysQuote) throws SQLException { - conn.enquoteIdentifier(null, alwaysQuote); + assertThrows(NullPointerException.class, () -> conn.enquoteIdentifier(null, alwaysQuote)); } /* * Validate that isSimpleIdentifier returns the expected value */ - @Test(dataProvider = "simpleIdentifierValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("simpleIdentifierValues") public void test05(String s, boolean expected) throws SQLException { - assertEquals(conn.isSimpleIdentifier(s), expected); + assertEquals(expected, conn.isSimpleIdentifier(s)); } /* * Validate a NullPointerException is thrown if the string passed to * isSimpleIdentifier is null */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test06() throws SQLException { - conn.isSimpleIdentifier(null); + assertThrows(NullPointerException.class, () -> conn.isSimpleIdentifier(null)); } /* * Verify that enquoteLiteral creates a valid literal and converts every * single quote to two single quotes */ - @Test(dataProvider = "validEnquotedNCharLiteralValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validEnquotedNCharLiteralValues") public void test07(String s, String expected) throws SQLException { - assertEquals(conn.enquoteNCharLiteral(s), expected); + assertEquals(expected, conn.enquoteNCharLiteral(s)); } /* * Validate a NullPointerException is thrown if the string passed to * enquoteNCharLiteral is null */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test08() throws SQLException { - conn.enquoteNCharLiteral(null); + assertThrows(NullPointerException.class, () -> conn.enquoteNCharLiteral(null)); } } diff --git a/test/jdk/java/sql/testng/test/sql/DataTruncationTests.java b/test/jdk/java/sql/test/sql/DataTruncationTests.java similarity index 97% rename from test/jdk/java/sql/testng/test/sql/DataTruncationTests.java rename to test/jdk/java/sql/test/sql/DataTruncationTests.java index fbf7eebe90a..9d221b4a037 100644 --- a/test/jdk/java/sql/testng/test/sql/DataTruncationTests.java +++ b/test/jdk/java/sql/test/sql/DataTruncationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,12 +20,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.DataTruncation; import java.sql.SQLException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class DataTruncationTests extends BaseTest { diff --git a/test/jdk/java/sql/testng/test/sql/DateTests.java b/test/jdk/java/sql/test/sql/DateTests.java similarity index 80% rename from test/jdk/java/sql/testng/test/sql/DateTests.java rename to test/jdk/java/sql/test/sql/DateTests.java index ae6c276c4f6..0c66dd15c98 100644 --- a/test/jdk/java/sql/testng/test/sql/DateTests.java +++ b/test/jdk/java/sql/test/sql/DateTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,14 +20,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.Date; -import java.time.Instant; import java.time.LocalDate; -import static org.testng.Assert.*; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + import util.BaseTest; public class DateTests extends BaseTest { @@ -35,17 +39,18 @@ public class DateTests extends BaseTest { /* * Validate an IllegalArgumentException is thrown for an invalid Date string */ - @Test(dataProvider = "invalidDateValues", - expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidDateValues") public void test(String d) throws Exception { - Date.valueOf(d); + assertThrows(IllegalArgumentException.class, () -> Date.valueOf(d)); } /* * Test that a date created from a date string is equal to the value * returned from toString() */ - @Test(dataProvider = "validDateValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validDateValues") public void test00(String d, String expectedD) { Date d1 = Date.valueOf(d); Date d2 = Date.valueOf(expectedD); @@ -207,20 +212,20 @@ public class DateTests extends BaseTest { /* * Validate an NPE occurs when a null LocalDate is passed to valueOf */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test15() throws Exception { LocalDate ld = null; - Date.valueOf(ld); + assertThrows(NullPointerException.class, () -> Date.valueOf(ld)); } /* * Validate an UnsupportedOperationException occurs when toInstant() is * called */ - @Test(expectedExceptions = UnsupportedOperationException.class) + @Test public void test16() throws Exception { Date d = Date.valueOf("1961-08-30"); - Instant instant = d.toInstant(); + assertThrows(UnsupportedOperationException.class, d::toInstant); } /* @@ -271,55 +276,55 @@ public class DateTests extends BaseTest { /* * Validate an IllegalArgumentException is thrown for calling getHours */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test21() throws Exception { Date d = Date.valueOf("1961-08-30"); - d.getHours(); + assertThrows(IllegalArgumentException.class, d::getHours); } /* * Validate an IllegalArgumentException is thrown for calling getMinutes */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test22() throws Exception { Date d = Date.valueOf("1961-08-30"); - d.getMinutes(); + assertThrows(IllegalArgumentException.class, d::getMinutes); } /* * Validate an IllegalArgumentException is thrown for calling getSeconds */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test23() throws Exception { Date d = Date.valueOf("1961-08-30"); - d.getSeconds(); + assertThrows(IllegalArgumentException.class, d::getSeconds); } /* * Validate an IllegalArgumentException is thrown for calling setHours */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test24() throws Exception { Date d = Date.valueOf("1961-08-30"); - d.setHours(8); + assertThrows(IllegalArgumentException.class, () -> d.setHours(8)); } /* * Validate an IllegalArgumentException is thrown for calling setMinutes */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test25() throws Exception { Date d = Date.valueOf("1961-08-30"); - d.setMinutes(0); + assertThrows(IllegalArgumentException.class, () -> d.setMinutes(0)); } /* * Validate an IllegalArgumentException is thrown for calling setSeconds */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test26() throws Exception { Date d = Date.valueOf("1961-08-30"); - d.setSeconds(0); + assertThrows(IllegalArgumentException.class, () -> d.setSeconds(0)); } /* @@ -327,32 +332,31 @@ public class DateTests extends BaseTest { * to validate that an IllegalArgumentException will be thrown from the * valueOf method */ - @DataProvider(name = "invalidDateValues") - private Object[][] invalidDateValues() { - return new Object[][]{ - {"20009-11-01"}, - {"09-11-01"}, - {"-11-01"}, - {"2009-111-01"}, - {"2009--01"}, - {"2009-13-01"}, - {"2009-11-011"}, - {"2009-11-"}, - {"2009-11-00"}, - {"2009-11-33"}, - {"--"}, - {""}, - {null}, - {"-"}, - {"2009"}, - {"2009-01"}, - {"---"}, - {"2009-13--1"}, - {"1900-1-0"}, - {"2009-01-01 10:50:01"}, - {"1996-12-10 12:26:19.1"}, - {"10:50:01"} - }; + private Stream invalidDateValues() { + return Stream.of( + "20009-11-01", + "09-11-01", + "-11-01", + "2009-111-01", + "2009--01", + "2009-13-01", + "2009-11-011", + "2009-11-", + "2009-11-00", + "2009-11-33", + "--", + "", + null, + "-", + "2009", + "2009-01", + "---", + "2009-13--1", + "1900-1-0", + "2009-01-01 10:50:01", + "1996-12-10 12:26:19.1", + "10:50:01" + ); } /* @@ -360,14 +364,12 @@ public class DateTests extends BaseTest { * to validate that an IllegalArgumentException will not be thrown from the * valueOf method and the corect value from toString() is returned */ - @DataProvider(name = "validDateValues") - private Object[][] validDateValues() { - return new Object[][]{ - {"2009-08-30", "2009-08-30"}, - {"2009-01-8", "2009-01-08"}, - {"2009-1-01", "2009-01-01"}, - {"2009-1-1", "2009-01-01"} - - }; + private Stream validDateValues() { + return Stream.of( + Arguments.of("2009-08-30", "2009-08-30"), + Arguments.of("2009-01-8", "2009-01-08"), + Arguments.of("2009-1-01", "2009-01-01"), + Arguments.of("2009-1-1", "2009-01-01") + ); } } diff --git a/test/jdk/java/sql/testng/test/sql/DriverManagerTests.java b/test/jdk/java/sql/test/sql/DriverManagerTests.java similarity index 84% rename from test/jdk/java/sql/testng/test/sql/DriverManagerTests.java rename to test/jdk/java/sql/test/sql/DriverManagerTests.java index 6b6e8386835..3797b625d21 100644 --- a/test/jdk/java/sql/testng/test/sql/DriverManagerTests.java +++ b/test/jdk/java/sql/test/sql/DriverManagerTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.io.BufferedReader; import java.io.ByteArrayInputStream; @@ -39,12 +39,10 @@ import java.util.Collections; import java.util.Properties; import java.util.stream.Collectors; -import static org.testng.Assert.*; -import org.testng.annotations.AfterClass; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import util.StubDriver; public class DriverManagerTests { @@ -58,23 +56,11 @@ public class DriverManagerTests { public DriverManagerTests() { } - @BeforeClass - public static void setUpClass() throws Exception { - } - - @AfterClass - public static void tearDownClass() throws Exception { - } - - @BeforeMethod + @BeforeEach public void setUpMethod() throws Exception { removeAllDrivers(); } - @AfterMethod - public void tearDownMethod() throws Exception { - } - /** * Utility method to remove all registered drivers */ @@ -113,7 +99,7 @@ public class DriverManagerTests { int[] vals = {-1, 0, 5}; for (int val : vals) { DriverManager.setLoginTimeout(val); - assertEquals(val, DriverManager.getLoginTimeout()); + assertEquals(DriverManager.getLoginTimeout(), val); } } @@ -121,20 +107,22 @@ public class DriverManagerTests { * Validate that NullPointerException is thrown when null is passed to * registerDriver */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test1() throws Exception { Driver d = null; - DriverManager.registerDriver(d); + assertThrows(NullPointerException.class, + () -> DriverManager.registerDriver(d)); } /** * Validate that NullPointerException is thrown when null is passed to * registerDriver */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test2() throws Exception { Driver d = null; - DriverManager.registerDriver(d, null); + assertThrows(NullPointerException.class, () -> + DriverManager.registerDriver(d, null)); } /** @@ -150,68 +138,68 @@ public class DriverManagerTests { * Validate that SQLException is thrown when there is no Driver to service * the URL */ - @Test(expectedExceptions = SQLException.class) + @Test public void test4() throws Exception { - DriverManager.getConnection(InvalidURL); + assertThrows(SQLException.class, () -> DriverManager.getConnection(InvalidURL)); } /** * Validate that SQLException is thrown when there is no Driver to service * the URL */ - @Test(expectedExceptions = SQLException.class) + @Test public void test5() throws Exception { - DriverManager.getConnection(InvalidURL, new Properties()); + assertThrows(SQLException.class, () -> DriverManager.getConnection(InvalidURL, new Properties())); } /** * Validate that SQLException is thrown when there is no Driver to service * the URL */ - @Test(expectedExceptions = SQLException.class) + @Test public void test6() throws Exception { - DriverManager.getConnection(InvalidURL, "LuckyDog", "tennisanyone"); + assertThrows(SQLException.class, () -> DriverManager.getConnection(InvalidURL, "LuckyDog", "tennisanyone")); } /** * Validate that SQLException is thrown when null is passed for the URL */ - @Test(expectedExceptions = SQLException.class) + @Test public void test7() throws Exception { - DriverManager.getConnection(null); + assertThrows(SQLException.class, () -> DriverManager.getConnection(null)); } /** * Validate that SQLException is thrown when null is passed for the URL */ - @Test(expectedExceptions = SQLException.class) + @Test public void test8() throws Exception { - DriverManager.getConnection(null, new Properties()); + assertThrows(SQLException.class, () -> DriverManager.getConnection(null, new Properties())); } /** * Validate that SQLException is thrown when null is passed for the URL */ - @Test(expectedExceptions = SQLException.class) + @Test public void test9() throws Exception { - DriverManager.getConnection(null, "LuckyDog", "tennisanyone"); + assertThrows(SQLException.class, () -> DriverManager.getConnection(null, "LuckyDog", "tennisanyone")); } /** * Validate that SQLException is thrown when there is no Driver to service * the URL */ - @Test(expectedExceptions = SQLException.class) + @Test public void test10() throws Exception { - DriverManager.getDriver(InvalidURL); + assertThrows(SQLException.class, () -> DriverManager.getDriver(InvalidURL)); } /** * Validate that SQLException is thrown when null is passed for the URL */ - @Test(expectedExceptions = SQLException.class) + @Test public void test11() throws Exception { - DriverManager.getDriver(null); + assertThrows(SQLException.class, () -> DriverManager.getDriver(null)); } /** @@ -229,10 +217,10 @@ public class DriverManagerTests { * Validate that SQLException is thrown when the URL is not valid for any of * the registered drivers */ - @Test(expectedExceptions = SQLException.class) + @Test public void test13() throws Exception { DriverManager.registerDriver(new StubDriver()); - DriverManager.getDriver(InvalidURL); + assertThrows(SQLException.class, () -> DriverManager.getDriver(InvalidURL)); } /** @@ -370,9 +358,9 @@ public class DriverManagerTests { } Collection expectedDrivers = Collections.list(DriverManager.getDrivers()); - assertEquals(expectedDrivers.size(), n); + assertEquals(n, expectedDrivers.size()); Collection drivers = DriverManager.drivers().collect(Collectors.toList()); - assertEquals(drivers, expectedDrivers); + assertEquals(expectedDrivers, drivers); } } diff --git a/test/jdk/java/sql/test/sql/JavatimeTest.java b/test/jdk/java/sql/test/sql/JavatimeTest.java new file mode 100644 index 00000000000..acc0ac3e841 --- /dev/null +++ b/test/jdk/java/sql/test/sql/JavatimeTest.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2013, 2026, 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 sql; + +/* + * @test + * @bug 8007520 + * @summary Test those bridge methods to/from java.time date/time classes + * @key randomness + */ + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.FieldSource; + +import java.util.List; +import java.util.Random; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.stream.IntStream; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class JavatimeTest { + + private static final int NANOS_PER_SECOND = 1000000000; + private static final long t1970 = new java.util.Date(70, 0, 01).getTime(); + private static final Random R = new Random(); + // Data provider contains 10,000 randomized arguments + // which are used as the dates and times for the tests + private static final List DATE_TIME_ARGS = IntStream.range(0, 10_000) + .mapToObj(i -> { + int days = R.nextInt(50) * 365 + R.nextInt(365); + long secs = t1970 + days * 86400 + R.nextInt(86400); + int nanos = R.nextInt(NANOS_PER_SECOND); + int nanos_ms = nanos / 1000000 * 1000000; // millis precision + long millis = secs * 1000 + R.nextInt(1000); + LocalDateTime ldt = LocalDateTime.ofEpochSecond(secs, nanos, ZoneOffset.UTC); + return Arguments.of(millis, nanos, ldt, secs, nanos_ms); + }).toList(); + + @ParameterizedTest(autoCloseArguments = false) + @FieldSource("DATE_TIME_ARGS") + void timestampTest(long millis, int nanos, LocalDateTime ldt, long secs) { + Timestamp ta = new Timestamp(millis); + ta.setNanos(nanos); + assertTrue(isEqual(ta.toLocalDateTime(), ta), + errMsg("j.s.ts -> ldt", millis, nanos, ldt, results(ta.toLocalDateTime(), ta))); + + assertTrue(isEqual(ldt, Timestamp.valueOf(ldt)), + errMsg("ldt -> j.s.ts", millis, nanos, ldt, results(ldt, Timestamp.valueOf(ldt)))); + + Instant inst0 = ta.toInstant(); + assertAll(errMsg("j.s.ts -> instant -> j.s.ts", millis, nanos, ldt), + () -> assertEquals(ta.getTime(), inst0.toEpochMilli()), + () -> assertEquals(ta.getNanos(), inst0.getNano()), + () -> assertEquals(ta, Timestamp.from(inst0)) + ); + + Instant inst = Instant.ofEpochSecond(secs, nanos); + Timestamp ta0 = Timestamp.from(inst); + assertAll(errMsg("instant -> timestamp -> instant", millis, nanos, ldt), + () -> assertEquals(ta0.getTime(), inst.toEpochMilli()), + () -> assertEquals(ta0.getNanos(), inst.getNano()), + () -> assertEquals(inst, ta0.toInstant()) + ); + } + + @ParameterizedTest(autoCloseArguments = false) + @FieldSource("DATE_TIME_ARGS") + void sqlDateTest(long millis, int nanos, LocalDateTime ldt) { + // j.s.d/t uses j.u.d.equals() !!!!!!!! + java.sql.Date jsd = new java.sql.Date(millis); + assertTrue(isEqual(jsd.toLocalDate(), jsd), + errMsg("j.s.d -> ld", millis, nanos, ldt, results(jsd.toLocalDate(), jsd))); + + LocalDate ld = ldt.toLocalDate(); + assertTrue(isEqual(ld, java.sql.Date.valueOf(ld)), + errMsg("ld -> j.s.d", millis, nanos, ldt, results(ld, java.sql.Date.valueOf(ld)))); + } + + @ParameterizedTest(autoCloseArguments = false) + @FieldSource("DATE_TIME_ARGS") + void sqlTimeTest(long millis, int nanos, LocalDateTime ldt, long secs, int nanos_ms) { + java.sql.Time jst = new java.sql.Time(millis); + assertTrue(isEqual(jst.toLocalTime(), jst), + errMsg("j.s.t -> lt", millis, nanos, ldt, results(jst.toLocalTime(), jst))); + + // millis precision + LocalDateTime ldt_ms = LocalDateTime.ofEpochSecond(secs, nanos_ms, ZoneOffset.UTC); + LocalTime lt = ldt_ms.toLocalTime(); + assertTrue(isEqual(lt, java.sql.Time.valueOf(lt)), + errMsg("lt -> j.s.t", millis, nanos, ldt, results(lt, java.sql.Time.valueOf(lt)))); + } + + private static boolean isEqual(LocalDateTime ldt, Timestamp ts) { + ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault()); + return zdt.getYear() == ts.getYear() + 1900 && + zdt.getMonthValue() == ts.getMonth() + 1 && + zdt.getDayOfMonth() == ts.getDate() && + zdt.getHour() == ts.getHours() && + zdt.getMinute() == ts.getMinutes() && + zdt.getSecond() == ts.getSeconds() && + zdt.getNano() == ts.getNanos(); + } + + private static String results(LocalDateTime ldt, Timestamp ts) { + ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault()); + return "ldt:ts %d/%d, %d/%d, %d/%d, %d/%d, %d/%d, %d/%d, nano:[%d/%d]%n".formatted( + zdt.getYear(), ts.getYear() + 1900, + zdt.getMonthValue(), ts.getMonth() + 1, + zdt.getDayOfMonth(), ts.getDate(), + zdt.getHour(), ts.getHours(), + zdt.getMinute(), ts.getMinutes(), + zdt.getSecond(), ts.getSeconds(), + zdt.getNano(), ts.getNanos()); + } + + private static boolean isEqual(LocalDate ld, java.sql.Date d) { + return ld.getYear() == d.getYear() + 1900 && + ld.getMonthValue() == d.getMonth() + 1 && + ld.getDayOfMonth() == d.getDate(); + } + + private static String results(LocalDate ld, java.sql.Date d) { + return "%d/%d, %d/%d, %d/%d%n".formatted( + ld.getYear(), d.getYear() + 1900, + ld.getMonthValue(), d.getMonth() + 1, + ld.getDayOfMonth(), d.getDate()); + } + + private static boolean isEqual(LocalTime lt, java.sql.Time t) { + return lt.getHour() == t.getHours() && + lt.getMinute() == t.getMinutes() && + lt.getSecond() == t.getSeconds(); + } + + private static String results(LocalTime lt, java.sql.Time t) { + return "%d/%d, %d/%d, %d/%d%n".formatted( + lt.getHour(), t.getHours(), + lt.getMinute(), t.getMinutes(), + lt.getSecond(), t.getSeconds()); + } + + private static String errMsg(String testCase, long millis, int nanos, + LocalDateTime ldt, String results) { + return "FAILED: %s%n INPUTS: ms: %16d ns: %10d ldt:[%s]%n ACTUAL: %s" + .formatted(testCase, millis, nanos, ldt, results); + } + + private static String errMsg(String testCase, long millis, int nanos, + LocalDateTime ldt) { + return "FAILED: %s%n INPUTS: ms: %16d ns: %10d ldt:[%s]%n" + .formatted(testCase, millis, nanos, ldt); + } +} \ No newline at end of file diff --git a/test/jdk/java/sql/testng/test/sql/PreparedStatementTests.java b/test/jdk/java/sql/test/sql/PreparedStatementTests.java similarity index 62% rename from test/jdk/java/sql/testng/test/sql/PreparedStatementTests.java rename to test/jdk/java/sql/test/sql/PreparedStatementTests.java index 7813038361d..574b0369b4e 100644 --- a/test/jdk/java/sql/testng/test/sql/PreparedStatementTests.java +++ b/test/jdk/java/sql/test/sql/PreparedStatementTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,29 +20,34 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import org.junit.jupiter.params.provider.ValueSource; import util.BaseTest; import util.StubConnection; import java.sql.PreparedStatement; import java.sql.SQLException; -import static org.testng.Assert.assertEquals; +import org.junit.jupiter.api.AfterEach; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class PreparedStatementTests extends BaseTest { private PreparedStatement pstmt; - @BeforeMethod + @BeforeEach public void setUpMethod() throws Exception { pstmt = new StubConnection().prepareStatement("Select * from foo were bar = ?"); } - @AfterMethod + @AfterEach public void tearDownMethod() throws Exception { pstmt.close(); } @@ -51,80 +56,84 @@ public class PreparedStatementTests extends BaseTest { * Verify that enquoteLiteral creates a valid literal and converts every * single quote to two single quotes */ - @Test(dataProvider = "validEnquotedLiteralValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validEnquotedLiteralValues") public void test00(String s, String expected) throws SQLException { - assertEquals(pstmt.enquoteLiteral(s), expected); + assertEquals(expected, pstmt.enquoteLiteral(s)); } /* * Validate a NullPointerException is thrown if the string passed to * enquoteLiteral is null */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test01() throws SQLException { - pstmt.enquoteLiteral(null); + assertThrows(NullPointerException.class, () -> pstmt.enquoteLiteral(null)); } /* * Validate that enquoteIdentifier returns the expected value */ - @Test(dataProvider = "validIdentifierValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validEnquotedIdentifierValues") public void test02(String s, boolean alwaysQuote, String expected) throws SQLException { - assertEquals(pstmt.enquoteIdentifier(s, alwaysQuote), expected); + assertEquals(expected, pstmt.enquoteIdentifier(s, alwaysQuote)); } /* * Validate that a SQLException is thrown for values that are not valid * for a SQL identifier */ - @Test(dataProvider = "invalidIdentifierValues", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidEnquotedIdentifierValues") public void test03(String s, boolean alwaysQuote) throws SQLException { - pstmt.enquoteIdentifier(s, alwaysQuote); + assertThrows(SQLException.class, () -> pstmt.enquoteIdentifier(s, alwaysQuote)); } /* * Validate a NullPointerException is thrown is the string passed to * enquoteIdentiifer is null */ - @Test(dataProvider = "trueFalse", - expectedExceptions = NullPointerException.class) + @ParameterizedTest(autoCloseArguments = false) + @ValueSource(booleans = {true, false}) public void test04(boolean alwaysQuote) throws SQLException { - pstmt.enquoteIdentifier(null, alwaysQuote); + assertThrows(NullPointerException.class, () -> pstmt.enquoteIdentifier(null, alwaysQuote)); } /* * Validate that isSimpleIdentifier returns the expected value */ - @Test(dataProvider = "simpleIdentifierValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("simpleIdentifierValues") public void test05(String s, boolean expected) throws SQLException { - assertEquals(pstmt.isSimpleIdentifier(s), expected); + assertEquals(expected, pstmt.isSimpleIdentifier(s)); } /* * Validate a NullPointerException is thrown if the string passed to * isSimpleIdentifier is null */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test06() throws SQLException { - pstmt.isSimpleIdentifier(null); + assertThrows(NullPointerException.class, () -> pstmt.isSimpleIdentifier(null)); } /* * Verify that enquoteLiteral creates a valid literal and converts every * single quote to two single quotes */ - @Test(dataProvider = "validEnquotedNCharLiteralValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validEnquotedNCharLiteralValues") public void test07(String s, String expected) throws SQLException { - assertEquals(pstmt.enquoteNCharLiteral(s), expected); + assertEquals(expected, pstmt.enquoteNCharLiteral(s)); } /* * Validate a NullPointerException is thrown if the string passed to * enquoteNCharLiteral is null */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test08() throws SQLException { - pstmt.enquoteNCharLiteral(null); + assertThrows(NullPointerException.class, () -> pstmt.enquoteNCharLiteral(null)); } } diff --git a/test/jdk/java/sql/testng/test/sql/SQLClientInfoExceptionTests.java b/test/jdk/java/sql/test/sql/SQLClientInfoExceptionTests.java similarity index 97% rename from test/jdk/java/sql/testng/test/sql/SQLClientInfoExceptionTests.java rename to test/jdk/java/sql/test/sql/SQLClientInfoExceptionTests.java index 84230b86758..bea35d95c1c 100644 --- a/test/jdk/java/sql/testng/test/sql/SQLClientInfoExceptionTests.java +++ b/test/jdk/java/sql/test/sql/SQLClientInfoExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,14 +20,16 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.ClientInfoStatus; import java.sql.SQLClientInfoException; import java.sql.SQLException; import java.util.HashMap; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SQLClientInfoExceptionTests extends BaseTest { diff --git a/test/jdk/java/sql/testng/test/sql/SQLDataExceptionTests.java b/test/jdk/java/sql/test/sql/SQLDataExceptionTests.java similarity index 97% rename from test/jdk/java/sql/testng/test/sql/SQLDataExceptionTests.java rename to test/jdk/java/sql/test/sql/SQLDataExceptionTests.java index 8a5f8d1a2c1..a18f6406e66 100644 --- a/test/jdk/java/sql/testng/test/sql/SQLDataExceptionTests.java +++ b/test/jdk/java/sql/test/sql/SQLDataExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,13 +20,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.SQLDataException; import java.sql.SQLException; import java.sql.SQLNonTransientException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SQLDataExceptionTests extends BaseTest { diff --git a/test/jdk/java/sql/testng/test/sql/SQLExceptionTests.java b/test/jdk/java/sql/test/sql/SQLExceptionTests.java similarity index 97% rename from test/jdk/java/sql/testng/test/sql/SQLExceptionTests.java rename to test/jdk/java/sql/test/sql/SQLExceptionTests.java index e3643ef119c..8a7850d8fd9 100644 --- a/test/jdk/java/sql/testng/test/sql/SQLExceptionTests.java +++ b/test/jdk/java/sql/test/sql/SQLExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,11 +20,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.SQLException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SQLExceptionTests extends BaseTest { diff --git a/test/jdk/java/sql/testng/test/sql/SQLFeatureNotSupportedExceptionTests.java b/test/jdk/java/sql/test/sql/SQLFeatureNotSupportedExceptionTests.java similarity index 97% rename from test/jdk/java/sql/testng/test/sql/SQLFeatureNotSupportedExceptionTests.java rename to test/jdk/java/sql/test/sql/SQLFeatureNotSupportedExceptionTests.java index 5b95894412c..24049addfa1 100644 --- a/test/jdk/java/sql/testng/test/sql/SQLFeatureNotSupportedExceptionTests.java +++ b/test/jdk/java/sql/test/sql/SQLFeatureNotSupportedExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,13 +20,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.sql.SQLNonTransientException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SQLFeatureNotSupportedExceptionTests extends BaseTest { diff --git a/test/jdk/java/sql/testng/test/sql/SQLIntegrityConstraintViolationExceptionTests.java b/test/jdk/java/sql/test/sql/SQLIntegrityConstraintViolationExceptionTests.java similarity index 97% rename from test/jdk/java/sql/testng/test/sql/SQLIntegrityConstraintViolationExceptionTests.java rename to test/jdk/java/sql/test/sql/SQLIntegrityConstraintViolationExceptionTests.java index 082e0af15c8..c8c0958e3f3 100644 --- a/test/jdk/java/sql/testng/test/sql/SQLIntegrityConstraintViolationExceptionTests.java +++ b/test/jdk/java/sql/test/sql/SQLIntegrityConstraintViolationExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,13 +20,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.SQLException; import java.sql.SQLIntegrityConstraintViolationException; import java.sql.SQLNonTransientException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SQLIntegrityConstraintViolationExceptionTests extends BaseTest { diff --git a/test/jdk/java/sql/testng/test/sql/SQLInvalidAuthorizationSpecExceptionTests.java b/test/jdk/java/sql/test/sql/SQLInvalidAuthorizationSpecExceptionTests.java similarity index 97% rename from test/jdk/java/sql/testng/test/sql/SQLInvalidAuthorizationSpecExceptionTests.java rename to test/jdk/java/sql/test/sql/SQLInvalidAuthorizationSpecExceptionTests.java index 6e4eaa567ee..82a9a345a0e 100644 --- a/test/jdk/java/sql/testng/test/sql/SQLInvalidAuthorizationSpecExceptionTests.java +++ b/test/jdk/java/sql/test/sql/SQLInvalidAuthorizationSpecExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,13 +20,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.SQLException; import java.sql.SQLInvalidAuthorizationSpecException; import java.sql.SQLNonTransientException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SQLInvalidAuthorizationSpecExceptionTests extends BaseTest { diff --git a/test/jdk/java/sql/testng/test/sql/SQLNonTransientConnectionExceptionTests.java b/test/jdk/java/sql/test/sql/SQLNonTransientConnectionExceptionTests.java similarity index 97% rename from test/jdk/java/sql/testng/test/sql/SQLNonTransientConnectionExceptionTests.java rename to test/jdk/java/sql/test/sql/SQLNonTransientConnectionExceptionTests.java index dbd8b685844..fa4c75ed672 100644 --- a/test/jdk/java/sql/testng/test/sql/SQLNonTransientConnectionExceptionTests.java +++ b/test/jdk/java/sql/test/sql/SQLNonTransientConnectionExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,13 +20,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.SQLException; import java.sql.SQLNonTransientConnectionException; import java.sql.SQLNonTransientException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SQLNonTransientConnectionExceptionTests extends BaseTest { diff --git a/test/jdk/java/sql/testng/test/sql/SQLNonTransientExceptionTests.java b/test/jdk/java/sql/test/sql/SQLNonTransientExceptionTests.java similarity index 97% rename from test/jdk/java/sql/testng/test/sql/SQLNonTransientExceptionTests.java rename to test/jdk/java/sql/test/sql/SQLNonTransientExceptionTests.java index 061ffe20840..0f37f905fa7 100644 --- a/test/jdk/java/sql/testng/test/sql/SQLNonTransientExceptionTests.java +++ b/test/jdk/java/sql/test/sql/SQLNonTransientExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,12 +20,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.SQLException; import java.sql.SQLNonTransientException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SQLNonTransientExceptionTests extends BaseTest { diff --git a/test/jdk/java/sql/testng/test/sql/SQLRecoverableExceptionTests.java b/test/jdk/java/sql/test/sql/SQLRecoverableExceptionTests.java similarity index 97% rename from test/jdk/java/sql/testng/test/sql/SQLRecoverableExceptionTests.java rename to test/jdk/java/sql/test/sql/SQLRecoverableExceptionTests.java index d23a131dbcd..d447e08593c 100644 --- a/test/jdk/java/sql/testng/test/sql/SQLRecoverableExceptionTests.java +++ b/test/jdk/java/sql/test/sql/SQLRecoverableExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,12 +20,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.SQLException; import java.sql.SQLRecoverableException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SQLRecoverableExceptionTests extends BaseTest { diff --git a/test/jdk/java/sql/testng/test/sql/SQLSyntaxErrorExceptionTests.java b/test/jdk/java/sql/test/sql/SQLSyntaxErrorExceptionTests.java similarity index 97% rename from test/jdk/java/sql/testng/test/sql/SQLSyntaxErrorExceptionTests.java rename to test/jdk/java/sql/test/sql/SQLSyntaxErrorExceptionTests.java index 863213cfcb8..c859f5aa0d2 100644 --- a/test/jdk/java/sql/testng/test/sql/SQLSyntaxErrorExceptionTests.java +++ b/test/jdk/java/sql/test/sql/SQLSyntaxErrorExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,13 +20,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.SQLException; import java.sql.SQLNonTransientException; import java.sql.SQLSyntaxErrorException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SQLSyntaxErrorExceptionTests extends BaseTest { diff --git a/test/jdk/java/sql/testng/test/sql/SQLTimeoutExceptionTests.java b/test/jdk/java/sql/test/sql/SQLTimeoutExceptionTests.java similarity index 97% rename from test/jdk/java/sql/testng/test/sql/SQLTimeoutExceptionTests.java rename to test/jdk/java/sql/test/sql/SQLTimeoutExceptionTests.java index dfe341545e4..a4e249658d9 100644 --- a/test/jdk/java/sql/testng/test/sql/SQLTimeoutExceptionTests.java +++ b/test/jdk/java/sql/test/sql/SQLTimeoutExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,13 +20,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.SQLException; import java.sql.SQLTimeoutException; import java.sql.SQLTransientException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SQLTimeoutExceptionTests extends BaseTest { diff --git a/test/jdk/java/sql/testng/test/sql/SQLTransactionRollbackExceptionTests.java b/test/jdk/java/sql/test/sql/SQLTransactionRollbackExceptionTests.java similarity index 97% rename from test/jdk/java/sql/testng/test/sql/SQLTransactionRollbackExceptionTests.java rename to test/jdk/java/sql/test/sql/SQLTransactionRollbackExceptionTests.java index 8453ebe1364..7a7d94cd060 100644 --- a/test/jdk/java/sql/testng/test/sql/SQLTransactionRollbackExceptionTests.java +++ b/test/jdk/java/sql/test/sql/SQLTransactionRollbackExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,13 +20,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.SQLException; import java.sql.SQLTransactionRollbackException; import java.sql.SQLTransientException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SQLTransactionRollbackExceptionTests extends BaseTest { diff --git a/test/jdk/java/sql/testng/test/sql/SQLTransientConnectionExceptionTests.java b/test/jdk/java/sql/test/sql/SQLTransientConnectionExceptionTests.java similarity index 97% rename from test/jdk/java/sql/testng/test/sql/SQLTransientConnectionExceptionTests.java rename to test/jdk/java/sql/test/sql/SQLTransientConnectionExceptionTests.java index 7999253b1fa..8ac6ef98222 100644 --- a/test/jdk/java/sql/testng/test/sql/SQLTransientConnectionExceptionTests.java +++ b/test/jdk/java/sql/test/sql/SQLTransientConnectionExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,13 +20,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.SQLException; import java.sql.SQLTransientConnectionException; import java.sql.SQLTransientException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SQLTransientConnectionExceptionTests extends BaseTest { diff --git a/test/jdk/java/sql/testng/test/sql/SQLTransientExceptionTests.java b/test/jdk/java/sql/test/sql/SQLTransientExceptionTests.java similarity index 97% rename from test/jdk/java/sql/testng/test/sql/SQLTransientExceptionTests.java rename to test/jdk/java/sql/test/sql/SQLTransientExceptionTests.java index d86f86b8fc6..4c43b6c693e 100644 --- a/test/jdk/java/sql/testng/test/sql/SQLTransientExceptionTests.java +++ b/test/jdk/java/sql/test/sql/SQLTransientExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,12 +20,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.SQLException; import java.sql.SQLTransientException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SQLTransientExceptionTests extends BaseTest { diff --git a/test/jdk/java/sql/testng/test/sql/SQLWarningTests.java b/test/jdk/java/sql/test/sql/SQLWarningTests.java similarity index 97% rename from test/jdk/java/sql/testng/test/sql/SQLWarningTests.java rename to test/jdk/java/sql/test/sql/SQLWarningTests.java index 2856742dc5c..ab15a877dbd 100644 --- a/test/jdk/java/sql/testng/test/sql/SQLWarningTests.java +++ b/test/jdk/java/sql/test/sql/SQLWarningTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,12 +20,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.SQLException; import java.sql.SQLWarning; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SQLWarningTests extends BaseTest { diff --git a/test/jdk/java/sql/testng/test/sql/StatementTests.java b/test/jdk/java/sql/test/sql/StatementTests.java similarity index 62% rename from test/jdk/java/sql/testng/test/sql/StatementTests.java rename to test/jdk/java/sql/test/sql/StatementTests.java index f2bfe712eb5..42e971cc971 100644 --- a/test/jdk/java/sql/testng/test/sql/StatementTests.java +++ b/test/jdk/java/sql/test/sql/StatementTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,14 +20,21 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.SQLException; import java.sql.Statement; -import static org.testng.Assert.assertEquals; +import org.junit.jupiter.api.AfterEach; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; -import org.testng.annotations.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import org.junit.jupiter.params.provider.ValueSource; import util.BaseTest; import util.StubConnection; @@ -35,12 +42,12 @@ public class StatementTests extends BaseTest { private Statement stmt; - @BeforeMethod + @BeforeEach public void setUpMethod() throws Exception { stmt = new StubConnection().createStatement(); } - @AfterMethod + @AfterEach public void tearDownMethod() throws Exception { stmt.close(); } @@ -48,80 +55,84 @@ public class StatementTests extends BaseTest { * Verify that enquoteLiteral creates a valid literal and converts every * single quote to two single quotes */ - @Test(dataProvider = "validEnquotedLiteralValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validEnquotedLiteralValues") public void test00(String s, String expected) throws SQLException { - assertEquals(stmt.enquoteLiteral(s), expected); + assertEquals(expected, stmt.enquoteLiteral(s)); } /* * Validate a NullPointerException is thrown if the string passed to * enquoteLiteral is null */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test01() throws SQLException { - stmt.enquoteLiteral(null); + assertThrows(NullPointerException.class, () -> stmt.enquoteLiteral(null)); } /* * Validate that enquoteIdentifier returns the expected value */ - @Test(dataProvider = "validIdentifierValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validEnquotedIdentifierValues") public void test02(String s, boolean alwaysQuote, String expected) throws SQLException { - assertEquals(stmt.enquoteIdentifier(s, alwaysQuote), expected); + assertEquals(expected, stmt.enquoteIdentifier(s, alwaysQuote)); } /* * Validate that a SQLException is thrown for values that are not valid * for a SQL identifier */ - @Test(dataProvider = "invalidIdentifierValues", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidEnquotedIdentifierValues") public void test03(String s, boolean alwaysQuote) throws SQLException { - stmt.enquoteIdentifier(s, alwaysQuote); + assertThrows(SQLException.class, () -> stmt.enquoteIdentifier(s, alwaysQuote)); } /* * Validate a NullPointerException is thrown is the string passed to * enquoteIdentiifer is null */ - @Test(dataProvider = "trueFalse", - expectedExceptions = NullPointerException.class) + @ParameterizedTest(autoCloseArguments = false) + @ValueSource(booleans = {true, false}) public void test04(boolean alwaysQuote) throws SQLException { - stmt.enquoteIdentifier(null, alwaysQuote); + assertThrows(NullPointerException.class, () -> stmt.enquoteIdentifier(null, alwaysQuote)); } /* * Validate that isSimpleIdentifier returns the expected value */ - @Test(dataProvider = "simpleIdentifierValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("simpleIdentifierValues") public void test05(String s, boolean expected) throws SQLException { - assertEquals(stmt.isSimpleIdentifier(s), expected); + assertEquals(expected, stmt.isSimpleIdentifier(s)); } /* * Validate a NullPointerException is thrown if the string passed to * isSimpleIdentifier is null */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test06() throws SQLException { - stmt.isSimpleIdentifier(null); + assertThrows(NullPointerException.class, () -> stmt.isSimpleIdentifier(null)); } /* * Verify that enquoteLiteral creates a valid literal and converts every * single quote to two single quotes */ - @Test(dataProvider = "validEnquotedNCharLiteralValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validEnquotedNCharLiteralValues") public void test07(String s, String expected) throws SQLException { - assertEquals(stmt.enquoteNCharLiteral(s), expected); + assertEquals(expected, stmt.enquoteNCharLiteral(s)); } /* * Validate a NullPointerException is thrown if the string passed to * enquoteNCharLiteral is null */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test08() throws SQLException { - stmt.enquoteNCharLiteral(null); + assertThrows(NullPointerException.class, () -> stmt.enquoteNCharLiteral(null)); } } diff --git a/test/jdk/java/sql/testng/test/sql/TimeTests.java b/test/jdk/java/sql/test/sql/TimeTests.java similarity index 76% rename from test/jdk/java/sql/testng/test/sql/TimeTests.java rename to test/jdk/java/sql/test/sql/TimeTests.java index 7b99679754b..71208f03222 100644 --- a/test/jdk/java/sql/testng/test/sql/TimeTests.java +++ b/test/jdk/java/sql/test/sql/TimeTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,13 +20,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.Time; import java.time.LocalTime; -import static org.testng.Assert.*; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + import util.BaseTest; public class TimeTests extends BaseTest { @@ -34,73 +39,73 @@ public class TimeTests extends BaseTest { /* * Validate an IllegalArgumentException is thrown for calling getYear */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test01() { Time t = Time.valueOf("08:30:59"); - t.getYear(); + assertThrows(IllegalArgumentException.class, t::getYear); } /* * Validate an IllegalArgumentException is thrown for calling getMonth */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test02() { Time t = Time.valueOf("08:30:59"); - t.getMonth(); + assertThrows(IllegalArgumentException.class, t::getMonth); } /* * Validate an IllegalArgumentException is thrown for calling getDay */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test03() { Time t = Time.valueOf("08:30:59"); - t.getDay(); + assertThrows(IllegalArgumentException.class, t::getDay); } /** * Validate an IllegalArgumentException is thrown for calling getDate */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test04() { Time t = Time.valueOf("08:30:59"); - t.getDate(); + assertThrows(IllegalArgumentException.class, t::getDate); } /* * Validate an IllegalArgumentException is thrown for calling setYear */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test05() { Time t = Time.valueOf("08:30:59"); - t.setYear(8); + assertThrows(IllegalArgumentException.class, () -> t.setYear(8)); } /* * Validate an IllegalArgumentException is thrown for calling setMonth */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test06() { Time t = Time.valueOf("08:30:59"); - t.setMonth(8); + assertThrows(IllegalArgumentException.class, () -> t.setMonth(8)); } /* * Validate an IllegalArgumentException is thrown for calling setDate */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test07() { Time t = Time.valueOf("08:30:59"); - t.setDate(30); + assertThrows(IllegalArgumentException.class, () -> t.setDate(30)); } /* * Validate an IllegalArgumentException is thrown for calling getDate */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test08() { Time t = Time.valueOf("08:30:59"); - t.getDate(); + assertThrows(IllegalArgumentException.class, t::getDate); } /* @@ -128,20 +133,20 @@ public class TimeTests extends BaseTest { /* * Validate an NPE occurs when a null LocalDate is passed to valueOf */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test11() throws Exception { LocalTime ld = null; - Time.valueOf(ld); + assertThrows(NullPointerException.class, () -> Time.valueOf(ld)); } /* * Validate an UnsupportedOperationException occurs when toInstant() is * called */ - @Test(expectedExceptions = UnsupportedOperationException.class) + @Test public void test12() throws Exception { Time t = new Time(System.currentTimeMillis()); - t.toInstant(); + assertThrows(UnsupportedOperationException.class, t::toInstant); } /* @@ -149,7 +154,8 @@ public class TimeTests extends BaseTest { * toString() of the other and that the correct value is returned from * toString() */ - @Test(dataProvider = "validTimeValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validTimeValues") public void test13(String time, String expected) { Time t1 = Time.valueOf(time); Time t2 = Time.valueOf(t1.toString()); @@ -182,10 +188,10 @@ public class TimeTests extends BaseTest { /* * Validate an IllegalArgumentException is thrown for an invalid Time string */ - @Test(dataProvider = "invalidTimeValues", - expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidTimeValues") public void test16(String time) throws Exception { - Time.valueOf(time); + assertThrows(IllegalArgumentException.class, () -> Time.valueOf(time)); } /* @@ -299,29 +305,28 @@ public class TimeTests extends BaseTest { * to validate that an IllegalArgumentException will be thrown from the * valueOf method */ - @DataProvider(name = "invalidTimeValues") - private Object[][] invalidTimeValues() { - return new Object[][]{ - {"2009-11-01 10:50:01"}, - {"1961-08-30 10:50:01.1"}, - {"1961-08-30"}, - {"00:00:00."}, - {"10:50:0.1"}, - {":00:00"}, - {"00::00"}, - {"00:00:"}, - {"::"}, - {" : : "}, - {"0a:00:00"}, - {"00:bb:00"}, - {"00:01:cc"}, - {"08:10:Batman"}, - {"08:10:10:10"}, - {"08:10"}, - {"a:b:c"}, - {null}, - {"8:"} - }; + private Stream invalidTimeValues() { + return Stream.of( + "2009-11-01 10:50:01", + "1961-08-30 10:50:01.1", + "1961-08-30", + "00:00:00.", + "10:50:0.1", + ":00:00", + "00::00", + "00:00:", + "::", + " : : ", + "0a:00:00", + "00:bb:00", + "00:01:cc", + "08:10:Batman", + "08:10:10:10", + "08:10", + "a:b:c", + null, + "8:" + ); } /* @@ -330,19 +335,18 @@ public class TimeTests extends BaseTest { * valueOf method. It also contains the expected return value from * toString() */ - @DataProvider(name = "validTimeValues") - private Object[][] validTimeValues() { - return new Object[][]{ - {"10:50:01", "10:50:01"}, - {"01:1:1", "01:01:01"}, - {"01:01:1", "01:01:01"}, - {"1:01:1", "01:01:01"}, - {"2:02:02", "02:02:02"}, - {"2:02:2", "02:02:02"}, - {"10:50:1", "10:50:01"}, - {"00:00:00", "00:00:00"}, - {"08:30:59", "08:30:59"}, - {"9:0:1", "09:00:01"} - }; + private Stream validTimeValues() { + return Stream.of( + Arguments.of("10:50:01", "10:50:01"), + Arguments.of("01:1:1", "01:01:01"), + Arguments.of("01:01:1", "01:01:01"), + Arguments.of("1:01:1", "01:01:01"), + Arguments.of("2:02:02", "02:02:02"), + Arguments.of("2:02:2", "02:02:02"), + Arguments.of("10:50:1", "10:50:01"), + Arguments.of("00:00:00", "00:00:00"), + Arguments.of("08:30:59", "08:30:59"), + Arguments.of("9:0:1", "09:00:01") + ); } } diff --git a/test/jdk/java/sql/testng/test/sql/TimestampTests.java b/test/jdk/java/sql/test/sql/TimestampTests.java similarity index 73% rename from test/jdk/java/sql/testng/test/sql/TimestampTests.java rename to test/jdk/java/sql/test/sql/TimestampTests.java index 6baea9fa26f..33a58c8d857 100644 --- a/test/jdk/java/sql/testng/test/sql/TimestampTests.java +++ b/test/jdk/java/sql/test/sql/TimestampTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql; +package sql; import java.sql.Date; import java.sql.Time; @@ -30,11 +30,16 @@ import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Calendar; import java.util.TimeZone; -import static org.testng.Assert.*; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import java.util.stream.Stream; + +import org.junit.jupiter.api.AfterAll; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + import util.BaseTest; public class TimestampTests extends BaseTest { @@ -45,7 +50,7 @@ public class TimestampTests extends BaseTest { * Need to set and use a custom TimeZone which does not * observe daylight savings time for this test. */ - @BeforeClass + @BeforeAll public static void setUpClass() throws Exception { defaultTimeZone = TimeZone.getDefault(); TimeZone tzone = TimeZone.getTimeZone("GMT+01"); @@ -56,7 +61,7 @@ public class TimestampTests extends BaseTest { /* * Conservatively reset the default time zone after test. */ - @AfterClass + @AfterAll public static void tearDownClass() throws Exception { TimeZone.setDefault(defaultTimeZone); } @@ -64,10 +69,10 @@ public class TimestampTests extends BaseTest { /* * Validate an IllegalArgumentException is thrown for an invalid Timestamp */ - @Test(dataProvider = "invalidTimestampValues", - expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidTimestampValues") public void test(String ts) throws Exception { - Timestamp.valueOf(ts); + assertThrows(IllegalArgumentException.class, () -> Timestamp.valueOf(ts)); } /* @@ -80,7 +85,7 @@ public class TimestampTests extends BaseTest { String ExpectedTS = "2009-01-01 10:50:0"; Timestamp ts = Timestamp.valueOf(testTS); Timestamp ts2 = Timestamp.valueOf(ExpectedTS); - assertEquals(ts, ts2, "Error ts1 != ts2"); + assertEquals(ts2, ts, "Error ts1 != ts2"); } /* @@ -91,7 +96,7 @@ public class TimestampTests extends BaseTest { String testTS = "2009-01-01 10:50:0"; Timestamp ts = Timestamp.valueOf(testTS); Timestamp ts2 = Timestamp.valueOf(testTS); - assertEquals(ts, ts2, "Error ts1 != ts2"); + assertEquals(ts2, ts, "Error ts1 != ts2"); } /* @@ -104,7 +109,7 @@ public class TimestampTests extends BaseTest { String ExpectedTS = "2009-01-01 10:50:0"; Timestamp ts = Timestamp.valueOf(testTS); Timestamp ts2 = Timestamp.valueOf(ExpectedTS); - assertEquals(ts, ts2, "Error ts1 != ts2"); + assertEquals(ts2, ts, "Error ts1 != ts2"); } /* @@ -117,7 +122,7 @@ public class TimestampTests extends BaseTest { String ExpectedTS = "2009-01-01 10:50:0"; Timestamp ts = Timestamp.valueOf(testTS); Timestamp ts2 = Timestamp.valueOf(ExpectedTS); - assertEquals(ts, ts2, "Error ts1 != ts2"); + assertEquals(ts2, ts, "Error ts1 != ts2"); } /* @@ -130,7 +135,7 @@ public class TimestampTests extends BaseTest { String ExpectedTS = "2009-01-01 10:50:0"; Timestamp ts = Timestamp.valueOf(testTS); Timestamp ts2 = Timestamp.valueOf(ExpectedTS); - assertEquals(ts, ts2, "Error ts1 != ts2"); + assertEquals(ts2, ts, "Error ts1 != ts2"); } /* @@ -142,7 +147,7 @@ public class TimestampTests extends BaseTest { String ExpectedTS = "2005-01-01 10:20:50.00"; Timestamp ts = Timestamp.valueOf(testTS); Timestamp ts2 = Timestamp.valueOf(ExpectedTS); - assertEquals(ts, ts2, "Error ts1 != ts2"); + assertEquals(ts2, ts, "Error ts1 != ts2"); } /* @@ -219,7 +224,8 @@ public class TimestampTests extends BaseTest { * Validate that two Timestamps are equal when one is created from the * toString() of the other */ - @Test(dataProvider = "validTimestampValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validTimestampValues") public void test13(String ts, String expectedTS) { Timestamp ts1 = Timestamp.valueOf(ts); Timestamp ts2 = Timestamp.valueOf(ts1.toString()); @@ -263,10 +269,10 @@ public class TimestampTests extends BaseTest { * Validate that a NullPointerException is thrown if a null is passed to * the before method */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test17() throws Exception { Timestamp ts1 = Timestamp.valueOf("1996-12-13 14:15:25.745634"); - ts1.before(null); + assertThrows(NullPointerException.class, () -> ts1.before(null)); } /* @@ -316,10 +322,10 @@ public class TimestampTests extends BaseTest { * Validate that a NullPointerException is thrown if a null is passed to the * after method */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test22() throws Exception { Timestamp ts1 = Timestamp.valueOf("1966-08-30 08:08:08"); - ts1.after(null); + assertThrows(NullPointerException.class, () -> ts1.after(null)); } /* @@ -476,21 +482,21 @@ public class TimestampTests extends BaseTest { /* * Validate an IllegalArgumentException is thrown for an invalid nanos value */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test38() throws Exception { Timestamp ts1 = Timestamp.valueOf("1961-08-30 00:00:00"); - ts1.setNanos(-1); + assertThrows(IllegalArgumentException.class, () -> ts1.setNanos(-1)); } /* * Validate an IllegalArgumentException is thrown for an invalid nanos value */ - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test39() throws Exception { int nanos = 999999999; Timestamp ts1 = Timestamp.valueOf("1961-08-30 00:00:00"); - ts1.setNanos(nanos + 1); + assertThrows(IllegalArgumentException.class, () -> ts1.setNanos(nanos + 1)); } /* @@ -541,10 +547,10 @@ public class TimestampTests extends BaseTest { /* * Validate an NPE occurs when a null LocalDateTime is passed to valueOF */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test44() throws Exception { LocalDateTime ldt = null; - Timestamp.valueOf(ldt); + assertThrows(NullPointerException.class, () -> Timestamp.valueOf(ldt)); } /* @@ -572,10 +578,10 @@ public class TimestampTests extends BaseTest { /* * Validate an NPE occurs when a null instant is passed to from */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test47() throws Exception { Instant instant = null; - Timestamp.from(instant); + assertThrows(NullPointerException.class, () -> Timestamp.from(instant)); } // Added SQE tests @@ -628,7 +634,8 @@ public class TimestampTests extends BaseTest { * Validate that two Timestamps are equal when one is created from the * toString() of the other */ - @Test(dataProvider = "validateNanos") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validateNanos") public void test51(String ts, int nanos) { Timestamp ts1 = Timestamp.valueOf(ts); Timestamp ts2 = Timestamp.valueOf(ts1.toString()); @@ -636,35 +643,36 @@ public class TimestampTests extends BaseTest { "Error with Nanos"); } - @Test(dataProvider = "validTimestampLongValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validTimestampLongValues") public void test52(long value, String ts) { Timestamp ts1 = new Timestamp(value); - assertEquals(ts1.toString(), ts, "ts1.toString() != ts"); + assertEquals(ts, ts1.toString(), "ts1.toString() != ts"); } @Test public void test53() { // The latest Instant that can be converted to a Timestamp. Instant instant1 = Instant.ofEpochSecond(Long.MAX_VALUE / 1000, 999_999_999); - assertEquals(Timestamp.from(instant1).toInstant(), instant1); + assertEquals(instant1, Timestamp.from(instant1).toInstant()); // One nanosecond more, and converting it gets an overflow. Instant instant2 = instant1.plusNanos(1); - expectThrows(IllegalArgumentException.class, () -> Timestamp.from(instant2)); + assertThrows(IllegalArgumentException.class, () -> Timestamp.from(instant2)); // The earliest Instant that can be converted to a Timestamp. Instant instant3 = Instant.ofEpochSecond(Long.MIN_VALUE / 1000, 0); - assertEquals(Timestamp.from(instant3).toInstant(), instant3); + assertEquals(instant3, Timestamp.from(instant3).toInstant()); // One nanosecond less, and converting it gets an overflow. Instant instant4 = instant3.minusNanos(1); - expectThrows(IllegalArgumentException.class, () -> Timestamp.from(instant4)); + assertThrows(IllegalArgumentException.class, () -> Timestamp.from(instant4)); // The latest possible Instant will certainly overflow. - expectThrows(IllegalArgumentException.class, () -> Timestamp.from(Instant.MAX)); + assertThrows(IllegalArgumentException.class, () -> Timestamp.from(Instant.MAX)); // The earliest possible Instant will certainly overflow. - expectThrows(IllegalArgumentException.class, () -> Timestamp.from(Instant.MIN)); + assertThrows(IllegalArgumentException.class, () -> Timestamp.from(Instant.MIN)); } /* @@ -683,7 +691,7 @@ public class TimestampTests extends BaseTest { assertTrue(ts1.equals(ts2)); // As the Timestamp values, including the nanos are the same, the hashCode's // should be equal - assertEquals(ts1.hashCode(), ts2.hashCode()); + assertEquals(ts2.hashCode(), ts1.hashCode()); } /* @@ -702,7 +710,7 @@ public class TimestampTests extends BaseTest { assertTrue(ts2.equals(ts2)); assertFalse(ts1.equals(ts2)); // As the nanos differ, the hashCode values should differ - assertNotEquals(ts1.hashCode(), ts2.hashCode()); + assertNotEquals(ts2.hashCode(), ts1.hashCode()); } /* @@ -710,33 +718,32 @@ public class TimestampTests extends BaseTest { * to validate that an IllegalArgumentException will be thrown from the * valueOf method */ - @DataProvider(name = "invalidTimestampValues") - private Object[][] invalidTimestampValues() { - return new Object[][]{ - {"2009-11-01-01 10:50:01"}, - {"aaaa-11-01-01 10:50"}, - {"aaaa-11-01 10:50"}, - {"1961--30 00:00:00"}, - {"--30 00:00:00"}, - {"-- 00:00:00"}, - {"1961-1- 00:00:00"}, - {"2009-11-01"}, - {"10:50:01"}, - {"1961-a-30 00:00:00"}, - {"1961-01-bb 00:00:00"}, - {"1961-08-30 00:00:00."}, - {"1961-08-30 :00:00"}, - {"1961-08-30 00::00"}, - {"1961-08-30 00:00:"}, - {"1961-08-30 ::"}, - {"1961-08-30 0a:00:00"}, - {"1961-08-30 00:bb:00"}, - {"1961-08-30 00:01:cc"}, - {"1961-08-30 00:00:00.01a"}, - {"1961-08-30 00:00:00.a"}, - {"1996-12-10 12:26:19.1234567890"}, - {null} - }; + private Stream invalidTimestampValues() { + return Stream.of( + "2009-11-01-01 10:50:01", + "aaaa-11-01-01 10:50", + "aaaa-11-01 10:50", + "1961--30 00:00:00", + "--30 00:00:00", + "-- 00:00:00", + "1961-1- 00:00:00", + "2009-11-01", + "10:50:01", + "1961-a-30 00:00:00", + "1961-01-bb 00:00:00", + "1961-08-30 00:00:00.", + "1961-08-30 :00:00", + "1961-08-30 00::00", + "1961-08-30 00:00:", + "1961-08-30 ::", + "1961-08-30 0a:00:00", + "1961-08-30 00:bb:00", + "1961-08-30 00:01:cc", + "1961-08-30 00:00:00.01a", + "1961-08-30 00:00:00.a", + "1996-12-10 12:26:19.1234567890", + null + ); } /* @@ -744,67 +751,65 @@ public class TimestampTests extends BaseTest { * to validate that an IllegalArgumentException will not be thrown from the * valueOf method and the corect value from toString() is returned */ - @DataProvider(name = "validTimestampValues") - private Object[][] validTimestampValues() { - return new Object[][]{ - {"1961-08-30 00:00:00", "1961-08-30 00:00:00.0"}, - {"1961-08-30 11:22:33", "1961-08-30 11:22:33.0"}, - {"1961-8-30 00:00:00", "1961-08-30 00:00:00.0"}, - {"1966-08-1 00:00:00", "1966-08-01 00:00:00.0"}, - {"1996-12-10 12:26:19.1", "1996-12-10 12:26:19.1"}, - {"1996-12-10 12:26:19.12", "1996-12-10 12:26:19.12"}, - {"1996-12-10 12:26:19.123", "1996-12-10 12:26:19.123"}, - {"1996-12-10 12:26:19.1234", "1996-12-10 12:26:19.1234"}, - {"1996-12-10 12:26:19.12345", "1996-12-10 12:26:19.12345"}, - {"1996-12-10 12:26:19.123456", "1996-12-10 12:26:19.123456"}, - {"1996-12-10 12:26:19.1234567", "1996-12-10 12:26:19.1234567"}, - {"1996-12-10 12:26:19.12345678", "1996-12-10 12:26:19.12345678"}, - {"1996-12-10 12:26:19.123456789", "1996-12-10 12:26:19.123456789"}, - {"1996-12-10 12:26:19.000000001", "1996-12-10 12:26:19.000000001"}, - {"1996-12-10 12:26:19.000000012", "1996-12-10 12:26:19.000000012"}, - {"1996-12-10 12:26:19.000000123", "1996-12-10 12:26:19.000000123"}, - {"1996-12-10 12:26:19.000001234", "1996-12-10 12:26:19.000001234"}, - {"1996-12-10 12:26:19.000012345", "1996-12-10 12:26:19.000012345"}, - {"1996-12-10 12:26:19.000123456", "1996-12-10 12:26:19.000123456"}, - {"1996-12-10 12:26:19.001234567", "1996-12-10 12:26:19.001234567"}, - {"1996-12-10 12:26:19.12345678", "1996-12-10 12:26:19.12345678"}, - {"1996-12-10 12:26:19.0", "1996-12-10 12:26:19.0"}, - {"1996-12-10 12:26:19.01230", "1996-12-10 12:26:19.0123"} - }; + private Stream validTimestampValues() { + return Stream.of( + Arguments.of("1961-08-30 00:00:00", "1961-08-30 00:00:00.0"), + Arguments.of("1961-08-30 11:22:33", "1961-08-30 11:22:33.0"), + Arguments.of("1961-8-30 00:00:00", "1961-08-30 00:00:00.0"), + Arguments.of("1966-08-1 00:00:00", "1966-08-01 00:00:00.0"), + Arguments.of("1996-12-10 12:26:19.1", "1996-12-10 12:26:19.1"), + Arguments.of("1996-12-10 12:26:19.12", "1996-12-10 12:26:19.12"), + Arguments.of("1996-12-10 12:26:19.123", "1996-12-10 12:26:19.123"), + Arguments.of("1996-12-10 12:26:19.1234", "1996-12-10 12:26:19.1234"), + Arguments.of("1996-12-10 12:26:19.12345", "1996-12-10 12:26:19.12345"), + Arguments.of("1996-12-10 12:26:19.123456", "1996-12-10 12:26:19.123456"), + Arguments.of("1996-12-10 12:26:19.1234567", "1996-12-10 12:26:19.1234567"), + Arguments.of("1996-12-10 12:26:19.12345678", "1996-12-10 12:26:19.12345678"), + Arguments.of("1996-12-10 12:26:19.123456789", "1996-12-10 12:26:19.123456789"), + Arguments.of("1996-12-10 12:26:19.000000001", "1996-12-10 12:26:19.000000001"), + Arguments.of("1996-12-10 12:26:19.000000012", "1996-12-10 12:26:19.000000012"), + Arguments.of("1996-12-10 12:26:19.000000123", "1996-12-10 12:26:19.000000123"), + Arguments.of("1996-12-10 12:26:19.000001234", "1996-12-10 12:26:19.000001234"), + Arguments.of("1996-12-10 12:26:19.000012345", "1996-12-10 12:26:19.000012345"), + Arguments.of("1996-12-10 12:26:19.000123456", "1996-12-10 12:26:19.000123456"), + Arguments.of("1996-12-10 12:26:19.001234567", "1996-12-10 12:26:19.001234567"), + Arguments.of("1996-12-10 12:26:19.12345678", "1996-12-10 12:26:19.12345678"), + Arguments.of("1996-12-10 12:26:19.0", "1996-12-10 12:26:19.0"), + Arguments.of("1996-12-10 12:26:19.01230", "1996-12-10 12:26:19.0123") + ); } - @DataProvider(name = "validTimestampLongValues") - private Object[][] validTimestampLongValues() { - return new Object[][]{ - {1L, "1970-01-01 01:00:00.001"}, - {-3600*1000L - 1, "1969-12-31 23:59:59.999"}, - {-(20000L*365*24*60*60*1000), "18018-08-28 01:00:00.0"}, - {Timestamp.valueOf("1961-08-30 11:22:33").getTime(), "1961-08-30 11:22:33.0"}, - {Timestamp.valueOf("1961-08-30 11:22:33.54321000").getTime(), "1961-08-30 11:22:33.543"}, // nanoprecision lost - {new Timestamp(114, 10, 10, 10, 10, 10, 100000000).getTime(), "2014-11-10 10:10:10.1"}, - {new Timestamp(0, 10, 10, 10, 10, 10, 100000).getTime(), "1900-11-10 10:10:10.0"}, // nanoprecision lost - {new Date(114, 10, 10).getTime(), "2014-11-10 00:00:00.0"}, - {new Date(0, 10, 10).getTime(), "1900-11-10 00:00:00.0"}, - {LocalDateTime.of(1960, 10, 10, 10, 10, 10, 50000).atZone(ZoneId.of("America/Los_Angeles")) - .toInstant().toEpochMilli(), "1960-10-10 19:10:10.0"}, + private Stream validTimestampLongValues() { + return Stream.of( + Arguments.of(1L, "1970-01-01 01:00:00.001"), + Arguments.of(-3600*1000L - 1, "1969-12-31 23:59:59.999"), + Arguments.of(-(20000L*365*24*60*60*1000), "18018-08-28 01:00:00.0"), + Arguments.of(Timestamp.valueOf("1961-08-30 11:22:33").getTime(), "1961-08-30 11:22:33.0"), + Arguments.of(Timestamp.valueOf("1961-08-30 11:22:33.54321000").getTime(), "1961-08-30 11:22:33.543"), // nanoprecision lost + Arguments.of(new Timestamp(114, 10, 10, 10, 10, 10, 100000000).getTime(), "2014-11-10 10:10:10.1"), + Arguments.of(new Timestamp(0, 10, 10, 10, 10, 10, 100000).getTime(), "1900-11-10 10:10:10.0"), // nanoprecision lost + Arguments.of(new Date(114, 10, 10).getTime(), "2014-11-10 00:00:00.0"), + Arguments.of(new Date(0, 10, 10).getTime(), "1900-11-10 00:00:00.0"), + Arguments.of(LocalDateTime.of(1960, 10, 10, 10, 10, 10, 50000).atZone(ZoneId.of("America/Los_Angeles")) + .toInstant().toEpochMilli(), "1960-10-10 19:10:10.0"), // millisecond timestamps wraps around at year 1, so Long.MIN_VALUE looks similar // Long.MAX_VALUE, while actually representing 292278994 BCE - {Long.MIN_VALUE, "292278994-08-17 08:12:55.192"}, - {Long.MAX_VALUE + 1, "292278994-08-17 08:12:55.192"}, - {Long.MAX_VALUE, "292278994-08-17 08:12:55.807"}, - {Long.MIN_VALUE - 1, "292278994-08-17 08:12:55.807"}, + Arguments.of(Long.MIN_VALUE, "292278994-08-17 08:12:55.192"), + Arguments.of(Long.MAX_VALUE + 1, "292278994-08-17 08:12:55.192"), + Arguments.of(Long.MAX_VALUE, "292278994-08-17 08:12:55.807"), + Arguments.of(Long.MIN_VALUE - 1, "292278994-08-17 08:12:55.807"), // wrap around point near 0001-01-01, test that we never get a negative year: - {-(1970L*365*24*60*60*1000), "0001-04-25 01:00:00.0"}, - {-(1970L*365*24*60*60*1000 + 115*24*60*60*1000L), "0001-12-31 01:00:00.0"}, - {-(1970L*365*24*60*60*1000 + 115*24*60*60*1000L - 23*60*60*1000L), "0001-01-01 00:00:00.0"}, + Arguments.of(-(1970L*365*24*60*60*1000), "0001-04-25 01:00:00.0"), + Arguments.of(-(1970L*365*24*60*60*1000 + 115*24*60*60*1000L), "0001-12-31 01:00:00.0"), + Arguments.of(-(1970L*365*24*60*60*1000 + 115*24*60*60*1000L - 23*60*60*1000L), "0001-01-01 00:00:00.0"), - {LocalDateTime.of(0, 1, 1, 10, 10, 10, 50000).atZone(ZoneId.of("America/Los_Angeles")) - .toInstant().toEpochMilli() - 2*24*60*60*1000L, "0001-01-01 19:03:08.0"}, // 1 BCE - {LocalDateTime.of(0, 1, 1, 10, 10, 10, 50000).atZone(ZoneId.of("America/Los_Angeles")) - .toInstant().toEpochMilli() - 3*24*60*60*1000L, "0002-12-31 19:03:08.0"} // 2 BCE - }; + Arguments.of(LocalDateTime.of(0, 1, 1, 10, 10, 10, 50000).atZone(ZoneId.of("America/Los_Angeles")) + .toInstant().toEpochMilli() - 2*24*60*60*1000L, "0001-01-01 19:03:08.0"), // 1 BCE + Arguments.of(LocalDateTime.of(0, 1, 1, 10, 10, 10, 50000).atZone(ZoneId.of("America/Los_Angeles")) + .toInstant().toEpochMilli() - 3*24*60*60*1000L, "0002-12-31 19:03:08.0") // 2 BCE + ); } /* @@ -812,29 +817,28 @@ public class TimestampTests extends BaseTest { * validate that the correct Nanos value is generated from the specified * Timestamp */ - @DataProvider(name = "validateNanos") - private Object[][] validateNanos() { - return new Object[][]{ - {"1961-08-30 00:00:00", 0}, - {"1996-12-10 12:26:19.1", 100000000}, - {"1996-12-10 12:26:19.12", 120000000}, - {"1996-12-10 12:26:19.123", 123000000}, - {"1996-12-10 12:26:19.1234", 123400000}, - {"1996-12-10 12:26:19.12345", 123450000}, - {"1996-12-10 12:26:19.123456", 123456000}, - {"1996-12-10 12:26:19.1234567", 123456700}, - {"1996-12-10 12:26:19.12345678", 123456780}, - {"1996-12-10 12:26:19.123456789", 123456789}, - {"1996-12-10 12:26:19.000000001", 1}, - {"1996-12-10 12:26:19.000000012", 12}, - {"1996-12-10 12:26:19.000000123", 123}, - {"1996-12-10 12:26:19.000001234", 1234}, - {"1996-12-10 12:26:19.000012345", 12345}, - {"1996-12-10 12:26:19.000123456", 123456}, - {"1996-12-10 12:26:19.001234567", 1234567}, - {"1996-12-10 12:26:19.012345678", 12345678}, - {"1996-12-10 12:26:19.0", 0}, - {"1996-12-10 12:26:19.01230", 12300000} - }; + private Stream validateNanos() { + return Stream.of( + Arguments.of("1961-08-30 00:00:00", 0), + Arguments.of("1996-12-10 12:26:19.1", 100000000), + Arguments.of("1996-12-10 12:26:19.12", 120000000), + Arguments.of("1996-12-10 12:26:19.123", 123000000), + Arguments.of("1996-12-10 12:26:19.1234", 123400000), + Arguments.of("1996-12-10 12:26:19.12345", 123450000), + Arguments.of("1996-12-10 12:26:19.123456", 123456000), + Arguments.of("1996-12-10 12:26:19.1234567", 123456700), + Arguments.of("1996-12-10 12:26:19.12345678", 123456780), + Arguments.of("1996-12-10 12:26:19.123456789", 123456789), + Arguments.of("1996-12-10 12:26:19.000000001", 1), + Arguments.of("1996-12-10 12:26:19.000000012", 12), + Arguments.of("1996-12-10 12:26:19.000000123", 123), + Arguments.of("1996-12-10 12:26:19.000001234", 1234), + Arguments.of("1996-12-10 12:26:19.000012345", 12345), + Arguments.of("1996-12-10 12:26:19.000123456", 123456), + Arguments.of("1996-12-10 12:26:19.001234567", 1234567), + Arguments.of("1996-12-10 12:26:19.012345678", 12345678), + Arguments.of("1996-12-10 12:26:19.0", 0), + Arguments.of("1996-12-10 12:26:19.01230", 12300000) + ); } } diff --git a/test/jdk/java/sql/testng/test/sql/othervm/DriverManagerInitTests.java b/test/jdk/java/sql/test/sql/drivermanager/DriverManagerInitTests.java similarity index 93% rename from test/jdk/java/sql/testng/test/sql/othervm/DriverManagerInitTests.java rename to test/jdk/java/sql/test/sql/drivermanager/DriverManagerInitTests.java index d2570993533..f77fde4b166 100644 --- a/test/jdk/java/sql/testng/test/sql/othervm/DriverManagerInitTests.java +++ b/test/jdk/java/sql/test/sql/drivermanager/DriverManagerInitTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.sql.othervm; +package sql.drivermanager; import java.io.BufferedReader; import java.io.CharArrayReader; @@ -33,8 +33,8 @@ import java.util.Enumeration; import java.util.logging.Level; import java.util.logging.Logger; -import static org.testng.Assert.*; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class DriverManagerInitTests { diff --git a/test/jdk/java/sql/driverModuleTests/DriverManagerModuleTests.java b/test/jdk/java/sql/test/sql/drivermanager/DriverManagerModuleTests.java similarity index 84% rename from test/jdk/java/sql/driverModuleTests/DriverManagerModuleTests.java rename to test/jdk/java/sql/test/sql/drivermanager/DriverManagerModuleTests.java index aad39cdb1dd..083153ac38f 100644 --- a/test/jdk/java/sql/driverModuleTests/DriverManagerModuleTests.java +++ b/test/jdk/java/sql/test/sql/drivermanager/DriverManagerModuleTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,23 +20,19 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package sql.drivermanager; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; -import static org.testng.Assert.*; -import org.testng.annotations.AfterClass; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; /* * @test - * @library /java/sql/modules * @build luckydogdriver/* mystubdriver/* - * @run testng/othervm DriverManagerModuleTests * @summary Tests that a JDBC Driver that is a module can be loaded * via the service-provider loading mechanism. */ @@ -46,28 +42,12 @@ public class DriverManagerModuleTests { private static final String STUBDRIVERURL = "jdbc:stub:myDB"; private static final String CONNECTION_CLASS_NAME = "com.luckydogtennis.StubConnection"; - @BeforeClass - public static void setUpClass() throws Exception { - } - - @AfterClass - public static void tearDownClass() throws Exception { - } - - @BeforeMethod - public void setUpMethod() throws Exception { - } - - @AfterMethod - public void tearDownMethod() throws Exception { - } - /** * Validate JDBC drivers as modules will be accessible. One driver will be * loaded and registered via the service-provider loading mechanism. The * other driver will need to be explictly loaded * - * @throws java.lang.Exception + * @throws Exception */ @Test public void test() throws Exception { @@ -101,7 +81,7 @@ public class DriverManagerModuleTests { * Validate that a Connection can be obtained from a JDBC driver which is a * module and loaded via the service-provider loading mechanism. * - * @throws java.lang.Exception + * @throws Exception */ @Test public void test00() throws Exception { diff --git a/test/jdk/java/sql/test/sql/drivermanager/TEST.properties b/test/jdk/java/sql/test/sql/drivermanager/TEST.properties new file mode 100644 index 00000000000..0fed686adad --- /dev/null +++ b/test/jdk/java/sql/test/sql/drivermanager/TEST.properties @@ -0,0 +1,4 @@ +# drivermanager tests are run in othervm +othervm.dirs = . +# Required by DriverManagerModuleTests.java +lib.dirs = /java/sql/modules diff --git a/test/jdk/java/sql/testng/TEST.properties b/test/jdk/java/sql/testng/TEST.properties deleted file mode 100644 index 66b1566374a..00000000000 --- a/test/jdk/java/sql/testng/TEST.properties +++ /dev/null @@ -1,4 +0,0 @@ -# JDBC unit tests uses TestNG -TestNG.dirs = . -othervm.dirs = test/sql/othervm - diff --git a/test/jdk/java/sql/testng/util/BaseTest.java b/test/jdk/java/sql/util/BaseTest.java similarity index 54% rename from test/jdk/java/sql/testng/util/BaseTest.java rename to test/jdk/java/sql/util/BaseTest.java index 8751183726d..1a1b14e795a 100644 --- a/test/jdk/java/sql/testng/util/BaseTest.java +++ b/test/jdk/java/sql/util/BaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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 @@ -29,9 +29,12 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.sql.JDBCType; import java.sql.SQLException; +import java.util.stream.Stream; -import org.testng.annotations.DataProvider; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.provider.Arguments; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class BaseTest { protected final String reason = "reason"; @@ -73,29 +76,11 @@ public class BaseTest { return o1; } - /* - * DataProvider used to specify the value to set and check for - * methods using boolean values - */ - @DataProvider(name = "trueFalse") - protected Object[][] trueFalse() { - return new Object[][]{ - {true}, - {false} - }; - } - /* * DataProvider used to specify the standard JDBC Types */ - @DataProvider(name = "jdbcTypes") - protected Object[][] jdbcTypes() { - Object[][] o = new Object[JDBCType.values().length][1]; - int pos = 0; - for (JDBCType c : JDBCType.values()) { - o[pos++][0] = c.getVendorTypeNumber(); - } - return o; + protected Stream jdbcTypes() { + return Stream.of(JDBCType.values()).map(JDBCType::getVendorTypeNumber); } /* @@ -103,15 +88,14 @@ public class BaseTest { * that enquoteLiteral converts a string to a literal and every instance of * a single quote will be converted into two single quotes in the literal. */ - @DataProvider(name = "validEnquotedLiteralValues") - protected Object[][] validEnquotedLiteralValues() { - return new Object[][]{ - {"Hello", "'Hello'"}, - {"G'Day", "'G''Day'"}, - {"'G''Day'", "'''G''''Day'''"}, - {"I'''M", "'I''''''M'"}, - {"The Dark Knight", "'The Dark Knight'"}, - }; + protected Stream validEnquotedLiteralValues() { + return Stream.of( + Arguments.of("Hello", "'Hello'"), + Arguments.of("G'Day", "'G''Day'"), + Arguments.of("'G''Day'", "'''G''''Day'''"), + Arguments.of("I'''M", "'I''''''M'"), + Arguments.of("The Dark Knight", "'The Dark Knight'") + ); } /* @@ -119,37 +103,37 @@ public class BaseTest { * that enqouteIdentifier returns a simple SQL Identifier or a * quoted identifier */ - @DataProvider(name = "validIdentifierValues") - protected Object[][] validEnquotedIdentifierValues() { - return new Object[][]{ - {"b", false, "b"}, - {"b", true, "\"b\""}, - {MAX_LENGTH_IDENTIFIER, false, MAX_LENGTH_IDENTIFIER}, - {MAX_LENGTH_IDENTIFIER, true, "\"" + MAX_LENGTH_IDENTIFIER + "\""}, - {"Hello", false, "Hello"}, - {"Hello", true, "\"Hello\""}, - {"G'Day", false, "\"G'Day\""}, - {"G'Day", true, "\"G'Day\""}, - {"Bruce Wayne", false, "\"Bruce Wayne\""}, - {"Bruce Wayne", true, "\"Bruce Wayne\""}, - {"select", false, "\"select\""}, - {"table", true, "\"table\""}, - {"GoodDay$", false, "\"GoodDay$\""}, - {"GoodDay$", true, "\"GoodDay$\""},}; + protected Stream validEnquotedIdentifierValues() { + return Stream.of( + Arguments.of("b", false, "b"), + Arguments.of("b", true, "\"b\""), + Arguments.of(MAX_LENGTH_IDENTIFIER, false, MAX_LENGTH_IDENTIFIER), + Arguments.of(MAX_LENGTH_IDENTIFIER, true, "\"" + MAX_LENGTH_IDENTIFIER + "\""), + Arguments.of("Hello", false, "Hello"), + Arguments.of("Hello", true, "\"Hello\""), + Arguments.of("G'Day", false, "\"G'Day\""), + Arguments.of("G'Day", true, "\"G'Day\""), + Arguments.of("Bruce Wayne", false, "\"Bruce Wayne\""), + Arguments.of("Bruce Wayne", true, "\"Bruce Wayne\""), + Arguments.of("select", false, "\"select\""), + Arguments.of("table", true, "\"table\""), + Arguments.of("GoodDay$", false, "\"GoodDay$\""), + Arguments.of("GoodDay$", true, "\"GoodDay$\"") + ); } /* * DataProvider used to provide strings are invalid for enquoteIdentifier * resulting in a SQLException being thrown */ - @DataProvider(name = "invalidIdentifierValues") - protected Object[][] invalidEnquotedIdentifierValues() { - return new Object[][]{ - {"Hel\"lo", false}, - {"\"Hel\"lo\"", true}, - {"Hello" + '\0', false}, - {"", false}, - {MAX_LENGTH_IDENTIFIER + 'a', false},}; + protected Stream invalidEnquotedIdentifierValues() { + return Stream.of( + Arguments.of("Hel\"lo", false), + Arguments.of("\"Hel\"lo\"", true), + Arguments.of("Hello" + '\0', false), + Arguments.of("", false), + Arguments.of(MAX_LENGTH_IDENTIFIER + 'a', false) + ); } /* @@ -157,22 +141,21 @@ public class BaseTest { * that isSimpleIdentifier returns the correct value based on the * identifier specified. */ - @DataProvider(name = "simpleIdentifierValues") - protected Object[][] simpleIdentifierValues() { - return new Object[][]{ - {"b", true}, - {"Hello", true}, - {"\"Gotham\"", false}, - {"G'Day", false}, - {"Bruce Wayne", false}, - {"GoodDay$", false}, - {"Dick_Grayson", true}, - {"Batmobile1966", true}, - {MAX_LENGTH_IDENTIFIER, true}, - {MAX_LENGTH_IDENTIFIER + 'a', false}, - {"", false}, - {"select", false} - }; + protected Stream simpleIdentifierValues() { + return Stream.of( + Arguments.of("b", true), + Arguments.of("Hello", true), + Arguments.of("\"Gotham\"", false), + Arguments.of("G'Day", false), + Arguments.of("Bruce Wayne", false), + Arguments.of("GoodDay$", false), + Arguments.of("Dick_Grayson", true), + Arguments.of("Batmobile1966", true), + Arguments.of(MAX_LENGTH_IDENTIFIER, true), + Arguments.of(MAX_LENGTH_IDENTIFIER + 'a', false), + Arguments.of("", false), + Arguments.of("select", false) + ); } /* @@ -181,15 +164,14 @@ public class BaseTest { * literal and every instance of * a single quote will be converted into two single quotes in the literal. */ - @DataProvider(name = "validEnquotedNCharLiteralValues") - protected Object[][] validEnquotedNCharLiteralValues() { - return new Object[][]{ - {"Hello", "N'Hello'"}, - {"G'Day", "N'G''Day'"}, - {"'G''Day'", "N'''G''''Day'''"}, - {"I'''M", "N'I''''''M'"}, - {"N'Hello'", "N'N''Hello'''"}, - {"The Dark Knight", "N'The Dark Knight'"} - }; + protected Stream validEnquotedNCharLiteralValues() { + return Stream.of( + Arguments.of("Hello", "N'Hello'"), + Arguments.of("G'Day", "N'G''Day'"), + Arguments.of("'G''Day'", "N'''G''''Day'''"), + Arguments.of("I'''M", "N'I''''''M'"), + Arguments.of("N'Hello'", "N'N''Hello'''"), + Arguments.of("The Dark Knight", "N'The Dark Knight'") + ); } } diff --git a/test/jdk/java/sql/testng/util/DriverActionImpl.java b/test/jdk/java/sql/util/DriverActionImpl.java similarity index 94% rename from test/jdk/java/sql/testng/util/DriverActionImpl.java rename to test/jdk/java/sql/util/DriverActionImpl.java index 4a286ad8f3c..48fed8086a7 100644 --- a/test/jdk/java/sql/testng/util/DriverActionImpl.java +++ b/test/jdk/java/sql/util/DriverActionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/java/sql/testng/util/SerializedBatchUpdateException.java b/test/jdk/java/sql/util/SerializedBatchUpdateException.java similarity index 99% rename from test/jdk/java/sql/testng/util/SerializedBatchUpdateException.java rename to test/jdk/java/sql/util/SerializedBatchUpdateException.java index 00efc5275a7..08473e6a184 100644 --- a/test/jdk/java/sql/testng/util/SerializedBatchUpdateException.java +++ b/test/jdk/java/sql/util/SerializedBatchUpdateException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/java/sql/testng/util/StubCallableStatement.java b/test/jdk/java/sql/util/StubCallableStatement.java similarity index 99% rename from test/jdk/java/sql/testng/util/StubCallableStatement.java rename to test/jdk/java/sql/util/StubCallableStatement.java index 4a7c27314bb..4700699c4ba 100644 --- a/test/jdk/java/sql/testng/util/StubCallableStatement.java +++ b/test/jdk/java/sql/util/StubCallableStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/java/sql/testng/util/StubConnection.java b/test/jdk/java/sql/util/StubConnection.java similarity index 99% rename from test/jdk/java/sql/testng/util/StubConnection.java rename to test/jdk/java/sql/util/StubConnection.java index cd013572adc..e1a60efc323 100644 --- a/test/jdk/java/sql/testng/util/StubConnection.java +++ b/test/jdk/java/sql/util/StubConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/java/sql/testng/util/StubDatabaseMetaData.java b/test/jdk/java/sql/util/StubDatabaseMetaData.java similarity index 99% rename from test/jdk/java/sql/testng/util/StubDatabaseMetaData.java rename to test/jdk/java/sql/util/StubDatabaseMetaData.java index 3bf70afaa8f..3c95ac94793 100644 --- a/test/jdk/java/sql/testng/util/StubDatabaseMetaData.java +++ b/test/jdk/java/sql/util/StubDatabaseMetaData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/java/sql/testng/util/StubDriver.java b/test/jdk/java/sql/util/StubDriver.java similarity index 96% rename from test/jdk/java/sql/testng/util/StubDriver.java rename to test/jdk/java/sql/util/StubDriver.java index 12253080377..c45b9ec9919 100644 --- a/test/jdk/java/sql/testng/util/StubDriver.java +++ b/test/jdk/java/sql/util/StubDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/java/sql/testng/util/StubDriverDA.java b/test/jdk/java/sql/util/StubDriverDA.java similarity index 96% rename from test/jdk/java/sql/testng/util/StubDriverDA.java rename to test/jdk/java/sql/util/StubDriverDA.java index 5b23f0846d8..f134a9d28cf 100644 --- a/test/jdk/java/sql/testng/util/StubDriverDA.java +++ b/test/jdk/java/sql/util/StubDriverDA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/java/sql/testng/util/StubPreparedStatement.java b/test/jdk/java/sql/util/StubPreparedStatement.java similarity index 99% rename from test/jdk/java/sql/testng/util/StubPreparedStatement.java rename to test/jdk/java/sql/util/StubPreparedStatement.java index a3b95a65f4e..fdb90df4797 100644 --- a/test/jdk/java/sql/testng/util/StubPreparedStatement.java +++ b/test/jdk/java/sql/util/StubPreparedStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/java/sql/testng/util/StubStatement.java b/test/jdk/java/sql/util/StubStatement.java similarity index 99% rename from test/jdk/java/sql/testng/util/StubStatement.java rename to test/jdk/java/sql/util/StubStatement.java index c8f6a3ac071..00ed6268856 100644 --- a/test/jdk/java/sql/testng/util/StubStatement.java +++ b/test/jdk/java/sql/util/StubStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/TEST.properties b/test/jdk/javax/sql/TEST.properties similarity index 68% rename from test/jdk/javax/sql/testng/TEST.properties rename to test/jdk/javax/sql/TEST.properties index cb97c160507..d9ed805344a 100644 --- a/test/jdk/javax/sql/testng/TEST.properties +++ b/test/jdk/javax/sql/TEST.properties @@ -1,7 +1,7 @@ -# JDBC unit tests uses TestNG -TestNG.dirs= . +# JDBC unit tests uses JUnit +JUnit.dirs= . othervm.dirs= . -lib.dirs = /java/sql/testng +lib.dirs = /java/sql/util modules = java.sql.rowset/com.sun.rowset \ java.sql.rowset/com.sun.rowset.internal \ java.sql.rowset/com.sun.rowset.providers diff --git a/test/jdk/javax/sql/testng/jars/badFactory/META-INF/services/javax.sql.rowset.RowSetFactory b/test/jdk/javax/sql/jars/badFactory/META-INF/services/javax.sql.rowset.RowSetFactory similarity index 100% rename from test/jdk/javax/sql/testng/jars/badFactory/META-INF/services/javax.sql.rowset.RowSetFactory rename to test/jdk/javax/sql/jars/badFactory/META-INF/services/javax.sql.rowset.RowSetFactory diff --git a/test/jdk/javax/sql/testng/jars/goodFactory/META-INF/services/javax.sql.rowset.RowSetFactory b/test/jdk/javax/sql/jars/goodFactory/META-INF/services/javax.sql.rowset.RowSetFactory similarity index 100% rename from test/jdk/javax/sql/testng/jars/goodFactory/META-INF/services/javax.sql.rowset.RowSetFactory rename to test/jdk/javax/sql/jars/goodFactory/META-INF/services/javax.sql.rowset.RowSetFactory diff --git a/test/jdk/javax/sql/rowset/TEST.properties b/test/jdk/javax/sql/rowset/TEST.properties deleted file mode 100644 index 6c5a2c7aceb..00000000000 --- a/test/jdk/javax/sql/rowset/TEST.properties +++ /dev/null @@ -1 +0,0 @@ -modules = java.sql.rowset diff --git a/test/jdk/javax/sql/rowset/serial/SerialBlob/SetBinaryStream.java b/test/jdk/javax/sql/rowset/serial/SerialBlob/SetBinaryStream.java deleted file mode 100644 index a2d7ea2f8cb..00000000000 --- a/test/jdk/javax/sql/rowset/serial/SerialBlob/SetBinaryStream.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2011, 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 javax.sql.rowset.serial.SerialBlob; -import javax.sql.rowset.serial.SerialException; - -/** - * @test - * @bug 7077451 - * @summary tests if the correct exception is thrown when calling method setBinaryStream() on SerialBlob - */ -public class SetBinaryStream { - - public static void main(String[] args) throws Exception { - SerialBlob blob = new SerialBlob(new byte[0]); - try { - blob.setBinaryStream(0); - } catch (SerialException e) { - System.out.println("Test PASSED"); - } - } - -} diff --git a/test/jdk/javax/sql/rowset/serial/SerialClob/SetAsciiStream.java b/test/jdk/javax/sql/rowset/serial/SerialClob/SetAsciiStream.java deleted file mode 100644 index 10deaf523e9..00000000000 --- a/test/jdk/javax/sql/rowset/serial/SerialClob/SetAsciiStream.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2011, 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 javax.sql.rowset.serial.SerialClob; -import javax.sql.rowset.serial.SerialException; - -/** - * @test - * @bug 7077451 - * @summary tests if the correct exception is thrown when calling method setAsciiStream() on SerialClob - */ -public class SetAsciiStream { - - public static void main(String[] args) throws Exception { - SerialClob clob = new SerialClob(new char[0]); - try { - clob.setAsciiStream(0); - } catch (SerialException e) { - System.out.println("Test PASSED"); - } - } - -} diff --git a/test/jdk/javax/sql/rowset/serial/SerialClob/SetCharacterStream.java b/test/jdk/javax/sql/rowset/serial/SerialClob/SetCharacterStream.java deleted file mode 100644 index be861e43723..00000000000 --- a/test/jdk/javax/sql/rowset/serial/SerialClob/SetCharacterStream.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2011, 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 javax.sql.rowset.serial.SerialClob; -import javax.sql.rowset.serial.SerialException; - -/** - * @test - * @bug 7077451 - * @summary tests if the correct exception is thrown when calling method setCharacterStream() on SerialClob - */ -public class SetCharacterStream { - - public static void main(String[] args) throws Exception { - SerialClob clob = new SerialClob(new char[0]); - try { - clob.setCharacterStream(0); - } catch (SerialException e) { - System.out.println("Test PASSED"); - } - } - -} diff --git a/test/jdk/javax/sql/testng/test/rowset/BaseRowSetTests.java b/test/jdk/javax/sql/test/rowset/BaseRowSetTests.java similarity index 83% rename from test/jdk/javax/sql/testng/test/rowset/BaseRowSetTests.java rename to test/jdk/javax/sql/test/rowset/BaseRowSetTests.java index c1d2d9a2ed0..8c47415db39 100644 --- a/test/jdk/javax/sql/testng/test/rowset/BaseRowSetTests.java +++ b/test/jdk/javax/sql/test/rowset/BaseRowSetTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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,14 +40,19 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.Calendar; +import java.util.stream.Stream; import javax.sql.RowSet; import javax.sql.rowset.serial.SerialArray; import javax.sql.rowset.serial.SerialBlob; import javax.sql.rowset.serial.SerialClob; import javax.sql.rowset.serial.SerialRef; -import static org.testng.Assert.*; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + import util.StubArray; import util.StubBaseRowSet; import util.StubBlob; @@ -67,7 +72,8 @@ public class BaseRowSetTests extends CommonRowSetTests { /* * Create a RowSetListener and validate that notifyCursorMoved is called */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void baseRowSetTest0000(StubBaseRowSet rs) throws Exception { TestRowSetListener rsl = new TestRowSetListener(); rs.addRowSetListener(rsl); @@ -78,7 +84,8 @@ public class BaseRowSetTests extends CommonRowSetTests { /* * Create a RowSetListener and validate that notifyRowChanged is called */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void baseRowSetTest0001(StubBaseRowSet rs) throws Exception { TestRowSetListener rsl = new TestRowSetListener(); rs.addRowSetListener(rsl); @@ -89,7 +96,8 @@ public class BaseRowSetTests extends CommonRowSetTests { /* * Create a RowSetListener and validate that notifyRowSetChanged is called */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void baseRowSetTest0002(StubBaseRowSet rs) throws Exception { TestRowSetListener rsl = new TestRowSetListener(); rs.addRowSetListener(rsl); @@ -101,7 +109,8 @@ public class BaseRowSetTests extends CommonRowSetTests { * Create multiple RowSetListeners and validate that notifyRowSetChanged * is called on all listeners */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void baseRowSetTest0003(StubBaseRowSet rs) throws Exception { TestRowSetListener rsl = new TestRowSetListener(); TestRowSetListener rsl2 = new TestRowSetListener(); @@ -116,7 +125,8 @@ public class BaseRowSetTests extends CommonRowSetTests { * Create multiple RowSetListeners and validate that notifyRowChanged * is called on all listeners */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void baseRowSetTest0004(StubBaseRowSet rs) throws Exception { TestRowSetListener rsl = new TestRowSetListener(); TestRowSetListener rsl2 = new TestRowSetListener(); @@ -131,7 +141,8 @@ public class BaseRowSetTests extends CommonRowSetTests { * Create multiple RowSetListeners and validate that notifyCursorMoved * is called on all listeners */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void baseRowSetTest0005(StubBaseRowSet rs) throws Exception { TestRowSetListener rsl = new TestRowSetListener(); TestRowSetListener rsl2 = new TestRowSetListener(); @@ -146,7 +157,8 @@ public class BaseRowSetTests extends CommonRowSetTests { * Create a RowSetListener and validate that notifyRowSetChanged, * notifyRowChanged() and notifyCursorMoved are called */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void baseRowSetTest0006(StubBaseRowSet rs) throws Exception { TestRowSetListener rsl = new TestRowSetListener(); rs.addRowSetListener(rsl); @@ -163,7 +175,8 @@ public class BaseRowSetTests extends CommonRowSetTests { * Create multiple RowSetListeners and validate that notifyRowSetChanged, * notifyRowChanged() and notifyCursorMoved are called on all listeners */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void baseRowSetTest0007(StubBaseRowSet rs) throws Exception { TestRowSetListener rsl = new TestRowSetListener(); TestRowSetListener rsl2 = new TestRowSetListener(); @@ -185,7 +198,8 @@ public class BaseRowSetTests extends CommonRowSetTests { * remove the listener, invoke notifyRowSetChanged again and verify the * listner is not called */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void baseRowSetTest0008(StubBaseRowSet rs) throws Exception { TestRowSetListener rsl = new TestRowSetListener(); rs.addRowSetListener(rsl); @@ -202,7 +216,8 @@ public class BaseRowSetTests extends CommonRowSetTests { * Set the base parameters and validate that the value set is * the correct type and value */ - @Test(dataProvider = "testBaseParameters") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("testBaseParameters") public void baseRowSetTest0009(int pos, Object o) throws Exception { assertTrue(getParam(pos, o).getClass().isInstance(o)); assertTrue(o.equals(getParam(pos, o))); @@ -212,7 +227,8 @@ public class BaseRowSetTests extends CommonRowSetTests { * Set the complex parameters and validate that the value set is * the correct type */ - @Test(dataProvider = "testAdvancedParameters") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("testAdvancedParameters") public void baseRowSetTest0010(int pos, Object o) throws Exception { assertTrue(getParam(pos, o).getClass().isInstance(o)); } @@ -220,7 +236,8 @@ public class BaseRowSetTests extends CommonRowSetTests { /* * Validate setNull specifying the supported type values */ - @Test(dataProvider = "jdbcTypes") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("jdbcTypes") public void baseRowSetTest0011(Integer type) throws Exception { brs = new StubBaseRowSet(); brs.setNull(1, type); @@ -231,7 +248,8 @@ public class BaseRowSetTests extends CommonRowSetTests { * Validate setNull specifying the supported type values and that * typeName is set internally */ - @Test(dataProvider = "jdbcTypes") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("jdbcTypes") public void baseRowSetTest0012(Integer type) throws Exception { brs = new StubBaseRowSet(); brs.setNull(1, type, "SUPERHERO"); @@ -274,7 +292,8 @@ public class BaseRowSetTests extends CommonRowSetTests { /* * Validate that initParams() initializes the parameters */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void baseRowSetTest0016(StubBaseRowSet rs) throws Exception { rs.setInt(1, 1); rs.initParams(); @@ -285,8 +304,7 @@ public class BaseRowSetTests extends CommonRowSetTests { /* * DataProvider used to set parameters for basic types that are supported */ - @DataProvider(name = "testBaseParameters") - private Object[][] testBaseParameters() throws SQLException { + private Stream testBaseParameters() throws SQLException { Integer aInt = 1; Long aLong = Long.MAX_VALUE; Short aShort = Short.MIN_VALUE; @@ -320,34 +338,32 @@ public class BaseRowSetTests extends CommonRowSetTests { brs.setObject(17, query, Types.CHAR); brs.setObject(18, query, Types.CHAR, 0); - return new Object[][]{ - {1, aInt}, - {2, query}, - {3, aLong}, - {4, aBoolean}, - {5, aShort}, - {6, aDouble}, - {7, bd}, - {8, aFloat}, - {9, aByte}, - {10, aDate}, - {11, aTime}, - {12, aTimeStamp}, - {13, aDate}, - {14, aTime}, - {15, aTimeStamp}, - {16, query}, - {17, query}, - {18, query} - - }; + return Stream.of( + Arguments.of(1, aInt), + Arguments.of(2, query), + Arguments.of(3, aLong), + Arguments.of(4, aBoolean), + Arguments.of(5, aShort), + Arguments.of(6, aDouble), + Arguments.of(7, bd), + Arguments.of(8, aFloat), + Arguments.of(9, aByte), + Arguments.of(10, aDate), + Arguments.of(11, aTime), + Arguments.of(12, aTimeStamp), + Arguments.of(13, aDate), + Arguments.of(14, aTime), + Arguments.of(15, aTimeStamp), + Arguments.of(16, query), + Arguments.of(17, query), + Arguments.of(18, query) + ); } /* * DataProvider used to set advanced parameters for types that are supported */ - @DataProvider(name = "testAdvancedParameters") - private Object[][] testAdvancedParameters() throws SQLException { + private Stream testAdvancedParameters() throws SQLException { byte[] bytes = new byte[10]; Ref aRef = new SerialRef(new StubRef("INTEGER", query)); @@ -367,17 +383,17 @@ public class BaseRowSetTests extends CommonRowSetTests { brs.setUnicodeStream(8, is, query.length()); brs.setCharacterStream(9, rdr, query.length()); - return new Object[][]{ - {1, bytes}, - {2, is}, - {3, aRef}, - {4, aArray}, - {5, aBlob}, - {6, aClob}, - {7, is}, - {8, is}, - {9, rdr} - }; + return Stream.of( + Arguments.of(1, bytes), + Arguments.of(2, is), + Arguments.of(3, aRef), + Arguments.of(4, aArray), + Arguments.of(5, aBlob), + Arguments.of(6, aClob), + Arguments.of(7, is), + Arguments.of(8, is), + Arguments.of(9, rdr) + ); } /* diff --git a/test/jdk/javax/sql/testng/test/rowset/CommonRowSetTests.java b/test/jdk/javax/sql/test/rowset/CommonRowSetTests.java similarity index 67% rename from test/jdk/javax/sql/testng/test/rowset/CommonRowSetTests.java rename to test/jdk/javax/sql/test/rowset/CommonRowSetTests.java index 89492aefed5..5e8163fbf05 100644 --- a/test/jdk/javax/sql/testng/test/rowset/CommonRowSetTests.java +++ b/test/jdk/javax/sql/test/rowset/CommonRowSetTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, 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 @@ -43,17 +43,23 @@ import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Stream; import javax.sql.RowSet; import javax.sql.rowset.BaseRowSet; import javax.sql.rowset.CachedRowSet; import javax.sql.rowset.RowSetFactory; import javax.sql.rowset.RowSetMetaDataImpl; import javax.sql.rowset.RowSetProvider; -import org.testng.Assert; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + import util.BaseTest; import util.StubBlob; import util.StubClob; @@ -98,7 +104,7 @@ public abstract class CommonRowSetTests extends BaseTest { try { rsf = RowSetProvider.newFactory(); } catch (SQLException ex) { - Assert.fail(ex.getMessage()); + fail(ex.getMessage()); } } @@ -111,84 +117,76 @@ public abstract class CommonRowSetTests extends BaseTest { * DataProvider used to specify the value to set and check for the * methods for fetch direction */ - @DataProvider(name = "rowSetFetchDirection") - protected Object[][] rowSetFetchDirection() throws Exception { + protected Stream rowSetFetchDirection() throws Exception { RowSet rs = newInstance(); - return new Object[][]{ - {rs, ResultSet.FETCH_FORWARD}, - {rs, ResultSet.FETCH_REVERSE}, - {rs, ResultSet.FETCH_UNKNOWN} - }; + return Stream.of( + Arguments.of(rs, ResultSet.FETCH_FORWARD), + Arguments.of(rs, ResultSet.FETCH_REVERSE), + Arguments.of(rs, ResultSet.FETCH_UNKNOWN) + ); } /* * DataProvider used to specify the value to set and check for the * methods for Cursor Scroll Type */ - @DataProvider(name = "rowSetScrollTypes") - protected Object[][] rowSetScrollTypes() throws Exception { + protected Stream rowSetScrollTypes() throws Exception { RowSet rs = newInstance(); - return new Object[][]{ - {rs, ResultSet.TYPE_FORWARD_ONLY}, - {rs, ResultSet.TYPE_SCROLL_INSENSITIVE}, - {rs, ResultSet.TYPE_SCROLL_SENSITIVE} - }; + return Stream.of( + Arguments.of(rs, ResultSet.TYPE_FORWARD_ONLY), + Arguments.of(rs, ResultSet.TYPE_SCROLL_INSENSITIVE), + Arguments.of(rs, ResultSet.TYPE_SCROLL_SENSITIVE) + ); } /* * DataProvider used to specify the value to set and check for * methods using transaction isolation types */ - @DataProvider(name = "rowSetIsolationTypes") - protected Object[][] rowSetIsolationTypes() throws Exception { + protected Stream rowSetIsolationTypes() throws Exception { RowSet rs = newInstance(); - return new Object[][]{ - {rs, Connection.TRANSACTION_NONE}, - {rs, Connection.TRANSACTION_READ_COMMITTED}, - {rs, Connection.TRANSACTION_READ_UNCOMMITTED}, - {rs, Connection.TRANSACTION_REPEATABLE_READ}, - {rs, Connection.TRANSACTION_SERIALIZABLE} - }; + return Stream.of( + Arguments.of(rs, Connection.TRANSACTION_NONE), + Arguments.of(rs, Connection.TRANSACTION_READ_COMMITTED), + Arguments.of(rs, Connection.TRANSACTION_READ_UNCOMMITTED), + Arguments.of(rs, Connection.TRANSACTION_REPEATABLE_READ), + Arguments.of(rs, Connection.TRANSACTION_SERIALIZABLE) + ); } /* * DataProvider used to specify the value to set and check for the * methods for Concurrency */ - @DataProvider(name = "rowSetConcurrencyTypes") - protected Object[][] rowSetConcurrencyTypes() throws Exception { + protected Stream rowSetConcurrencyTypes() throws Exception { RowSet rs = newInstance(); - return new Object[][]{ - {rs, ResultSet.CONCUR_READ_ONLY}, - {rs, ResultSet.CONCUR_UPDATABLE} - }; + return Stream.of( + Arguments.of(rs, ResultSet.CONCUR_READ_ONLY), + Arguments.of(rs, ResultSet.CONCUR_UPDATABLE) + ); } /* * DataProvider used to specify the value to set and check for * methods using boolean values */ - @DataProvider(name = "rowSetTrueFalse") - protected Object[][] rowSetTrueFalse() throws Exception { + protected Stream rowSetTrueFalse() throws Exception { RowSet rs = newInstance(); - return new Object[][]{ - {rs, true}, - {rs, false} - }; + return Stream.of( + Arguments.of(rs, true), + Arguments.of(rs, false) + ); } /* * DataProvider used to specify the type of RowSet to use. We also must * initialize the RowSet */ - @DataProvider(name = "rowSetType") - protected Object[][] rowSetType() throws Exception { + protected Stream rowSetType() throws Exception { RowSet rs = newInstance(); - return new Object[][]{ - {rs} - }; + return Stream.of(rs); } /* @@ -503,7 +501,8 @@ public abstract class CommonRowSetTests extends BaseTest { /* * Validate that getCommand() returns null by default */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0000(RowSet rs) { assertNull(rs.getCommand()); } @@ -511,7 +510,8 @@ public abstract class CommonRowSetTests extends BaseTest { /* * Validate that getCommand() returns command specified to setCommand */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0001(RowSet rs) throws Exception { rs.setCommand(query); assertTrue(rs.getCommand().equals(query)); @@ -521,7 +521,8 @@ public abstract class CommonRowSetTests extends BaseTest { /* * Validate that getCurrency() returns the correct default value */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0002(RowSet rs) throws Exception { assertTrue(rs.getConcurrency() == ResultSet.CONCUR_UPDATABLE); } @@ -530,7 +531,8 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate that getCurrency() returns the correct value * after a call to setConcurrency()) */ - @Test(dataProvider = "rowSetConcurrencyTypes") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetConcurrencyTypes") public void commonRowSetTest0003(RowSet rs, int concurType) throws Exception { rs.setConcurrency(concurType); assertTrue(rs.getConcurrency() == concurType); @@ -539,15 +541,17 @@ public abstract class CommonRowSetTests extends BaseTest { /* * Validate that getCurrency() throws a SQLException for an invalid value */ - @Test(dataProvider = "rowSetType", expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0004(RowSet rs) throws Exception { - rs.setConcurrency(ResultSet.CLOSE_CURSORS_AT_COMMIT); + assertThrows(SQLException.class, () -> rs.setConcurrency(ResultSet.CLOSE_CURSORS_AT_COMMIT)); } /* * Validate that getDataSourceName() returns null by default */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0005(RowSet rs) throws Exception { assertTrue(rs.getDataSourceName() == null); } @@ -556,7 +560,8 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate that getDataSourceName() returns the value specified * by setDataSourceName() and getUrl() returns null */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0006(RowSet rs) throws Exception { rs.setUrl(url); rs.setDataSourceName(dsName); @@ -568,16 +573,20 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate that setDataSourceName() throws a SQLException for an empty * String specified for the data source name */ - @Test(dataProvider = "rowSetType", expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0007(RowSet rs) throws Exception { - String dsname = ""; - rs.setDataSourceName(dsname); + assertThrows(SQLException.class, () -> { + String dsname = ""; + rs.setDataSourceName(dsname); + }); } /* * Validate that getEscapeProcessing() returns false by default */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0008(RowSet rs) throws Exception { assertTrue(rs.getEscapeProcessing()); } @@ -586,7 +595,8 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate that getEscapeProcessing() returns value set by * setEscapeProcessing() */ - @Test(dataProvider = "rowSetTrueFalse") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetTrueFalse") public void commonRowSetTest0009(RowSet rs, boolean val) throws Exception { rs.setEscapeProcessing(val); assertTrue(rs.getEscapeProcessing() == val); @@ -595,7 +605,8 @@ public abstract class CommonRowSetTests extends BaseTest { /* * Validate that getFetchDirection() returns the correct default value */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0010(RowSet rs) throws Exception { assertTrue(rs.getFetchDirection() == ResultSet.FETCH_FORWARD); } @@ -604,7 +615,8 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate that getFetchDirection() returns the value set by * setFetchDirection() */ - @Test(dataProvider = "rowSetFetchDirection") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetFetchDirection") public void commonRowSetTest0011(RowSet rs, int direction) throws Exception { rs.setFetchDirection(direction); assertTrue(rs.getFetchDirection() == direction); @@ -613,26 +625,31 @@ public abstract class CommonRowSetTests extends BaseTest { /* * Validate that setFetchSize() throws a SQLException for an invalid value */ - @Test(dataProvider = "rowSetType", expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0013(RowSet rs) throws Exception { - rs.setFetchSize(-1); + assertThrows(SQLException.class, () -> rs.setFetchSize(-1)); } /* * Validate that setFetchSize() throws a SQLException for a * value greater than getMaxRows() */ - @Test(dataProvider = "rowSetType", expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0014(RowSet rs) throws Exception { - rs.setMaxRows(5); - rs.setFetchSize(rs.getMaxRows() + 1); + assertThrows(SQLException.class, () -> { + rs.setMaxRows(5); + rs.setFetchSize(rs.getMaxRows() + 1); + }); } /* * Validate that getFetchSize() returns the correct value after * setFetchSize() has been called */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0015(RowSet rs) throws Exception { int maxRows = 150; rs.setFetchSize(0); @@ -647,16 +664,18 @@ public abstract class CommonRowSetTests extends BaseTest { /* * Validate that setMaxFieldSize() throws a SQLException for an invalid value */ - @Test(dataProvider = "rowSetType", expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0016(RowSet rs) throws Exception { - rs.setMaxFieldSize(-1); + assertThrows(SQLException.class, () -> rs.setMaxFieldSize(-1)); } /* * Validate that getMaxFieldSize() returns the value set by * setMaxFieldSize() */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0017(RowSet rs) throws Exception { rs.setMaxFieldSize(0); assertTrue(rs.getMaxFieldSize() == 0); @@ -670,7 +689,8 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate that isReadOnly() returns value set by * setReadOnly() */ - @Test(dataProvider = "rowSetTrueFalse") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetTrueFalse") public void commonRowSetTest0018(RowSet rs, boolean val) throws Exception { rs.setReadOnly(val); assertTrue(rs.isReadOnly() == val); @@ -680,7 +700,8 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate that getTransactionIsolation() returns value set by * setTransactionIsolation() */ - @Test(dataProvider = "rowSetIsolationTypes") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetIsolationTypes") public void commonRowSetTest0019(RowSet rs, int val) throws Exception { rs.setTransactionIsolation(val); assertTrue(rs.getTransactionIsolation() == val); @@ -689,7 +710,8 @@ public abstract class CommonRowSetTests extends BaseTest { /* * Validate that getType() returns value set by setType() */ - @Test(dataProvider = "rowSetScrollTypes") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetScrollTypes") public void commonRowSetTest0020(RowSet rs, int val) throws Exception { rs.setType(val); assertTrue(rs.getType() == val); @@ -699,7 +721,8 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate that getEscapeProcessing() returns value set by * setEscapeProcessing() */ - @Test(dataProvider = "rowSetTrueFalse") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetTrueFalse") public void commonRowSetTest0021(BaseRowSet rs, boolean val) throws Exception { rs.setShowDeleted(val); assertTrue(rs.getShowDeleted() == val); @@ -709,7 +732,8 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate that getTypeMap() returns same value set by * setTypeMap() */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0022(RowSet rs) throws Exception { Map> map = new HashMap<>(); map.put("SUPERHERO", Class.forName("util.SuperHero")); @@ -721,7 +745,8 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate that getUsername() returns same value set by * setUsername() */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0023(RowSet rs) throws Exception { rs.setUsername(user); assertTrue(rs.getUsername().equals(user)); @@ -731,7 +756,8 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate that getPassword() returns same password set by * setPassword() */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0024(RowSet rs) throws Exception { rs.setPassword(password); assertTrue(rs.getPassword().equals(password)); @@ -741,7 +767,8 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate that getQueryTimeout() returns same value set by * setQueryTimeout() and that 0 is a valid timeout value */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0025(RowSet rs) throws Exception { int timeout = 0; rs.setQueryTimeout(timeout); @@ -752,7 +779,8 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate that getQueryTimeout() returns same value set by * setQueryTimeout() and that 0 is a valid timeout value */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0026(RowSet rs) throws Exception { int timeout = 10000; rs.setQueryTimeout(timeout); @@ -763,9 +791,10 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate that setQueryTimeout() throws a SQLException for a timeout * value < 0 */ - @Test(dataProvider = "rowSetType", expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0027(RowSet rs) throws Exception { - rs.setQueryTimeout(-1); + assertThrows(SQLException.class, () -> rs.setQueryTimeout(-1)); } @@ -773,7 +802,8 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate addRowSetListener does not throw an Exception when null is * passed as the parameter */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0028(RowSet rs) throws Exception { rs.addRowSetListener(null); } @@ -782,7 +812,8 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate removeRowSetListener does not throw an Exception when null is * passed as the parameter */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0029(RowSet rs) throws Exception { rs.removeRowSetListener(null); } @@ -790,7 +821,8 @@ public abstract class CommonRowSetTests extends BaseTest { /* * Set two parameters and then validate clearParameters() will clear them */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0030(BaseRowSet rs) throws Exception { rs.setInt(1, 1); rs.setString(2, query); @@ -803,7 +835,8 @@ public abstract class CommonRowSetTests extends BaseTest { * Validate that getURL() returns same value set by * setURL() */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0031(RowSet rs) throws Exception { rs.setUrl(url); assertTrue(rs.getUrl().equals(url)); @@ -813,560 +846,614 @@ public abstract class CommonRowSetTests extends BaseTest { * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0100(RowSet rs) throws Exception { - InputStream is = null; - rs.setAsciiStream(1, is); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + InputStream is = null; + rs.setAsciiStream(1, is); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0101(RowSet rs) throws Exception { - InputStream is = null; - rs.setAsciiStream("one", is); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + InputStream is = null; + rs.setAsciiStream("one", is); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0102(RowSet rs) throws Exception { - InputStream is = null; - rs.setAsciiStream("one", is, query.length()); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + InputStream is = null; + rs.setAsciiStream("one", is, query.length()); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0103(RowSet rs) throws Exception { - InputStream is = null; - rs.setBinaryStream(1, is); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + InputStream is = null; + rs.setBinaryStream(1, is); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0104(RowSet rs) throws Exception { - InputStream is = null; - rs.setBinaryStream("one", is); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + InputStream is = null; + rs.setBinaryStream("one", is); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0105(RowSet rs) throws Exception { - InputStream is = null; - rs.setBinaryStream("one", is, query.length()); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + InputStream is = null; + rs.setBinaryStream("one", is, query.length()); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0106(RowSet rs) throws Exception { - rs.setBigDecimal("one", BigDecimal.ONE); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setBigDecimal("one", BigDecimal.ONE)); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0107(RowSet rs) throws Exception { - InputStream is = null; - rs.setBlob(1, is); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + InputStream is = null; + rs.setBlob(1, is); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0108(RowSet rs) throws Exception { - InputStream is = null; - rs.setBlob("one", is); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + InputStream is = null; + rs.setBlob("one", is); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0109(RowSet rs) throws Exception { - InputStream is = null; - rs.setBlob("one", is, query.length()); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + InputStream is = null; + rs.setBlob("one", is, query.length()); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0110(RowSet rs) throws Exception { - rs.setBlob("one", new StubBlob()); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setBlob("one", new StubBlob())); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0111(RowSet rs) throws Exception { - rs.setBoolean("one", true); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setBoolean("one", true)); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0112(RowSet rs) throws Exception { - byte b = 1; - rs.setByte("one", b); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + byte b = 1; + rs.setByte("one", b); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0113(RowSet rs) throws Exception { - byte b = 1; - rs.setBytes("one", new byte[10]); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + byte b = 1; + rs.setBytes("one", new byte[10]); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0114(RowSet rs) throws Exception { - Reader rdr = null; - rs.setCharacterStream("one", rdr, query.length()); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + Reader rdr = null; + rs.setCharacterStream("one", rdr, query.length()); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0115(RowSet rs) throws Exception { - Reader rdr = null; - rs.setCharacterStream("one", rdr); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + Reader rdr = null; + rs.setCharacterStream("one", rdr); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0116(RowSet rs) throws Exception { - Reader rdr = null; - rs.setCharacterStream(1, rdr); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + Reader rdr = null; + rs.setCharacterStream(1, rdr); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0117(RowSet rs) throws Exception { - Reader rdr = null; - rs.setClob(1, rdr); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + Reader rdr = null; + rs.setClob(1, rdr); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0118(RowSet rs) throws Exception { - Reader rdr = null; - rs.setClob("one", rdr); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + Reader rdr = null; + rs.setClob("one", rdr); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0119(RowSet rs) throws Exception { - Reader rdr = null; - rs.setClob("one", rdr, query.length()); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + Reader rdr = null; + rs.setClob("one", rdr, query.length()); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0120(RowSet rs) throws Exception { - rs.setClob("one", new StubClob()); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setClob("one", new StubClob())); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0121(RowSet rs) throws Exception { - rs.setDate("one", Date.valueOf(LocalDate.now())); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setDate("one", Date.valueOf(LocalDate.now()))); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0122(RowSet rs) throws Exception { - rs.setDate("one", Date.valueOf(LocalDate.now()), - Calendar.getInstance()); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setDate("one", Date.valueOf(LocalDate.now()), + Calendar.getInstance())); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0123(RowSet rs) throws Exception { - rs.setTime("one", Time.valueOf(LocalTime.now())); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setTime("one", Time.valueOf(LocalTime.now()))); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0124(RowSet rs) throws Exception { - rs.setTime("one", Time.valueOf(LocalTime.now()), - Calendar.getInstance()); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setTime("one", Time.valueOf(LocalTime.now()), + Calendar.getInstance())); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0125(RowSet rs) throws Exception { - rs.setTimestamp("one", Timestamp.valueOf(LocalDateTime.now())); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setTimestamp("one", Timestamp.valueOf(LocalDateTime.now()))); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0126(RowSet rs) throws Exception { - rs.setTimestamp("one", Timestamp.valueOf(LocalDateTime.now()), - Calendar.getInstance()); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setTimestamp("one", Timestamp.valueOf(LocalDateTime.now()), + Calendar.getInstance())); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0127(RowSet rs) throws Exception { - rs.setDouble("one", 2.0d); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setDouble("one", 2.0d)); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0128(RowSet rs) throws Exception { - rs.setFloat("one", 2.0f); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setFloat("one", 2.0f)); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0129(RowSet rs) throws Exception { - rs.setInt("one", 21); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setInt("one", 21)); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0130(RowSet rs) throws Exception { - rs.setLong("one", 21l); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setLong("one", 21l)); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0131(RowSet rs) throws Exception { - Reader rdr = null; - rs.setNCharacterStream("one", rdr, query.length()); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + Reader rdr = null; + rs.setNCharacterStream("one", rdr, query.length()); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0132(RowSet rs) throws Exception { - Reader rdr = null; - rs.setNCharacterStream("one", rdr); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + Reader rdr = null; + rs.setNCharacterStream("one", rdr); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0133(RowSet rs) throws Exception { - Reader rdr = null; - rs.setNCharacterStream(1, rdr); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + Reader rdr = null; + rs.setNCharacterStream(1, rdr); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0134(RowSet rs) throws Exception { - Reader rdr = null; - rs.setNCharacterStream(1, rdr, query.length()); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + Reader rdr = null; + rs.setNCharacterStream(1, rdr, query.length()); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0135(RowSet rs) throws Exception { - Reader rdr = null; - rs.setClob("one", rdr); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + Reader rdr = null; + rs.setClob("one", rdr); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0136(RowSet rs) throws Exception { - Reader rdr = null; - rs.setClob("one", rdr, query.length()); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + Reader rdr = null; + rs.setClob("one", rdr, query.length()); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0137(RowSet rs) throws Exception { - rs.setNClob("one", new StubNClob()); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setNClob("one", new StubNClob())); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0138(RowSet rs) throws Exception { - Reader rdr = null; - rs.setNClob(1, rdr); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + Reader rdr = null; + rs.setNClob(1, rdr); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0139(RowSet rs) throws Exception { - Reader rdr = null; - rs.setNClob(1, rdr, query.length()); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + Reader rdr = null; + rs.setNClob(1, rdr, query.length()); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0140(RowSet rs) throws Exception { - rs.setNClob(1, new StubNClob()); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setNClob(1, new StubNClob())); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0141(RowSet rs) throws Exception { - rs.setNString(1, query); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setNString(1, query)); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0142(RowSet rs) throws Exception { - rs.setNull("one", Types.INTEGER); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setNull("one", Types.INTEGER)); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0143(RowSet rs) throws Exception { - rs.setNull("one", Types.INTEGER, "my.type"); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setNull("one", Types.INTEGER, "my.type")); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0144(RowSet rs) throws Exception { - rs.setObject("one", query, Types.VARCHAR); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setObject("one", query, Types.VARCHAR)); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0145(RowSet rs) throws Exception { - rs.setObject("one", query, Types.VARCHAR, 0); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setObject("one", query, Types.VARCHAR, 0)); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0146(RowSet rs) throws Exception { - rs.setObject("one", query); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setObject("one", query)); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0147(RowSet rs) throws Exception { - RowId aRowid = null; - rs.setRowId("one", aRowid); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + RowId aRowid = null; + rs.setRowId("one", aRowid); + }); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0148(RowSet rs) throws Exception { - rs.setSQLXML("one", new StubSQLXML()); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setSQLXML("one", new StubSQLXML())); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0149(RowSet rs) throws Exception { - rs.setSQLXML(1, new StubSQLXML()); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setSQLXML(1, new StubSQLXML())); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0150(RowSet rs) throws Exception { - rs.setNString(1, query); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setNString(1, query)); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0151(RowSet rs) throws Exception { - rs.setNString("one", query); + assertThrows(SQLFeatureNotSupportedException.class, () -> rs.setNString("one", query)); } /* * This method is currently not implemented in BaseRowSet and will * throw a SQLFeatureNotSupportedException */ - @Test(dataProvider = "rowSetType", - expectedExceptions = SQLFeatureNotSupportedException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonRowSetTest0152(RowSet rs) throws Exception { - short val = 21; - rs.setShort("one", val); + assertThrows(SQLFeatureNotSupportedException.class, () -> { + short val = 21; + rs.setShort("one", val); + }); } } diff --git a/test/jdk/javax/sql/testng/test/rowset/RowSetFactoryTests.java b/test/jdk/javax/sql/test/rowset/RowSetFactoryTests.java similarity index 80% rename from test/jdk/javax/sql/testng/test/rowset/RowSetFactoryTests.java rename to test/jdk/javax/sql/test/rowset/RowSetFactoryTests.java index 72a4341c7aa..480033afc2b 100644 --- a/test/jdk/javax/sql/testng/test/rowset/RowSetFactoryTests.java +++ b/test/jdk/javax/sql/test/rowset/RowSetFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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,11 +23,15 @@ package test.rowset; import java.sql.SQLException; +import java.util.stream.Stream; import javax.sql.rowset.RowSetFactory; import javax.sql.rowset.RowSetProvider; -import static org.testng.Assert.*; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + import util.BaseTest; public class RowSetFactoryTests extends BaseTest { @@ -50,7 +54,8 @@ public class RowSetFactoryTests extends BaseTest { * Validate that the RowSetFactory returned by RowSetProvider.newFactory() * returns the correct RowSet implementations */ - @Test(dataProvider = "RowSetValues", enabled = true) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("RowSetValues") public void test(RowSetFactory rsf, String impl) throws SQLException { validateRowSetImpl(rsf, impl); } @@ -98,22 +103,20 @@ public class RowSetFactoryTests extends BaseTest { * DataProvider used to provide the RowSetFactory and the RowSet * implementation that should be returned */ - @DataProvider(name = "RowSetValues") - private Object[][] RowSetValues() throws SQLException { + private Stream RowSetValues() throws SQLException { RowSetFactory rsf = RowSetProvider.newFactory(); RowSetFactory rsf1 = RowSetProvider.newFactory(STUB_FACTORY_CLASSNAME, null); - return new Object[][]{ - {rsf, DEFAULT_CACHEDROWSET_CLASSNAME}, - {rsf, DEFAULT_FILTEREDROWSET_CLASSNAME}, - {rsf, DEFAULT_JDBCROWSET_CLASSNAME}, - {rsf, DEFAULT_JOINROWSET_CLASSNAME}, - {rsf, DEFAULT_WEBROWSET_CLASSNAME}, - {rsf1, STUB_CACHEDROWSET_CLASSNAME}, - {rsf1, STUB_FILTEREDROWSET_CLASSNAME}, - {rsf1, STUB_JDBCROWSET_CLASSNAME}, - {rsf1, STUB_JOINROWSET_CLASSNAME}, - {rsf1, STUB_WEBROWSET_CLASSNAME} - - }; + return Stream.of( + Arguments.of(rsf, DEFAULT_CACHEDROWSET_CLASSNAME), + Arguments.of(rsf, DEFAULT_FILTEREDROWSET_CLASSNAME), + Arguments.of(rsf, DEFAULT_JDBCROWSET_CLASSNAME), + Arguments.of(rsf, DEFAULT_JOINROWSET_CLASSNAME), + Arguments.of(rsf, DEFAULT_WEBROWSET_CLASSNAME), + Arguments.of(rsf1, STUB_CACHEDROWSET_CLASSNAME), + Arguments.of(rsf1, STUB_FILTEREDROWSET_CLASSNAME), + Arguments.of(rsf1, STUB_JDBCROWSET_CLASSNAME), + Arguments.of(rsf1, STUB_JOINROWSET_CLASSNAME), + Arguments.of(rsf1, STUB_WEBROWSET_CLASSNAME) + ); } } diff --git a/test/jdk/javax/sql/testng/test/rowset/RowSetMetaDataTests.java b/test/jdk/javax/sql/test/rowset/RowSetMetaDataTests.java similarity index 55% rename from test/jdk/javax/sql/testng/test/rowset/RowSetMetaDataTests.java rename to test/jdk/javax/sql/test/rowset/RowSetMetaDataTests.java index 8a944a8bbb1..59dc4f43033 100644 --- a/test/jdk/javax/sql/testng/test/rowset/RowSetMetaDataTests.java +++ b/test/jdk/javax/sql/test/rowset/RowSetMetaDataTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,19 @@ package test.rowset; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Types; +import java.util.stream.IntStream; +import java.util.stream.Stream; import javax.sql.RowSetMetaData; import javax.sql.rowset.RowSetMetaDataImpl; -import static org.testng.Assert.*; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import org.junit.jupiter.params.provider.ValueSource; import util.BaseTest; public class RowSetMetaDataTests extends BaseTest { @@ -40,7 +47,7 @@ public class RowSetMetaDataTests extends BaseTest { // Instance to be used within the tests private RowSetMetaDataImpl rsmd; - @BeforeMethod + @BeforeEach public void setUpMethod() throws Exception { rsmd = new RowSetMetaDataImpl(); rsmd.setColumnCount(MAX_COLUMNS); @@ -49,325 +56,325 @@ public class RowSetMetaDataTests extends BaseTest { /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test(Integer col) throws Exception { - rsmd.getCatalogName(col); + assertThrows(SQLException.class, () -> rsmd.getCatalogName(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test01(Integer col) throws Exception { - rsmd.getColumnClassName(col); + assertThrows(SQLException.class, () -> rsmd.getColumnClassName(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test02(Integer col) throws Exception { - rsmd.getColumnDisplaySize(col); + assertThrows(SQLException.class, () -> rsmd.getColumnDisplaySize(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test03(Integer col) throws Exception { - rsmd.getColumnLabel(col); + assertThrows(SQLException.class, () -> rsmd.getColumnLabel(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test04(Integer col) throws Exception { - rsmd.getColumnName(col); + assertThrows(SQLException.class, () -> rsmd.getColumnName(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test05(Integer col) throws Exception { - rsmd.getColumnType(col); + assertThrows(SQLException.class, () -> rsmd.getColumnType(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test06(Integer col) throws Exception { - rsmd.getColumnTypeName(col); + assertThrows(SQLException.class, () -> rsmd.getColumnTypeName(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test07(Integer col) throws Exception { - rsmd.getPrecision(col); + assertThrows(SQLException.class, () -> rsmd.getPrecision(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test08(Integer col) throws Exception { - rsmd.getScale(col); + assertThrows(SQLException.class, () -> rsmd.getScale(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test09(Integer col) throws Exception { - rsmd.getSchemaName(col); + assertThrows(SQLException.class, () -> rsmd.getSchemaName(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test10(Integer col) throws Exception { - rsmd.getTableName(col); + assertThrows(SQLException.class, () -> rsmd.getTableName(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test11(Integer col) throws Exception { - rsmd.isAutoIncrement(col); + assertThrows(SQLException.class, () -> rsmd.isAutoIncrement(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test12(Integer col) throws Exception { - rsmd.isCaseSensitive(col); + assertThrows(SQLException.class, () -> rsmd.isCaseSensitive(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test13(Integer col) throws Exception { - rsmd.isCurrency(col); + assertThrows(SQLException.class, () -> rsmd.isCurrency(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test14(Integer col) throws Exception { - rsmd.isDefinitelyWritable(col); + assertThrows(SQLException.class, () -> rsmd.isDefinitelyWritable(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test15(Integer col) throws Exception { - rsmd.isNullable(col); + assertThrows(SQLException.class, () -> rsmd.isNullable(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test16(Integer col) throws Exception { - rsmd.isReadOnly(col); + assertThrows(SQLException.class, () -> rsmd.isReadOnly(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test17(Integer col) throws Exception { - rsmd.isSearchable(col); + assertThrows(SQLException.class, () -> rsmd.isSearchable(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test18(Integer col) throws Exception { - rsmd.isSigned(col); + assertThrows(SQLException.class, () -> rsmd.isSigned(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test19(Integer col) throws Exception { - rsmd.isWritable(col); + assertThrows(SQLException.class, () -> rsmd.isWritable(col)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test20(Integer col) throws Exception { - rsmd.setAutoIncrement(col, true); + assertThrows(SQLException.class, () -> rsmd.setAutoIncrement(col, true)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test21(Integer col) throws Exception { - rsmd.setCaseSensitive(col, true); + assertThrows(SQLException.class, () -> rsmd.setCaseSensitive(col, true)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test22(Integer col) throws Exception { - rsmd.setCatalogName(col, null); + assertThrows(SQLException.class, () -> rsmd.setCatalogName(col, null)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test23(Integer col) throws Exception { - rsmd.setColumnDisplaySize(col, 5); + assertThrows(SQLException.class, () -> rsmd.setColumnDisplaySize(col, 5)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test24(Integer col) throws Exception { - rsmd.setColumnLabel(col, "label"); + assertThrows(SQLException.class, () -> rsmd.setColumnLabel(col, "label")); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test25(Integer col) throws Exception { - rsmd.setColumnName(col, "F1"); + assertThrows(SQLException.class, () -> rsmd.setColumnName(col, "F1")); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test26(Integer col) throws Exception { - rsmd.setColumnType(col, Types.CHAR); + assertThrows(SQLException.class, () -> rsmd.setColumnType(col, Types.CHAR)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test27(Integer col) throws Exception { - rsmd.setColumnTypeName(col, "F1"); + assertThrows(SQLException.class, () -> rsmd.setColumnTypeName(col, "F1")); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test28(Integer col) throws Exception { - rsmd.setCurrency(col, true); + assertThrows(SQLException.class, () -> rsmd.setCurrency(col, true)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test29(Integer col) throws Exception { - rsmd.setNullable(col, ResultSetMetaData.columnNoNulls); + assertThrows(SQLException.class, () -> rsmd.setNullable(col, ResultSetMetaData.columnNoNulls)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test30(Integer col) throws Exception { - rsmd.setPrecision(col, 2); + assertThrows(SQLException.class, () -> rsmd.setPrecision(col, 2)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test31(Integer col) throws Exception { - rsmd.setScale(col, 2); + assertThrows(SQLException.class, () -> rsmd.setScale(col, 2)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test32(Integer col) throws Exception { - rsmd.setSchemaName(col, "Gotham"); + assertThrows(SQLException.class, () -> rsmd.setSchemaName(col, "Gotham")); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test33(Integer col) throws Exception { - rsmd.setSearchable(col, false); + assertThrows(SQLException.class, () -> rsmd.setSearchable(col, false)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test34(Integer col) throws Exception { - rsmd.setSigned(col, false); + assertThrows(SQLException.class, () -> rsmd.setSigned(col, false)); } /* * Validate a SQLException is thrown for an invalid column index */ - @Test(dataProvider = "invalidColumnRanges", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("invalidColumnRanges") public void test35(Integer col) throws Exception { - rsmd.setTableName(col, "SUPERHEROS"); + assertThrows(SQLException.class, () -> rsmd.setTableName(col, "SUPERHEROS")); } /* @@ -375,7 +382,8 @@ public class RowSetMetaDataTests extends BaseTest { * Note: Once setColumnClassName is added to RowSetMetaData, this * method will need to change. */ - @Test(dataProvider = "columnClassNames") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("columnClassNames") public void test36(Integer type, String name) throws Exception { rsmd.setColumnType(1, type); assertTrue(rsmd.getColumnClassName(1).equals(name)); @@ -385,7 +393,8 @@ public class RowSetMetaDataTests extends BaseTest { * Validate that all of the methods are accessible and the correct value * is returned for each column */ - @Test(dataProvider = "columnRanges") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("columnRanges") public void test37(Integer col) throws Exception { rsmd.setAutoIncrement(col, true); assertTrue(rsmd.isAutoIncrement(col)); @@ -429,7 +438,8 @@ public class RowSetMetaDataTests extends BaseTest { /* * Validate that the proper values are accepted by setNullable */ - @Test(dataProvider = "validSetNullableValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("validSetNullableValues") public void test38(Integer val) throws Exception { rsmd.setNullable(1, val); } @@ -437,7 +447,8 @@ public class RowSetMetaDataTests extends BaseTest { /* * Validate that the correct type is returned for the column */ - @Test(dataProvider = "jdbcTypes") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("jdbcTypes") public void test39(Integer type) throws Exception { rsmd.setColumnType(1, type); assertTrue(type == rsmd.getColumnType(1)); @@ -446,7 +457,8 @@ public class RowSetMetaDataTests extends BaseTest { /* * Validate that the correct value is returned from the isXXX methods */ - @Test(dataProvider = "trueFalse") + @ParameterizedTest(autoCloseArguments = false) + @ValueSource(booleans = {true, false}) public void test40(Boolean b) throws Exception { rsmd.setAutoIncrement(1, b); rsmd.setCaseSensitive(1, b); @@ -483,73 +495,62 @@ public class RowSetMetaDataTests extends BaseTest { * to validate that an IllegalArgumentException will be thrown from the * valueOf method */ - @DataProvider(name = "validSetNullableValues") - private Object[][] validSetNullableValues() { - return new Object[][]{ - {ResultSetMetaData.columnNoNulls}, - {ResultSetMetaData.columnNullable}, - {ResultSetMetaData.columnNullableUnknown} - }; + private Stream validSetNullableValues() { + return Stream.of( + ResultSetMetaData.columnNoNulls, + ResultSetMetaData.columnNullable, + ResultSetMetaData.columnNullableUnknown + ); } /* * DataProvider used to provide column indexes that are out of range so that * SQLException is thrown */ - @DataProvider(name = "invalidColumnRanges") - private Object[][] invalidColumnRanges() { - return new Object[][]{ - {-1}, - {0}, - {MAX_COLUMNS + 1} - }; + private Stream invalidColumnRanges() { + return Stream.of( + -1, + 0, + MAX_COLUMNS + 1 + ); } /* * DataProvider used to provide the valid column ranges for the * RowSetMetaDataImpl object */ - @DataProvider(name = "columnRanges") - private Object[][] columnRanges() { - Object[][] o = new Object[MAX_COLUMNS][1]; - for (int i = 1; i <= MAX_COLUMNS; i++) { - o[i - 1][0] = i; - } - return o; + private Stream columnRanges() { + return IntStream.rangeClosed(1, MAX_COLUMNS).boxed(); } /* * DataProvider used to specify the value to set via setColumnType and * the expected value to be returned from getColumnClassName */ - @DataProvider(name = "columnClassNames") - private Object[][] columnClassNames() { - return new Object[][]{ - {Types.CHAR, "java.lang.String"}, - {Types.NCHAR, "java.lang.String"}, - {Types.VARCHAR, "java.lang.String"}, - {Types.NVARCHAR, "java.lang.String"}, - {Types.LONGVARCHAR, "java.lang.String"}, - {Types.LONGNVARCHAR, "java.lang.String"}, - {Types.NUMERIC, "java.math.BigDecimal"}, - {Types.DECIMAL, "java.math.BigDecimal"}, - {Types.BIT, "java.lang.Boolean"}, - {Types.TINYINT, "java.lang.Byte"}, - {Types.SMALLINT, "java.lang.Short"}, - {Types.INTEGER, "java.lang.Integer"}, - {Types.FLOAT, "java.lang.Double"}, - {Types.DOUBLE, "java.lang.Double"}, - {Types.BINARY, "byte[]"}, - {Types.VARBINARY, "byte[]"}, - {Types.LONGVARBINARY, "byte[]"}, - {Types.DATE, "java.sql.Date"}, - {Types.TIME, "java.sql.Time"}, - {Types.TIMESTAMP, "java.sql.Timestamp"}, - {Types.CLOB, "java.sql.Clob"}, - {Types.BLOB, "java.sql.Blob"} - - }; - + private Stream columnClassNames() { + return Stream.of( + Arguments.of(Types.CHAR, "java.lang.String"), + Arguments.of(Types.NCHAR, "java.lang.String"), + Arguments.of(Types.VARCHAR, "java.lang.String"), + Arguments.of(Types.NVARCHAR, "java.lang.String"), + Arguments.of(Types.LONGVARCHAR, "java.lang.String"), + Arguments.of(Types.LONGNVARCHAR, "java.lang.String"), + Arguments.of(Types.NUMERIC, "java.math.BigDecimal"), + Arguments.of(Types.DECIMAL, "java.math.BigDecimal"), + Arguments.of(Types.BIT, "java.lang.Boolean"), + Arguments.of(Types.TINYINT, "java.lang.Byte"), + Arguments.of(Types.SMALLINT, "java.lang.Short"), + Arguments.of(Types.INTEGER, "java.lang.Integer"), + Arguments.of(Types.FLOAT, "java.lang.Double"), + Arguments.of(Types.DOUBLE, "java.lang.Double"), + Arguments.of(Types.BINARY, "byte[]"), + Arguments.of(Types.VARBINARY, "byte[]"), + Arguments.of(Types.LONGVARBINARY, "byte[]"), + Arguments.of(Types.DATE, "java.sql.Date"), + Arguments.of(Types.TIME, "java.sql.Time"), + Arguments.of(Types.TIMESTAMP, "java.sql.Timestamp"), + Arguments.of(Types.CLOB, "java.sql.Clob"), + Arguments.of(Types.BLOB, "java.sql.Blob") + ); } - } diff --git a/test/jdk/javax/sql/testng/test/rowset/RowSetProviderTests.java b/test/jdk/javax/sql/test/rowset/RowSetProviderTests.java similarity index 79% rename from test/jdk/javax/sql/testng/test/rowset/RowSetProviderTests.java rename to test/jdk/javax/sql/test/rowset/RowSetProviderTests.java index 47a5cdb1eb0..25422cf0950 100644 --- a/test/jdk/javax/sql/testng/test/rowset/RowSetProviderTests.java +++ b/test/jdk/javax/sql/test/rowset/RowSetProviderTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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,14 +27,19 @@ import java.io.File; import java.net.URL; import java.net.URLClassLoader; import java.sql.SQLException; +import java.util.stream.Stream; import javax.sql.rowset.RowSetFactory; import javax.sql.rowset.RowSetProvider; -import static org.testng.Assert.*; -import org.testng.annotations.AfterClass; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + import util.BaseTest; import util.StubRowSetFactory; @@ -57,7 +62,7 @@ public class RowSetProviderTests extends BaseTest { * Save off the original property value for javax.sql.rowset.RowSetFactory, * original classloader and define the path to the jars directory */ - @BeforeClass + @BeforeAll public static void setUpClass() throws Exception { origFactoryProperty = System.getProperty("javax.sql.rowset.RowSetFactory"); cl = Thread.currentThread().getContextClassLoader(); @@ -68,7 +73,7 @@ public class RowSetProviderTests extends BaseTest { /* * Install the original javax.sql.rowset.RowSetFactory property value */ - @AfterClass + @AfterAll public static void tearDownClass() throws Exception { if (origFactoryProperty != null) { System.setProperty("javax.sql.rowset.RowSetFactory", @@ -80,7 +85,7 @@ public class RowSetProviderTests extends BaseTest { * Clear the javax.sql.rowset.RowSetFactory property value and * reset the classloader to its original value */ - @AfterMethod + @AfterEach public void tearDownMethod() throws Exception { System.clearProperty("javax.sql.rowset.RowSetFactory"); Thread.currentThread().setContextClassLoader(cl); @@ -89,7 +94,8 @@ public class RowSetProviderTests extends BaseTest { /* * Validate that the correct RowSetFactory is returned by newFactory(). */ - @Test(dataProvider = "RowSetFactoryValues") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("RowSetFactoryValues") public void test(RowSetFactory rsf, String impl) throws SQLException { validateProvider(rsf, impl); } @@ -109,7 +115,7 @@ public class RowSetProviderTests extends BaseTest { * Validate that the correct RowSetFactory is returned by newFactory() * when specified by the javax.sql.rowset.RowSetFactory property. */ - @Test(enabled = true) + @Test public void test02() throws SQLException { System.setProperty("javax.sql.rowset.RowSetFactory", STUB_FACTORY_CLASSNAME); validateProvider(RowSetProvider.newFactory(), STUB_FACTORY_CLASSNAME); @@ -120,11 +126,13 @@ public class RowSetProviderTests extends BaseTest { * when specified RowSetFactory specified by the * javax.sql.rowset.RowSetFactory property is not valid. */ - @Test(expectedExceptions = SQLException.class) + @Test public void test03() throws SQLException { - System.setProperty("javax.sql.rowset.RowSetFactory", - "invalid.RowSetFactoryImpl"); - RowSetFactory rsf = RowSetProvider.newFactory(); + assertThrows(SQLException.class, () -> { + System.setProperty("javax.sql.rowset.RowSetFactory", + "invalid.RowSetFactoryImpl"); + RowSetFactory rsf = RowSetProvider.newFactory(); + }); } /* @@ -144,13 +152,15 @@ public class RowSetProviderTests extends BaseTest { * Validate that a SQLException is thrown by newFactory() if the default * RowSetFactory specified by the ServiceLoader API is not valid */ - @Test(expectedExceptions = SQLException.class) + @Test public void test05() throws Exception { - File f = new File(jarPath + "badFactory"); - URLClassLoader loader = new URLClassLoader(new URL[]{ - new URL(f.toURI().toString())}, getClass().getClassLoader()); - Thread.currentThread().setContextClassLoader(loader); - RowSetProvider.newFactory(); + assertThrows(SQLException.class, () -> { + File f = new File(jarPath + "badFactory"); + URLClassLoader loader = new URLClassLoader(new URL[]{ + new URL(f.toURI().toString())}, getClass().getClassLoader()); + Thread.currentThread().setContextClassLoader(loader); + RowSetProvider.newFactory(); + }); } /* @@ -174,16 +184,15 @@ public class RowSetProviderTests extends BaseTest { * DataProvider used to provide a RowSetFactory and the expected * RowSetFactory implementation that should be returned */ - @DataProvider(name = "RowSetFactoryValues") - private Object[][] RowSetFactoryValues() throws SQLException { + private Stream RowSetFactoryValues() throws SQLException { RowSetFactory rsf = RowSetProvider.newFactory(); RowSetFactory rsf1 = RowSetProvider.newFactory(STUB_FACTORY_CLASSNAME, null); RowSetFactory rsf2 = RowSetProvider.newFactory(DEFFAULT_FACTORY_CLASSNAME, null); - return new Object[][]{ - {rsf, NO_VALADATE_IMPL}, - {rsf, DEFFAULT_FACTORY_CLASSNAME}, - {rsf1, STUB_FACTORY_CLASSNAME}, - {rsf2, DEFFAULT_FACTORY_CLASSNAME} - }; + return Stream.of( + Arguments.of(rsf, NO_VALADATE_IMPL), + Arguments.of(rsf, DEFFAULT_FACTORY_CLASSNAME), + Arguments.of(rsf1, STUB_FACTORY_CLASSNAME), + Arguments.of(rsf2, DEFFAULT_FACTORY_CLASSNAME) + ); } } diff --git a/test/jdk/javax/sql/testng/test/rowset/RowSetWarningTests.java b/test/jdk/javax/sql/test/rowset/RowSetWarningTests.java similarity index 97% rename from test/jdk/javax/sql/testng/test/rowset/RowSetWarningTests.java rename to test/jdk/javax/sql/test/rowset/RowSetWarningTests.java index 41b52c4ef57..81ae97af785 100644 --- a/test/jdk/javax/sql/testng/test/rowset/RowSetWarningTests.java +++ b/test/jdk/javax/sql/test/rowset/RowSetWarningTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,10 @@ package test.rowset; import java.sql.SQLException; import javax.sql.rowset.RowSetWarning; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class RowSetWarningTests extends BaseTest { diff --git a/test/jdk/javax/sql/testng/test/rowset/cachedrowset/CachedRowSetTests.java b/test/jdk/javax/sql/test/rowset/cachedrowset/CachedRowSetTests.java similarity index 94% rename from test/jdk/javax/sql/testng/test/rowset/cachedrowset/CachedRowSetTests.java rename to test/jdk/javax/sql/test/rowset/cachedrowset/CachedRowSetTests.java index 1155a889187..5fd473924c3 100644 --- a/test/jdk/javax/sql/testng/test/rowset/cachedrowset/CachedRowSetTests.java +++ b/test/jdk/javax/sql/test/rowset/cachedrowset/CachedRowSetTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/test/rowset/cachedrowset/CommonCachedRowSetTests.java b/test/jdk/javax/sql/test/rowset/cachedrowset/CommonCachedRowSetTests.java similarity index 79% rename from test/jdk/javax/sql/testng/test/rowset/cachedrowset/CommonCachedRowSetTests.java rename to test/jdk/javax/sql/test/rowset/cachedrowset/CommonCachedRowSetTests.java index 642c03c9a45..bc63ce28497 100644 --- a/test/jdk/javax/sql/testng/test/rowset/cachedrowset/CommonCachedRowSetTests.java +++ b/test/jdk/javax/sql/test/rowset/cachedrowset/CommonCachedRowSetTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, 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,6 +37,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.Collection; +import java.util.stream.Stream; import javax.sql.RowSet; import javax.sql.rowset.CachedRowSet; import javax.sql.rowset.RowSetMetaDataImpl; @@ -44,12 +45,18 @@ import javax.sql.rowset.serial.SerialRef; import javax.sql.rowset.spi.SyncFactory; import javax.sql.rowset.spi.SyncProvider; import javax.sql.rowset.spi.SyncProviderException; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + import test.rowset.CommonRowSetTests; import util.StubArray; import util.StubRef; @@ -83,52 +90,43 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { /* * DataProvider that uses a RowSet with the COFFEE_HOUSES Table */ - @DataProvider(name = "rowsetUsingCoffeeHouses") - protected Object[][] rowsetUsingCoffeeHouses() throws Exception { - RowSet rs = createCoffeeHousesRowSet(); - return new Object[][]{ - {rs} - }; + protected Stream rowsetUsingCoffeeHouses() throws Exception { + return Stream.of(createCoffeeHousesRowSet()); } /* * DataProvider that uses a RowSet with the COFFEES Table */ - @DataProvider(name = "rowsetUsingCoffees") - protected Object[][] rowsetUsingCoffees() throws Exception { - RowSet rs = createCoffeesRowSet(); - return new Object[][]{ - {rs} - }; + protected Stream rowsetUsingCoffees() throws Exception { + return Stream.of(createCoffeesRowSet()); } /* * DataProvider that uses a RowSet with the DATAYPES Table and * used to validate the various supported data types */ - @DataProvider(name = "rowsetUsingDataTypes") - protected Object[][] rowsetUsingDataTypes() throws Exception { + protected Stream rowsetUsingDataTypes() throws Exception { CachedRowSet rs = createDataTypesRowSet(); - return new Object[][]{ - {rs, JDBCType.INTEGER}, - {rs, JDBCType.CHAR}, - {rs, JDBCType.VARCHAR}, - {rs, JDBCType.BIGINT}, - {rs, JDBCType.BOOLEAN}, - {rs, JDBCType.SMALLINT}, - {rs, JDBCType.DOUBLE}, - {rs, JDBCType.DECIMAL}, - {rs, JDBCType.REAL}, - {rs, JDBCType.TINYINT}, - {rs, JDBCType.DATE}, - {rs, JDBCType.TIME}, - {rs, JDBCType.TIMESTAMP}, - {rs, JDBCType.VARBINARY}, - {rs, JDBCType.ARRAY}, - {rs, JDBCType.REF}, - {rs, JDBCType.FLOAT} - }; + return Stream.of( + Arguments.of(rs, JDBCType.INTEGER), + Arguments.of(rs, JDBCType.CHAR), + Arguments.of(rs, JDBCType.VARCHAR), + Arguments.of(rs, JDBCType.BIGINT), + Arguments.of(rs, JDBCType.BOOLEAN), + Arguments.of(rs, JDBCType.SMALLINT), + Arguments.of(rs, JDBCType.DOUBLE), + Arguments.of(rs, JDBCType.DECIMAL), + Arguments.of(rs, JDBCType.REAL), + Arguments.of(rs, JDBCType.TINYINT), + Arguments.of(rs, JDBCType.DATE), + Arguments.of(rs, JDBCType.TIME), + Arguments.of(rs, JDBCType.TIMESTAMP), + Arguments.of(rs, JDBCType.VARBINARY), + Arguments.of(rs, JDBCType.ARRAY), + Arguments.of(rs, JDBCType.REF), + Arguments.of(rs, JDBCType.FLOAT) + ); } /* @@ -254,7 +252,7 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { private void compareMetaData(ResultSetMetaData rsmd, ResultSetMetaData rsmd1) throws SQLException { - assertEquals(rsmd1.getColumnCount(), rsmd.getColumnCount()); + assertEquals(rsmd.getColumnCount(), rsmd1.getColumnCount()); int cols = rsmd.getColumnCount(); for (int i = 1; i <= cols; i++) { assertTrue(rsmd1.getCatalogName(i).equals(rsmd.getCatalogName(i))); @@ -356,26 +354,33 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate SyncProviderException is thrown when acceptChanges is called * but there is not a way to make a connection to the datasource */ - @Test(dataProvider = "rowSetType", expectedExceptions = SyncProviderException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0000(CachedRowSet rs) throws Exception { - rs.acceptChanges(); - rs.close(); + assertThrows(SyncProviderException.class, () -> { + rs.acceptChanges(); + rs.close(); + }); } /* * Validate SyncProviderException is thrown when acceptChanges is called * when null is passed as the datasource */ - @Test(dataProvider = "rowSetType", expectedExceptions = SyncProviderException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0001(CachedRowSet rs) throws Exception { - rs.acceptChanges(null); - rs.close(); + assertThrows(SyncProviderException.class, () -> { + rs.acceptChanges(null); + rs.close(); + }); } /* * Validate that that RIOPtimsticProvider is the default SyncProvider */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0002(CachedRowSet rs) throws SQLException { SyncProvider sp = rs.getSyncProvider(); assertTrue(sp instanceof com.sun.rowset.providers.RIOptimisticProvider); @@ -385,7 +390,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { /* * Validate that you can specify a SyncProvider */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0003(CachedRowSet rs) throws SQLException { // Register a provider and make sure it is avaiable @@ -400,7 +406,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { /* * Create a RowSetListener and validate that notifyRowSetChanged is called */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0004(CachedRowSet rs) throws Exception { TestRowSetListener rsl = new TestRowSetListener(); rs.addRowSetListener(rsl); @@ -412,7 +419,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { /* * Create a RowSetListener and validate that notifyRowSetChanged is called */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0005(CachedRowSet rs) throws Exception { TestRowSetListener rsl = new TestRowSetListener(); rs.addRowSetListener(rsl); @@ -424,7 +432,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { /* * Create a RowSetListener and validate that notifyRowChanged is called */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0006(RowSet rs) throws Exception { TestRowSetListener rsl = new TestRowSetListener(); rs.addRowSetListener(rsl); @@ -443,7 +452,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Create a multiple RowSetListeners and validate that notifyRowChanged, * notifiyMoved is called on all listners */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0007(RowSet rs) throws Exception { TestRowSetListener rsl = new TestRowSetListener(); TestRowSetListener rsl2 = new TestRowSetListener(); @@ -467,7 +477,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Create a RowSetListener and validate that notifyRowChanged and * notifyCursorMoved are called */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0008(CachedRowSet rs) throws Exception { TestRowSetListener rsl = new TestRowSetListener(); rs.addRowSetListener(rsl); @@ -487,7 +498,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { /* * Create a RowSetListener and validate that notifyCursorMoved is called */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0009(RowSet rs) throws Exception { TestRowSetListener rsl = new TestRowSetListener(); rs.addRowSetListener(rsl); @@ -499,7 +511,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { /* * Validate that getTableName() returns the proper values */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0010(CachedRowSet rs) throws Exception { assertNull(rs.getTableName()); rs.setTableName(COFFEE_HOUSES_TABLE); @@ -510,12 +523,13 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { /* * Validate that getKeyColumns() returns the proper values */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0011(CachedRowSet rs) throws Exception { int[] pkeys = {1, 3}; assertNull(rs.getKeyColumns()); rs.setKeyColumns(pkeys); - assertEquals(rs.getKeyColumns(), pkeys); + assertArrayEquals(pkeys, rs.getKeyColumns()); rs.close(); } @@ -523,52 +537,62 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate that setMatchColumn throws a SQLException if the column * index specified is out of range */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0012(CachedRowSet rs) throws Exception { - rs.setMatchColumn(-1); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.setMatchColumn(-1); + rs.close(); + }); } /* * Validate that setMatchColumn throws a SQLException if the column * index specified is out of range */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0013(CachedRowSet rs) throws Exception { - int[] cols = {1, -1}; - rs.setMatchColumn(cols); - rs.close(); + assertThrows(SQLException.class, () -> { + int[] cols = {1, -1}; + rs.setMatchColumn(cols); + rs.close(); + }); } /* * Validate that setMatchColumn throws a SQLException if the column * index specified is out of range */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0014(CachedRowSet rs) throws Exception { - rs.setMatchColumn((String) null); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.setMatchColumn((String) null); + rs.close(); + }); } /* * Validate that setMatchColumn throws a SQLException if the column * index specified is out of range */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0015(CachedRowSet rs) throws Exception { - String[] cols = {"ID", null}; - rs.setMatchColumn(cols); + assertThrows(SQLException.class, () -> { + String[] cols = {"ID", null}; + rs.setMatchColumn(cols); + }); } /* * Validate that getMatchColumn returns the same value specified by * setMatchColumn */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", enabled = false) + @Disabled + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0016(CachedRowSet rs) throws Exception { int[] expectedCols = {1}; String[] expectedColNames = {"ID"}; @@ -578,8 +602,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { for (int i = 0; i < actualCols.length; i++) { System.out.println(actualCols[i]); } - assertEquals(actualCols, expectedCols); - assertEquals(actualColNames, expectedColNames); + assertArrayEquals(expectedCols, actualCols); + assertArrayEquals(expectedColNames, actualColNames); rs.close(); } @@ -587,15 +611,17 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate that getMatchColumn returns the same value specified by * setMatchColumn */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", enabled = false) + @Disabled + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0017(CachedRowSet rs) throws Exception { int[] expectedCols = {1}; String[] expectedColNames = {"ID"}; rs.setMatchColumn(expectedColNames[0]); int[] actualCols = rs.getMatchColumnIndexes(); String[] actualColNames = rs.getMatchColumnNames(); - assertEquals(actualCols, expectedCols); - assertEquals(actualColNames, expectedColNames); + assertArrayEquals(expectedCols, actualCols); + assertArrayEquals(expectedColNames, actualColNames); rs.close(); } @@ -603,16 +629,18 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate that getMatchColumn returns the same valid value specified by * setMatchColumn */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", enabled = false) + @Disabled + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0018(CachedRowSet rs) throws Exception { int[] expectedCols = {1, 3}; String[] expectedColNames = {"COF_ID", "SUP_ID"}; rs.setMatchColumn(expectedCols); int[] actualCols = rs.getMatchColumnIndexes(); String[] actualColNames = rs.getMatchColumnNames(); - assertEquals(actualCols, expectedCols); - assertEquals(actualColNames, expectedColNames); - assertEquals(actualCols, expectedCols); + assertArrayEquals(expectedCols, actualCols); + assertArrayEquals(expectedColNames, actualColNames); + assertArrayEquals(expectedCols, actualCols); rs.close(); } @@ -620,15 +648,17 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate that getMatchColumn returns the same valid value specified by * setMatchColumn */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", enabled = false) + @Disabled + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0019(CachedRowSet rs) throws Exception { int[] expectedCols = {1, 3}; String[] expectedColNames = {"COF_ID", "SUP_ID"}; rs.setMatchColumn(expectedColNames); int[] actualCols = rs.getMatchColumnIndexes(); String[] actualColNames = rs.getMatchColumnNames(); - assertEquals(actualCols, expectedCols); - assertEquals(actualColNames, expectedColNames); + assertArrayEquals(expectedCols, actualCols); + assertArrayEquals(expectedColNames, actualColNames); rs.close(); } @@ -636,69 +666,78 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate that getMatchColumnIndexes throws a SQLException if * unsetMatchColumn has been called */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0020(CachedRowSet rs) throws Exception { - rs.setMatchColumn(1); - int[] actualCols = rs.getMatchColumnIndexes(); - assertTrue(actualCols != null); - rs.unsetMatchColumn(1); - actualCols = rs.getMatchColumnIndexes(); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.setMatchColumn(1); + int[] actualCols = rs.getMatchColumnIndexes(); + assertTrue(actualCols != null); + rs.unsetMatchColumn(1); + actualCols = rs.getMatchColumnIndexes(); + rs.close(); + }); } /* * Validate that getMatchColumnNames throws a SQLException if * unsetMatchColumn has been called */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0021(CachedRowSet rs) throws Exception { - String matchColumn = "ID"; - rs.setMatchColumn(matchColumn); - String[] actualColNames = rs.getMatchColumnNames(); - assertTrue(actualColNames != null); - rs.unsetMatchColumn(matchColumn); - actualColNames = rs.getMatchColumnNames(); - rs.close(); + assertThrows(SQLException.class, () -> { + String matchColumn = "ID"; + rs.setMatchColumn(matchColumn); + String[] actualColNames = rs.getMatchColumnNames(); + assertTrue(actualColNames != null); + rs.unsetMatchColumn(matchColumn); + actualColNames = rs.getMatchColumnNames(); + rs.close(); + }); } /* * Validate that getMatchColumnIndexes throws a SQLException if * unsetMatchColumn has been called */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0022(CachedRowSet rs) throws Exception { - int[] expectedCols = {1, 3}; - rs.setMatchColumn(expectedCols); - int[] actualCols = rs.getMatchColumnIndexes(); - assertTrue(actualCols != null); - rs.unsetMatchColumn(expectedCols); - actualCols = rs.getMatchColumnIndexes(); - rs.close(); + assertThrows(SQLException.class, () -> { + int[] expectedCols = {1, 3}; + rs.setMatchColumn(expectedCols); + int[] actualCols = rs.getMatchColumnIndexes(); + assertTrue(actualCols != null); + rs.unsetMatchColumn(expectedCols); + actualCols = rs.getMatchColumnIndexes(); + rs.close(); + }); } /* * Validate that getMatchColumnNames throws a SQLException if * unsetMatchColumn has been called */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0023(CachedRowSet rs) throws Exception { - String[] expectedColNames = {"COF_ID", "SUP_ID"}; - rs.setMatchColumn(expectedColNames); - String[] actualColNames = rs.getMatchColumnNames(); - assertTrue(actualColNames != null); - rs.unsetMatchColumn(expectedColNames); - actualColNames = rs.getMatchColumnNames(); - rs.close(); + assertThrows(SQLException.class, () -> { + String[] expectedColNames = {"COF_ID", "SUP_ID"}; + rs.setMatchColumn(expectedColNames); + String[] actualColNames = rs.getMatchColumnNames(); + assertTrue(actualColNames != null); + rs.unsetMatchColumn(expectedColNames); + actualColNames = rs.getMatchColumnNames(); + rs.close(); + }); } /* * Validate size() returns the correct number of rows */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0024(CachedRowSet rs) throws Exception { assertTrue(rs.size() == COFFEE_HOUSES_ROWS); rs.close(); @@ -708,9 +747,10 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate that the correct rows are returned comparing the primary * keys */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0025(RowSet rs) throws SQLException { - assertEquals(getPrimaryKeys(rs), COFFEE_HOUSES_PRIMARY_KEYS); + assertArrayEquals(COFFEE_HOUSES_PRIMARY_KEYS, getPrimaryKeys(rs)); rs.close(); } @@ -719,7 +759,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate the visibility of the row depending on the value of * setShowdelete */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0026(CachedRowSet rs) throws Exception { Object[] afterDelete = { 10023, 33002, 10040, 32001, 10042, 10024, 10039, 10041, @@ -727,13 +768,13 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { }; int rowToDelete = 10035; // All rows should be found - assertEquals(getPrimaryKeys(rs), COFFEE_HOUSES_PRIMARY_KEYS); + assertArrayEquals(COFFEE_HOUSES_PRIMARY_KEYS, getPrimaryKeys(rs)); // Delete the row assertTrue(deleteRowByPrimaryKey(rs, rowToDelete, 1)); // With setShowDeleted(false) which is the default, // the deleted row should not be visible assertFalse(findRowByPrimaryKey(rs, rowToDelete, 1)); - assertEquals(getPrimaryKeys(rs), afterDelete); + assertArrayEquals(afterDelete, getPrimaryKeys(rs)); assertTrue(rs.size() == COFFEE_HOUSES_ROWS); // With setShowDeleted(true), the deleted row should be visible rs.setShowDeleted(true); @@ -744,7 +785,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { /* * Validate that there is no page size by default */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0027(CachedRowSet rs) throws Exception { assertTrue(rs.getPageSize() == 0); rs.close(); @@ -754,7 +796,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate the value you set via setPageSize is returned by getPageSize * then reset to having no limit */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0028(CachedRowSet rs) throws Exception { int rows = 100; rs.setPageSize(rows); @@ -768,30 +811,39 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate SQLException is thrown when an invalid value is specified * for setPageSize */ - @Test(dataProvider = "rowSetType", expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0029(CachedRowSet rs) throws Exception { - rs.setPageSize(-1); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.setPageSize(-1); + rs.close(); + }); } /* * Validate SQLException is thrown when nextPage is called without a * call to populate or execute */ - @Test(dataProvider = "rowSetType", expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0030(CachedRowSet rs) throws Exception { - rs.nextPage(); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.nextPage(); + rs.close(); + }); } /* * Validate SQLException is thrown when previousPage is called without a * call to populate or execute */ - @Test(dataProvider = "rowSetType", expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0031(CachedRowSet rs) throws Exception { - rs.previousPage(); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.previousPage(); + rs.close(); + }); } @@ -799,40 +851,48 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate SQLException is thrown when execute is called * but there is not a way to make a connection to the datasource */ - @Test(dataProvider = "rowSetType", expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0032(CachedRowSet rs) throws Exception { - rs.execute(null); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.execute(null); + rs.close(); + }); } /* * Validate SQLException is thrown when execute is called * but there is not a way to make a connection to the datasource */ - @Test(dataProvider = "rowSetType", expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0033(CachedRowSet rs) throws Exception { - rs.execute(); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.execute(); + rs.close(); + }); } /* * Validate that toCollection() returns the proper values */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0034(CachedRowSet rs) throws Exception { Object[] cities = {"Mendocino", "Seattle", "SF", "Portland", "SF", "Sacramento", "Carmel", "LA", "Olympia", "Seattle", "SF", "LA", "San Jose", "Eugene"}; rs.beforeFirst(); - assertEquals(rs.toCollection(2).toArray(), cities); - assertEquals(rs.toCollection("CITY").toArray(), cities); + assertArrayEquals(cities, rs.toCollection(2).toArray()); + assertArrayEquals(cities, rs.toCollection("CITY").toArray()); rs.close(); } /* * Validate that toCollection() returns the proper values */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0035(CachedRowSet rs) throws Exception { Collection col = rs.toCollection(); assertTrue(rs.size() == col.size()); @@ -850,7 +910,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { /* * Validate that createCopy() returns the proper values */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0036(CachedRowSet rs) throws Exception { try (CachedRowSet crs1 = rs.createCopy()) { compareRowSets(rs, crs1); @@ -861,7 +922,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { /* * Validate that createCopySchema() returns the proper values */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0037(CachedRowSet rs) throws Exception { try (CachedRowSet crs1 = rs.createCopySchema()) { assertTrue(crs1.size() == 0); @@ -875,7 +937,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * and getMatchColumnIndexes should throw a SQLException. This test * specifies setMatchColumn(int) */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0038(CachedRowSet rs) throws Exception { rs.setMatchColumn(1); try (CachedRowSet crs1 = rs.createCopyNoConstraints()) { @@ -904,7 +967,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * and getMatchColumnIndexes should throw a SQLException. This test * specifies setMatchColumn(String) */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0039(CachedRowSet rs) throws Exception { rs.setMatchColumn("ID"); try (CachedRowSet crs1 = rs.createCopyNoConstraints()) { @@ -932,7 +996,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate that columnUpdated works with the various datatypes specifying * the column index */ - @Test(dataProvider = "rowsetUsingDataTypes") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingDataTypes") public void commonCachedRowSetTest0040(CachedRowSet rs, JDBCType type) throws Exception { rs.beforeFirst(); assertTrue(rs.next()); @@ -1029,7 +1094,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate that columnUpdated works with the various datatypes specifying * the column name */ - @Test(dataProvider = "rowsetUsingDataTypes") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingDataTypes") public void commonCachedRowSetTest0041(CachedRowSet rs, JDBCType type) throws Exception { rs.beforeFirst(); assertTrue(rs.next()); @@ -1127,7 +1193,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate isBeforeFirst(), isFirst() and first() return the correct * results */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0042(RowSet rs) throws Exception { assertFalse(rs.isBeforeFirst()); assertFalse(rs.isFirst()); @@ -1150,7 +1217,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate isAfterLast(), isLast() and last() return the correct * results */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0043(RowSet rs) throws Exception { assertFalse(rs.isAfterLast()); assertFalse(rs.isLast()); @@ -1173,121 +1241,140 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate a SQLException is thrown when undoDelete is called on the * insertRow */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0044(CachedRowSet rs) throws Exception { - rs.insertRow(); - rs.undoDelete(); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.insertRow(); + rs.undoDelete(); + rs.close(); + }); } /* * Validate a SQLException is thrown when undoDelete is called when * cursor is before the first row */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0045(CachedRowSet rs) throws Exception { - rs.setShowDeleted(true); - rs.beforeFirst(); - rs.undoDelete(); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.setShowDeleted(true); + rs.beforeFirst(); + rs.undoDelete(); + rs.close(); + }); } /* * Validate a SQLException is thrown when undoDelete is called when * cursor is after the last row */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0046(CachedRowSet rs) throws Exception { - rs.setShowDeleted(true); - rs.afterLast(); - rs.undoDelete(); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.setShowDeleted(true); + rs.afterLast(); + rs.undoDelete(); + rs.close(); + }); } /* * Validate a SQLException is thrown when undoUpdate is called on the * insertRow */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0047(CachedRowSet rs) throws Exception { - rs.insertRow(); - rs.undoUpdate(); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.insertRow(); + rs.undoUpdate(); + rs.close(); + }); } /* * Validate a SQLException is thrown when undoUpdate is called when * cursor is before the first row */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0048(CachedRowSet rs) throws Exception { - rs.setShowDeleted(true); - rs.beforeFirst(); - rs.undoUpdate(); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.setShowDeleted(true); + rs.beforeFirst(); + rs.undoUpdate(); + rs.close(); + }); } /* * Validate a SQLException is thrown when undoUpdate is called when * cursor is after the last row */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0049(CachedRowSet rs) throws Exception { - rs.setShowDeleted(true); - rs.afterLast(); - rs.undoUpdate(); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.setShowDeleted(true); + rs.afterLast(); + rs.undoUpdate(); + rs.close(); + }); } /* * Validate a SQLException is thrown when undoInsert is called on the * insertRow */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0050(CachedRowSet rs) throws Exception { - rs.insertRow(); - rs.undoInsert(); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.insertRow(); + rs.undoInsert(); + rs.close(); + }); } /* * Validate a SQLException is thrown when undoInsert is called when * cursor is before the first row */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0051(CachedRowSet rs) throws Exception { - rs.setShowDeleted(true); - rs.beforeFirst(); - rs.undoInsert(); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.setShowDeleted(true); + rs.beforeFirst(); + rs.undoInsert(); + rs.close(); + }); } /* * Validate a SQLException is thrown when undoInsert is called when * cursor is after the last row */ - @Test(dataProvider = "rowsetUsingCoffeeHouses", - expectedExceptions = SQLException.class) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0052(CachedRowSet rs) throws Exception { - rs.setShowDeleted(true); - rs.afterLast(); - rs.undoInsert(); - rs.close(); + assertThrows(SQLException.class, () -> { + rs.setShowDeleted(true); + rs.afterLast(); + rs.undoInsert(); + rs.close(); + }); } /* * Insert a row, then call undoInsert to roll back the insert and validate * the row is not there */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0053(CachedRowSet rs) throws Exception { int rowToInsert = 1961; assertTrue(rs.size() == COFFEE_HOUSES_ROWS); @@ -1314,7 +1401,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Insert a row, delete the row and then call undoDelete to make sure it * is comes back */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0054(CachedRowSet rs) throws Exception { int rowToDelete = 1961; assertTrue(rs.size() == COFFEE_HOUSES_ROWS); @@ -1348,7 +1436,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Insert a row, modify a field and then call undoUpdate to revert the * insert */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0055(CachedRowSet rs) throws Exception { int rowToInsert = 1961; assertTrue(rs.size() == COFFEE_HOUSES_ROWS); @@ -1385,7 +1474,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate getOriginal returns a ResultSet which is a copy of the original * RowSet */ - @Test(dataProvider = "rowsetUsingCoffees") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffees") public void commonCachedRowSetTest0056(CachedRowSet rs) throws Exception { String coffee = "Hazelnut"; int sales = 100; @@ -1414,12 +1504,12 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { assertTrue(rs1.getInt(1) == origId); assertTrue(rs1.getString(2).equals(origCoffee)); assertTrue(rs1.getInt(5) == origSales); - assertEquals(getPrimaryKeys(rs1), COFFEES_PRIMARY_KEYS); + assertArrayEquals(COFFEES_PRIMARY_KEYS, getPrimaryKeys(rs1)); // Check current rowset assertTrue(rs.getInt(1) == id); assertTrue(rs.getString(2).equals(coffee)); assertTrue(rs.getInt(5) == sales); - assertEquals(getPrimaryKeys(rs), updatedPkeys); + assertArrayEquals(updatedPkeys, getPrimaryKeys(rs)); } rs.close(); } @@ -1428,7 +1518,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate getOriginalRow returns a ResultSet which is a copy of the * original row that was modified */ - @Test(dataProvider = "rowsetUsingCoffees") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffees") public void commonCachedRowSetTest0057(CachedRowSet rs) throws Exception { String coffee = "Hazelnut"; int sales = 100; @@ -1463,7 +1554,7 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { assertTrue(rs.getInt(1) == id); assertTrue(rs.getString(2).equals(coffee)); assertTrue(rs.getInt(5) == sales); - assertEquals(getPrimaryKeys(rs), updatedPkeys); + assertArrayEquals(updatedPkeys, getPrimaryKeys(rs)); } rs.close(); } @@ -1472,7 +1563,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate that restoreOrginal will restore the RowSet to its * state prior to the insert of a row */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0058(CachedRowSet rs) throws Exception { int rowToInsert = 1961; assertTrue(rs.size() == COFFEE_HOUSES_ROWS); @@ -1509,7 +1601,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate that restoreOrginal will restore the RowSet to its * state prior to deleting a row */ - @Test(dataProvider = "rowsetUsingCoffees", enabled = true) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffees") public void commonCachedRowSetTest0059(CachedRowSet rs) throws Exception { int rowToDelete = 2; try (CachedRowSet crs1 = rsf.createCachedRowSet()) { @@ -1540,7 +1633,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate that restoreOrginal will restore the RowSet to its * state prior to updating a row */ - @Test(dataProvider = "rowsetUsingCoffees", enabled = true) + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffees") public void commonCachedRowSetTest0060(CachedRowSet rs) throws Exception { int rowToUpdate = 2; String coffee = "Hazelnut"; @@ -1578,7 +1672,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Initialize a RowSet via the populate method. Validate it matches * the original ResultSet */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0061(CachedRowSet rs) throws Exception { try (CachedRowSet crs1 = rsf.createCachedRowSet()) { rs.beforeFirst(); @@ -1593,7 +1688,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { * Validate it matches the original ResultSet starting for the specofied * offset */ - @Test(dataProvider = "rowsetUsingCoffeeHouses") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffeeHouses") public void commonCachedRowSetTest0062(CachedRowSet rs) throws Exception { Object[] expectedRows = { 32001, 10042, 10024, 10039, 10041, 33005, 33010, 10035, 10037, @@ -1603,8 +1699,8 @@ public abstract class CommonCachedRowSetTests extends CommonRowSetTests { try (CachedRowSet crs1 = rsf.createCachedRowSet()) { rs.beforeFirst(); crs1.populate(rs, startingRow); - assertEquals(crs1.size(), COFFEE_HOUSES_ROWS - startingRow + 1); - assertEquals(getPrimaryKeys(crs1), expectedRows); + assertEquals(COFFEE_HOUSES_ROWS - startingRow + 1, crs1.size()); + assertArrayEquals(expectedRows, getPrimaryKeys(crs1)); } rs.close(); } diff --git a/test/jdk/javax/sql/testng/test/rowset/filteredrowset/CityFilter.java b/test/jdk/javax/sql/test/rowset/filteredrowset/CityFilter.java similarity index 97% rename from test/jdk/javax/sql/testng/test/rowset/filteredrowset/CityFilter.java rename to test/jdk/javax/sql/test/rowset/filteredrowset/CityFilter.java index 2188c4eed08..458088ccb45 100644 --- a/test/jdk/javax/sql/testng/test/rowset/filteredrowset/CityFilter.java +++ b/test/jdk/javax/sql/test/rowset/filteredrowset/CityFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/test/rowset/filteredrowset/FilteredRowSetTests.java b/test/jdk/javax/sql/test/rowset/filteredrowset/FilteredRowSetTests.java similarity index 81% rename from test/jdk/javax/sql/testng/test/rowset/filteredrowset/FilteredRowSetTests.java rename to test/jdk/javax/sql/test/rowset/filteredrowset/FilteredRowSetTests.java index 263a79a68b6..55d9323f373 100644 --- a/test/jdk/javax/sql/testng/test/rowset/filteredrowset/FilteredRowSetTests.java +++ b/test/jdk/javax/sql/test/rowset/filteredrowset/FilteredRowSetTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,24 +26,30 @@ import java.sql.SQLException; import javax.sql.RowSet; import javax.sql.rowset.FilteredRowSet; import javax.sql.rowset.Predicate; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; + +import org.junit.jupiter.api.AfterEach; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import test.rowset.webrowset.CommonWebRowSetTests; public class FilteredRowSetTests extends CommonWebRowSetTests { private FilteredRowSet frs; - @BeforeMethod + @BeforeEach public void setUpMethod() throws Exception { frs = createCoffeeHousesRowSet(); } - @AfterMethod + @AfterEach public void tearDownMethod() throws Exception { frs.close(); } @@ -83,7 +89,7 @@ public class FilteredRowSetTests extends CommonWebRowSetTests { 10023, 10040, 10042, 10024, 10039, 10041, 10035, 10037, 10034 }; frs.setFilter(new PrimaryKeyFilter(10000, 10999, 1)); - assertEquals(getPrimaryKeys(frs), expectedKeys); + assertArrayEquals(expectedKeys, getPrimaryKeys(frs)); } /* @@ -96,7 +102,7 @@ public class FilteredRowSetTests extends CommonWebRowSetTests { 10023, 10040, 10042, 10024, 10039, 10041, 10035, 10037, 10034 }; frs.setFilter(new PrimaryKeyFilter(10000, 10999, "STORE_ID")); - assertEquals(getPrimaryKeys(frs), expectedKeys); + assertArrayEquals(expectedKeys, getPrimaryKeys(frs)); } @@ -111,7 +117,7 @@ public class FilteredRowSetTests extends CommonWebRowSetTests { }; String[] cityArray = {"SF", "LA"}; frs.setFilter(new CityFilter(cityArray, 2)); - assertEquals(getPrimaryKeys(frs), expectedKeys); + assertArrayEquals(expectedKeys, getPrimaryKeys(frs)); } /* @@ -125,14 +131,16 @@ public class FilteredRowSetTests extends CommonWebRowSetTests { }; String[] cityArray = {"SF", "LA"}; frs.setFilter(new CityFilter(cityArray, "CITY")); - assertEquals(getPrimaryKeys(frs), expectedKeys); + assertArrayEquals(expectedKeys, getPrimaryKeys(frs)); } // Tests that are common but need to be disabled due to an implementation bug - @Test(dataProvider = "rowSetType", enabled = false) + @Disabled + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0043(RowSet rs) throws Exception { // Need to fix bug in FilteredRowSets } diff --git a/test/jdk/javax/sql/testng/test/rowset/filteredrowset/PrimaryKeyFilter.java b/test/jdk/javax/sql/test/rowset/filteredrowset/PrimaryKeyFilter.java similarity index 97% rename from test/jdk/javax/sql/testng/test/rowset/filteredrowset/PrimaryKeyFilter.java rename to test/jdk/javax/sql/test/rowset/filteredrowset/PrimaryKeyFilter.java index 2a748314006..0353312419c 100644 --- a/test/jdk/javax/sql/testng/test/rowset/filteredrowset/PrimaryKeyFilter.java +++ b/test/jdk/javax/sql/test/rowset/filteredrowset/PrimaryKeyFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/test/rowset/jdbcrowset/JdbcRowSetDriverManagerTest.java b/test/jdk/javax/sql/test/rowset/jdbcrowset/JdbcRowSetDriverManagerTest.java similarity index 95% rename from test/jdk/javax/sql/testng/test/rowset/jdbcrowset/JdbcRowSetDriverManagerTest.java rename to test/jdk/javax/sql/test/rowset/jdbcrowset/JdbcRowSetDriverManagerTest.java index be86798177a..5b135e16b5c 100644 --- a/test/jdk/javax/sql/testng/test/rowset/jdbcrowset/JdbcRowSetDriverManagerTest.java +++ b/test/jdk/javax/sql/test/rowset/jdbcrowset/JdbcRowSetDriverManagerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,9 @@ import java.sql.SQLException; import javax.sql.rowset.JdbcRowSet; import javax.sql.rowset.RowSetFactory; import javax.sql.rowset.RowSetProvider; -import org.testng.annotations.Test; + +import org.junit.jupiter.api.Test; + import util.BaseTest; import util.StubDriver; @@ -41,7 +43,7 @@ public class JdbcRowSetDriverManagerTest extends BaseTest { * Validate that JDBCRowSetImpl can connect to a JDBC driver that is * register by DriverManager. */ - @Test(enabled = true) + @Test public void test0000() throws SQLException { DriverManager.registerDriver(new StubDriver()); diff --git a/test/jdk/javax/sql/testng/test/rowset/joinrowset/JoinRowSetTests.java b/test/jdk/javax/sql/test/rowset/joinrowset/JoinRowSetTests.java similarity index 83% rename from test/jdk/javax/sql/testng/test/rowset/joinrowset/JoinRowSetTests.java rename to test/jdk/javax/sql/test/rowset/joinrowset/JoinRowSetTests.java index b84453e9a3b..92ce09bcf85 100644 --- a/test/jdk/javax/sql/testng/test/rowset/joinrowset/JoinRowSetTests.java +++ b/test/jdk/javax/sql/test/rowset/joinrowset/JoinRowSetTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,16 +26,22 @@ import java.sql.SQLException; import java.sql.Types; import java.util.ArrayList; import java.util.List; +import java.util.stream.Stream; import javax.sql.RowSet; import javax.sql.rowset.CachedRowSet; import javax.sql.rowset.JoinRowSet; import javax.sql.rowset.RowSetMetaDataImpl; import javax.sql.rowset.WebRowSet; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + import test.rowset.webrowset.CommonWebRowSetTests; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + public class JoinRowSetTests extends CommonWebRowSetTests { private final String SUPPLIERS_TABLE = "SUPPLIERS"; @@ -150,8 +156,7 @@ public class JoinRowSetTests extends CommonWebRowSetTests { /* * DataProvider used to set parameters for basic types that are supported */ - @DataProvider(name = "createCachedRowSetsToUse") - private Object[][] createCachedRowSetsToUse() throws SQLException { + private Stream createCachedRowSetsToUse() throws SQLException { CachedRowSet crs = rsf.createCachedRowSet(); initCoffeesMetaData(crs); createCoffeesRows(crs); @@ -162,9 +167,7 @@ public class JoinRowSetTests extends CommonWebRowSetTests { createSuppiersRows(crs1); // Make sure you are not on the insertRow crs1.moveToCurrentRow(); - return new Object[][]{ - {crs, crs1} - }; + return Stream.of(Arguments.of(crs, crs1)); } /* @@ -178,13 +181,14 @@ public class JoinRowSetTests extends CommonWebRowSetTests { results.add(jrs.getInt("COF_ID")); } } - assertEquals(results.toArray(), EXPECTED); + assertArrayEquals(EXPECTED, results.toArray()); } /* * Join two CachedRowSets specifying a column name to join against */ - @Test(dataProvider = "createCachedRowSetsToUse") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("createCachedRowSetsToUse") public void joinRowSetTests0000(CachedRowSet crs, CachedRowSet crs1) throws Exception { @@ -200,7 +204,8 @@ public class JoinRowSetTests extends CommonWebRowSetTests { /* * Join two CachedRowSets specifying a column index to join against */ - @Test(dataProvider = "createCachedRowSetsToUse") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("createCachedRowSetsToUse") public void joinRowSetTests0001(CachedRowSet crs, CachedRowSet crs1) throws Exception { @@ -216,7 +221,8 @@ public class JoinRowSetTests extends CommonWebRowSetTests { /* * Join two CachedRowSets specifying a column name to join against */ - @Test(dataProvider = "createCachedRowSetsToUse") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("createCachedRowSetsToUse") public void joinRowSetTests0002(CachedRowSet crs, CachedRowSet crs1) throws Exception { @@ -233,7 +239,8 @@ public class JoinRowSetTests extends CommonWebRowSetTests { /* * Join two CachedRowSets specifying a column index to join against */ - @Test(dataProvider = "createCachedRowSetsToUse") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("createCachedRowSetsToUse") public void joinRowSetTests0003(CachedRowSet crs, CachedRowSet crs1) throws Exception { @@ -251,7 +258,8 @@ public class JoinRowSetTests extends CommonWebRowSetTests { /* * Join two CachedRowSets specifying a column name to join against */ - @Test(dataProvider = "createCachedRowSetsToUse") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("createCachedRowSetsToUse") public void joinRowSetTests0005(CachedRowSet crs, CachedRowSet crs1) throws Exception { @@ -269,7 +277,8 @@ public class JoinRowSetTests extends CommonWebRowSetTests { /* * Join two CachedRowSets specifying a column index to join against */ - @Test(dataProvider = "createCachedRowSetsToUse") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("createCachedRowSetsToUse") public void joinRowSetTests0006(CachedRowSet crs, CachedRowSet crs1) throws Exception { @@ -286,39 +295,56 @@ public class JoinRowSetTests extends CommonWebRowSetTests { } // Disabled tests due to bugs in JoinRowSet - @Test(dataProvider = "rowSetType", enabled = false) + @Disabled + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0004(CachedRowSet rs) throws Exception { } - @Test(dataProvider = "rowSetType", enabled = false) + @Disabled + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0005(CachedRowSet rs) throws Exception { } - @Test(dataProvider = "rowSetType", enabled = false) + @Disabled + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0008(CachedRowSet rs) throws Exception { } - @Test(dataProvider = "rowSetType", enabled = false) + @Disabled + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0026(CachedRowSet rs) throws Exception { } - @Test(dataProvider = "rowSetType", enabled = false) + @Disabled + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0027(CachedRowSet rs) throws Exception { } - @Test(dataProvider = "rowSetType", enabled = false) + @Disabled + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0053(CachedRowSet rs) throws Exception { } - @Test(dataProvider = "rowSetType", enabled = false) + @Disabled + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0054(CachedRowSet rs) throws Exception { } - @Test(dataProvider = "rowSetType", enabled = false) + @Disabled + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void commonCachedRowSetTest0055(CachedRowSet rs) throws Exception { } - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void WebRowSetTest0009(WebRowSet wrs1) throws Exception { } } diff --git a/test/jdk/javax/sql/test/rowset/resourcebundle/TEST.properties b/test/jdk/javax/sql/test/rowset/resourcebundle/TEST.properties new file mode 100644 index 00000000000..045227a0c2b --- /dev/null +++ b/test/jdk/javax/sql/test/rowset/resourcebundle/TEST.properties @@ -0,0 +1,2 @@ +# Enabled for ValidateGetBundle.java +modules = java.sql.rowset/com.sun.rowset:+open diff --git a/test/jdk/javax/sql/resourceBundleTests/ValidateGetBundle.java b/test/jdk/javax/sql/test/rowset/resourcebundle/ValidateGetBundle.java similarity index 94% rename from test/jdk/javax/sql/resourceBundleTests/ValidateGetBundle.java rename to test/jdk/javax/sql/test/rowset/resourcebundle/ValidateGetBundle.java index be17caed5c8..63f12740c09 100644 --- a/test/jdk/javax/sql/resourceBundleTests/ValidateGetBundle.java +++ b/test/jdk/javax/sql/test/rowset/resourcebundle/ValidateGetBundle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package test.rowset.resourcebundle; import com.sun.rowset.JdbcRowSetResourceBundle; @@ -35,8 +36,6 @@ import org.junit.jupiter.params.provider.Arguments; * @test * @bug 8294989 * @summary Check JDBC RowSet resource bundle access - * @modules java.sql.rowset/com.sun.rowset:+open - * @run junit/othervm ValidateGetBundle */ public class ValidateGetBundle{ diff --git a/test/jdk/javax/sql/testng/test/rowset/ValidateResourceBundleAccess.java b/test/jdk/javax/sql/test/rowset/resourcebundle/ValidateResourceBundleAccess.java similarity index 89% rename from test/jdk/javax/sql/testng/test/rowset/ValidateResourceBundleAccess.java rename to test/jdk/javax/sql/test/rowset/resourcebundle/ValidateResourceBundleAccess.java index 7591891c42b..5deca26cb25 100644 --- a/test/jdk/javax/sql/testng/test/rowset/ValidateResourceBundleAccess.java +++ b/test/jdk/javax/sql/test/rowset/resourcebundle/ValidateResourceBundleAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,21 +20,21 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.rowset; +package test.rowset.resourcebundle; import java.util.Locale; import java.sql.SQLException; import javax.sql.rowset.RowSetProvider; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeClass; -import static org.testng.Assert.*; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; /** * @test * @bug 8294989 * @summary Check that the resource bundle can be accessed * @throws SQLException if an unexpected error occurs - * @run testng/othervm */ public class ValidateResourceBundleAccess{ // Expected JDBCResourceBundle message, jdbcrowsetimpl.invalstate @@ -43,8 +43,8 @@ public class ValidateResourceBundleAccess{ private static final String RSREADERERROR = "Internal Error in RowSetReader: no connection or command"; // Checking against English messages, set to US Locale - @BeforeClass - public void setEnglishEnvironment() { + @BeforeAll + public static void setEnglishEnvironment() { Locale.setDefault(Locale.US); } diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java b/test/jdk/javax/sql/test/rowset/serial/SQLInputImplTests.java similarity index 92% rename from test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java rename to test/jdk/javax/sql/test/rowset/serial/SQLInputImplTests.java index 5bd10ed8848..33efda61c4e 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java +++ b/test/jdk/javax/sql/test/rowset/serial/SQLInputImplTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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 @@ -33,9 +33,11 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; import javax.sql.rowset.serial.SQLInputImpl; -import static org.testng.Assert.*; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import util.BaseTest; import util.StubArray; import util.StubBlob; @@ -54,7 +56,7 @@ public class SQLInputImplTests extends BaseTest { private SuperHero hero; private final String sqlType = "SUPERHERO"; - @BeforeMethod + @BeforeEach public void setUpMethod() throws Exception { map = new HashMap<>(); impl = new TestSQLDataImpl("TestSQLData"); @@ -68,18 +70,22 @@ public class SQLInputImplTests extends BaseTest { * Validate that a SQLException is thrown if the attribute value is * null */ - @Test(expectedExceptions = SQLException.class) + @Test public void test() throws Exception { - SQLInputImpl x = new SQLInputImpl(null, map); + assertThrows(SQLException.class, () -> { + SQLInputImpl x = new SQLInputImpl(null, map); + }); } /* * Validate that a SQLException is thrown if the map value is * null */ - @Test(expectedExceptions = SQLException.class) + @Test public void test02() throws Exception { - SQLInputImpl x = new SQLInputImpl(typeValues, null); + assertThrows(SQLException.class, () -> { + SQLInputImpl x = new SQLInputImpl(typeValues, null); + }); } /* @@ -124,7 +130,7 @@ public class SQLInputImplTests extends BaseTest { /* * Validate a Array can be read */ - @Test(enabled = true) + @Test public void test06() throws Exception { Object[] coffees = new Object[]{"Espresso", "Colombian", "French Roast", "Cappuccino"}; @@ -139,7 +145,7 @@ public class SQLInputImplTests extends BaseTest { /* * Validate a Blob can be read */ - @Test(enabled = true) + @Test public void test07() throws Exception { Blob b = new StubBlob(); Object[] values = {b}; @@ -153,7 +159,7 @@ public class SQLInputImplTests extends BaseTest { /* * Validate a Clob can be read */ - @Test(enabled = true) + @Test public void test08() throws Exception { Clob c = new StubClob(); Object[] values = {c}; @@ -166,7 +172,7 @@ public class SQLInputImplTests extends BaseTest { /* * Validate a Ref can be read */ - @Test(enabled = true) + @Test public void test09() throws Exception { Ref ref = new StubRef(sqlType, hero); Object[] values = {ref}; @@ -179,7 +185,7 @@ public class SQLInputImplTests extends BaseTest { /* * Validate a URL can be read */ - @Test(enabled = true) + @Test public void test10() throws Exception { URL u = new URL("http://www.oracle.com/"); Object[] values = {u}; diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SQLOutputImplTests.java b/test/jdk/javax/sql/test/rowset/serial/SQLOutputImplTests.java similarity index 91% rename from test/jdk/javax/sql/testng/test/rowset/serial/SQLOutputImplTests.java rename to test/jdk/javax/sql/test/rowset/serial/SQLOutputImplTests.java index 1f90c9981a7..83712e81396 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SQLOutputImplTests.java +++ b/test/jdk/javax/sql/test/rowset/serial/SQLOutputImplTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,9 +41,11 @@ import javax.sql.rowset.serial.SerialClob; import javax.sql.rowset.serial.SerialDatalink; import javax.sql.rowset.serial.SerialRef; import javax.sql.rowset.serial.SerialStruct; -import static org.testng.Assert.*; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import util.BaseTest; import util.StubArray; import util.StubBlob; @@ -64,7 +66,7 @@ public class SQLOutputImplTests extends BaseTest { private SuperHero hero; private SQLOutputImpl outImpl; - @BeforeMethod + @BeforeEach public void setUpMethod() throws Exception { results = new Vector(); impl = new TestSQLDataImpl("TestSQLData"); @@ -78,18 +80,22 @@ public class SQLOutputImplTests extends BaseTest { * Validate that a SQLException is thrown if the attribute value is * null */ - @Test(expectedExceptions = SQLException.class) + @Test public void test() throws Exception { - SQLOutputImpl x = new SQLOutputImpl(null, map); + assertThrows(SQLException.class, () -> { + SQLOutputImpl x = new SQLOutputImpl(null, map); + }); } /* * Validate that a SQLException is thrown if the map value is * null */ - @Test(expectedExceptions = SQLException.class) + @Test public void test02() throws Exception { - SQLOutputImpl x = new SQLOutputImpl(results, null); + assertThrows(SQLException.class, () -> { + SQLOutputImpl x = new SQLOutputImpl(results, null); + }); } /* @@ -109,7 +115,7 @@ public class SQLOutputImplTests extends BaseTest { /* * Validate a Array can be written and returned */ - @Test(enabled = true) + @Test public void test04() throws Exception { Object[] coffees = new Object[]{"Espresso", "Colombian", "French Roast", "Cappuccino"}; @@ -123,7 +129,7 @@ public class SQLOutputImplTests extends BaseTest { /* * Validate a Blob can be written and returned */ - @Test(enabled = true) + @Test public void test05() throws Exception { Blob b = new StubBlob(); outImpl.writeBlob(b); @@ -136,7 +142,7 @@ public class SQLOutputImplTests extends BaseTest { /* * Validate a Clob can be written and returned */ - @Test(enabled = true) + @Test public void test06() throws Exception { Clob c = new StubClob(); outImpl.writeClob(c); @@ -148,7 +154,7 @@ public class SQLOutputImplTests extends BaseTest { /* * Validate a Ref can be written and returned */ - @Test(enabled = true) + @Test public void test07() throws Exception { Ref ref = new StubRef(sqlType, hero); outImpl.writeRef(ref); @@ -159,7 +165,7 @@ public class SQLOutputImplTests extends BaseTest { /* * Validate a Struct can be written and returned */ - @Test(enabled = true) + @Test public void test08() throws Exception { Object[] attributes = new Object[]{"Bruce", "Wayne", 1939, "Batman"}; @@ -173,7 +179,7 @@ public class SQLOutputImplTests extends BaseTest { /* * Validate a DataLink can be written and returned */ - @Test(enabled = true) + @Test public void test09() throws Exception { URL u = new URL("http://www.oracle.com/"); outImpl.writeURL(u); @@ -186,7 +192,7 @@ public class SQLOutputImplTests extends BaseTest { /* * Validate an Object implementing SQLData can be written and returned */ - @Test(enabled = true) + @Test public void test10() throws Exception { Object[] attributes = new Object[]{"Bruce", "Wayne", 1939, "Batman"}; diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SerialArrayTests.java b/test/jdk/javax/sql/test/rowset/serial/SerialArrayTests.java similarity index 72% rename from test/jdk/javax/sql/testng/test/rowset/serial/SerialArrayTests.java rename to test/jdk/javax/sql/test/rowset/serial/SerialArrayTests.java index 345315b7f05..892de9416a1 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SerialArrayTests.java +++ b/test/jdk/javax/sql/test/rowset/serial/SerialArrayTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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 @@ -29,9 +29,11 @@ import java.util.HashMap; import java.util.Map; import javax.sql.rowset.serial.SerialArray; import javax.sql.rowset.serial.SerialException; -import static org.testng.Assert.*; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import util.BaseTest; import util.StubArray; @@ -42,7 +44,7 @@ public class SerialArrayTests extends BaseTest { private Array a; private Map> map; - @BeforeMethod + @BeforeEach public void setUpMethod() throws Exception { coffees = new Object[]{"Espresso", "Colombian", "French Roast", "Cappuccino"}; @@ -61,111 +63,133 @@ public class SerialArrayTests extends BaseTest { /* * Validate a SQLException is thrown if the map is null */ - @Test(expectedExceptions = SQLException.class) + @Test public void test02() throws Exception { - SerialArray sa = new SerialArray(a, null); + assertThrows(SQLException.class, () -> { + SerialArray sa = new SerialArray(a, null); + }); } /* * Validate a SerialException is thrown when getResultSet() is called */ - @Test(expectedExceptions = SerialException.class) + @Test public void test03() throws Exception { - SerialArray sa = new SerialArray(a); - sa.getResultSet(); + assertThrows(SerialException.class, () -> { + SerialArray sa = new SerialArray(a); + sa.getResultSet(); + }); } /* * Validate a SerialException is thrown when getResultSet() is called */ - @Test(expectedExceptions = SerialException.class) + @Test public void test04() throws Exception { - SerialArray sa = new SerialArray(a); - sa.getResultSet(null); + assertThrows(SerialException.class, () -> { + SerialArray sa = new SerialArray(a); + sa.getResultSet(null); + }); } /* * Validate a SerialException is thrown when getResultSet() is called */ - @Test(expectedExceptions = SerialException.class) + @Test public void test05() throws Exception { - SerialArray sa = new SerialArray(a); - sa.getResultSet(1, 1); + assertThrows(SerialException.class, () -> { + SerialArray sa = new SerialArray(a); + sa.getResultSet(1, 1); + }); } /* * Validate a SerialException is thrown when getResultSet() is called */ - @Test(expectedExceptions = SerialException.class) + @Test public void test06() throws Exception { - SerialArray sa = new SerialArray(a); - sa.getResultSet(1, 1, null); + assertThrows(SerialException.class, () -> { + SerialArray sa = new SerialArray(a); + sa.getResultSet(1, 1, null); + }); } /* * Validate a SerialException is thrown when getArray() is invoked after * free() is called */ - @Test(expectedExceptions = SerialException.class) + @Test public void test07() throws Exception { - SerialArray sa = new SerialArray(a); - sa.free(); - sa.getArray(); + assertThrows(SerialException.class, () -> { + SerialArray sa = new SerialArray(a); + sa.free(); + sa.getArray(); + }); } /* * Validate a SerialException is thrown when getArray() is invoked after * free() is called */ - @Test(expectedExceptions = SerialException.class) + @Test public void test08() throws Exception { - SerialArray sa = new SerialArray(a); - sa.free(); - sa.getArray(map); + assertThrows(SerialException.class, () -> { + SerialArray sa = new SerialArray(a); + sa.free(); + sa.getArray(map); + }); } /* * Validate a SerialException is thrown when getArray() is invoked after * free() is called */ - @Test(expectedExceptions = SerialException.class) + @Test public void test09() throws Exception { - SerialArray sa = new SerialArray(a); - sa.free(); - sa.getArray(1, 1, map); + assertThrows(SerialException.class, () -> { + SerialArray sa = new SerialArray(a); + sa.free(); + sa.getArray(1, 1, map); + }); } /* * Validate a SerialException is thrown when getArray() is invoked after * free() is called */ - @Test(expectedExceptions = SerialException.class) + @Test public void test10() throws Exception { - SerialArray sa = new SerialArray(a); - sa.free(); - sa.getArray(1, 1); + assertThrows(SerialException.class, () -> { + SerialArray sa = new SerialArray(a); + sa.free(); + sa.getArray(1, 1); + }); } /* * Validate a SerialException is thrown when getBaseType() is invoked after * free() is called */ - @Test(expectedExceptions = SerialException.class) + @Test public void test11() throws Exception { - SerialArray sa = new SerialArray(a); - sa.free(); - sa.getBaseType(); + assertThrows(SerialException.class, () -> { + SerialArray sa = new SerialArray(a); + sa.free(); + sa.getBaseType(); + }); } /* * Validate a SerialException is thrown when getBaseTypeName() is invoked after * free() is called */ - @Test(expectedExceptions = SerialException.class) + @Test public void test12() throws Exception { - SerialArray sa = new SerialArray(a); - sa.free(); - sa.getBaseTypeName(); + assertThrows(SerialException.class, () -> { + SerialArray sa = new SerialArray(a); + sa.free(); + sa.getBaseTypeName(); + }); } /* diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SerialBlobTests.java b/test/jdk/javax/sql/test/rowset/serial/SerialBlobTests.java similarity index 69% rename from test/jdk/javax/sql/testng/test/rowset/serial/SerialBlobTests.java rename to test/jdk/javax/sql/test/rowset/serial/SerialBlobTests.java index f3f6c327683..f4a32bc19d7 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SerialBlobTests.java +++ b/test/jdk/javax/sql/test/rowset/serial/SerialBlobTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,11 +24,14 @@ package test.rowset.serial; import java.io.InputStream; import java.io.OutputStream; +import java.sql.SQLException; import java.util.Arrays; import javax.sql.rowset.serial.SerialBlob; import javax.sql.rowset.serial.SerialException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; import util.StubBlob; @@ -37,6 +40,16 @@ public class SerialBlobTests extends BaseTest { // byte[] used to populate SerialBlob private byte[] bytes = new byte[]{1, 2, 3, 4, 5}; + /* + * Validate calling setBinaryStream() on a SerialBlob constructed from a + * byte array throws SerialException. Bug 7077451. + */ + @Test + void setBinaryStreamExceptionTest() throws SQLException { + SerialBlob blob = new SerialBlob(new byte[0]); + assertThrows(SerialException.class, () -> blob.setBinaryStream(0)); + } + /* * Validate calling free() does not throw an Exception */ @@ -50,110 +63,130 @@ public class SerialBlobTests extends BaseTest { * Validate calling getBinaryStream() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test01() throws Exception { - SerialBlob sb = new SerialBlob(new StubBlob()); - sb.free(); - sb.getBinaryStream(); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(new StubBlob()); + sb.free(); + sb.getBinaryStream(); + }); } /* * Validate calling getBinaryStream() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test02() throws Exception { - SerialBlob sb = new SerialBlob(new StubBlob()); - sb.free(); - sb.getBinaryStream(1, 5); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(new StubBlob()); + sb.free(); + sb.getBinaryStream(1, 5); + }); } /* * Validate calling getBytes() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test03() throws Exception { - SerialBlob sb = new SerialBlob(new StubBlob()); - sb.free(); - sb.getBytes(1, 1); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(new StubBlob()); + sb.free(); + sb.getBytes(1, 1); + }); } /* * Validate calling getLength() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test04() throws Exception { - SerialBlob sb = new SerialBlob(new StubBlob()); - sb.free(); - sb.length(); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(new StubBlob()); + sb.free(); + sb.length(); + }); } /* * Validate calling position() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test05() throws Exception { - SerialBlob sb = new SerialBlob(new StubBlob()); - sb.free(); - sb.position(new byte[5], 1); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(new StubBlob()); + sb.free(); + sb.position(new byte[5], 1); + }); } /* * Validate calling position() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test06() throws Exception { - SerialBlob sb = new SerialBlob(new StubBlob()); - sb.free(); - sb.position(new StubBlob(), 1); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(new StubBlob()); + sb.free(); + sb.position(new StubBlob(), 1); + }); } /* * Validate calling free() after calling setBinaryStream() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test07() throws Exception { - SerialBlob sb = new SerialBlob(new StubBlob()); - sb.free(); - sb.setBinaryStream(5); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(new StubBlob()); + sb.free(); + sb.setBinaryStream(5); + }); } /* * Validate calling free() after calling setBytes() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test08() throws Exception { - SerialBlob sb = new SerialBlob(new StubBlob()); - sb.free(); - sb.setBytes(1, new byte[5]); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(new StubBlob()); + sb.free(); + sb.setBytes(1, new byte[5]); + }); } /* * Validate calling setBytes() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test09() throws Exception { - SerialBlob sb = new SerialBlob(new StubBlob()); - sb.free(); - sb.setBytes(1, new byte[10], 0, 5); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(new StubBlob()); + sb.free(); + sb.setBytes(1, new byte[10], 0, 5); + }); } /* * Validate calling truncate() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test10() throws Exception { - SerialBlob sb = new SerialBlob(new StubBlob()); - sb.free(); - sb.truncate(1); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(new StubBlob()); + sb.free(); + sb.truncate(1); + }); } /* @@ -173,56 +206,68 @@ public class SerialBlobTests extends BaseTest { /* * Validate a SerialException is thrown if pos < 0 for getBinaryStream */ - @Test(expectedExceptions = SerialException.class) + @Test public void test12() throws Exception { - SerialBlob sb = new SerialBlob(bytes); - InputStream is = sb.getBinaryStream(-1, 3); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(bytes); + InputStream is = sb.getBinaryStream(-1, 3); + }); } /* * Validate a SerialException is thrown if pos = 0 for getBinaryStream */ - @Test(expectedExceptions = SerialException.class) + @Test public void test13() throws Exception { - SerialBlob sb = new SerialBlob(bytes); - InputStream is = sb.getBinaryStream(0, 3); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(bytes); + InputStream is = sb.getBinaryStream(0, 3); + }); } /* * Validate a SerialException is thrown if len > the length of the stream * for getBinaryStream */ - @Test(expectedExceptions = SerialException.class) + @Test public void test14() throws Exception { - SerialBlob sb = new SerialBlob(bytes); - InputStream is = sb.getBinaryStream(0, 3); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(bytes); + InputStream is = sb.getBinaryStream(0, 3); + }); } /* * Validate a SerialException is thrown if length < 1 */ - @Test(expectedExceptions = SerialException.class) + @Test public void test15() throws Exception { - SerialBlob sb = new SerialBlob(bytes); - InputStream is = sb.getBinaryStream(1, 0); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(bytes); + InputStream is = sb.getBinaryStream(1, 0); + }); } /* * Validate a SerialException is thrown if length > byte array length */ - @Test(expectedExceptions = SerialException.class) + @Test public void test16() throws Exception { - SerialBlob sb = new SerialBlob(bytes); - InputStream is = sb.getBinaryStream(1, 6); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(bytes); + InputStream is = sb.getBinaryStream(1, 6); + }); } /* * Validate a SerialException is thrown if pos > byte array length */ - @Test(expectedExceptions = SerialException.class) + @Test public void test17() throws Exception { - SerialBlob sb = new SerialBlob(bytes); - InputStream is = sb.getBinaryStream(bytes.length + 2, 6); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(bytes); + InputStream is = sb.getBinaryStream(bytes.length + 2, 6); + }); } /* @@ -241,12 +286,14 @@ public class SerialBlobTests extends BaseTest { /* * Test clone after free has been called that the clone is not accessible */ - @Test(expectedExceptions = SerialException.class) + @Test public void test19() throws Exception { - SerialBlob sb = new SerialBlob(bytes); - sb.free(); - SerialBlob sb2 = (SerialBlob) sb.clone(); - InputStream is = sb2.getBinaryStream(1, 3); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(bytes); + sb.free(); + SerialBlob sb2 = (SerialBlob) sb.clone(); + InputStream is = sb2.getBinaryStream(1, 3); + }); } /* @@ -264,10 +311,12 @@ public class SerialBlobTests extends BaseTest { * Validate a SerialException is thrown if byte[] is used to * create the SeriablBlob and setBinaryStream is called */ - @Test(expectedExceptions = SerialException.class) + @Test public void test21() throws Exception { - SerialBlob sb = new SerialBlob(bytes); - sb.setBinaryStream(3); + assertThrows(SerialException.class, () -> { + SerialBlob sb = new SerialBlob(bytes); + sb.setBinaryStream(3); + }); } /* @@ -281,7 +330,7 @@ public class SerialBlobTests extends BaseTest { byte[] expected = new byte[]{1, 7, 8, 9, 5}; SerialBlob sb = new SerialBlob(bytes); int written = sb.setBytes(2, diff); - assertEquals(written, diff.length); + assertEquals(diff.length, written); assertTrue( Arrays.equals(sb.getBytes(1, (int) sb.length()), expected), @@ -300,7 +349,7 @@ public class SerialBlobTests extends BaseTest { byte[] expected = new byte[]{1, 8, 9, 0, 5}; SerialBlob sb = new SerialBlob(bytes); int written = sb.setBytes(2, diff, 1, bytesToWrite); - assertEquals(written, bytesToWrite); + assertEquals(bytesToWrite, written); assertTrue( Arrays.equals(sb.getBytes(1, (int) sb.length()), expected), @@ -355,7 +404,7 @@ public class SerialBlobTests extends BaseTest { byte[] pattern = new byte[]{3, 4}; SerialBlob sb = new SerialBlob(bytes); long pos = sb.position(pattern, 1); - assertEquals(pos, expectedPos); + assertEquals(expectedPos, pos); } /* @@ -368,7 +417,7 @@ public class SerialBlobTests extends BaseTest { byte[] pattern = new byte[]{3, 4, 5}; SerialBlob sb = new SerialBlob(bytes); long pos = sb.position(pattern, 2); - assertEquals(pos, expectedPos); + assertEquals(expectedPos, pos); } /* @@ -381,7 +430,7 @@ public class SerialBlobTests extends BaseTest { byte[] pattern = new byte[]{4, 6}; SerialBlob sb = new SerialBlob(new StubBlob()); long pos = sb.position(pattern, 1); - assertEquals(pos, expectedPos); + assertEquals(expectedPos, pos); } /* @@ -394,7 +443,7 @@ public class SerialBlobTests extends BaseTest { byte[] pattern = new byte[]{6, 8}; SerialBlob sb = new SerialBlob(new StubBlob()); long pos = sb.position(pattern, 2); - assertEquals(pos, expectedPos); + assertEquals(expectedPos, pos); } /* @@ -411,8 +460,8 @@ public class SerialBlobTests extends BaseTest { byte[] expected = new byte[]{1, 2, 3, 4, 7}; SerialBlob sb = new SerialBlob(bytes); int written = sb.setBytes(writePos, diff, 0, bytesToWrite); - assertEquals(written, bytesToWrite); - assertEquals(sb.getBytes(1, (int) sb.length()), expected); + assertEquals(bytesToWrite, written); + assertArrayEquals(expected, sb.getBytes(1, (int) sb.length())); } /* @@ -428,8 +477,8 @@ public class SerialBlobTests extends BaseTest { byte[] expected = new byte[]{1, 2, 3, 4, 8, 9}; SerialBlob sb = new SerialBlob(bytes); int written = sb.setBytes(writePos, diff, 1, bytesToWrite); - assertEquals(written, bytesToWrite); - assertEquals(sb.getBytes(1, (int) sb.length()), expected); + assertEquals(bytesToWrite, written); + assertArrayEquals(expected, sb.getBytes(1, (int) sb.length())); } /* @@ -445,29 +494,33 @@ public class SerialBlobTests extends BaseTest { byte[] expected = new byte[]{1, 2, 3, 4, 5, 8, 9, 0}; SerialBlob sb = new SerialBlob(bytes); int written = sb.setBytes(writePos, diff, 1, bytesToWrite); - assertEquals(written, bytesToWrite); - assertEquals(sb.getBytes(1, (int) sb.length()), expected); + assertEquals(bytesToWrite, written); + assertArrayEquals(expected, sb.getBytes(1, (int) sb.length())); } /* * Validate a SerialException is thrown if length < 0 for setBytes */ - @Test(expectedExceptions = SerialException.class) + @Test public void test34() throws Exception { - int length = -1; - SerialBlob sb = new SerialBlob(bytes); - int written = sb.setBytes(1, new byte[]{1}, 1, length); + assertThrows(SerialException.class, () -> { + int length = -1; + SerialBlob sb = new SerialBlob(bytes); + int written = sb.setBytes(1, new byte[]{1}, 1, length); + }); } /* * Validate a SerialException is thrown if length + offset > * Integer.MAX_VALUE for setBytes */ - @Test(expectedExceptions = SerialException.class) + @Test public void test35() throws Exception { - int offset = 1; - int length = Integer.MAX_VALUE; - SerialBlob sb = new SerialBlob(bytes); - int written = sb.setBytes(1, new byte[]{1, 2, 3}, offset, length); + assertThrows(SerialException.class, () -> { + int offset = 1; + int length = Integer.MAX_VALUE; + SerialBlob sb = new SerialBlob(bytes); + int written = sb.setBytes(1, new byte[]{1, 2, 3}, offset, length); + }); } } diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SerialClobTests.java b/test/jdk/javax/sql/test/rowset/serial/SerialClobTests.java similarity index 72% rename from test/jdk/javax/sql/testng/test/rowset/serial/SerialClobTests.java rename to test/jdk/javax/sql/test/rowset/serial/SerialClobTests.java index 95c5f6f64a7..2636c3b6a84 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SerialClobTests.java +++ b/test/jdk/javax/sql/test/rowset/serial/SerialClobTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,10 +26,14 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; +import java.sql.SQLException; import javax.sql.rowset.serial.SerialClob; import javax.sql.rowset.serial.SerialException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + import util.BaseTest; import util.StubClob; @@ -43,6 +47,26 @@ public class SerialClobTests extends BaseTest { 'o', 'r', 'l', 'd'}; } + /* + * Validate calling setAsciiStream() on a SerialClob constructed from a + * char array throws SerialException. Bug 7077451. + */ + @Test + void setAsciiStreamExceptionTest() throws SQLException { + SerialClob clob = new SerialClob(new char[0]); + assertThrows(SerialException.class, () -> clob.setAsciiStream(0)); + } + + /* + * Validate calling setCharacterStream() on a SerialClob constructed from a + * char array throws SerialException. Bug 7077451. + */ + @Test + void setCharacterStreamExceptionTest() throws SQLException { + SerialClob clob = new SerialClob(new char[0]); + assertThrows(SerialException.class, () -> clob.setCharacterStream(0)); + } + /* * Validate calling free() does not throw an Exception */ @@ -56,192 +80,228 @@ public class SerialClobTests extends BaseTest { * Validate calling getCharacterStream() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test01() throws Exception { - SerialClob sc = new SerialClob(new StubClob()); - sc.free(); - sc.getCharacterStream(); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(new StubClob()); + sc.free(); + sc.getCharacterStream(); + }); } /* * Validate calling getCharacterStream() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test02() throws Exception { - SerialClob sc = new SerialClob(chars); - sc.free(); - sc.getCharacterStream(); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(chars); + sc.free(); + sc.getCharacterStream(); + }); } /* * Validate calling getCharacterStream() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test03() throws Exception { - SerialClob sc = new SerialClob(new StubClob()); - sc.free(); - sc.getCharacterStream(1, 5); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(new StubClob()); + sc.free(); + sc.getCharacterStream(1, 5); + }); } /* * Validate calling getSubString() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test04() throws Exception { - SerialClob sc = new SerialClob(new StubClob()); - sc.free(); - sc.getSubString(1, 1); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(new StubClob()); + sc.free(); + sc.getSubString(1, 1); + }); } /* * Validate calling truncate() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test05() throws Exception { - SerialClob sc = new SerialClob(new StubClob()); - sc.free(); - sc.truncate(1); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(new StubClob()); + sc.free(); + sc.truncate(1); + }); } /* * Validate calling getAsciiStream() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test06() throws Exception { - SerialClob sc = new SerialClob(new StubClob()); - sc.free(); - sc.getAsciiStream(); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(new StubClob()); + sc.free(); + sc.getAsciiStream(); + }); } /* * Validate calling length() after calling free() throws an SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test07() throws Exception { - SerialClob sc = new SerialClob(new StubClob()); - sc.free(); - sc.length(); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(new StubClob()); + sc.free(); + sc.length(); + }); } /* * Validate calling position() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test08() throws Exception { - SerialClob sc = new SerialClob(new StubClob()); - sc.free(); - sc.position("hello", 1); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(new StubClob()); + sc.free(); + sc.position("hello", 1); + }); } /* * Validate calling position() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test09() throws Exception { - SerialClob sc = new SerialClob(new StubClob()); - sc.free(); - sc.position(new StubClob(), 1); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(new StubClob()); + sc.free(); + sc.position(new StubClob(), 1); + }); } /* * Validate calling setAsciiStream() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test10() throws Exception { - SerialClob sc = new SerialClob(new StubClob()); - sc.free(); - sc.setAsciiStream(5); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(new StubClob()); + sc.free(); + sc.setAsciiStream(5); + }); } /* * Validate calling setCharacterStream() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test11() throws Exception { - SerialClob sc = new SerialClob(new StubClob()); - sc.free(); - sc.setCharacterStream(5); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(new StubClob()); + sc.free(); + sc.setCharacterStream(5); + }); } /* * Validate calling setString() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test12() throws Exception { - SerialClob sc = new SerialClob(new StubClob()); - sc.free(); - sc.setString(1, "hello"); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(new StubClob()); + sc.free(); + sc.setString(1, "hello"); + }); } /* * Validate calling setString() after calling free() throws an * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test13() throws Exception { - SerialClob sc = new SerialClob(new StubClob()); - sc.free(); - sc.setString(1, "hello", 0, 5); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(new StubClob()); + sc.free(); + sc.setString(1, "hello", 0, 5); + }); } /* * Test that SerialException is thrown if pos < 0 on a call to * getCharacterStream */ - @Test(expectedExceptions = SerialException.class) + @Test public void test14() throws Exception { - SerialClob sc = new SerialClob(chars); - sc.getCharacterStream(-1, 5); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(chars); + sc.getCharacterStream(-1, 5); + }); } /* * Test that SerialException is thrown if pos = 0 on a call to * getCharacterStream */ - @Test(expectedExceptions = SerialException.class) + @Test public void test15() throws Exception { - SerialClob sc = new SerialClob(chars); - sc.getCharacterStream(0, 5); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(chars); + sc.getCharacterStream(0, 5); + }); } /* * Test that SerialException is thrown if pos = 0 on a call to * getCharacterStream */ - @Test(expectedExceptions = SerialException.class) + @Test public void test16() throws Exception { - SerialClob sc = new SerialClob(chars); - sc.getCharacterStream(1, 100); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(chars); + sc.getCharacterStream(1, 100); + }); } /* * Test that SerialException is thrown if length = 0 on a call to * getCharacterStream */ - @Test(expectedExceptions = SerialException.class) + @Test public void test17() throws Exception { - SerialClob sc = new SerialClob(chars); - sc.getCharacterStream(1, 0); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(chars); + sc.getCharacterStream(1, 0); + }); } /* * Test that SerialException is thrown if pos > length on a call to * getCharacterStream */ - @Test(expectedExceptions = SerialException.class) + @Test public void test18() throws Exception { - SerialClob sc = new SerialClob(chars); - sc.getCharacterStream(100, 5); + assertThrows(SerialException.class, () -> { + SerialClob sc = new SerialClob(chars); + sc.getCharacterStream(100, 5); + }); } /* @@ -401,7 +461,7 @@ public class SerialClobTests extends BaseTest { String expected = "Hello, I am the Batman!"; SerialClob sc = new SerialClob(val.toCharArray()); int written = sc.setString(13, val1); - assertEquals(val1.length(), written); + assertEquals(written, val1.length()); assertTrue(expected.equals(sc.getSubString(1, (int) sc.length()))); } @@ -420,8 +480,8 @@ public class SerialClobTests extends BaseTest { String expected = "Hi, I am the Joker!!!!!"; SerialClob sc = new SerialClob(val.toCharArray()); int written = sc.setString(writePos, val1, offset, expectedWritten); - assertEquals(written, expectedWritten); - assertEquals(sc.getSubString(1, (int) sc.length()), expected); + assertEquals(expectedWritten, written); + assertEquals(expected, sc.getSubString(1, (int) sc.length())); } /* @@ -478,7 +538,8 @@ public class SerialClobTests extends BaseTest { * Check that getCharacterStream() returns a Reader and that the char[] that * was specified to create the SerialClob can be returned via the Reader */ - @Test(enabled = false) + @Test + @Disabled public void test37() throws Exception { SerialClob sc = new SerialClob(chars); String expected = "ello w"; @@ -504,12 +565,14 @@ public class SerialClobTests extends BaseTest { * Check calling setString() with offset > val1.length() throws a * SerialException */ - @Test(expectedExceptions = SerialException.class) + @Test public void test39() throws Exception { - String val1 = "hello"; - int offset = val1.length() + 1; - SerialClob sc = new SerialClob(chars); - sc.setString(1, val1, offset, 0); + assertThrows(SerialException.class, () -> { + String val1 = "hello"; + int offset = val1.length() + 1; + SerialClob sc = new SerialClob(chars); + sc.setString(1, val1, offset, 0); + }); } /* @@ -526,8 +589,8 @@ public class SerialClobTests extends BaseTest { String expected = "Hello, I am the Joker, who are you?!"; SerialClob sc = new SerialClob(val.toCharArray()); int written = sc.setString(writePos, val1, offset, expectedWritten); - assertEquals(written, expectedWritten); - assertEquals(sc.getSubString(1, (int) sc.length()), expected); + assertEquals(expectedWritten, written); + assertEquals(expected, sc.getSubString(1, (int) sc.length())); } /* @@ -544,29 +607,33 @@ public class SerialClobTests extends BaseTest { String expected = "Hi, I am the Joker!"; SerialClob sc = new SerialClob(val.toCharArray()); int written = sc.setString(writePos, val1, offset, expectedWritten); - assertEquals(written, expectedWritten); - assertEquals(sc.getSubString(1, (int) sc.length()), expected); + assertEquals(expectedWritten, written); + assertEquals(expected, sc.getSubString(1, (int) sc.length())); } /* * Validate a SerialException is thrown if length < 0 for setString */ - @Test(expectedExceptions = SerialException.class) + @Test public void test42() throws Exception { - int length = -1; - SerialClob sc = new SerialClob(chars); - int written = sc.setString(1, "hello", 1, length); + assertThrows(SerialException.class, () -> { + int length = -1; + SerialClob sc = new SerialClob(chars); + int written = sc.setString(1, "hello", 1, length); + }); } /* * Validate a SerialException is thrown if length + offset > * Integer.MAX_VALUE for setString */ - @Test(expectedExceptions = SerialException.class) + @Test public void test43() throws Exception { - int offset = 1; - int length = Integer.MAX_VALUE; - SerialClob sc = new SerialClob(chars); - int written = sc.setString(1, "hello", offset, length); + assertThrows(SerialException.class, () -> { + int offset = 1; + int length = Integer.MAX_VALUE; + SerialClob sc = new SerialClob(chars); + int written = sc.setString(1, "hello", offset, length); + }); } } diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SerialDataLinkTests.java b/test/jdk/javax/sql/test/rowset/serial/SerialDataLinkTests.java similarity index 90% rename from test/jdk/javax/sql/testng/test/rowset/serial/SerialDataLinkTests.java rename to test/jdk/javax/sql/test/rowset/serial/SerialDataLinkTests.java index 0c7f19e85b1..12c1341161d 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SerialDataLinkTests.java +++ b/test/jdk/javax/sql/test/rowset/serial/SerialDataLinkTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,11 @@ package test.rowset.serial; import java.net.URL; import javax.sql.rowset.serial.SerialDatalink; import javax.sql.rowset.serial.SerialException; -import static org.testng.Assert.*; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SerialDataLinkTests extends BaseTest { @@ -36,7 +38,7 @@ public class SerialDataLinkTests extends BaseTest { private URL u1; private SerialDatalink dl; - @BeforeMethod + @BeforeEach public void setUpMethod() throws Exception { u = new URL("http://www.oracle.com/"); u1 = new URL("http://www.usatoday.com/"); @@ -46,9 +48,11 @@ public class SerialDataLinkTests extends BaseTest { /* * Validate that a SerialException is thrown if the URL is null */ - @Test(expectedExceptions = SerialException.class) + @Test public void test() throws Exception { - SerialDatalink dl1 = new SerialDatalink(null); + assertThrows(SerialException.class, () -> { + SerialDatalink dl1 = new SerialDatalink(null); + }); } /* diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SerialExceptionTests.java b/test/jdk/javax/sql/test/rowset/serial/SerialExceptionTests.java similarity index 95% rename from test/jdk/javax/sql/testng/test/rowset/serial/SerialExceptionTests.java rename to test/jdk/javax/sql/test/rowset/serial/SerialExceptionTests.java index 8ef215584a9..51c733b995a 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SerialExceptionTests.java +++ b/test/jdk/javax/sql/test/rowset/serial/SerialExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,10 @@ package test.rowset.serial; import java.sql.SQLException; import javax.sql.rowset.serial.SerialException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SerialExceptionTests extends BaseTest { diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SerialJavaObjectTests.java b/test/jdk/javax/sql/test/rowset/serial/SerialJavaObjectTests.java similarity index 86% rename from test/jdk/javax/sql/testng/test/rowset/serial/SerialJavaObjectTests.java rename to test/jdk/javax/sql/test/rowset/serial/SerialJavaObjectTests.java index c2fcf2fa48f..e521125df97 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SerialJavaObjectTests.java +++ b/test/jdk/javax/sql/test/rowset/serial/SerialJavaObjectTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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,11 @@ import java.util.Arrays; import javax.sql.rowset.RowSetMetaDataImpl; import javax.sql.rowset.serial.SerialException; import javax.sql.rowset.serial.SerialJavaObject; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SerialJavaObjectTests extends BaseTest { @@ -37,18 +40,23 @@ public class SerialJavaObjectTests extends BaseTest { * Validate that an NPE is thrown when null is specified to create * the SerialJavaObject */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void test() throws Exception { - SerialJavaObject sjo = new SerialJavaObject(null); + assertThrows(NullPointerException.class, () -> { + SerialJavaObject sjo = new SerialJavaObject(null); + }); } /* * Validate that a SerialException is thrown when the object specified * contains public static fields */ - @Test(expectedExceptions = SerialException.class, enabled = false) + @Test + @Disabled public void test01() throws Exception { - SerialJavaObject sjo = new SerialJavaObject(new RowSetMetaDataImpl()); + assertThrows(SerialException.class, () -> { + SerialJavaObject sjo = new SerialJavaObject(new RowSetMetaDataImpl()); + }); } /* diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SerialRefTests.java b/test/jdk/javax/sql/test/rowset/serial/SerialRefTests.java similarity index 86% rename from test/jdk/javax/sql/testng/test/rowset/serial/SerialRefTests.java rename to test/jdk/javax/sql/test/rowset/serial/SerialRefTests.java index 8f23de70aa6..1b4e72593b0 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SerialRefTests.java +++ b/test/jdk/javax/sql/test/rowset/serial/SerialRefTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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,9 +27,12 @@ import java.sql.SQLException; import java.util.HashMap; import java.util.Map; import javax.sql.rowset.serial.SerialRef; -import static org.testng.Assert.*; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + import util.BaseTest; import util.StubRef; import util.SuperHero; @@ -41,7 +44,7 @@ public class SerialRefTests extends BaseTest { private final String sqlType = "SUPERHERO"; private SuperHero hero; - @BeforeMethod + @BeforeEach public void setUpMethod() throws Exception { map.put(sqlType, Class.forName("util.SuperHero")); hero = new SuperHero(sqlType, "Bruce", "Wayne", 1939, "Batman"); @@ -51,18 +54,22 @@ public class SerialRefTests extends BaseTest { /* * Validate that a SQLException() is thrown if the Ref is null */ - @Test(expectedExceptions = SQLException.class) + @Test public void test01() throws Exception { - SerialRef sr = new SerialRef(null); + assertThrows(SQLException.class, () -> { + SerialRef sr = new SerialRef(null); + }); } /* * Validate that a SQLException() is thrown if the typeName is null in the * Ref used to create the SerialRef */ - @Test(expectedExceptions = SQLException.class) + @Test public void test02() throws Exception { - SerialRef sr = new SerialRef(new StubRef(null, hero)); + assertThrows(SQLException.class, () -> { + SerialRef sr = new SerialRef(new StubRef(null, hero)); + }); } /* @@ -72,7 +79,7 @@ public class SerialRefTests extends BaseTest { @Test public void test03() throws Exception { SerialRef sr = new SerialRef(ref); - assertEquals(sr.getBaseTypeName(), sqlType); + assertEquals(sqlType, sr.getBaseTypeName()); } /* @@ -87,7 +94,8 @@ public class SerialRefTests extends BaseTest { /* * Validate that getObject() returns the same object used to create the Ref */ - @Test(enabled = false) + @Test + @Disabled public void test05() throws Exception { SerialRef sr = new SerialRef(ref); assertTrue(hero.equals(sr.getObject(map))); diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SerialStructTests.java b/test/jdk/javax/sql/test/rowset/serial/SerialStructTests.java similarity index 92% rename from test/jdk/javax/sql/testng/test/rowset/serial/SerialStructTests.java rename to test/jdk/javax/sql/test/rowset/serial/SerialStructTests.java index 79ac2421c9a..dfc34b60e2b 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SerialStructTests.java +++ b/test/jdk/javax/sql/test/rowset/serial/SerialStructTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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,9 +27,11 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; import javax.sql.rowset.serial.SerialStruct; -import static org.testng.Assert.*; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import util.BaseTest; import util.StubStruct; import util.SuperHero; @@ -42,7 +44,7 @@ public class SerialStructTests extends BaseTest { private final String sqlType = "SUPERHERO"; private SuperHero hero; - @BeforeMethod + @BeforeEach public void setUpMethod() throws Exception { attributes = new Object[]{"Bruce", "Wayne", 1939, "Batman"}; @@ -58,7 +60,7 @@ public class SerialStructTests extends BaseTest { @Test public void test01() throws Exception { SerialStruct ss = new SerialStruct(struct, map); - assertEquals(ss.getSQLTypeName(), sqlType); + assertEquals(sqlType, ss.getSQLTypeName()); } /* @@ -68,7 +70,7 @@ public class SerialStructTests extends BaseTest { @Test public void test02() throws Exception { SerialStruct ss = new SerialStruct(hero, map); - assertEquals(ss.getSQLTypeName(), sqlType); + assertEquals(sqlType, ss.getSQLTypeName()); } /* diff --git a/test/jdk/javax/sql/testng/test/rowset/spi/SyncFactoryExceptionTests.java b/test/jdk/javax/sql/test/rowset/spi/SyncFactoryExceptionTests.java similarity index 95% rename from test/jdk/javax/sql/testng/test/rowset/spi/SyncFactoryExceptionTests.java rename to test/jdk/javax/sql/test/rowset/spi/SyncFactoryExceptionTests.java index e93a6109ec7..b747c48989d 100644 --- a/test/jdk/javax/sql/testng/test/rowset/spi/SyncFactoryExceptionTests.java +++ b/test/jdk/javax/sql/test/rowset/spi/SyncFactoryExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,10 @@ package test.rowset.spi; import java.sql.SQLException; import javax.sql.rowset.spi.SyncFactoryException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + import util.BaseTest; public class SyncFactoryExceptionTests extends BaseTest { diff --git a/test/jdk/javax/sql/testng/test/rowset/spi/SyncFactoryTests.java b/test/jdk/javax/sql/test/rowset/spi/SyncFactoryTests.java similarity index 92% rename from test/jdk/javax/sql/testng/test/rowset/spi/SyncFactoryTests.java rename to test/jdk/javax/sql/test/rowset/spi/SyncFactoryTests.java index 415488abb9f..260cf150f59 100644 --- a/test/jdk/javax/sql/testng/test/rowset/spi/SyncFactoryTests.java +++ b/test/jdk/javax/sql/test/rowset/spi/SyncFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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 @@ -33,9 +33,11 @@ import javax.naming.Context; import javax.sql.rowset.spi.SyncFactory; import javax.sql.rowset.spi.SyncFactoryException; import javax.sql.rowset.spi.SyncProvider; -import static org.testng.Assert.*; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import util.PropertyStubProvider; import util.StubSyncProvider; import util.StubContext; @@ -67,7 +69,7 @@ public class SyncFactoryTests { ctx = new StubContext(); } - @BeforeMethod + @BeforeEach public void setUpMethod() throws Exception { // Make sure the provider provider that is registered is removed // before each run @@ -120,17 +122,21 @@ public class SyncFactoryTests { /* * Validate that a SyncFactoryException is thrown if the ProviderID is null */ - @Test(expectedExceptions = SyncFactoryException.class) + @Test public void test03() throws SyncFactoryException { - SyncProvider p = SyncFactory.getInstance(null); + assertThrows(SyncFactoryException.class, () -> { + SyncProvider p = SyncFactory.getInstance(null); + }); } /* * Validate that a SyncFactoryException is thrown if the Logger is null */ - @Test(expectedExceptions = SyncFactoryException.class,enabled=true) + @Test public void test04() throws SyncFactoryException { - Logger l = SyncFactory.getLogger(); + assertThrows(SyncFactoryException.class, () -> { + Logger l = SyncFactory.getLogger(); + }); } /* @@ -179,15 +185,15 @@ public class SyncFactoryTests { * Validate that setJNDIContext throws a SyncFactoryException if the * context is null */ - @Test(expectedExceptions = SyncFactoryException.class, enabled=true) + @Test public void test08() throws Exception { - SyncFactory.setJNDIContext(null); + assertThrows(SyncFactoryException.class, () -> SyncFactory.setJNDIContext(null)); } /* * Validate that setJNDIContext succeeds */ - @Test(enabled=true) + @Test public void test09() throws Exception { SyncFactory.setJNDIContext(ctx); } diff --git a/test/jdk/javax/sql/testng/test/rowset/spi/SyncProviderExceptionTests.java b/test/jdk/javax/sql/test/rowset/spi/SyncProviderExceptionTests.java similarity index 96% rename from test/jdk/javax/sql/testng/test/rowset/spi/SyncProviderExceptionTests.java rename to test/jdk/javax/sql/test/rowset/spi/SyncProviderExceptionTests.java index 22863b0f6bb..f8786f1b429 100644 --- a/test/jdk/javax/sql/testng/test/rowset/spi/SyncProviderExceptionTests.java +++ b/test/jdk/javax/sql/test/rowset/spi/SyncProviderExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,11 +27,12 @@ import java.sql.SQLException; import javax.sql.rowset.spi.SyncProviderException; import javax.sql.rowset.spi.SyncResolver; -import static org.testng.Assert.*; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import org.junit.jupiter.api.AfterAll; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import util.BaseTest; import util.StubSyncResolver; @@ -40,16 +41,16 @@ public class SyncProviderExceptionTests extends BaseTest { // Used by SyncProviderException::getSyncResolver tests private SyncResolver resolver; - @BeforeClass + @BeforeAll public static void setUpClass() throws Exception { System.out.println(System.getProperty("java.naming.factory.initial")); } - @AfterClass + @AfterAll public static void tearDownClass() throws Exception { } - @BeforeMethod + @BeforeEach public void setupTest() { resolver = new SyncProviderException().getSyncResolver(); } diff --git a/test/jdk/javax/sql/testng/test/rowset/webrowset/CommonWebRowSetTests.java b/test/jdk/javax/sql/test/rowset/webrowset/CommonWebRowSetTests.java similarity index 81% rename from test/jdk/javax/sql/testng/test/rowset/webrowset/CommonWebRowSetTests.java rename to test/jdk/javax/sql/test/rowset/webrowset/CommonWebRowSetTests.java index ce0801e0fe4..023adc8254b 100644 --- a/test/jdk/javax/sql/testng/test/rowset/webrowset/CommonWebRowSetTests.java +++ b/test/jdk/javax/sql/test/rowset/webrowset/CommonWebRowSetTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,11 +35,15 @@ import java.math.BigDecimal; import java.sql.ResultSet; import java.util.Arrays; import javax.sql.rowset.WebRowSet; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertEqualsNoOrder; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import test.rowset.cachedrowset.CommonCachedRowSetTests; public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { @@ -131,10 +135,11 @@ public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { /* * Validate the expected Rows are contained within the RowSet */ - @Test(dataProvider = "rowsetUsingCoffees") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffees") public void WebRowSetTest0000(WebRowSet wrs) throws Exception { - assertEquals(getPrimaryKeys(wrs), COFFEES_PRIMARY_KEYS); - assertEquals(wrs.size(), COFFEES_ROWS); + assertArrayEquals(COFFEES_PRIMARY_KEYS, getPrimaryKeys(wrs)); + assertEquals(COFFEES_ROWS, wrs.size()); wrs.close(); } @@ -142,14 +147,15 @@ public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { * Validate the expected Rows are contained within the RowSet * populated by readXML(Reader) */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void WebRowSetTest0001(WebRowSet wrs1) throws Exception { try (FileReader fr = new FileReader(COFFEE_ROWS_XML)) { wrs1.readXml(fr); } - assertEquals(getPrimaryKeys(wrs1), COFFEES_PRIMARY_KEYS); - assertEquals(wrs1.size(), COFFEES_ROWS); + assertArrayEquals(COFFEES_PRIMARY_KEYS, getPrimaryKeys(wrs1)); + assertEquals(COFFEES_ROWS, wrs1.size()); wrs1.close(); } @@ -158,13 +164,14 @@ public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { * Validate the expected Rows are contained within the RowSet * populated by readXML(InputStream) */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void WebRowSetTest0002(WebRowSet wrs1) throws Exception { try (FileInputStream fis = new FileInputStream(COFFEE_ROWS_XML)) { wrs1.readXml(fis); } - assertEquals(getPrimaryKeys(wrs1), COFFEES_PRIMARY_KEYS); - assertEquals(wrs1.size(), COFFEES_ROWS); + assertArrayEquals(COFFEES_PRIMARY_KEYS, getPrimaryKeys(wrs1)); + assertEquals(COFFEES_ROWS, wrs1.size()); wrs1.close(); } @@ -173,12 +180,13 @@ public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { * back via readXML(InputStream) and validate the primary keys * are the same */ - @Test(dataProvider = "rowsetUsingCoffees") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffees") public void WebRowSetTest0003(WebRowSet wrs) throws Exception { ByteArrayOutputStream baos = writeWebRowSetWithOutputStream(wrs); try (WebRowSet wrs1 = readWebRowSetWithOInputStream(baos)) { - assertEquals(getPrimaryKeys(wrs1), COFFEES_PRIMARY_KEYS); - assertEquals(wrs1.size(), COFFEES_ROWS); + assertArrayEquals(COFFEES_PRIMARY_KEYS, getPrimaryKeys(wrs1)); + assertEquals(COFFEES_ROWS, wrs1.size()); } } @@ -187,14 +195,15 @@ public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { * back via readXML(InputStream) and validate the primary keys * are the same */ - @Test(dataProvider = "rowsetUsingCoffees") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffees") public void WebRowSetTest0004(WebRowSet wrs) throws Exception { ResultSet rs = wrs; rs.beforeFirst(); ByteArrayOutputStream baos = writeWebRowSetWithOutputStream(rs); try (WebRowSet wrs1 = readWebRowSetWithOInputStream(baos)) { - assertEquals(getPrimaryKeys(wrs1), COFFEES_PRIMARY_KEYS); - assertEquals(wrs1.size(), COFFEES_ROWS); + assertArrayEquals(COFFEES_PRIMARY_KEYS, getPrimaryKeys(wrs1)); + assertEquals(COFFEES_ROWS, wrs1.size()); } } @@ -203,12 +212,13 @@ public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { * back via readXML(Reader) and validate the primary keys * are the same */ - @Test(dataProvider = "rowsetUsingCoffees") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffees") public void WebRowSetTest0005(WebRowSet wrs) throws Exception { ByteArrayOutputStream baos = writeWebRowSetWithOutputStreamWithWriter(wrs); try (WebRowSet wrs1 = readWebRowSetWithOInputStreamWithReader(baos)) { - assertEquals(getPrimaryKeys(wrs1), COFFEES_PRIMARY_KEYS); - assertEquals(wrs1.size(), COFFEES_ROWS); + assertArrayEquals(COFFEES_PRIMARY_KEYS, getPrimaryKeys(wrs1)); + assertEquals(COFFEES_ROWS, wrs1.size()); } } @@ -217,14 +227,15 @@ public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { * back via readXML(Reader) and validate the primary keys * are the same */ - @Test(dataProvider = "rowsetUsingCoffees") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffees") public void WebRowSetTest0006(WebRowSet wrs) throws Exception { ResultSet rs = wrs; rs.beforeFirst(); ByteArrayOutputStream baos = writeWebRowSetWithOutputStreamWithWriter(rs); try (WebRowSet wrs1 = readWebRowSetWithOInputStreamWithReader(baos)) { - assertEquals(getPrimaryKeys(wrs1), COFFEES_PRIMARY_KEYS); - assertEquals(wrs1.size(), COFFEES_ROWS); + assertArrayEquals(COFFEES_PRIMARY_KEYS, getPrimaryKeys(wrs1)); + assertEquals(COFFEES_ROWS, wrs1.size()); } } @@ -232,11 +243,13 @@ public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { * Validate the expected Rows are contained within the RowSet * after deleting the specified rows */ - @Test(dataProvider = "rowsetUsingCoffees", enabled = false) + @Disabled + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowsetUsingCoffees") public void WebRowSetTest0007(WebRowSet wrs) throws Exception { - assertEquals(getPrimaryKeys(wrs), COFFEES_PRIMARY_KEYS); + assertArrayEquals(COFFEES_PRIMARY_KEYS, getPrimaryKeys(wrs)); int[] rowsToDelete = {2, 4}; - assertEquals(getPrimaryKeys(wrs), COFFEES_PRIMARY_KEYS); + assertArrayEquals(COFFEES_PRIMARY_KEYS, getPrimaryKeys(wrs)); for (int row : rowsToDelete) { assertTrue(deleteRowByPrimaryKey(wrs, row, 1)); } @@ -262,12 +275,13 @@ public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { * that was populated by reading an xml file with all rows * marked as a currentRow */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void WebRowSetTest0008(WebRowSet wrs1) throws Exception { FileInputStream fis = new FileInputStream(COFFEE_ROWS_XML); wrs1.readXml(fis); assertTrue(wrs1.size() == COFFEES_ROWS); - assertEquals(getPrimaryKeys(wrs1), COFFEES_PRIMARY_KEYS); + assertArrayEquals(COFFEES_PRIMARY_KEYS, getPrimaryKeys(wrs1)); // Validate that the rows are not marked as deleted, inserted or updated wrs1.beforeFirst(); while (wrs1.next()) { @@ -284,14 +298,15 @@ public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { * Also validate that they are or are not visible based on the * setShowDeleted value */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void WebRowSetTest0009(WebRowSet wrs1) throws Exception { int[] rowsToDelete = {2, 4}; Object[] expectedRows = {1, 3, 5}; FileInputStream fis = new FileInputStream(DELETED_COFFEE_ROWS_XML); wrs1.readXml(fis); assertTrue(wrs1.size() == COFFEES_ROWS); - assertEquals(getPrimaryKeys(wrs1), expectedRows); + assertArrayEquals(expectedRows, getPrimaryKeys(wrs1)); // With setShowDeleted(false) which is the default, // the deleted row should not be visible for (int row : rowsToDelete) { @@ -302,7 +317,7 @@ public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { for (int row : rowsToDelete) { assertTrue(findRowByPrimaryKey(wrs1, row, 1)); } - assertEquals(getPrimaryKeys(wrs1), COFFEES_PRIMARY_KEYS); + assertArrayEquals(COFFEES_PRIMARY_KEYS, getPrimaryKeys(wrs1)); wrs1.close(); } @@ -311,12 +326,13 @@ public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { * Validate that the correct row in the WebRowSet that had been created * from an xml file is marked as updated and contains the correct values */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void WebRowSetTest0010(WebRowSet wrs1) throws Exception { FileInputStream fis = new FileInputStream(UPDATED_COFFEE_ROWS_XML); wrs1.readXml(fis); assertTrue(wrs1.size() == COFFEES_ROWS); - assertEquals(getPrimaryKeys(wrs1), COFFEES_PRIMARY_KEYS); + assertArrayEquals(COFFEES_PRIMARY_KEYS, getPrimaryKeys(wrs1)); wrs1.beforeFirst(); while (wrs1.next()) { if (wrs1.getInt(1) == 3) { @@ -337,7 +353,8 @@ public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { * Validate the correct row is marked as inserted in a WebRowSet * that is read from an xml file */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void WebRowSetTest0011(WebRowSet wrs1) throws Exception { int expectedSize = COFFEES_ROWS + 2; int addedRowPK = 15; @@ -348,7 +365,10 @@ public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { FileInputStream fis = new FileInputStream(INSERTED_COFFEE_ROWS_XML); wrs1.readXml(fis); assertTrue(wrs1.size() == expectedSize); - assertEqualsNoOrder(getPrimaryKeys(wrs1), expected); + var actual = getPrimaryKeys(wrs1); + Arrays.sort(actual); + Arrays.sort(expected); + assertArrayEquals(expected, actual); wrs1.beforeFirst(); while (wrs1.next()) { if (wrs1.getInt(1) == 15 || wrs1.getInt(1) == 20) { @@ -367,7 +387,8 @@ public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { /* * Read an xml file which contains a row that was inserted and updated */ - @Test(dataProvider = "rowSetType") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("rowSetType") public void WebRowSetTest0012(WebRowSet wrs1) throws Exception { int expectedSize = COFFEES_ROWS + 1; int addedRowPK = 100; @@ -376,7 +397,7 @@ public abstract class CommonWebRowSetTests extends CommonCachedRowSetTests { FileInputStream fis = new FileInputStream(UPDATED_INSERTED_COFFEE_ROWS_XML); wrs1.readXml(fis); assertTrue(wrs1.size() == expectedSize); - assertEquals(getPrimaryKeys(wrs1), expected); + assertArrayEquals(expected, getPrimaryKeys(wrs1)); wrs1.beforeFirst(); while (wrs1.next()) { if (wrs1.getInt(1) == addedRowPK) { diff --git a/test/jdk/javax/sql/testng/test/rowset/webrowset/WebRowSetTests.java b/test/jdk/javax/sql/test/rowset/webrowset/WebRowSetTests.java similarity index 94% rename from test/jdk/javax/sql/testng/test/rowset/webrowset/WebRowSetTests.java rename to test/jdk/javax/sql/test/rowset/webrowset/WebRowSetTests.java index 5f2890e0b5b..4692c0cee84 100644 --- a/test/jdk/javax/sql/testng/test/rowset/webrowset/WebRowSetTests.java +++ b/test/jdk/javax/sql/test/rowset/webrowset/WebRowSetTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/PropertyStubProvider.java b/test/jdk/javax/sql/util/PropertyStubProvider.java similarity index 92% rename from test/jdk/javax/sql/testng/util/PropertyStubProvider.java rename to test/jdk/javax/sql/util/PropertyStubProvider.java index d397cc1c7d4..1cadcef26bb 100644 --- a/test/jdk/javax/sql/testng/util/PropertyStubProvider.java +++ b/test/jdk/javax/sql/util/PropertyStubProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubArray.java b/test/jdk/javax/sql/util/StubArray.java similarity index 97% rename from test/jdk/javax/sql/testng/util/StubArray.java rename to test/jdk/javax/sql/util/StubArray.java index 1d2ef0e5b6f..b57760679a0 100644 --- a/test/jdk/javax/sql/testng/util/StubArray.java +++ b/test/jdk/javax/sql/util/StubArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubBaseRowSet.java b/test/jdk/javax/sql/util/StubBaseRowSet.java similarity index 99% rename from test/jdk/javax/sql/testng/util/StubBaseRowSet.java rename to test/jdk/javax/sql/util/StubBaseRowSet.java index e003b522ed9..94be7f8e348 100644 --- a/test/jdk/javax/sql/testng/util/StubBaseRowSet.java +++ b/test/jdk/javax/sql/util/StubBaseRowSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubBlob.java b/test/jdk/javax/sql/util/StubBlob.java similarity index 97% rename from test/jdk/javax/sql/testng/util/StubBlob.java rename to test/jdk/javax/sql/util/StubBlob.java index 727e8a926d5..f86fd540841 100644 --- a/test/jdk/javax/sql/testng/util/StubBlob.java +++ b/test/jdk/javax/sql/util/StubBlob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubCachedRowSetImpl.java b/test/jdk/javax/sql/util/StubCachedRowSetImpl.java similarity index 99% rename from test/jdk/javax/sql/testng/util/StubCachedRowSetImpl.java rename to test/jdk/javax/sql/util/StubCachedRowSetImpl.java index 9000deb1b65..65e8169dbb6 100644 --- a/test/jdk/javax/sql/testng/util/StubCachedRowSetImpl.java +++ b/test/jdk/javax/sql/util/StubCachedRowSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubClob.java b/test/jdk/javax/sql/util/StubClob.java similarity index 97% rename from test/jdk/javax/sql/testng/util/StubClob.java rename to test/jdk/javax/sql/util/StubClob.java index cb1e0c0a62a..b0db14b3526 100644 --- a/test/jdk/javax/sql/testng/util/StubClob.java +++ b/test/jdk/javax/sql/util/StubClob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubContext.java b/test/jdk/javax/sql/util/StubContext.java similarity index 98% rename from test/jdk/javax/sql/testng/util/StubContext.java rename to test/jdk/javax/sql/util/StubContext.java index af03534d991..6f03a1abd48 100644 --- a/test/jdk/javax/sql/testng/util/StubContext.java +++ b/test/jdk/javax/sql/util/StubContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubFilteredRowSetImpl.java b/test/jdk/javax/sql/util/StubFilteredRowSetImpl.java similarity index 99% rename from test/jdk/javax/sql/testng/util/StubFilteredRowSetImpl.java rename to test/jdk/javax/sql/util/StubFilteredRowSetImpl.java index 8fcbfa4c085..0b73abc6c01 100644 --- a/test/jdk/javax/sql/testng/util/StubFilteredRowSetImpl.java +++ b/test/jdk/javax/sql/util/StubFilteredRowSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubJdbcRowSetImpl.java b/test/jdk/javax/sql/util/StubJdbcRowSetImpl.java similarity index 99% rename from test/jdk/javax/sql/testng/util/StubJdbcRowSetImpl.java rename to test/jdk/javax/sql/util/StubJdbcRowSetImpl.java index ec59eb6c556..441b662ddc6 100644 --- a/test/jdk/javax/sql/testng/util/StubJdbcRowSetImpl.java +++ b/test/jdk/javax/sql/util/StubJdbcRowSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubJoinRowSetImpl.java b/test/jdk/javax/sql/util/StubJoinRowSetImpl.java similarity index 99% rename from test/jdk/javax/sql/testng/util/StubJoinRowSetImpl.java rename to test/jdk/javax/sql/util/StubJoinRowSetImpl.java index c7ece7cd523..1f506f830ef 100644 --- a/test/jdk/javax/sql/testng/util/StubJoinRowSetImpl.java +++ b/test/jdk/javax/sql/util/StubJoinRowSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubNClob.java b/test/jdk/javax/sql/util/StubNClob.java similarity index 93% rename from test/jdk/javax/sql/testng/util/StubNClob.java rename to test/jdk/javax/sql/util/StubNClob.java index 10682578b9a..0664aa42795 100644 --- a/test/jdk/javax/sql/testng/util/StubNClob.java +++ b/test/jdk/javax/sql/util/StubNClob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubRef.java b/test/jdk/javax/sql/util/StubRef.java similarity index 95% rename from test/jdk/javax/sql/testng/util/StubRef.java rename to test/jdk/javax/sql/util/StubRef.java index 052bd92c740..54a42df1e1c 100644 --- a/test/jdk/javax/sql/testng/util/StubRef.java +++ b/test/jdk/javax/sql/util/StubRef.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubRowId.java b/test/jdk/javax/sql/util/StubRowId.java similarity index 93% rename from test/jdk/javax/sql/testng/util/StubRowId.java rename to test/jdk/javax/sql/util/StubRowId.java index f8e90d49867..d3bc51b9320 100644 --- a/test/jdk/javax/sql/testng/util/StubRowId.java +++ b/test/jdk/javax/sql/util/StubRowId.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubRowSetFactory.java b/test/jdk/javax/sql/util/StubRowSetFactory.java similarity index 96% rename from test/jdk/javax/sql/testng/util/StubRowSetFactory.java rename to test/jdk/javax/sql/util/StubRowSetFactory.java index 624c53af1e7..abc34894a18 100644 --- a/test/jdk/javax/sql/testng/util/StubRowSetFactory.java +++ b/test/jdk/javax/sql/util/StubRowSetFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubSQLXML.java b/test/jdk/javax/sql/util/StubSQLXML.java similarity index 97% rename from test/jdk/javax/sql/testng/util/StubSQLXML.java rename to test/jdk/javax/sql/util/StubSQLXML.java index 44d1351b357..5e4d1647853 100644 --- a/test/jdk/javax/sql/testng/util/StubSQLXML.java +++ b/test/jdk/javax/sql/util/StubSQLXML.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubStruct.java b/test/jdk/javax/sql/util/StubStruct.java similarity index 95% rename from test/jdk/javax/sql/testng/util/StubStruct.java rename to test/jdk/javax/sql/util/StubStruct.java index 1dee8028a2c..a5a2004a09d 100644 --- a/test/jdk/javax/sql/testng/util/StubStruct.java +++ b/test/jdk/javax/sql/util/StubStruct.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubSyncProvider.java b/test/jdk/javax/sql/util/StubSyncProvider.java similarity index 97% rename from test/jdk/javax/sql/testng/util/StubSyncProvider.java rename to test/jdk/javax/sql/util/StubSyncProvider.java index 8947455c701..a6a44e0f509 100644 --- a/test/jdk/javax/sql/testng/util/StubSyncProvider.java +++ b/test/jdk/javax/sql/util/StubSyncProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubSyncResolver.java b/test/jdk/javax/sql/util/StubSyncResolver.java similarity index 99% rename from test/jdk/javax/sql/testng/util/StubSyncResolver.java rename to test/jdk/javax/sql/util/StubSyncResolver.java index 02477c7f9be..f24c3ec4b13 100644 --- a/test/jdk/javax/sql/testng/util/StubSyncResolver.java +++ b/test/jdk/javax/sql/util/StubSyncResolver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/StubWebRowSetImpl.java b/test/jdk/javax/sql/util/StubWebRowSetImpl.java similarity index 99% rename from test/jdk/javax/sql/testng/util/StubWebRowSetImpl.java rename to test/jdk/javax/sql/util/StubWebRowSetImpl.java index 918d5bd0482..48c237e73ae 100644 --- a/test/jdk/javax/sql/testng/util/StubWebRowSetImpl.java +++ b/test/jdk/javax/sql/util/StubWebRowSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/SuperHero.java b/test/jdk/javax/sql/util/SuperHero.java similarity index 97% rename from test/jdk/javax/sql/testng/util/SuperHero.java rename to test/jdk/javax/sql/util/SuperHero.java index c8afb3831de..2d6e68a7c9e 100644 --- a/test/jdk/javax/sql/testng/util/SuperHero.java +++ b/test/jdk/javax/sql/util/SuperHero.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/TestRowSetListener.java b/test/jdk/javax/sql/util/TestRowSetListener.java similarity index 96% rename from test/jdk/javax/sql/testng/util/TestRowSetListener.java rename to test/jdk/javax/sql/util/TestRowSetListener.java index 069ade29ca2..4f71f12da2e 100644 --- a/test/jdk/javax/sql/testng/util/TestRowSetListener.java +++ b/test/jdk/javax/sql/util/TestRowSetListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/util/TestSQLDataImpl.java b/test/jdk/javax/sql/util/TestSQLDataImpl.java similarity index 98% rename from test/jdk/javax/sql/testng/util/TestSQLDataImpl.java rename to test/jdk/javax/sql/util/TestSQLDataImpl.java index 0694add3ef9..f02eeb6fece 100644 --- a/test/jdk/javax/sql/testng/util/TestSQLDataImpl.java +++ b/test/jdk/javax/sql/util/TestSQLDataImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/javax/sql/testng/xml/COFFEE_ROWS.xml b/test/jdk/javax/sql/xml/COFFEE_ROWS.xml similarity index 100% rename from test/jdk/javax/sql/testng/xml/COFFEE_ROWS.xml rename to test/jdk/javax/sql/xml/COFFEE_ROWS.xml diff --git a/test/jdk/javax/sql/testng/xml/DELETED_COFFEE_ROWS.xml b/test/jdk/javax/sql/xml/DELETED_COFFEE_ROWS.xml similarity index 100% rename from test/jdk/javax/sql/testng/xml/DELETED_COFFEE_ROWS.xml rename to test/jdk/javax/sql/xml/DELETED_COFFEE_ROWS.xml diff --git a/test/jdk/javax/sql/testng/xml/INSERTED_COFFEE_ROWS.xml b/test/jdk/javax/sql/xml/INSERTED_COFFEE_ROWS.xml similarity index 100% rename from test/jdk/javax/sql/testng/xml/INSERTED_COFFEE_ROWS.xml rename to test/jdk/javax/sql/xml/INSERTED_COFFEE_ROWS.xml diff --git a/test/jdk/javax/sql/testng/xml/MODFIED_DELETED_COFFEE_ROWS.xml b/test/jdk/javax/sql/xml/MODFIED_DELETED_COFFEE_ROWS.xml similarity index 100% rename from test/jdk/javax/sql/testng/xml/MODFIED_DELETED_COFFEE_ROWS.xml rename to test/jdk/javax/sql/xml/MODFIED_DELETED_COFFEE_ROWS.xml diff --git a/test/jdk/javax/sql/testng/xml/UPDATED_COFFEE_ROWS.xml b/test/jdk/javax/sql/xml/UPDATED_COFFEE_ROWS.xml similarity index 100% rename from test/jdk/javax/sql/testng/xml/UPDATED_COFFEE_ROWS.xml rename to test/jdk/javax/sql/xml/UPDATED_COFFEE_ROWS.xml diff --git a/test/jdk/javax/sql/testng/xml/UPDATED_INSERTED_COFFEE_ROWS.xml b/test/jdk/javax/sql/xml/UPDATED_INSERTED_COFFEE_ROWS.xml similarity index 100% rename from test/jdk/javax/sql/testng/xml/UPDATED_INSERTED_COFFEE_ROWS.xml rename to test/jdk/javax/sql/xml/UPDATED_INSERTED_COFFEE_ROWS.xml From 3a4277db74f889d0b8350145515c1a1f4e399ec8 Mon Sep 17 00:00:00 2001 From: Srinivas Vamsi Parasa Date: Fri, 30 Jan 2026 17:50:58 +0000 Subject: [PATCH 269/328] =?UTF-8?q?8374744:=20Enable=20dumping=20of=20APX?= =?UTF-8?q?=20EGPRs=20(R16=E2=80=93R31)=20in=20JVM=20fatal=20error=20logs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: sviswanathan, dholmes --- src/hotspot/cpu/x86/vm_version_x86.cpp | 16 ++- src/hotspot/cpu/x86/vm_version_x86.hpp | 9 ++ src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp | 101 ++++++++++++++---- 3 files changed, 104 insertions(+), 22 deletions(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 0fff5b44e00..74df41f8682 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -143,7 +143,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator { Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4, std_cpuid24, std_cpuid29; Label sef_cpuid, sefsl1_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7; - Label ext_cpuid8, done, wrapup, vector_save_restore, apx_save_restore_warning; + Label ext_cpuid8, done, wrapup, vector_save_restore, apx_save_restore_warning, apx_xstate; Label legacy_setup, save_restore_except, legacy_save_restore, start_simd_check; StubCodeMark mark(this, "VM_Version", "get_cpu_info_stub"); @@ -468,6 +468,20 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ movq(Address(rsi, 0), r16); __ movq(Address(rsi, 8), r31); + // + // Query CPUID 0xD.19 for APX XSAVE offset + // Extended State Enumeration Sub-leaf 19 (APX) + // EAX = size of APX state (should be 128) + // EBX = offset in standard XSAVE format + // + __ movl(rax, 0xD); + __ movl(rcx, 19); + __ cpuid(); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::apx_xstate_size_offset()))); + __ movl(Address(rsi, 0), rax); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::apx_xstate_offset_offset()))); + __ movl(Address(rsi, 0), rbx); + UseAPX = save_apx; __ bind(vector_save_restore); // diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index cc93ee3564e..a3f2a801198 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -676,6 +676,10 @@ protected: // Space to save apx registers after signal handle jlong apx_save[2]; // Save r16 and r31 + // cpuid function 0xD, subleaf 19 (APX extended state) + uint32_t apx_xstate_size; // EAX: size of APX state (128) + uint32_t apx_xstate_offset; // EBX: offset in standard XSAVE area + VM_Features feature_flags() const; // Asserts @@ -739,6 +743,11 @@ public: static ByteSize ymm_save_offset() { return byte_offset_of(CpuidInfo, ymm_save); } static ByteSize zmm_save_offset() { return byte_offset_of(CpuidInfo, zmm_save); } static ByteSize apx_save_offset() { return byte_offset_of(CpuidInfo, apx_save); } + static ByteSize apx_xstate_offset_offset() { return byte_offset_of(CpuidInfo, apx_xstate_offset); } + static ByteSize apx_xstate_size_offset() { return byte_offset_of(CpuidInfo, apx_xstate_size); } + + static uint32_t apx_xstate_offset() { return _cpuid_info.apx_xstate_offset; } + static uint32_t apx_xstate_size() { return _cpuid_info.apx_xstate_size; } // The value used to check ymm register after signal handle static int ymm_test_value() { return 0xCAFEBABE; } diff --git a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp index 07f53582a76..ee08738c678 100644 --- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp +++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp @@ -52,6 +52,7 @@ #include "utilities/debug.hpp" #include "utilities/events.hpp" #include "utilities/vmError.hpp" +#include "runtime/vm_version.hpp" // put OS-includes here # include @@ -380,6 +381,43 @@ size_t os::Posix::default_stack_size(os::ThreadType thr_type) { ///////////////////////////////////////////////////////////////////////////// // helper functions for fatal error handler +// XSAVE constants - from Intel SDM Vol. 1, Chapter 13 +#define XSAVE_HDR_OFFSET 512 +#define XFEATURE_APX (1ULL << 19) + +// XSAVE header structure +// See: Intel SDM Vol. 1, Section 13.4.2 "XSAVE Header" +// Also: Linux kernel arch/x86/include/asm/fpu/types.h +struct xstate_header { + uint64_t xfeatures; + uint64_t xcomp_bv; + uint64_t reserved[6]; +}; + +// APX extended state - R16-R31 (16 x 64-bit registers) +// See: Intel APX Architecture Specification +struct apx_state { + uint64_t regs[16]; // r16-r31 +}; + +static apx_state* get_apx_state(const ucontext_t* uc) { + uint32_t offset = VM_Version::apx_xstate_offset(); + if (offset == 0 || uc->uc_mcontext.fpregs == nullptr) { + return nullptr; + } + + char* xsave = (char*)uc->uc_mcontext.fpregs; + xstate_header* hdr = (xstate_header*)(xsave + XSAVE_HDR_OFFSET); + + // Check if APX state is present in this context + if (!(hdr->xfeatures & XFEATURE_APX)) { + return nullptr; + } + + return (apx_state*)(xsave + offset); +} + + void os::print_context(outputStream *st, const void *context) { if (context == nullptr) return; @@ -406,6 +444,14 @@ void os::print_context(outputStream *st, const void *context) { st->print(", R14=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R14]); st->print(", R15=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R15]); st->cr(); + // Dump APX EGPRs (R16-R31) + apx_state* apx = UseAPX ? get_apx_state(uc) : nullptr; + if (apx != nullptr) { + for (int i = 0; i < 16; i++) { + st->print("%sR%d=" INTPTR_FORMAT, (i % 4 == 0) ? "" : ", ", 16 + i, (intptr_t)apx->regs[i]); + if (i % 4 == 3) st->cr(); + } + } st->print( "RIP=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RIP]); st->print(", EFLAGS=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_EFL]); st->print(", CSGSFS=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_CSGSFS]); @@ -432,37 +478,50 @@ void os::print_context(outputStream *st, const void *context) { } void os::print_register_info(outputStream *st, const void *context, int& continuation) { - const int register_count = 16; + if (context == nullptr) { + return; + } + const ucontext_t *uc = (const ucontext_t*)context; + apx_state* apx = UseAPX ? get_apx_state(uc) : nullptr; + + const int register_count = 16 + (apx != nullptr ? 16 : 0); int n = continuation; assert(n >= 0 && n <= register_count, "Invalid continuation value"); - if (context == nullptr || n == register_count) { + if (n == register_count) { return; } - const ucontext_t *uc = (const ucontext_t*)context; while (n < register_count) { // Update continuation with next index before printing location continuation = n + 1; + + if (n < 16) { + // Standard registers (RAX-R15) # define CASE_PRINT_REG(n, str, id) case n: st->print(str); print_location(st, uc->uc_mcontext.gregs[REG_##id]); - switch (n) { - CASE_PRINT_REG( 0, "RAX=", RAX); break; - CASE_PRINT_REG( 1, "RBX=", RBX); break; - CASE_PRINT_REG( 2, "RCX=", RCX); break; - CASE_PRINT_REG( 3, "RDX=", RDX); break; - CASE_PRINT_REG( 4, "RSP=", RSP); break; - CASE_PRINT_REG( 5, "RBP=", RBP); break; - CASE_PRINT_REG( 6, "RSI=", RSI); break; - CASE_PRINT_REG( 7, "RDI=", RDI); break; - CASE_PRINT_REG( 8, "R8 =", R8); break; - CASE_PRINT_REG( 9, "R9 =", R9); break; - CASE_PRINT_REG(10, "R10=", R10); break; - CASE_PRINT_REG(11, "R11=", R11); break; - CASE_PRINT_REG(12, "R12=", R12); break; - CASE_PRINT_REG(13, "R13=", R13); break; - CASE_PRINT_REG(14, "R14=", R14); break; - CASE_PRINT_REG(15, "R15=", R15); break; - } + switch (n) { + CASE_PRINT_REG( 0, "RAX=", RAX); break; + CASE_PRINT_REG( 1, "RBX=", RBX); break; + CASE_PRINT_REG( 2, "RCX=", RCX); break; + CASE_PRINT_REG( 3, "RDX=", RDX); break; + CASE_PRINT_REG( 4, "RSP=", RSP); break; + CASE_PRINT_REG( 5, "RBP=", RBP); break; + CASE_PRINT_REG( 6, "RSI=", RSI); break; + CASE_PRINT_REG( 7, "RDI=", RDI); break; + CASE_PRINT_REG( 8, "R8 =", R8); break; + CASE_PRINT_REG( 9, "R9 =", R9); break; + CASE_PRINT_REG(10, "R10=", R10); break; + CASE_PRINT_REG(11, "R11=", R11); break; + CASE_PRINT_REG(12, "R12=", R12); break; + CASE_PRINT_REG(13, "R13=", R13); break; + CASE_PRINT_REG(14, "R14=", R14); break; + CASE_PRINT_REG(15, "R15=", R15); break; + } # undef CASE_PRINT_REG + } else { + // APX extended general purpose registers (R16-R31) + st->print("R%d=", n); + print_location(st, apx->regs[n - 16]); + } ++n; } } From 32e00ff33785f0756cb320cd8c0ffad8eda76153 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 30 Jan 2026 19:07:59 +0000 Subject: [PATCH 270/328] 8375567: Remove AppContext usage from Swing Motif L&F classes Reviewed-by: serb, psadhukhan --- .../sun/java/swing/plaf/motif/MotifButtonUI.java | 13 ++----------- .../sun/java/swing/plaf/motif/MotifCheckBoxUI.java | 13 ++----------- .../com/sun/java/swing/plaf/motif/MotifLabelUI.java | 13 ++----------- .../java/swing/plaf/motif/MotifToggleButtonUI.java | 13 ++----------- 4 files changed, 8 insertions(+), 44 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java index 0e4c2e526ac..7a11e4a47e9 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java @@ -42,8 +42,6 @@ import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicButtonListener; import javax.swing.plaf.basic.BasicButtonUI; -import sun.awt.AppContext; - /** * MotifButton implementation * @@ -55,20 +53,13 @@ public class MotifButtonUI extends BasicButtonUI { private boolean defaults_initialized = false; - private static final Object MOTIF_BUTTON_UI_KEY = new Object(); + private static final ComponentUI UI = new MotifButtonUI(); // ******************************** // Create PLAF // ******************************** public static ComponentUI createUI(JComponent c) { - AppContext appContext = AppContext.getAppContext(); - MotifButtonUI motifButtonUI = - (MotifButtonUI) appContext.get(MOTIF_BUTTON_UI_KEY); - if (motifButtonUI == null) { - motifButtonUI = new MotifButtonUI(); - appContext.put(MOTIF_BUTTON_UI_KEY, motifButtonUI); - } - return motifButtonUI; + return UI; } // ******************************** diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java index 9e9f0008b07..7017eaf546c 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java @@ -30,8 +30,6 @@ import javax.swing.JComponent; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; -import sun.awt.AppContext; - /** * MotifCheckBox implementation * @@ -39,7 +37,7 @@ import sun.awt.AppContext; */ public class MotifCheckBoxUI extends MotifRadioButtonUI { - private static final Object MOTIF_CHECK_BOX_UI_KEY = new Object(); + private static final ComponentUI UI = new MotifCheckBoxUI(); private static final String propertyPrefix = "CheckBox" + "."; @@ -50,14 +48,7 @@ public class MotifCheckBoxUI extends MotifRadioButtonUI { // Create PLAF // ******************************** public static ComponentUI createUI(JComponent c) { - AppContext appContext = AppContext.getAppContext(); - MotifCheckBoxUI motifCheckBoxUI = - (MotifCheckBoxUI) appContext.get(MOTIF_CHECK_BOX_UI_KEY); - if (motifCheckBoxUI == null) { - motifCheckBoxUI = new MotifCheckBoxUI(); - appContext.put(MOTIF_CHECK_BOX_UI_KEY, motifCheckBoxUI); - } - return motifCheckBoxUI; + return UI; } @Override diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java index f19a3c23cb5..89c2e309f9e 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java @@ -29,8 +29,6 @@ import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicLabelUI; -import sun.awt.AppContext; - /** * A Motif {@literal L&F} implementation of LabelUI. * This merely sets up new default values in MotifLookAndFeel. @@ -39,16 +37,9 @@ import sun.awt.AppContext; */ public class MotifLabelUI extends BasicLabelUI { - private static final Object MOTIF_LABEL_UI_KEY = new Object(); + private static final ComponentUI UI = new MotifLabelUI(); public static ComponentUI createUI(JComponent c) { - AppContext appContext = AppContext.getAppContext(); - MotifLabelUI motifLabelUI = - (MotifLabelUI) appContext.get(MOTIF_LABEL_UI_KEY); - if (motifLabelUI == null) { - motifLabelUI = new MotifLabelUI(); - appContext.put(MOTIF_LABEL_UI_KEY, motifLabelUI); - } - return motifLabelUI; + return UI; } } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java index 7997145e648..7956023ed06 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java @@ -39,8 +39,6 @@ import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicToggleButtonUI; -import sun.awt.AppContext; - /** * BasicToggleButton implementation. * @@ -48,7 +46,7 @@ import sun.awt.AppContext; */ public class MotifToggleButtonUI extends BasicToggleButtonUI { - private static final Object MOTIF_TOGGLE_BUTTON_UI_KEY = new Object(); + private static final ComponentUI UI = new MotifToggleButtonUI(); protected Color selectColor; @@ -58,14 +56,7 @@ public class MotifToggleButtonUI extends BasicToggleButtonUI // Create PLAF // ******************************** public static ComponentUI createUI(JComponent b) { - AppContext appContext = AppContext.getAppContext(); - MotifToggleButtonUI motifToggleButtonUI = - (MotifToggleButtonUI) appContext.get(MOTIF_TOGGLE_BUTTON_UI_KEY); - if (motifToggleButtonUI == null) { - motifToggleButtonUI = new MotifToggleButtonUI(); - appContext.put(MOTIF_TOGGLE_BUTTON_UI_KEY, motifToggleButtonUI); - } - return motifToggleButtonUI; + return UI; } // ******************************** From 9ef98a5fb194eec3024b87ea9f9c9acee952dcf6 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 30 Jan 2026 19:08:20 +0000 Subject: [PATCH 271/328] 8376747: Remove AppContext from Swing LayoutStyle Reviewed-by: psadhukhan, azvegint --- .../share/classes/javax/swing/LayoutStyle.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/LayoutStyle.java b/src/java.desktop/share/classes/javax/swing/LayoutStyle.java index f1c384db6e2..bf84eb2379b 100644 --- a/src/java.desktop/share/classes/javax/swing/LayoutStyle.java +++ b/src/java.desktop/share/classes/javax/swing/LayoutStyle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ package javax.swing; import java.awt.Container; import javax.swing.plaf.ComponentUI; -import sun.awt.AppContext; /** * LayoutStyle provides information about how to position @@ -40,6 +39,9 @@ import sun.awt.AppContext; * @since 1.6 */ public abstract class LayoutStyle { + + private static LayoutStyle sharedInstance; + /** * Sets the shared instance of LayoutStyle. Specifying * null results in using the LayoutStyle from @@ -51,10 +53,10 @@ public abstract class LayoutStyle { public static void setInstance(LayoutStyle style) { synchronized(LayoutStyle.class) { if (style == null) { - AppContext.getAppContext().remove(LayoutStyle.class); + sharedInstance = null; } else { - AppContext.getAppContext().put(LayoutStyle.class, style); + sharedInstance = style; } } } @@ -70,8 +72,7 @@ public abstract class LayoutStyle { public static LayoutStyle getInstance() { LayoutStyle style; synchronized(LayoutStyle.class) { - style = (LayoutStyle)AppContext.getAppContext(). - get(LayoutStyle.class); + style = sharedInstance; } if (style == null) { return UIManager.getLookAndFeel().getLayoutStyle(); From c62c82d5e0485b8570bb1c61805e518fe05f3ec4 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 30 Jan 2026 19:27:45 +0000 Subject: [PATCH 272/328] 8376420: Remove AppContext from javax/swing/ImageIcon.java Reviewed-by: aivanov, psadhukhan --- .../share/classes/javax/swing/ImageIcon.java | 36 +++---------------- 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/ImageIcon.java b/src/java.desktop/share/classes/javax/swing/ImageIcon.java index aaaa2dfd4a4..ee6c08ebb15 100644 --- a/src/java.desktop/share/classes/javax/swing/ImageIcon.java +++ b/src/java.desktop/share/classes/javax/swing/ImageIcon.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -54,7 +54,6 @@ import javax.accessibility.AccessibleState; import javax.accessibility.AccessibleStateSet; import sun.awt.AWTAccessor; -import sun.awt.AppContext; /** * An implementation of the Icon interface that paints Icons @@ -110,18 +109,7 @@ public class ImageIcon implements Icon, Serializable, Accessible { * @deprecated since 1.8 */ @Deprecated - protected static final Component component = createComponent(); - - private static final Component createComponent() { - try { - Component component = new Component() {}; - // 6482575 - clear the appContext field so as not to leak it - AWTAccessor.getComponentAccessor().setAppContext(component, null); - return component; - } catch (Throwable t) { - return null; - } - } + protected static final Component component = new Component() {}; /** * Do not use this shared media tracker, which is used to load images. @@ -136,8 +124,6 @@ public class ImageIcon implements Icon, Serializable, Accessible { */ private static int mediaTrackerID; - private static final Object TRACKER_KEY = new StringBuilder("TRACKER_KEY"); - int width = -1; int height = -1; @@ -346,24 +332,12 @@ public class ImageIcon implements Icon, Serializable, Accessible { } } + private static final MediaTracker MEDIA_TRACKER = new MediaTracker(new Component() {}); /** - * Returns the MediaTracker for the current AppContext, creating a new - * MediaTracker if necessary. + * Returns the shared MediaTracker. */ private MediaTracker getTracker() { - Object trackerObj; - AppContext ac = AppContext.getAppContext(); - // Opt: Only synchronize if trackerObj comes back null? - // If null, synchronize, re-check for null, and put new tracker - synchronized(ac) { - trackerObj = ac.get(TRACKER_KEY); - if (trackerObj == null) { - Component comp = new Component() {}; - trackerObj = new MediaTracker(comp); - ac.put(TRACKER_KEY, trackerObj); - } - } - return (MediaTracker) trackerObj; + return MEDIA_TRACKER; } /** From 6ce2f3e18f31d1dbffc2c4f5adbb5dfe91613989 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Fri, 30 Jan 2026 22:37:43 +0000 Subject: [PATCH 273/328] 8376751: add preview project anchors to main-line ProblemList files Reviewed-by: kvn, rriggs, liach --- make/RunTests.gmk | 6 ++- test/docs/ProblemList.txt | 15 ++++++- test/hotspot/jtreg/ProblemList-AotJdk.txt | 13 ++++++ test/hotspot/jtreg/ProblemList-StaticJdk.txt | 42 +++++++++++++++++++ test/hotspot/jtreg/ProblemList-Virtual.txt | 14 ++++++- test/hotspot/jtreg/ProblemList-Xcomp.txt | 15 ++++++- .../jtreg/ProblemList-enable-preview.txt | 6 ++- .../jtreg/ProblemList-jvmti-stress-agent.txt | 15 ++++++- test/hotspot/jtreg/ProblemList-zgc.txt | 15 ++++++- test/hotspot/jtreg/ProblemList.txt | 15 ++++++- test/jaxp/ProblemList.txt | 14 ++++++- test/jdk/ProblemList-AotJdk.txt | 14 ++++++- test/jdk/ProblemList-StaticJdk.txt | 15 ++++++- test/jdk/ProblemList-Virtual.txt | 14 ++++++- test/jdk/ProblemList-Xcomp.txt | 15 ++++++- test/jdk/ProblemList-coh.txt | 41 ++++++++++++++++++ test/jdk/ProblemList-enable-preview.txt | 6 ++- test/jdk/ProblemList-jvmti-stress-agent.txt | 15 ++++++- test/jdk/ProblemList-shenandoah.txt | 12 ++++++ test/jdk/ProblemList-zgc.txt | 15 ++++++- test/jdk/ProblemList.txt | 13 ++++++ test/langtools/ProblemList-StaticJdk.txt | 15 ++++++- test/langtools/ProblemList-enable-preview.txt | 32 ++++++++++++++ test/langtools/ProblemList.txt | 15 ++++++- test/lib-test/ProblemList-StaticJdk.txt | 15 ++++++- test/lib-test/ProblemList.txt | 15 ++++++- 26 files changed, 400 insertions(+), 22 deletions(-) create mode 100644 test/jdk/ProblemList-coh.txt create mode 100644 test/langtools/ProblemList-enable-preview.txt diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 946b1332edc..02ea632e3ec 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2026, 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 @@ -972,6 +972,10 @@ define SetupRunJtregTestBody JTREG_AUTO_PROBLEM_LISTS += ProblemList-enable-preview.txt endif + ifneq ($$(findstring -XX:+UseCompactObjectHeaders, $$(JTREG_ALL_OPTIONS)), ) + JTREG_AUTO_PROBLEM_LISTS += ProblemList-coh.txt + endif + ifneq ($$(JTREG_EXTRA_PROBLEM_LISTS), ) # Accept both absolute paths as well as relative to the current test root. diff --git a/test/docs/ProblemList.txt b/test/docs/ProblemList.txt index c846678665d..d856f9c955e 100644 --- a/test/docs/ProblemList.txt +++ b/test/docs/ProblemList.txt @@ -1,6 +1,6 @@ ########################################################################### # -# Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2024, 2026, 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 @@ -39,3 +39,16 @@ # More than one label is allowed but must be on the same line. # ############################################################################# + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/hotspot/jtreg/ProblemList-AotJdk.txt b/test/hotspot/jtreg/ProblemList-AotJdk.txt index e27e85645f5..0a2177b8edb 100644 --- a/test/hotspot/jtreg/ProblemList-AotJdk.txt +++ b/test/hotspot/jtreg/ProblemList-AotJdk.txt @@ -56,3 +56,16 @@ compiler/ciReplay/TestInliningProtectionDomain.java 0000000 generic-all # These tests fail often with AotJdk due to JDK-8323727 compiler/arguments/TestStressReflectiveCode.java 8323727 generic-all compiler/arraycopy/TestCloneWithStressReflectiveCode.java 8323727 generic-all + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/hotspot/jtreg/ProblemList-StaticJdk.txt b/test/hotspot/jtreg/ProblemList-StaticJdk.txt index 1e5538ca5b9..a6112169f8d 100644 --- a/test/hotspot/jtreg/ProblemList-StaticJdk.txt +++ b/test/hotspot/jtreg/ProblemList-StaticJdk.txt @@ -1,3 +1,32 @@ +# +# Copyright (c) 2025, 2026, 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. +# + +############################################################################# +# +# List of quarantined tests for testing in StaticJdk mode. +# +############################################################################# + # Dynamically link with JDK/VM native libraries gtest/GTestWrapper.java 8356201 generic-all gtest/LargePageGtests.java#use-large-pages 8356201 generic-all @@ -6,3 +35,16 @@ gtest/MetaspaceGtests.java#no-ccs 8356201 generic-all gtest/NMTGtests.java#nmt-detail 8356201 generic-all gtest/NMTGtests.java#nmt-off 8356201 generic-all gtest/NMTGtests.java#nmt-summary 8356201 generic-all + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/hotspot/jtreg/ProblemList-Virtual.txt b/test/hotspot/jtreg/ProblemList-Virtual.txt index 31684662194..7c4846a9fb2 100644 --- a/test/hotspot/jtreg/ProblemList-Virtual.txt +++ b/test/hotspot/jtreg/ProblemList-Virtual.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022, 2026, 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 @@ -77,3 +77,15 @@ vmTestbase/nsk/jdi/VMOutOfMemoryException/VMOutOfMemoryException001/VMOutOfMemor # to make progress when all other threads are currently suspended. vmTestbase/nsk/jdi/ThreadReference/isSuspended/issuspended002/TestDescription.java 8338713 generic-all +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/hotspot/jtreg/ProblemList-Xcomp.txt b/test/hotspot/jtreg/ProblemList-Xcomp.txt index 758bb32e968..e4f1774e6e0 100644 --- a/test/hotspot/jtreg/ProblemList-Xcomp.txt +++ b/test/hotspot/jtreg/ProblemList-Xcomp.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -46,3 +46,16 @@ vmTestbase/nsk/jvmti/scenarios/capability/CM03/cm03t001/TestDescription.java 829 vmTestbase/nsk/stress/thread/thread006.java 8321476 linux-all gc/arguments/TestNewSizeFlags.java 8299116 macosx-aarch64 + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/hotspot/jtreg/ProblemList-enable-preview.txt b/test/hotspot/jtreg/ProblemList-enable-preview.txt index 31e09d372a8..1a831a0dde3 100644 --- a/test/hotspot/jtreg/ProblemList-enable-preview.txt +++ b/test/hotspot/jtreg/ProblemList-enable-preview.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ # # List of quarantined tests for testing with --enable-preview # +# These are failures that ONLY occur with the '--enable-preview' option +# specified. There are separate sub-sections for each preview project. +# ############################################################################# - diff --git a/test/hotspot/jtreg/ProblemList-jvmti-stress-agent.txt b/test/hotspot/jtreg/ProblemList-jvmti-stress-agent.txt index eb4131691c9..1e84a39c30b 100644 --- a/test/hotspot/jtreg/ProblemList-jvmti-stress-agent.txt +++ b/test/hotspot/jtreg/ProblemList-jvmti-stress-agent.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2025, 2026, 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 @@ -96,3 +96,16 @@ serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorThreadTest.java serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorTwoAgentsTest.java 0000000 generic-all serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorVMEventsTest.java#id0 0000000 generic-all serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorVMEventsTest.java#id1 0000000 generic-all + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/hotspot/jtreg/ProblemList-zgc.txt b/test/hotspot/jtreg/ProblemList-zgc.txt index 911e3adc9ca..3e52b7169df 100644 --- a/test/hotspot/jtreg/ProblemList-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-zgc.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2026, 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 @@ -113,3 +113,16 @@ compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/NativeCallTest.java compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java 8343233 generic-aarch64 compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java 8343233 generic-aarch64 compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/VirtualObjectDebugInfoTest.java 8343233 generic-aarch64 + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 7e521279a4c..3e4814180f6 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2026, 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 @@ -183,3 +183,16 @@ vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn001/forceEa vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi005/TestDescription.java 8076494 windows-x64 vmTestbase/nsk/monitoring/ThreadMXBean/findMonitorDeadlockedThreads/find006/TestDescription.java 8310144 macosx-aarch64 + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/jaxp/ProblemList.txt b/test/jaxp/ProblemList.txt index 23ebb07f5ff..8f7380a43f8 100644 --- a/test/jaxp/ProblemList.txt +++ b/test/jaxp/ProblemList.txt @@ -1,6 +1,6 @@ ########################################################################### # -# Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2026, 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,3 +23,15 @@ # ########################################################################### +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/jdk/ProblemList-AotJdk.txt b/test/jdk/ProblemList-AotJdk.txt index 20960652dcf..c98bf63b25f 100644 --- a/test/jdk/ProblemList-AotJdk.txt +++ b/test/jdk/ProblemList-AotJdk.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2024, 2026, 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 @@ -44,3 +44,15 @@ java/lang/invoke/DumpMethodHandleInternals.java 0000000 generic- # this message will not be printed in the production run. java/util/Locale/UseOldISOCodesTest.java 0000000 generic-all +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/jdk/ProblemList-StaticJdk.txt b/test/jdk/ProblemList-StaticJdk.txt index 70f0438c0c6..700099656e8 100644 --- a/test/jdk/ProblemList-StaticJdk.txt +++ b/test/jdk/ProblemList-StaticJdk.txt @@ -1,6 +1,6 @@ ########################################################################### # -# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,3 +24,16 @@ ########################################################################### # Currently empty + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/jdk/ProblemList-Virtual.txt b/test/jdk/ProblemList-Virtual.txt index fc5f31e3ce8..52f187086de 100644 --- a/test/jdk/ProblemList-Virtual.txt +++ b/test/jdk/ProblemList-Virtual.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -34,3 +34,15 @@ java/lang/ScopedValue/StressStackOverflow.java#default 8309646 generic-all java/lang/ScopedValue/StressStackOverflow.java#no-TieredCompilation 8309646 generic-all java/lang/ScopedValue/StressStackOverflow.java#TieredStopAtLevel1 8309646 generic-all +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/jdk/ProblemList-Xcomp.txt b/test/jdk/ProblemList-Xcomp.txt index 5ed171a1fea..44bad411f26 100644 --- a/test/jdk/ProblemList-Xcomp.txt +++ b/test/jdk/ProblemList-Xcomp.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2026, 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 @@ -29,3 +29,16 @@ java/lang/invoke/MethodHandles/CatchExceptionTest.java 8146623 generic-all java/lang/reflect/callerCache/ReflectionCallerCacheTest.java 8332028 generic-all + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/jdk/ProblemList-coh.txt b/test/jdk/ProblemList-coh.txt new file mode 100644 index 00000000000..b3bddb0c9f4 --- /dev/null +++ b/test/jdk/ProblemList-coh.txt @@ -0,0 +1,41 @@ +# +# Copyright (c) 2026, 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. +# + +############################################################################# +# +# List of quarantined tests for testing with -XX:+UseCompactObjectHeaders +# +############################################################################# + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/jdk/ProblemList-enable-preview.txt b/test/jdk/ProblemList-enable-preview.txt index 31e09d372a8..1a831a0dde3 100644 --- a/test/jdk/ProblemList-enable-preview.txt +++ b/test/jdk/ProblemList-enable-preview.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ # # List of quarantined tests for testing with --enable-preview # +# These are failures that ONLY occur with the '--enable-preview' option +# specified. There are separate sub-sections for each preview project. +# ############################################################################# - diff --git a/test/jdk/ProblemList-jvmti-stress-agent.txt b/test/jdk/ProblemList-jvmti-stress-agent.txt index 09be19c3d94..e9019b6014e 100644 --- a/test/jdk/ProblemList-jvmti-stress-agent.txt +++ b/test/jdk/ProblemList-jvmti-stress-agent.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2025, 2026, 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 @@ -29,3 +29,16 @@ com/sun/jdi/ThreadMemoryLeakTest.java 0000 # weak referenced are not cleared java/lang/WeakPairMap/Driver.java 0000000 generic-all java/lang/ref/ReachabilityFenceTest.java 0000000 generic-all + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/jdk/ProblemList-shenandoah.txt b/test/jdk/ProblemList-shenandoah.txt index 063795d69e8..522b77cb502 100644 --- a/test/jdk/ProblemList-shenandoah.txt +++ b/test/jdk/ProblemList-shenandoah.txt @@ -58,3 +58,15 @@ jdk/jfr/jcmd/TestJcmdStartPathToGCRoots.java 8342951 generic-all jdk/jfr/jvm/TestWaste.java 8342951 generic-all jdk/jfr/startupargs/TestOldObjectQueueSize.java 8342951 generic-all +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/jdk/ProblemList-zgc.txt b/test/jdk/ProblemList-zgc.txt index ab44c5e47a9..065a52f9a83 100644 --- a/test/jdk/ProblemList-zgc.txt +++ b/test/jdk/ProblemList-zgc.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2026, 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 @@ -38,3 +38,16 @@ sun/tools/jhsdb/heapconfig/JMapHeapConfigTest.java 8307393 generic-all sun/tools/jhsdb/HeapDumpTestWithActiveProcess.java 8307393 generic-all com/sun/jdi/ThreadMemoryLeakTest.java 8307402 generic-all + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 5e8406b13a6..36356c3c544 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -778,3 +778,16 @@ java/awt/Cursor/CursorDragTest/ListDragCursor.java 7177297 macosx-all # jdk_since_checks tools/sincechecker/modules/jdk.management.jfr/JdkManagementJfrCheckSince.java 8354921 generic-all + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/langtools/ProblemList-StaticJdk.txt b/test/langtools/ProblemList-StaticJdk.txt index 70f0438c0c6..700099656e8 100644 --- a/test/langtools/ProblemList-StaticJdk.txt +++ b/test/langtools/ProblemList-StaticJdk.txt @@ -1,6 +1,6 @@ ########################################################################### # -# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,3 +24,16 @@ ########################################################################### # Currently empty + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/langtools/ProblemList-enable-preview.txt b/test/langtools/ProblemList-enable-preview.txt new file mode 100644 index 00000000000..1a831a0dde3 --- /dev/null +++ b/test/langtools/ProblemList-enable-preview.txt @@ -0,0 +1,32 @@ +# +# Copyright (c) 2025, 2026, 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. +# + +############################################################################# +# +# List of quarantined tests for testing with --enable-preview +# +# These are failures that ONLY occur with the '--enable-preview' option +# specified. There are separate sub-sections for each preview project. +# +############################################################################# + diff --git a/test/langtools/ProblemList.txt b/test/langtools/ProblemList.txt index 9d61a20663d..07ab6937c07 100644 --- a/test/langtools/ProblemList.txt +++ b/test/langtools/ProblemList.txt @@ -1,6 +1,6 @@ ########################################################################### # -# Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2026, 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 @@ -71,3 +71,16 @@ tools/javap/output/RepeatingTypeAnnotations.java ########################################################################### # # jdeps + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/lib-test/ProblemList-StaticJdk.txt b/test/lib-test/ProblemList-StaticJdk.txt index 70f0438c0c6..700099656e8 100644 --- a/test/lib-test/ProblemList-StaticJdk.txt +++ b/test/lib-test/ProblemList-StaticJdk.txt @@ -1,6 +1,6 @@ ########################################################################### # -# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,3 +24,16 @@ ########################################################################### # Currently empty + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + diff --git a/test/lib-test/ProblemList.txt b/test/lib-test/ProblemList.txt index 011466088d3..2a5caedc8d8 100644 --- a/test/lib-test/ProblemList.txt +++ b/test/lib-test/ProblemList.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2026, 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,3 +37,16 @@ # More than one label is allowed but must be on the same line. # ############################################################################# + +############################################################################# + +# Preview project specific failures go here at the end of the file. +# +# These are NOT failures that occur with the '--enable-preview' option +# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# These are failures that occur WITHOUT the '--enable-preview' option +# specified AND occur because of some issue with preview project code, +# in either implementation or test code. + +############################################################################# + From ca95e5f3ddd5961dd43f825ed6c47054284c6798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Sat, 31 Jan 2026 23:30:18 +0000 Subject: [PATCH 274/328] 8375580: Avoid using ArrayDeque in jdk.internal.loader.URLClassPath Reviewed-by: liach, redestad, jpai --- .../jdk/internal/loader/URLClassPath.java | 93 ++++----- .../JarManifestClassPathOrder.java | 178 ++++++++++++++++++ 2 files changed, 228 insertions(+), 43 deletions(-) create mode 100644 test/jdk/jdk/internal/loader/URLClassPath/JarManifestClassPathOrder.java diff --git a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java index 3504ce7e8b3..90771575657 100644 --- a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java +++ b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,6 @@ import java.net.URLStreamHandler; import java.net.URLStreamHandlerFactory; import java.security.CodeSigner; import java.security.cert.Certificate; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -98,11 +97,20 @@ public class URLClassPath { DEBUG_CP_URL_CHECK = p != null ? p.equals("true") || p.isEmpty() : false; } - /* The original search path of URLs. */ - private final ArrayList path; + /* Search path of URLs passed to the constructor or by calls to addURL. + * Access is guarded by a monitor on 'searchPath' itself + */ + private final ArrayList searchPath; - /* The deque of unopened URLs */ - private final ArrayDeque unopenedUrls; + /* Index of the next URL in the search path to process. + * Access is guarded by a monitor on 'searchPath' + */ + private int nextURL = 0; + + /* List of URLs found during expansion of JAR 'Class-Path' attributes. + * Access is guarded by a monitor on 'searchPath' + */ + private final ArrayList manifestClassPath = new ArrayList<>(); /* The resulting search path of Loaders */ private final ArrayList loaders = new ArrayList<>(); @@ -128,14 +136,8 @@ public class URLClassPath { */ public URLClassPath(URL[] urls, URLStreamHandlerFactory factory) { - ArrayList path = new ArrayList<>(urls.length); - ArrayDeque unopenedUrls = new ArrayDeque<>(urls.length); - for (URL url : urls) { - path.add(url); - unopenedUrls.add(url); - } - this.path = path; - this.unopenedUrls = unopenedUrls; + // Reject null URL array or any null element in the array + this.searchPath = new ArrayList<>(List.of(urls)); if (factory != null) { jarHandler = factory.createURLStreamHandler("jar"); @@ -174,16 +176,7 @@ public class URLClassPath { off = next + 1; } while (next != -1); } - - // can't use ArrayDeque#addAll or new ArrayDeque(Collection); - // it's too early in the bootstrap to trigger use of lambdas - int size = path.size(); - ArrayDeque unopenedUrls = new ArrayDeque<>(size); - for (int i = 0; i < size; i++) - unopenedUrls.add(path.get(i)); - - this.unopenedUrls = unopenedUrls; - this.path = path; + this.searchPath = path; // the application class loader uses the built-in protocol handler to avoid protocol // handler lookup when opening JAR files on the class path. this.jarHandler = new sun.net.www.protocol.jar.Handler(); @@ -215,10 +208,9 @@ public class URLClassPath { public synchronized void addURL(URL url) { if (closed || url == null) return; - synchronized (unopenedUrls) { - if (! path.contains(url)) { - unopenedUrls.addLast(url); - path.add(url); + synchronized (searchPath) { + if (! searchPath.contains(url)) { + searchPath.add(url); } } } @@ -249,8 +241,8 @@ public class URLClassPath { * Returns the original search path of URLs. */ public URL[] getURLs() { - synchronized (unopenedUrls) { - return path.toArray(new URL[0]); + synchronized (searchPath) { + return searchPath.toArray(new URL[0]); } } @@ -379,6 +371,23 @@ public class URLClassPath { }; } + /* + * Returns the next URL to process or null if finished + */ + private URL nextURL() { + synchronized (searchPath) { + // Check paths discovered during 'Class-Path' expansion first + if (!manifestClassPath.isEmpty()) { + return manifestClassPath.removeLast(); + } + // Check the regular search path + if (nextURL < searchPath.size()) { + return searchPath.get(nextURL++); + } + // All paths exhausted + return null; + } + } /* * Returns the Loader at the specified position in the URL search * path. The URLs are opened and expanded as needed. Returns null @@ -389,14 +398,13 @@ public class URLClassPath { return null; } // Expand URL search path until the request can be satisfied - // or unopenedUrls is exhausted. + // or all paths are exhausted. while (loaders.size() < index + 1) { - final URL url; - synchronized (unopenedUrls) { - url = unopenedUrls.pollFirst(); - if (url == null) - return null; + final URL url = nextURL(); + if (url == null) { + return null; } + // Skip this URL if it already has a Loader. String urlNoFragString = URLUtil.urlNoFragString(url); if (lmap.containsKey(urlNoFragString)) { @@ -422,7 +430,7 @@ public class URLClassPath { continue; } if (loaderClassPathURLs != null) { - push(loaderClassPathURLs); + addManifestClassPaths(loaderClassPathURLs); } // Finally, add the Loader to the search path. loaders.add(loader); @@ -475,13 +483,12 @@ public class URLClassPath { } /* - * Pushes the specified URLs onto the head of unopened URLs. + * Adds the specified URLs to the list of 'Class-Path' expanded URLs */ - private void push(URL[] urls) { - synchronized (unopenedUrls) { - for (int i = urls.length - 1; i >= 0; --i) { - unopenedUrls.addFirst(urls[i]); - } + private void addManifestClassPaths(URL[] urls) { + synchronized (searchPath) { + // Adding in reversed order since manifestClassPath is consumed tail-first + manifestClassPath.addAll(Arrays.asList(urls).reversed()); } } diff --git a/test/jdk/jdk/internal/loader/URLClassPath/JarManifestClassPathOrder.java b/test/jdk/jdk/internal/loader/URLClassPath/JarManifestClassPathOrder.java new file mode 100644 index 00000000000..c1cda1d448a --- /dev/null +++ b/test/jdk/jdk/internal/loader/URLClassPath/JarManifestClassPathOrder.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2026, 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 org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/* + * @test + * @summary Verify that URLClassPath discovers JAR Class-Path URLs in the expected order + * @run junit JarManifestClassPathOrder + */ +public class JarManifestClassPathOrder { + + // Name of the JAR resource use for lookups + private static final String ENTRY_NAME = "JarClassPathOrdering.txt"; + + /** + * Verify that URLClassPath discovers JAR files in the expected order when + * only root JARs are on the 'original' class path and the other JARs are + * found via multiple levels of Class-Path Manifest attributes. + * + * @throws IOException if an unexpected error occurs + */ + @Test + public void shouldLoadJARsInExpectedOrder() throws IOException { + + // Set up a 'Class-Path' JAR tree of depth 3 + JarTree specs = new JarTree(); + specs.addJars(3); + + // List of "root" JAR file URLs to use for URLClassLoader + List searchPath = new ArrayList<>(); + + // Order of JAR files we expect URLClassPath to find after a DFS search + List expectedJarNames = new ArrayList<>(); + + for (JarSpec spec : specs.dfs) { + Path jar = createJar(spec); + expectedJarNames.add(jar.getFileName().toString()); + // Only root JARs in the search path, others are discovered transitively via "Class-Path" + if (spec.isRoot()) { + searchPath.add(jar.toUri().toURL()); + } + } + + // Load ENTRY_NAME to identify all JARs found by URLClassPath + try (URLClassLoader loader = new URLClassLoader(searchPath.toArray(new URL[0]))) { + Enumeration resources = loader.getResources(ENTRY_NAME); + // Collect all JAR file names in the order discovered by URLClassPath + List actualJarNames = Collections.list(resources) + .stream() + .map(this::extractJarName) + .collect(Collectors.toList()); + // JARs should be found in DFS order + assertEquals(expectedJarNames, actualJarNames, "JAR files not found in expected order"); + } + } + + // Extract file name of JAR file from a JAR URL + private String extractJarName(URL url) { + String jarPath = url.getPath().substring(0, url.getPath().indexOf("!/")); + String jarName = jarPath.substring(jarPath.lastIndexOf('/') + 1); + return jarName; + } + + // Create a JAR file according to the spec, possibly including a Class-Path attribute + private Path createJar(JarSpec spec) throws IOException { + Path file = Path.of(spec.name +".jar"); + Manifest man = new Manifest(); + Attributes attrs = man.getMainAttributes(); + attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0"); + + // Set Class-Path attribute + if (!spec.children.isEmpty()) { + String path = String.join(" ", spec.children + .stream() + .map(js -> js.name +".jar") + .collect(Collectors.toList())); + attrs.put(Attributes.Name.CLASS_PATH, path); + } + + try (JarOutputStream out = new JarOutputStream(Files.newOutputStream(file), man)) { + // All JARs include the same entry + out.putNextEntry(new JarEntry(ENTRY_NAME)); + } + + return file; + } + + + // Helper class to represent a tree of JARs related by "Class-Path" + static class JarTree { + static final List NAMES = List.of("a", "b", "c"); + List dfs = new ArrayList<>(); + + private void addJar(String prefix, String name, JarSpec parent, int depth, int maxDepth) { + if (depth > maxDepth) { + return; + } + JarSpec spec = new JarSpec(prefix + name, parent); + dfs.add(spec); + + if (parent != null) { + parent.children.add(spec); + } + + for (String childName : NAMES) { + addJar(prefix + name, childName, spec, depth + 1, maxDepth); + } + } + + /* Make a tree of JARs related by the 'Class-Path' Manifest attribute: + * a.jar + * aa.jar + * aaa.jar + * aab.jar + * [...] + * ccc.jar + */ + public void addJars(int maxDepth) { + for (String name : NAMES) { + addJar("", name, null, 1, maxDepth); + } + } + } + + // Helper class to represent a JAR file to be found by URLClassPath + static class JarSpec { + final String name; + final JarSpec parent; + final List children = new ArrayList<>(); + + JarSpec(String name, JarSpec parent) { + this.name = name; + this.parent = parent; + } + boolean isRoot() { + return parent == null; + } + } +} From f4765abd7ef76108c1ae5777f2822800be22030e Mon Sep 17 00:00:00 2001 From: Phil Race Date: Sun, 1 Feb 2026 19:19:18 +0000 Subject: [PATCH 275/328] 8376755: Remove AppContext from Swing javax/swing/plaf/basic classes Reviewed-by: dnguyen, kizune --- .../javax/swing/plaf/basic/BasicButtonUI.java | 14 +---- .../swing/plaf/basic/BasicCheckBoxUI.java | 15 +---- .../swing/plaf/basic/BasicComboBoxUI.java | 19 +------ .../javax/swing/plaf/basic/BasicLabelUI.java | 3 +- .../swing/plaf/basic/BasicLookAndFeel.java | 56 ++++--------------- .../swing/plaf/basic/BasicPopupMenuUI.java | 37 +++++------- .../swing/plaf/basic/BasicRadioButtonUI.java | 14 +---- .../javax/swing/plaf/basic/BasicTextUI.java | 18 ++---- .../swing/plaf/basic/BasicToggleButtonUI.java | 15 +---- .../swing/JPopupMenu/6495920/bug6495920.java | 11 ++-- 10 files changed, 52 insertions(+), 150 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicButtonUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicButtonUI.java index c7c036e859f..7846e04b565 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicButtonUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,6 @@ import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; import javax.swing.text.View; -import sun.awt.AppContext; import sun.swing.SwingUtilities2; /** @@ -88,7 +87,7 @@ public class BasicButtonUI extends ButtonUI{ private static final String propertyPrefix = "Button" + "."; - private static final Object BASIC_BUTTON_UI_KEY = new Object(); + private static final ComponentUI UI = new BasicButtonUI(); private KeyListener keyListener = null; @@ -107,14 +106,7 @@ public class BasicButtonUI extends ButtonUI{ * @return an instance of {@code BasicButtonUI} */ public static ComponentUI createUI(JComponent c) { - AppContext appContext = AppContext.getAppContext(); - BasicButtonUI buttonUI = - (BasicButtonUI) appContext.get(BASIC_BUTTON_UI_KEY); - if (buttonUI == null) { - buttonUI = new BasicButtonUI(); - appContext.put(BASIC_BUTTON_UI_KEY, buttonUI); - } - return buttonUI; + return UI; } /** diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicCheckBoxUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicCheckBoxUI.java index 24af28c94c0..49549521005 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicCheckBoxUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicCheckBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,6 @@ package javax.swing.plaf.basic; -import sun.awt.AppContext; - import javax.swing.*; import java.awt.*; @@ -51,7 +49,7 @@ import java.io.Serializable; */ public class BasicCheckBoxUI extends BasicRadioButtonUI { - private static final Object BASIC_CHECK_BOX_UI_KEY = new Object(); + private static final ComponentUI UI = new BasicCheckBoxUI(); private static final String propertyPrefix = "CheckBox" + "."; @@ -71,14 +69,7 @@ public class BasicCheckBoxUI extends BasicRadioButtonUI { * @return an instance of {@code BasicCheckBoxUI} */ public static ComponentUI createUI(JComponent b) { - AppContext appContext = AppContext.getAppContext(); - BasicCheckBoxUI checkboxUI = - (BasicCheckBoxUI) appContext.get(BASIC_CHECK_BOX_UI_KEY); - if (checkboxUI == null) { - checkboxUI = new BasicCheckBoxUI(); - appContext.put(BASIC_CHECK_BOX_UI_KEY, checkboxUI); - } - return checkboxUI; + return UI; } public String getPropertyPrefix() { diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java index 2d1a458e0d7..de3cb1adf75 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,6 @@ import javax.swing.text.*; import javax.swing.event.*; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; -import sun.awt.AppContext; import sun.swing.DefaultLookup; import sun.swing.SwingUtilities2; import sun.swing.UIAction; @@ -202,10 +201,6 @@ public class BasicComboBoxUI extends ComboBoxUI { // Cached the size that the display needs to render the largest item private Dimension cachedDisplaySize = new Dimension( 0, 0 ); - // Key used for lookup of the DefaultListCellRenderer in the AppContext. - private static final Object COMBO_UI_LIST_CELL_RENDERER_KEY = - new StringBuffer("DefaultListCellRendererKey"); - static final StringBuffer HIDE_POPUP_KEY = new StringBuffer("HidePopupKey"); @@ -237,18 +232,10 @@ public class BasicComboBoxUI extends ComboBoxUI { */ public BasicComboBoxUI() {} + private static final ListCellRenderer CELL_RENDERER = new DefaultListCellRenderer(); // Used for calculating the default size. private static ListCellRenderer getDefaultListCellRenderer() { - @SuppressWarnings("unchecked") - ListCellRenderer renderer = (ListCellRenderer)AppContext. - getAppContext().get(COMBO_UI_LIST_CELL_RENDERER_KEY); - - if (renderer == null) { - renderer = new DefaultListCellRenderer(); - AppContext.getAppContext().put(COMBO_UI_LIST_CELL_RENDERER_KEY, - new DefaultListCellRenderer()); - } - return renderer; + return CELL_RENDERER; } /** diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLabelUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLabelUI.java index 279de053fd6..04251ca6266 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLabelUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLabelUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ package javax.swing.plaf.basic; import sun.swing.SwingUtilities2; import sun.swing.DefaultLookup; import sun.swing.UIAction; -import sun.awt.AppContext; import javax.swing.*; import javax.swing.plaf.*; diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java index 12b871d6efd..964ee1cb9c9 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -78,7 +78,6 @@ import javax.swing.plaf.FontUIResource; import javax.swing.plaf.InsetsUIResource; import javax.swing.text.DefaultEditorKit; -import sun.awt.AppContext; import sun.awt.SunToolkit; import sun.swing.SwingAccessor; import sun.swing.SwingUtilities2; @@ -126,11 +125,6 @@ public abstract class BasicLookAndFeel extends LookAndFeel implements Serializab AWTEventHelper invocator = null; - /* - * Listen for our AppContext being disposed - */ - private PropertyChangeListener disposer = null; - /** * Constructor for subclasses to call. */ @@ -174,18 +168,6 @@ public abstract class BasicLookAndFeel extends LookAndFeel implements Serializab if (invocator == null) { invocator = new AWTEventHelper(); needsEventHelper = true; - - // Add a PropertyChangeListener to our AppContext so we're alerted - // when the AppContext is disposed(), at which time this laf should - // be uninitialize()d. - disposer = new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent prpChg) { - uninitialize(); - } - }; - AppContext.getAppContext().addPropertyChangeListener( - AppContext.GUI_DISPOSED, - disposer); } } @@ -193,35 +175,21 @@ public abstract class BasicLookAndFeel extends LookAndFeel implements Serializab * {@inheritDoc} */ public void uninitialize() { - AppContext context = AppContext.getAppContext(); - synchronized (BasicPopupMenuUI.MOUSE_GRABBER_KEY) { - Object grabber = context.get(BasicPopupMenuUI.MOUSE_GRABBER_KEY); - if (grabber != null) { - ((BasicPopupMenuUI.MouseGrabber)grabber).uninstall(); - } - } - synchronized (BasicPopupMenuUI.MENU_KEYBOARD_HELPER_KEY) { - Object helper = - context.get(BasicPopupMenuUI.MENU_KEYBOARD_HELPER_KEY); - if (helper != null) { - ((BasicPopupMenuUI.MenuKeyboardHelper)helper).uninstall(); - } - } + synchronized (BasicPopupMenuUI.class) { + if (BasicPopupMenuUI.mouseGrabber != null) { + BasicPopupMenuUI.mouseGrabber.uninstall(); + BasicPopupMenuUI.mouseGrabber = null; + } + if (BasicPopupMenuUI.menuKeyboardHelper != null) { + BasicPopupMenuUI.menuKeyboardHelper.uninstall(); + BasicPopupMenuUI.menuKeyboardHelper = null; + } + } - if(invocator != null) { + if (invocator != null) { invocator.run(); invocator = null; } - - if (disposer != null) { - // Note that we're likely calling removePropertyChangeListener() - // during the course of AppContext.firePropertyChange(). - // However, EventListenerAggregate has code to safely modify - // the list under such circumstances. - context.removePropertyChangeListener(AppContext.GUI_DISPOSED, - disposer); - disposer = null; - } } /** diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java index 6fab795e36c..8df27d3e3cb 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,8 +41,6 @@ import java.util.*; import sun.swing.UIAction; -import sun.awt.AppContext; - /** * A Windows L&F implementation of PopupMenuUI. This implementation * is a "combined" view/controller. @@ -52,10 +50,9 @@ import sun.awt.AppContext; * @author Arnaud Weber */ public class BasicPopupMenuUI extends PopupMenuUI { - static final StringBuilder MOUSE_GRABBER_KEY = new StringBuilder( - "javax.swing.plaf.basic.BasicPopupMenuUI.MouseGrabber"); - static final StringBuilder MENU_KEYBOARD_HELPER_KEY = new StringBuilder( - "javax.swing.plaf.basic.BasicPopupMenuUI.MenuKeyboardHelper"); + + static MouseGrabber mouseGrabber = new MouseGrabber(); + static MenuKeyboardHelper menuKeyboardHelper = null; /** * The instance of {@code JPopupMenu}. @@ -126,23 +123,18 @@ public class BasicPopupMenuUI extends PopupMenuUI { } popupMenu.addMenuKeyListener(menuKeyListener); - AppContext context = AppContext.getAppContext(); - synchronized (MOUSE_GRABBER_KEY) { - MouseGrabber mouseGrabber = (MouseGrabber)context.get( - MOUSE_GRABBER_KEY); - if (mouseGrabber == null) { - mouseGrabber = new MouseGrabber(); - context.put(MOUSE_GRABBER_KEY, mouseGrabber); - } + synchronized (MouseGrabber.class) { + if (mouseGrabber == null) mouseGrabber = new MouseGrabber(); } - synchronized (MENU_KEYBOARD_HELPER_KEY) { - MenuKeyboardHelper helper = - (MenuKeyboardHelper)context.get(MENU_KEYBOARD_HELPER_KEY); + + synchronized (BasicPopupMenuUI.class) { + MenuKeyboardHelper helper = menuKeyboardHelper; if (helper == null) { helper = new MenuKeyboardHelper(); - context.put(MENU_KEYBOARD_HELPER_KEY, helper); MenuSelectionManager msm = MenuSelectionManager.defaultManager(); msm.addChangeListener(helper); + menuKeyboardHelper = helper; + } } } @@ -768,10 +760,10 @@ public class BasicPopupMenuUI extends PopupMenuUI { } void uninstall() { - synchronized (MOUSE_GRABBER_KEY) { + synchronized (MouseGrabber.class) { MenuSelectionManager.defaultManager().removeChangeListener(this); ungrabWindow(); - AppContext.getAppContext().remove(MOUSE_GRABBER_KEY); + mouseGrabber = null; } } @@ -1233,9 +1225,8 @@ public class BasicPopupMenuUI extends PopupMenuUI { } void uninstall() { - synchronized (MENU_KEYBOARD_HELPER_KEY) { + synchronized (BasicPopupMenuUI.class) { MenuSelectionManager.defaultManager().removeChangeListener(this); - AppContext.getAppContext().remove(MENU_KEYBOARD_HELPER_KEY); } } } diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java index 9439059e03e..fdc68d3244f 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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,6 @@ import javax.swing.*; import javax.swing.plaf.*; import javax.swing.text.View; import sun.swing.SwingUtilities2; -import sun.awt.AppContext; /** * RadioButtonUI implementation for BasicRadioButtonUI @@ -39,7 +38,7 @@ import sun.awt.AppContext; */ public class BasicRadioButtonUI extends BasicToggleButtonUI { - private static final Object BASIC_RADIO_BUTTON_UI_KEY = new Object(); + private static final ComponentUI UI = new BasicRadioButtonUI(); /** * The icon. @@ -66,14 +65,7 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI * @return an instance of {@code BasicRadioButtonUI} */ public static ComponentUI createUI(JComponent b) { - AppContext appContext = AppContext.getAppContext(); - BasicRadioButtonUI radioButtonUI = - (BasicRadioButtonUI) appContext.get(BASIC_RADIO_BUTTON_UI_KEY); - if (radioButtonUI == null) { - radioButtonUI = new BasicRadioButtonUI(); - appContext.put(BASIC_RADIO_BUTTON_UI_KEY, radioButtonUI); - } - return radioButtonUI; + return UI; } @Override diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java index 391cfdf0b65..d144b5b7240 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,6 @@ import javax.swing.border.Border; import javax.swing.plaf.UIResource; import javax.swing.plaf.synth.SynthUI; import sun.swing.DefaultLookup; -import sun.awt.AppContext; import sun.swing.SwingUtilities2; import javax.swing.plaf.basic.DragRecognitionSupport.BeforeDrag; @@ -2234,24 +2233,19 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory { } } + private static volatile DragListener dragListenerSingleton; + private static DragListener getDragListener() { synchronized(DragListener.class) { - DragListener listener = - (DragListener)AppContext.getAppContext(). - get(DragListener.class); - - if (listener == null) { - listener = new DragListener(); - AppContext.getAppContext().put(DragListener.class, listener); + if (dragListenerSingleton == null) { + dragListenerSingleton = new DragListener(); } - - return listener; + return dragListenerSingleton; } } /** * Listens for mouse events for the purposes of detecting drag gestures. - * BasicTextUI will maintain one of these per AppContext. */ static class DragListener extends MouseInputAdapter implements BeforeDrag { diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicToggleButtonUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicToggleButtonUI.java index 2b68fe2b4f3..1a7dfe87353 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicToggleButtonUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicToggleButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,6 @@ package javax.swing.plaf.basic; -import sun.awt.AppContext; - import java.awt.*; import java.awt.event.*; @@ -44,7 +42,7 @@ import javax.swing.text.View; */ public class BasicToggleButtonUI extends BasicButtonUI { - private static final Object BASIC_TOGGLE_BUTTON_UI_KEY = new Object(); + private static final ComponentUI UI = new BasicToggleButtonUI(); private static final String propertyPrefix = "ToggleButton" + "."; @@ -64,14 +62,7 @@ public class BasicToggleButtonUI extends BasicButtonUI { * @return an instance of {@code BasicToggleButtonUI} */ public static ComponentUI createUI(JComponent b) { - AppContext appContext = AppContext.getAppContext(); - BasicToggleButtonUI toggleButtonUI = - (BasicToggleButtonUI) appContext.get(BASIC_TOGGLE_BUTTON_UI_KEY); - if (toggleButtonUI == null) { - toggleButtonUI = new BasicToggleButtonUI(); - appContext.put(BASIC_TOGGLE_BUTTON_UI_KEY, toggleButtonUI); - } - return toggleButtonUI; + return UI; } protected String getPropertyPrefix() { diff --git a/test/jdk/javax/swing/JPopupMenu/6495920/bug6495920.java b/test/jdk/javax/swing/JPopupMenu/6495920/bug6495920.java index 6a8c132c4e4..cc37cb97b18 100644 --- a/test/jdk/javax/swing/JPopupMenu/6495920/bug6495920.java +++ b/test/jdk/javax/swing/JPopupMenu/6495920/bug6495920.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, 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 @@ -29,12 +29,9 @@ interaction with GNOME is not crippled * @author Sergey Malenkov * @library ../.. - * @modules java.desktop/sun.awt * @modules java.desktop/javax.swing.plaf.basic:open */ -import sun.awt.AppContext; - import java.awt.Point; import java.awt.Robot; import java.awt.event.InputEvent; @@ -92,12 +89,12 @@ public class bug6495920 implements Thread.UncaughtExceptionHandler { } public void thirdValidate() throws Exception { - Field key = BasicPopupMenuUI.class.getDeclaredField("MOUSE_GRABBER_KEY"); + Field key = BasicPopupMenuUI.class.getDeclaredField("mouseGrabber"); key.setAccessible(true); - Object grabber = AppContext.getAppContext().get(key.get(null)); + Object grabber = key.get(null); if (grabber == null) { - throw new Exception("cannot find a mouse grabber in app's context"); + throw new Exception("cannot find a mouse grabber"); } Field field = grabber.getClass().getDeclaredField("grabbedWindow"); From 3a32757743b459902aa97092d95eb9b0cb3099d6 Mon Sep 17 00:00:00 2001 From: Feilong Jiang Date: Mon, 2 Feb 2026 02:15:42 +0000 Subject: [PATCH 276/328] 8376572: RISC-V: Interpreter: Load array index as signed int Reviewed-by: fyang, dzhang --- src/hotspot/cpu/riscv/templateTable_riscv.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp index 5a3644f70bb..0fb529d1683 100644 --- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp @@ -708,7 +708,6 @@ void TemplateTable::index_check(Register array, Register index) { __ mv(x11, index); } Label ok; - __ sext(index, index, 32); __ bltu(index, length, ok); __ mv(x13, array); __ mv(t1, Interpreter::_throw_ArrayIndexOutOfBoundsException_entry); @@ -1052,7 +1051,7 @@ void TemplateTable::aastore() { transition(vtos, vtos); // stack: ..., array, index, value __ ld(x10, at_tos()); // value - __ ld(x12, at_tos_p1()); // index + __ lw(x12, at_tos_p1()); // index __ ld(x13, at_tos_p2()); // array index_check(x13, x12); // kills x11 @@ -1462,9 +1461,9 @@ void TemplateTable::iinc() { transition(vtos, vtos); __ load_signed_byte(x11, at_bcp(2)); // get constant locals_index(x12); - __ ld(x10, iaddress(x12, x10, _masm)); + __ lw(x10, iaddress(x12, x10, _masm)); __ addw(x10, x10, x11); - __ sd(x10, iaddress(x12, t0, _masm)); + __ sw(x10, iaddress(x12, t0, _masm)); } void TemplateTable::wide_iinc() { @@ -1477,9 +1476,9 @@ void TemplateTable::wide_iinc() { __ orr(x11, x11, t1); locals_index_wide(x12); - __ ld(x10, iaddress(x12, t0, _masm)); + __ lw(x10, iaddress(x12, t0, _masm)); __ addw(x10, x10, x11); - __ sd(x10, iaddress(x12, t0, _masm)); + __ sw(x10, iaddress(x12, t0, _masm)); } void TemplateTable::convert() { From f8b0ff26c9e6643e96f06c18c509ddaf50326205 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 2 Feb 2026 07:12:32 +0000 Subject: [PATCH 277/328] 8376472: Shenandoah: Assembler store barriers read destination memory despite the decorators Reviewed-by: mdoerr, wkemper --- .../shenandoahBarrierSetAssembler_aarch64.cpp | 80 +++++++------- .../shenandoahBarrierSetAssembler_aarch64.hpp | 25 ++--- .../shenandoahBarrierSetAssembler_ppc.cpp | 55 ++++++---- .../shenandoahBarrierSetAssembler_ppc.hpp | 24 ++--- .../shenandoahBarrierSetAssembler_riscv.cpp | 82 +++++++------- .../shenandoahBarrierSetAssembler_riscv.hpp | 25 ++--- .../shenandoahBarrierSetAssembler_x86.cpp | 101 ++++++++---------- .../shenandoahBarrierSetAssembler_x86.hpp | 21 ++-- .../gc/shenandoah/shenandoahBarrierSet.cpp | 18 +++- .../gc/shenandoah/shenandoahBarrierSet.hpp | 2 + 10 files changed, 210 insertions(+), 223 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp index 9a035d9f40e..ad7bac4e067 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp @@ -85,26 +85,16 @@ void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Dec } } -void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register thread, - Register tmp, - bool tosca_live, - bool expand_call) { - if (ShenandoahSATBBarrier) { - satb_write_barrier_pre(masm, obj, pre_val, thread, tmp, rscratch1, tosca_live, expand_call); - } -} +void ShenandoahBarrierSetAssembler::satb_barrier(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2, + bool tosca_live, + bool expand_call) { + assert(ShenandoahSATBBarrier, "Should be checked by caller"); -void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register thread, - Register tmp1, - Register tmp2, - bool tosca_live, - bool expand_call) { // If expand_call is true then we expand the call_VM_leaf macro // directly to skip generating the check by // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp. @@ -358,20 +348,20 @@ void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet d if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) { __ enter(/*strip_ret_addr*/true); __ push_call_clobbered_registers(); - satb_write_barrier_pre(masm /* masm */, - noreg /* obj */, - dst /* pre_val */, - rthread /* thread */, - tmp1 /* tmp1 */, - tmp2 /* tmp2 */, - true /* tosca_live */, - true /* expand_call */); + satb_barrier(masm /* masm */, + noreg /* obj */, + dst /* pre_val */, + rthread /* thread */, + tmp1 /* tmp1 */, + tmp2 /* tmp2 */, + true /* tosca_live */, + true /* expand_call */); __ pop_call_clobbered_registers(); __ leave(); } } -void ShenandoahBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj) { +void ShenandoahBarrierSetAssembler::card_barrier(MacroAssembler* masm, Register obj) { assert(ShenandoahCardBarrier, "Should have been checked by caller"); __ lsr(obj, obj, CardTable::card_shift()); @@ -394,13 +384,13 @@ void ShenandoahBarrierSetAssembler::store_check(MacroAssembler* masm, Register o void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { - bool on_oop = is_reference_type(type); - if (!on_oop) { + // 1: non-reference types require no barriers + if (!is_reference_type(type)) { BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3); return; } - // flatten object address if needed + // Flatten object address right away for simplicity: likely needed by barriers if (dst.index() == noreg && dst.offset() == 0) { if (dst.base() != tmp3) { __ mov(tmp3, dst.base()); @@ -409,20 +399,26 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet __ lea(tmp3, dst); } - shenandoah_write_barrier_pre(masm, - tmp3 /* obj */, - tmp2 /* pre_val */, - rthread /* thread */, - tmp1 /* tmp */, - val != noreg /* tosca_live */, - false /* expand_call */); + bool storing_non_null = (val != noreg); + // 2: pre-barrier: SATB needs the previous value + if (ShenandoahBarrierSet::need_satb_barrier(decorators, type)) { + satb_barrier(masm, + tmp3 /* obj */, + tmp2 /* pre_val */, + rthread /* thread */, + tmp1 /* tmp */, + rscratch1 /* tmp2 */, + storing_non_null /* tosca_live */, + false /* expand_call */); + } + + // Store! BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), val, noreg, noreg, noreg); - bool in_heap = (decorators & IN_HEAP) != 0; - bool needs_post_barrier = (val != noreg) && in_heap && ShenandoahCardBarrier; - if (needs_post_barrier) { - store_check(masm, tmp3); + // 3: post-barrier: card barrier needs store address + if (ShenandoahBarrierSet::need_card_barrier(decorators, type) && storing_non_null) { + card_barrier(masm, tmp3); } } diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp index c0e708e1292..362fcae1ccd 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp @@ -40,23 +40,16 @@ class StubCodeGenerator; class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { private: - void satb_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register thread, - Register tmp1, - Register tmp2, - bool tosca_live, - bool expand_call); - void shenandoah_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register thread, - Register tmp, - bool tosca_live, - bool expand_call); + void satb_barrier(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2, + bool tosca_live, + bool expand_call); - void store_check(MacroAssembler* masm, Register obj); + void card_barrier(MacroAssembler* masm, Register obj); void resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp = noreg); void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp = noreg); diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp index 9d143c14d27..c3bb1811031 100644 --- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp @@ -50,14 +50,14 @@ #define __ masm-> -void ShenandoahBarrierSetAssembler::satb_write_barrier(MacroAssembler *masm, - Register base, RegisterOrConstant ind_or_offs, - Register tmp1, Register tmp2, Register tmp3, - MacroAssembler::PreservationLevel preservation_level) { +void ShenandoahBarrierSetAssembler::satb_barrier(MacroAssembler *masm, + Register base, RegisterOrConstant ind_or_offs, + Register tmp1, Register tmp2, Register tmp3, + MacroAssembler::PreservationLevel preservation_level) { if (ShenandoahSATBBarrier) { - __ block_comment("satb_write_barrier (shenandoahgc) {"); - satb_write_barrier_impl(masm, 0, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level); - __ block_comment("} satb_write_barrier (shenandoahgc)"); + __ block_comment("satb_barrier (shenandoahgc) {"); + satb_barrier_impl(masm, 0, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level); + __ block_comment("} satb_barrier (shenandoahgc)"); } } @@ -198,11 +198,12 @@ void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Dec // In "load mode", this register acts as a temporary register and must // thus not be 'noreg'. In "preloaded mode", its content will be sustained. // tmp1/tmp2: Temporary registers, one of which must be non-volatile in "preloaded mode". -void ShenandoahBarrierSetAssembler::satb_write_barrier_impl(MacroAssembler *masm, DecoratorSet decorators, - Register base, RegisterOrConstant ind_or_offs, - Register pre_val, - Register tmp1, Register tmp2, - MacroAssembler::PreservationLevel preservation_level) { +void ShenandoahBarrierSetAssembler::satb_barrier_impl(MacroAssembler *masm, DecoratorSet decorators, + Register base, RegisterOrConstant ind_or_offs, + Register pre_val, + Register tmp1, Register tmp2, + MacroAssembler::PreservationLevel preservation_level) { + assert(ShenandoahSATBBarrier, "Should be checked by caller"); assert_different_registers(tmp1, tmp2, pre_val, noreg); Label skip_barrier; @@ -574,13 +575,13 @@ void ShenandoahBarrierSetAssembler::load_at( if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) { if (ShenandoahSATBBarrier) { __ block_comment("keep_alive_barrier (shenandoahgc) {"); - satb_write_barrier_impl(masm, 0, noreg, noreg, dst, tmp1, tmp2, preservation_level); + satb_barrier_impl(masm, 0, noreg, noreg, dst, tmp1, tmp2, preservation_level); __ block_comment("} keep_alive_barrier (shenandoahgc)"); } } } -void ShenandoahBarrierSetAssembler::store_check(MacroAssembler* masm, Register base, RegisterOrConstant ind_or_offs, Register tmp) { +void ShenandoahBarrierSetAssembler::card_barrier(MacroAssembler* masm, Register base, RegisterOrConstant ind_or_offs, Register tmp) { assert(ShenandoahCardBarrier, "Should have been checked by caller"); assert_different_registers(base, tmp, R0); @@ -603,21 +604,33 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler *masm, DecoratorSet Register base, RegisterOrConstant ind_or_offs, Register val, Register tmp1, Register tmp2, Register tmp3, MacroAssembler::PreservationLevel preservation_level) { - if (is_reference_type(type)) { - if (ShenandoahSATBBarrier) { - satb_write_barrier(masm, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level); - } + // 1: non-reference types require no barriers + if (!is_reference_type(type)) { + BarrierSetAssembler::store_at(masm, decorators, type, + base, ind_or_offs, + val, + tmp1, tmp2, tmp3, + preservation_level); + return; } + bool storing_non_null = (val != noreg); + + // 2: pre-barrier: SATB needs the previous value + if (ShenandoahBarrierSet::need_satb_barrier(decorators, type)) { + satb_barrier(masm, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level); + } + + // Store! BarrierSetAssembler::store_at(masm, decorators, type, base, ind_or_offs, val, tmp1, tmp2, tmp3, preservation_level); - // No need for post barrier if storing null - if (ShenandoahCardBarrier && is_reference_type(type) && val != noreg) { - store_check(masm, base, ind_or_offs, tmp1); + // 3: post-barrier: card barrier needs store address + if (ShenandoahBarrierSet::need_card_barrier(decorators, type) && storing_non_null) { + card_barrier(masm, base, ind_or_offs, tmp1); } } diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp index b058dcf1a2e..52615a740af 100644 --- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp @@ -45,15 +45,15 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { private: /* ==== Actual barrier implementations ==== */ - void satb_write_barrier_impl(MacroAssembler* masm, DecoratorSet decorators, - Register base, RegisterOrConstant ind_or_offs, - Register pre_val, - Register tmp1, Register tmp2, - MacroAssembler::PreservationLevel preservation_level); + void satb_barrier_impl(MacroAssembler* masm, DecoratorSet decorators, + Register base, RegisterOrConstant ind_or_offs, + Register pre_val, + Register tmp1, Register tmp2, + MacroAssembler::PreservationLevel preservation_level); - void store_check(MacroAssembler* masm, - Register base, RegisterOrConstant ind_or_offs, - Register tmp); + void card_barrier(MacroAssembler* masm, + Register base, RegisterOrConstant ind_or_offs, + Register tmp); void load_reference_barrier_impl(MacroAssembler* masm, DecoratorSet decorators, Register base, RegisterOrConstant ind_or_offs, @@ -85,10 +85,10 @@ public: #endif /* ==== Available barriers (facades of the actual implementations) ==== */ - void satb_write_barrier(MacroAssembler* masm, - Register base, RegisterOrConstant ind_or_offs, - Register tmp1, Register tmp2, Register tmp3, - MacroAssembler::PreservationLevel preservation_level); + void satb_barrier(MacroAssembler* masm, + Register base, RegisterOrConstant ind_or_offs, + Register tmp1, Register tmp2, Register tmp3, + MacroAssembler::PreservationLevel preservation_level); void load_reference_barrier(MacroAssembler* masm, DecoratorSet decorators, Register base, RegisterOrConstant ind_or_offs, diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp index dd6c8556307..3cbbb783258 100644 --- a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp @@ -88,26 +88,16 @@ void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Dec } } -void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register thread, - Register tmp, - bool tosca_live, - bool expand_call) { - if (ShenandoahSATBBarrier) { - satb_write_barrier_pre(masm, obj, pre_val, thread, tmp, t0, tosca_live, expand_call); - } -} +void ShenandoahBarrierSetAssembler::satb_barrier(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2, + bool tosca_live, + bool expand_call) { + assert(ShenandoahSATBBarrier, "Should be checked by caller"); -void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register thread, - Register tmp1, - Register tmp2, - bool tosca_live, - bool expand_call) { // If expand_call is true then we expand the call_VM_leaf macro // directly to skip generating the check by // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp. @@ -376,21 +366,21 @@ void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) { __ enter(); __ push_call_clobbered_registers(); - satb_write_barrier_pre(masm /* masm */, - noreg /* obj */, - dst /* pre_val */, - xthread /* thread */, - tmp1 /* tmp1 */, - tmp2 /* tmp2 */, - true /* tosca_live */, - true /* expand_call */); + satb_barrier(masm /* masm */, + noreg /* obj */, + dst /* pre_val */, + xthread /* thread */, + tmp1 /* tmp1 */, + tmp2 /* tmp2 */, + true /* tosca_live */, + true /* expand_call */); __ pop_call_clobbered_registers(); __ leave(); } } -void ShenandoahBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj) { - assert(ShenandoahCardBarrier, "Did you mean to enable ShenandoahCardBarrier?"); +void ShenandoahBarrierSetAssembler::card_barrier(MacroAssembler* masm, Register obj) { + assert(ShenandoahCardBarrier, "Should have been checked by caller"); __ srli(obj, obj, CardTable::card_shift()); @@ -413,13 +403,13 @@ void ShenandoahBarrierSetAssembler::store_check(MacroAssembler* masm, Register o void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { - bool on_oop = is_reference_type(type); - if (!on_oop) { + // 1: non-reference types require no barriers + if (!is_reference_type(type)) { BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3); return; } - // flatten object address if needed + // Flatten object address right away for simplicity: likely needed by barriers if (dst.offset() == 0) { if (dst.base() != tmp3) { __ mv(tmp3, dst.base()); @@ -428,20 +418,26 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet __ la(tmp3, dst); } - shenandoah_write_barrier_pre(masm, - tmp3 /* obj */, - tmp2 /* pre_val */, - xthread /* thread */, - tmp1 /* tmp */, - val != noreg /* tosca_live */, - false /* expand_call */); + bool storing_non_null = (val != noreg); + // 2: pre-barrier: SATB needs the previous value + if (ShenandoahBarrierSet::need_satb_barrier(decorators, type)) { + satb_barrier(masm, + tmp3 /* obj */, + tmp2 /* pre_val */, + xthread /* thread */, + tmp1 /* tmp */, + t0 /* tmp2 */, + storing_non_null /* tosca_live */, + false /* expand_call */); + } + + // Store! BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), val, noreg, noreg, noreg); - bool in_heap = (decorators & IN_HEAP) != 0; - bool needs_post_barrier = (val != noreg) && in_heap && ShenandoahCardBarrier; - if (needs_post_barrier) { - store_check(masm, tmp3); + // 3: post-barrier: card barrier needs store address + if (ShenandoahBarrierSet::need_card_barrier(decorators, type) && storing_non_null) { + card_barrier(masm, tmp3); } } diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp index c8a7c35fb83..5085be26b2e 100644 --- a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp @@ -41,23 +41,16 @@ class StubCodeGenerator; class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { private: - void satb_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register thread, - Register tmp1, - Register tmp2, - bool tosca_live, - bool expand_call); - void shenandoah_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register thread, - Register tmp, - bool tosca_live, - bool expand_call); + void satb_barrier(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2, + bool tosca_live, + bool expand_call); - void store_check(MacroAssembler* masm, Register obj); + void card_barrier(MacroAssembler* masm, Register obj); void resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp = noreg); void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp = noreg); diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp index 9e321391f6c..97829a10a3b 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp @@ -174,24 +174,14 @@ void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Dec } } -void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register tmp, - bool tosca_live, - bool expand_call) { +void ShenandoahBarrierSetAssembler::satb_barrier(MacroAssembler* masm, + Register obj, + Register pre_val, + Register tmp, + bool tosca_live, + bool expand_call) { + assert(ShenandoahSATBBarrier, "Should be checked by caller"); - if (ShenandoahSATBBarrier) { - satb_write_barrier_pre(masm, obj, pre_val, tmp, tosca_live, expand_call); - } -} - -void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register tmp, - bool tosca_live, - bool expand_call) { // If expand_call is true then we expand the call_VM_leaf macro // directly to skip generating the check by // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp. @@ -533,18 +523,18 @@ void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet d assert_different_registers(dst, tmp1, r15_thread); // Generate the SATB pre-barrier code to log the value of // the referent field in an SATB buffer. - shenandoah_write_barrier_pre(masm /* masm */, - noreg /* obj */, - dst /* pre_val */, - tmp1 /* tmp */, - true /* tosca_live */, - true /* expand_call */); + satb_barrier(masm /* masm */, + noreg /* obj */, + dst /* pre_val */, + tmp1 /* tmp */, + true /* tosca_live */, + true /* expand_call */); restore_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ true); } } -void ShenandoahBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj) { +void ShenandoahBarrierSetAssembler::card_barrier(MacroAssembler* masm, Register obj) { assert(ShenandoahCardBarrier, "Should have been checked by caller"); // Does a store check for the oop in register obj. The content of @@ -575,41 +565,40 @@ void ShenandoahBarrierSetAssembler::store_check(MacroAssembler* masm, Register o void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { - bool on_oop = is_reference_type(type); - bool in_heap = (decorators & IN_HEAP) != 0; - bool as_normal = (decorators & AS_NORMAL) != 0; - if (on_oop && in_heap) { - bool needs_pre_barrier = as_normal; + // 1: non-reference types require no barriers + if (!is_reference_type(type)) { + BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3); + return; + } - // flatten object address if needed - // We do it regardless of precise because we need the registers - if (dst.index() == noreg && dst.disp() == 0) { - if (dst.base() != tmp1) { - __ movptr(tmp1, dst.base()); - } - } else { - __ lea(tmp1, dst); - } - - assert_different_registers(val, tmp1, tmp2, tmp3, r15_thread); - - if (needs_pre_barrier) { - shenandoah_write_barrier_pre(masm /*masm*/, - tmp1 /* obj */, - tmp2 /* pre_val */, - tmp3 /* tmp */, - val != noreg /* tosca_live */, - false /* expand_call */); - } - - BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg); - if (val != noreg) { - if (ShenandoahCardBarrier) { - store_check(masm, tmp1); - } + // Flatten object address right away for simplicity: likely needed by barriers + assert_different_registers(val, tmp1, tmp2, tmp3, r15_thread); + if (dst.index() == noreg && dst.disp() == 0) { + if (dst.base() != tmp1) { + __ movptr(tmp1, dst.base()); } } else { - BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3); + __ lea(tmp1, dst); + } + + bool storing_non_null = (val != noreg); + + // 2: pre-barrier: SATB needs the previous value + if (ShenandoahBarrierSet::need_satb_barrier(decorators, type)) { + satb_barrier(masm, + tmp1 /* obj */, + tmp2 /* pre_val */, + tmp3 /* tmp */, + storing_non_null /* tosca_live */, + false /* expand_call */); + } + + // Store! + BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg); + + // 3: post-barrier: card barrier needs store address + if (ShenandoahBarrierSet::need_card_barrier(decorators, type) && storing_non_null) { + card_barrier(masm, tmp1); } } diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp index b0185f2dbff..b5cc5c8d834 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp @@ -41,21 +41,14 @@ class StubCodeGenerator; class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { private: - void satb_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register tmp, - bool tosca_live, - bool expand_call); + void satb_barrier(MacroAssembler* masm, + Register obj, + Register pre_val, + Register tmp, + bool tosca_live, + bool expand_call); - void shenandoah_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register pre_val, - Register tmp, - bool tosca_live, - bool expand_call); - - void store_check(MacroAssembler* masm, Register obj); + void card_barrier(MacroAssembler* masm, Register obj); void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp index 2aa37d7c575..004558a9fa8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp @@ -72,21 +72,33 @@ void ShenandoahBarrierSet::print_on(outputStream* st) const { bool ShenandoahBarrierSet::need_load_reference_barrier(DecoratorSet decorators, BasicType type) { if (!ShenandoahLoadRefBarrier) return false; - // Only needed for references return is_reference_type(type); } bool ShenandoahBarrierSet::need_keep_alive_barrier(DecoratorSet decorators, BasicType type) { if (!ShenandoahSATBBarrier) return false; - // Only needed for references if (!is_reference_type(type)) return false; - bool keep_alive = (decorators & AS_NO_KEEPALIVE) == 0; bool unknown = (decorators & ON_UNKNOWN_OOP_REF) != 0; bool on_weak_ref = (decorators & (ON_WEAK_OOP_REF | ON_PHANTOM_OOP_REF)) != 0; return (on_weak_ref || unknown) && keep_alive; } +bool ShenandoahBarrierSet::need_satb_barrier(DecoratorSet decorators, BasicType type) { + if (!ShenandoahSATBBarrier) return false; + if (!is_reference_type(type)) return false; + bool as_normal = (decorators & AS_NORMAL) != 0; + bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0; + return as_normal && !dest_uninitialized; +} + +bool ShenandoahBarrierSet::need_card_barrier(DecoratorSet decorators, BasicType type) { + if (!ShenandoahCardBarrier) return false; + if (!is_reference_type(type)) return false; + bool in_heap = (decorators & IN_HEAP) != 0; + return in_heap; +} + void ShenandoahBarrierSet::on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) { #if COMPILER2_OR_JVMCI if (ReduceInitialCardMarks && ShenandoahCardBarrier && !ShenandoahHeap::heap()->is_in_young(new_obj)) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp index 28765605267..e7a0ed57740 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp @@ -60,6 +60,8 @@ public: static bool need_load_reference_barrier(DecoratorSet decorators, BasicType type); static bool need_keep_alive_barrier(DecoratorSet decorators, BasicType type); + static bool need_satb_barrier(DecoratorSet decorators, BasicType type); + static bool need_card_barrier(DecoratorSet decorators, BasicType type); static bool is_strong_access(DecoratorSet decorators) { return (decorators & (ON_WEAK_OOP_REF | ON_PHANTOM_OOP_REF)) == 0; From f22bc1cd518bc7f09dc49b78e40d06210226d2b7 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 2 Feb 2026 07:58:01 +0000 Subject: [PATCH 278/328] 8376131: Convert ContiguousSpace to use Atomic Reviewed-by: dholmes, kbarrett --- src/hotspot/share/gc/shared/space.cpp | 12 ++++-------- src/hotspot/share/gc/shared/space.hpp | 14 ++++++-------- src/hotspot/share/gc/shared/vmStructs_gc.hpp | 4 ++-- src/hotspot/share/runtime/vmStructs.cpp | 3 ++- 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/hotspot/share/gc/shared/space.cpp b/src/hotspot/share/gc/shared/space.cpp index 011a0f5cfd8..84ba21527fd 100644 --- a/src/hotspot/share/gc/shared/space.cpp +++ b/src/hotspot/share/gc/shared/space.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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,6 @@ #include "memory/iterator.inline.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/java.hpp" #include "runtime/safepoint.hpp" #include "utilities/align.hpp" @@ -69,7 +68,7 @@ void ContiguousSpace::clear(bool mangle_space) { #ifndef PRODUCT void ContiguousSpace::mangle_unused_area() { - mangle_unused_area(MemRegion(_top, _end)); + mangle_unused_area(MemRegion(top(), _end)); } void ContiguousSpace::mangle_unused_area(MemRegion mr) { @@ -128,11 +127,8 @@ inline HeapWord* ContiguousSpace::par_allocate_impl(size_t size) { HeapWord* obj = top(); if (pointer_delta(end(), obj) >= size) { HeapWord* new_top = obj + size; - HeapWord* result = AtomicAccess::cmpxchg(top_addr(), obj, new_top); - // result can be one of two: - // the old top value: the exchange succeeded - // otherwise: the new value of the top is returned. - if (result == obj) { + // Retry if we did not successfully updated the top pointers. + if (_top.compare_set(obj, new_top)) { assert(is_object_aligned(obj) && is_object_aligned(new_top), "checking alignment"); return obj; } diff --git a/src/hotspot/share/gc/shared/space.hpp b/src/hotspot/share/gc/shared/space.hpp index 7f2887275b3..05b22f680bf 100644 --- a/src/hotspot/share/gc/shared/space.hpp +++ b/src/hotspot/share/gc/shared/space.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ #include "memory/iterator.hpp" #include "memory/memRegion.hpp" #include "oops/markWord.hpp" +#include "runtime/atomic.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/align.hpp" #include "utilities/macros.hpp" @@ -53,7 +54,7 @@ class ContiguousSpace: public CHeapObj { private: HeapWord* _bottom; HeapWord* _end; - HeapWord* _top; + Atomic _top; // Allocation helpers (return null if full). inline HeapWord* allocate_impl(size_t word_size); @@ -64,12 +65,12 @@ public: // Accessors HeapWord* bottom() const { return _bottom; } - HeapWord* end() const { return _end; } - HeapWord* top() const { return _top; } + HeapWord* end() const { return _end; } + HeapWord* top() const { return _top.load_relaxed(); } void set_bottom(HeapWord* value) { _bottom = value; } void set_end(HeapWord* value) { _end = value; } - void set_top(HeapWord* value) { _top = value; } + void set_top(HeapWord* value) { _top.store_relaxed(value); } // Testers bool is_empty() const { return used() == 0; } @@ -121,9 +122,6 @@ public: // Iteration void object_iterate(ObjectClosure* blk); - // Addresses for inlined allocation - HeapWord** top_addr() { return &_top; } - // Debugging void verify() const; }; diff --git a/src/hotspot/share/gc/shared/vmStructs_gc.hpp b/src/hotspot/share/gc/shared/vmStructs_gc.hpp index db968e28f67..6a29eb25b37 100644 --- a/src/hotspot/share/gc/shared/vmStructs_gc.hpp +++ b/src/hotspot/share/gc/shared/vmStructs_gc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -97,7 +97,7 @@ \ nonstatic_field(ContiguousSpace, _bottom, HeapWord*) \ nonstatic_field(ContiguousSpace, _end, HeapWord*) \ - nonstatic_field(ContiguousSpace, _top, HeapWord*) \ + nonstatic_field(ContiguousSpace, _top, Atomic) \ \ nonstatic_field(MemRegion, _start, HeapWord*) \ nonstatic_field(MemRegion, _word_size, size_t) diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 4ecc8f9ca01..02572e16728 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -901,6 +901,7 @@ /*****************************/ \ \ declare_toplevel_type(void*) \ + declare_toplevel_type(Atomic) \ declare_toplevel_type(int*) \ declare_toplevel_type(char*) \ declare_toplevel_type(char**) \ From 766e03b151b2972108ddc207eed10428e9a91c30 Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Mon, 2 Feb 2026 08:02:07 +0000 Subject: [PATCH 279/328] 8367993: G1: Speed up ConcurrentMark initialization Reviewed-by: sjohanss, tschatzl --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 23 ++++++----- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 1 - src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 39 ++++++++++++++----- src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 3 ++ src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp | 2 +- src/hotspot/share/gc/g1/g1Policy.cpp | 4 +- .../share/gc/g1/g1RegionMarkStatsCache.cpp | 2 +- src/hotspot/share/gc/g1/g1VMOperations.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 2 +- 9 files changed, 51 insertions(+), 27 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 8f83a653885..9424a804bd8 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -1320,7 +1320,6 @@ G1CollectedHeap::G1CollectedHeap() : _card_set_freelist_pool(G1CardSetConfiguration::num_mem_object_types()), _young_regions_cset_group(card_set_config(), &_card_set_freelist_pool, G1CSetCandidateGroup::YoungRegionId), _cm(nullptr), - _cm_thread(nullptr), _cr(nullptr), _task_queues(nullptr), _partial_array_state_manager(nullptr), @@ -1564,7 +1563,6 @@ jint G1CollectedHeap::initialize() { // Create the G1ConcurrentMark data structure and thread. // (Must do this late, so that "max_[reserved_]regions" is defined.) _cm = new G1ConcurrentMark(this, bitmap_storage); - _cm_thread = _cm->cm_thread(); // Now expand into the initial heap size. if (!expand(init_byte_size, _workers)) { @@ -1636,7 +1634,9 @@ jint G1CollectedHeap::initialize() { } bool G1CollectedHeap::concurrent_mark_is_terminating() const { - return _cm_thread->should_terminate(); + assert(_cm != nullptr, "_cm must have been created"); + assert(_cm->is_fully_initialized(), "thread must exist in order to check if mark is terminating"); + return _cm->cm_thread()->should_terminate(); } void G1CollectedHeap::stop() { @@ -1645,7 +1645,9 @@ void G1CollectedHeap::stop() { // that are destroyed during shutdown. _cr->stop(); _service_thread->stop(); - _cm_thread->stop(); + if (_cm->is_fully_initialized()) { + _cm->cm_thread()->stop(); + } } void G1CollectedHeap::safepoint_synchronize_begin() { @@ -1842,7 +1844,7 @@ void G1CollectedHeap::increment_old_marking_cycles_completed(bool concurrent, // is set) so that if a waiter requests another System.gc() it doesn't // incorrectly see that a marking cycle is still in progress. if (concurrent) { - _cm_thread->set_idle(); + _cm->cm_thread()->set_idle(); } // Notify threads waiting in System.gc() (with ExplicitGCInvokesConcurrent) @@ -2421,7 +2423,6 @@ void G1CollectedHeap::print_gc_on(outputStream* st) const { void G1CollectedHeap::gc_threads_do(ThreadClosure* tc) const { workers()->threads_do(tc); - tc->do_thread(_cm_thread); _cm->threads_do(tc); _cr->threads_do(tc); tc->do_thread(_service_thread); @@ -2542,15 +2543,15 @@ HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size, } void G1CollectedHeap::start_concurrent_cycle(bool concurrent_operation_is_full_mark) { - assert(!_cm_thread->in_progress(), "Can not start concurrent operation while in progress"); - + assert(_cm->is_fully_initialized(), "sanity"); + assert(!_cm->in_progress(), "Can not start concurrent operation while in progress"); MutexLocker x(G1CGC_lock, Mutex::_no_safepoint_check_flag); if (concurrent_operation_is_full_mark) { _cm->post_concurrent_mark_start(); - _cm_thread->start_full_mark(); + _cm->cm_thread()->start_full_mark(); } else { _cm->post_concurrent_undo_start(); - _cm_thread->start_undo_mark(); + _cm->cm_thread()->start_undo_mark(); } G1CGC_lock->notify(); } @@ -2726,6 +2727,8 @@ void G1CollectedHeap::do_collection_pause_at_safepoint(size_t allocation_word_si _bytes_used_during_gc = 0; + _cm->fully_initialize(); + policy()->decide_on_concurrent_start_pause(); // Record whether this pause may need to trigger a concurrent operation. Later, // when we signal the G1ConcurrentMarkThread, the collector state has already diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 1f900c76851..8ff9d481000 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -823,7 +823,6 @@ public: // The concurrent marker (and the thread it runs in.) G1ConcurrentMark* _cm; - G1ConcurrentMarkThread* _cm_thread; // The concurrent refiner. G1ConcurrentRefine* _cr; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 2bbfb5032b3..29de5a12599 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -473,7 +473,7 @@ bool G1CMRootMemRegions::wait_until_scan_finished() { G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* bitmap_storage) : - // _cm_thread set inside the constructor + _cm_thread(nullptr), _g1h(g1h), _mark_bitmap(), @@ -484,13 +484,12 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, _global_mark_stack(), - // _finger set in set_non_marking_state + _finger(nullptr), // _finger set in set_non_marking_state _worker_id_offset(G1ConcRefinementThreads), // The refinement control thread does not refine cards, so it's just the worker threads. _max_num_tasks(MAX2(ConcGCThreads, ParallelGCThreads)), - // _num_active_tasks set in set_non_marking_state() - // _tasks set inside the constructor - + _num_active_tasks(0), // _num_active_tasks set in set_non_marking_state() + _tasks(nullptr), // _tasks set inside late_init() _task_queues(new G1CMTaskQueueSet(_max_num_tasks)), _terminator(_max_num_tasks, _task_queues), _partial_array_state_manager(new PartialArrayStateManager(_max_num_tasks)), @@ -525,6 +524,12 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, assert(G1CGC_lock != nullptr, "CGC_lock must be initialized"); _mark_bitmap.initialize(g1h->reserved(), bitmap_storage); +} + +void G1ConcurrentMark::fully_initialize() { + if (is_fully_initialized()) { + return; + } // Create & start ConcurrentMark thread. _cm_thread = new G1ConcurrentMarkThread(this); @@ -560,6 +565,10 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, reset_at_marking_complete(); } +bool G1ConcurrentMark::in_progress() const { + return is_fully_initialized() ? _cm_thread->in_progress() : false; +} + PartialArrayStateManager* G1ConcurrentMark::partial_array_state_manager() const { return _partial_array_state_manager; } @@ -765,7 +774,7 @@ private: // as asserts here to minimize their overhead on the product. However, we // will have them as guarantees at the beginning / end of the bitmap // clearing to get some checking in the product. - assert(!suspendible() || _cm->cm_thread()->in_progress(), "invariant"); + assert(!suspendible() || _cm->in_progress(), "invariant"); assert(!suspendible() || !G1CollectedHeap::heap()->collector_state()->mark_or_rebuild_in_progress(), "invariant"); // Abort iteration if necessary. @@ -821,7 +830,8 @@ void G1ConcurrentMark::clear_bitmap(WorkerThreads* workers, bool may_yield) { void G1ConcurrentMark::cleanup_for_next_mark() { // Make sure that the concurrent mark thread looks to still be in // the current cycle. - guarantee(cm_thread()->in_progress(), "invariant"); + guarantee(is_fully_initialized(), "should be initializd"); + guarantee(in_progress(), "invariant"); // We are finishing up the current cycle by clearing the next // marking bitmap and getting it ready for the next cycle. During @@ -834,7 +844,8 @@ void G1ConcurrentMark::cleanup_for_next_mark() { reset_partial_array_state_manager(); // Repeat the asserts from above. - guarantee(cm_thread()->in_progress(), "invariant"); + guarantee(is_fully_initialized(), "should be initializd"); + guarantee(in_progress(), "invariant"); guarantee(!_g1h->collector_state()->mark_or_rebuild_in_progress(), "invariant"); } @@ -1925,7 +1936,8 @@ bool G1ConcurrentMark::concurrent_cycle_abort() { // nothing, but this situation should be extremely rare (a full gc after shutdown // has been signalled is already rare), and this work should be negligible compared // to actual full gc work. - if (!cm_thread()->in_progress() && !_g1h->concurrent_mark_is_terminating()) { + + if (!is_fully_initialized() || (!cm_thread()->in_progress() && !_g1h->concurrent_mark_is_terminating())) { return false; } @@ -1987,6 +1999,10 @@ void G1ConcurrentMark::print_summary_info() { } log.trace(" Concurrent marking:"); + if (!is_fully_initialized()) { + log.trace(" has not been initialized yet"); + return; + } print_ms_time_info(" ", "remarks", _remark_times); { print_ms_time_info(" ", "final marks", _remark_mark_times); @@ -2003,7 +2019,10 @@ void G1ConcurrentMark::print_summary_info() { } void G1ConcurrentMark::threads_do(ThreadClosure* tc) const { - _concurrent_workers->threads_do(tc); + if (is_fully_initialized()) { // they are initialized late + tc->do_thread(_cm_thread); + _concurrent_workers->threads_do(tc); + } } void G1ConcurrentMark::print_on(outputStream* st) const { diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 836d7793f81..367568aeff4 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -555,6 +555,9 @@ public: uint worker_id_offset() const { return _worker_id_offset; } + void fully_initialize(); + bool is_fully_initialized() const { return _cm_thread != nullptr; } + bool in_progress() const; uint max_num_tasks() const {return _max_num_tasks; } // Clear statistics gathered during the concurrent cycle for the given region after diff --git a/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp b/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp index 50002ac2bfe..f280d76f3c7 100644 --- a/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp +++ b/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp @@ -39,7 +39,7 @@ bool G1PeriodicGCTask::should_start_periodic_gc(G1CollectedHeap* g1h, SuspendibleThreadSetJoiner sts; // If we are currently in a concurrent mark we are going to uncommit memory soon. - if (g1h->concurrent_mark()->cm_thread()->in_progress()) { + if (g1h->concurrent_mark()->in_progress()) { log_debug(gc, periodic)("Concurrent cycle in progress. Skipping."); return false; } diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 1d0b29c303e..98e6acc1d77 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -739,7 +739,7 @@ double G1Policy::constant_other_time_ms(double pause_time_ms) const { } bool G1Policy::about_to_start_mixed_phase() const { - return _g1h->concurrent_mark()->cm_thread()->in_progress() || collector_state()->in_young_gc_before_mixed(); + return _g1h->concurrent_mark()->in_progress() || collector_state()->in_young_gc_before_mixed(); } bool G1Policy::need_to_start_conc_mark(const char* source, size_t allocation_word_size) { @@ -1235,7 +1235,7 @@ bool G1Policy::force_concurrent_start_if_outside_cycle(GCCause::Cause gc_cause) // We actually check whether we are marking here and not if we are in a // reclamation phase. This means that we will schedule a concurrent mark // even while we are still in the process of reclaiming memory. - bool during_cycle = _g1h->concurrent_mark()->cm_thread()->in_progress(); + bool during_cycle = _g1h->concurrent_mark()->in_progress(); if (!during_cycle) { log_debug(gc, ergo)("Request concurrent cycle initiation (requested by GC cause). " "GC cause: %s", diff --git a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp index d9b7ec294bd..c5f55e1d20c 100644 --- a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp +++ b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp @@ -29,12 +29,12 @@ G1RegionMarkStatsCache::G1RegionMarkStatsCache(G1RegionMarkStats* target, uint num_cache_entries) : _target(target), + _cache(NEW_C_HEAP_ARRAY(G1RegionMarkStatsCacheEntry, num_cache_entries, mtGC)), _num_cache_entries(num_cache_entries), _num_cache_entries_mask(_num_cache_entries - 1) { guarantee(is_power_of_2(num_cache_entries), "Number of cache entries must be power of two, but is %u", num_cache_entries); - _cache = NEW_C_HEAP_ARRAY(G1RegionMarkStatsCacheEntry, _num_cache_entries, mtGC); } G1RegionMarkStatsCache::~G1RegionMarkStatsCache() { diff --git a/src/hotspot/share/gc/g1/g1VMOperations.cpp b/src/hotspot/share/gc/g1/g1VMOperations.cpp index 1c024f2943b..56ab3a4b0fe 100644 --- a/src/hotspot/share/gc/g1/g1VMOperations.cpp +++ b/src/hotspot/share/gc/g1/g1VMOperations.cpp @@ -85,7 +85,7 @@ void VM_G1TryInitiateConcMark::doit() { GCCauseSetter x(g1h, _gc_cause); _mark_in_progress = g1h->collector_state()->mark_in_progress(); - _cycle_already_in_progress = g1h->concurrent_mark()->cm_thread()->in_progress(); + _cycle_already_in_progress = g1h->concurrent_mark()->in_progress(); if (!g1h->policy()->force_concurrent_start_if_outside_cycle(_gc_cause)) { // Failure to force the next GC pause to be a concurrent start indicates diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index de5bc9ea58f..35e0b83d25f 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -578,7 +578,7 @@ WB_END WB_ENTRY(jboolean, WB_G1InConcurrentMark(JNIEnv* env, jobject o)) if (UseG1GC) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - return g1h->concurrent_mark()->cm_thread()->in_progress(); + return g1h->concurrent_mark()->in_progress(); } THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_G1InConcurrentMark: G1 GC is not enabled"); WB_END From 1f3fd3da1d24118a29d28f01d3fa59d7712607e5 Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Mon, 2 Feb 2026 08:20:00 +0000 Subject: [PATCH 280/328] 8366659: ObjectMonitor::wait() liveness problem with a suspension request Co-authored-by: Patricio Chilano Mateo Co-authored-by: Daniel D. Daugherty Reviewed-by: dcubed, sspitsyn, dholmes, pchilanomate --- src/hotspot/share/runtime/objectMonitor.cpp | 226 ++++++----- src/hotspot/share/runtime/objectMonitor.hpp | 19 +- .../SuspendWithObjectMonitorWait.java | 371 ------------------ .../SuspendWithObjectMonitorWaitBase.java | 236 +++++++++++ .../SuspendWithObjectMonitorWaitDefault.java | 138 +++++++ ...WithObjectMonitorWaitReentryPartFirst.java | 152 +++++++ ...ithObjectMonitorWaitReentryPartSecond.java | 162 ++++++++ .../SuspendWithObjectMonitorWaitWorker.java | 128 ++++++ .../libSuspendWithObjectMonitorWait.cpp | 6 +- 9 files changed, 952 insertions(+), 486 deletions(-) delete mode 100644 test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWait.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitBase.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitDefault.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitReentryPartFirst.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitReentryPartSecond.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitWorker.java diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index 785ee2af592..144533cd959 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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 @@ -339,15 +339,6 @@ void ObjectMonitor::ExitOnSuspend::operator()(JavaThread* current) { } } -void ObjectMonitor::ClearSuccOnSuspend::operator()(JavaThread* current) { - if (current->is_suspended()) { - if (_om->has_successor(current)) { - _om->clear_successor(); - OrderAccess::fence(); // always do a full fence when successor is cleared - } - } -} - #define assert_mark_word_consistency() \ assert(UseObjectMonitorTable || object()->mark() == markWord::encode(this), \ "object mark must match encoded this: mark=" INTPTR_FORMAT \ @@ -500,7 +491,7 @@ bool ObjectMonitor::spin_enter(JavaThread* current) { return false; } -bool ObjectMonitor::enter(JavaThread* current) { +bool ObjectMonitor::enter(JavaThread* current, bool post_jvmti_events) { assert(current == JavaThread::current(), "must be"); if (spin_enter(current)) { @@ -521,15 +512,15 @@ bool ObjectMonitor::enter(JavaThread* current) { } // At this point this ObjectMonitor cannot be deflated, finish contended enter - enter_with_contention_mark(current, contention_mark); + enter_with_contention_mark(current, contention_mark, post_jvmti_events); return true; } -void ObjectMonitor::notify_contended_enter(JavaThread* current) { +void ObjectMonitor::notify_contended_enter(JavaThread* current, bool post_jvmti_events) { current->set_current_pending_monitor(this); DTRACE_MONITOR_PROBE(contended__enter, this, object(), current); - if (JvmtiExport::should_post_monitor_contended_enter()) { + if (post_jvmti_events && JvmtiExport::should_post_monitor_contended_enter()) { JvmtiExport::post_monitor_contended_enter(current, this); // The current thread does not yet own the monitor and does not @@ -540,7 +531,7 @@ void ObjectMonitor::notify_contended_enter(JavaThread* current) { } } -void ObjectMonitor::enter_with_contention_mark(JavaThread* current, ObjectMonitorContentionMark &cm) { +void ObjectMonitor::enter_with_contention_mark(JavaThread* current, ObjectMonitorContentionMark &cm, bool post_jvmti_events) { assert(current == JavaThread::current(), "must be"); assert(!has_owner(current), "must be"); assert(cm._monitor == this, "must be"); @@ -564,7 +555,7 @@ void ObjectMonitor::enter_with_contention_mark(JavaThread* current, ObjectMonito ContinuationEntry* ce = current->last_continuation(); bool is_virtual = ce != nullptr && ce->is_virtual_thread(); if (is_virtual) { - notify_contended_enter(current); + notify_contended_enter(current, post_jvmti_events); result = Continuation::try_preempt(current, ce->cont_oop(current)); if (result == freeze_ok) { bool acquired = vthread_monitor_enter(current); @@ -573,7 +564,7 @@ void ObjectMonitor::enter_with_contention_mark(JavaThread* current, ObjectMonito // _entry_list so cancel preemption. We will still go through the preempt stub // but instead of unmounting we will call thaw to continue execution. current->set_preemption_cancelled(true); - if (JvmtiExport::should_post_monitor_contended_entered()) { + if (post_jvmti_events && JvmtiExport::should_post_monitor_contended_entered()) { // We are going to call thaw again after this and finish the VMTS // transition so no need to do it here. We will post the event there. current->set_contended_entered_monitor(this); @@ -610,7 +601,8 @@ void ObjectMonitor::enter_with_contention_mark(JavaThread* current, ObjectMonito // states will still report that the thread is blocked trying to // acquire it. // If there is a suspend request, ExitOnSuspend will exit the OM - // and set the OM as pending. + // and set the OM as pending, the thread will not be reported as + // having "-locked" the monitor. } if (!eos.exited()) { // ExitOnSuspend did not exit the OM @@ -644,7 +636,7 @@ void ObjectMonitor::enter_with_contention_mark(JavaThread* current, ObjectMonito // spinning we could increment JVMStat counters, etc. DTRACE_MONITOR_PROBE(contended__entered, this, object(), current); - if (JvmtiExport::should_post_monitor_contended_entered()) { + if (post_jvmti_events && JvmtiExport::should_post_monitor_contended_entered()) { JvmtiExport::post_monitor_contended_entered(current, this); // The current thread already owns the monitor and is not going to @@ -1102,11 +1094,10 @@ void ObjectMonitor::enter_internal(JavaThread* current) { void ObjectMonitor::reenter_internal(JavaThread* current, ObjectWaiter* currentNode) { assert(current != nullptr, "invariant"); - assert(current->thread_state() != _thread_blocked, "invariant"); + assert(current->thread_state() == _thread_blocked, "invariant"); assert(currentNode != nullptr, "invariant"); assert(currentNode->_thread == current, "invariant"); assert(_waiters > 0, "invariant"); - assert_mark_word_consistency(); // If there are unmounted virtual threads ahead in the _entry_list we want // to do a timed-park instead to alleviate some deadlock cases where one @@ -1142,22 +1133,15 @@ void ObjectMonitor::reenter_internal(JavaThread* current, ObjectWaiter* currentN { OSThreadContendState osts(current->osthread()); - - assert(current->thread_state() == _thread_in_vm, "invariant"); - - { - ClearSuccOnSuspend csos(this); - ThreadBlockInVMPreprocess tbivs(current, csos, true /* allow_suspend */); - if (do_timed_parked) { - current->_ParkEvent->park(recheck_interval); - // Increase the recheck_interval, but clamp the value. - recheck_interval *= 8; - if (recheck_interval > MAX_RECHECK_INTERVAL) { - recheck_interval = MAX_RECHECK_INTERVAL; - } - } else { - current->_ParkEvent->park(); + if (do_timed_parked) { + current->_ParkEvent->park(recheck_interval); + // Increase the recheck_interval, but clamp the value. + recheck_interval *= 8; + if (recheck_interval > MAX_RECHECK_INTERVAL) { + recheck_interval = MAX_RECHECK_INTERVAL; } + } else { + current->_ParkEvent->park(); } } @@ -1184,7 +1168,6 @@ void ObjectMonitor::reenter_internal(JavaThread* current, ObjectWaiter* currentN // Current has acquired the lock -- Unlink current from the _entry_list. assert(has_owner(current), "invariant"); - assert_mark_word_consistency(); unlink_after_acquire(current, currentNode); if (has_successor(current)) clear_successor(); assert(!has_successor(current), "invariant"); @@ -1883,7 +1866,7 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { // while (!timeout && !interrupted && node.TState == TS_WAIT) park() int ret = OS_OK; - bool was_notified = false; + bool was_notified = true; // Need to check interrupt state whilst still _thread_in_vm bool interrupted = interruptible && current->is_interrupted(false); @@ -1895,8 +1878,7 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { assert(current->thread_state() == _thread_in_vm, "invariant"); { - ClearSuccOnSuspend csos(this); - ThreadBlockInVMPreprocess tbivs(current, csos, true /* allow_suspend */); + ThreadBlockInVM tbivm(current, false /* allow_suspend */); if (interrupted || HAS_PENDING_EXCEPTION) { // Intentionally empty } else if (node.TState == ObjectWaiter::TS_WAIT) { @@ -1928,17 +1910,16 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { if (node.TState == ObjectWaiter::TS_WAIT) { dequeue_specific_waiter(&node); // unlink from wait_set node.TState = ObjectWaiter::TS_RUN; + was_notified = false; } } - - // The thread is now either on off-list (TS_RUN), + // The thread is now either off-list (TS_RUN), // or on the entry_list (TS_ENTER). // The Node's TState variable is stable from the perspective of this thread. // No other threads will asynchronously modify TState. guarantee(node.TState != ObjectWaiter::TS_WAIT, "invariant"); OrderAccess::loadload(); if (has_successor(current)) clear_successor(); - was_notified = node.TState == ObjectWaiter::TS_ENTER; // Reentry phase -- reacquire the monitor. // re-enter contended monitor after object.wait(). @@ -1947,27 +1928,19 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { // although the raw address of the object may have changed. // (Don't cache naked oops over safepoints, of course). - // post monitor waited event. Note that this is past-tense, we are done waiting. - if (JvmtiExport::should_post_monitor_waited()) { - JvmtiExport::post_monitor_waited(current, this, ret == OS_TIMEOUT); + // Post monitor waited event. Note that this is past-tense, we are done waiting. + // An event could have been enabled after notification, in this case + // a thread will have TS_ENTER state and posting the event may hit a suspension point. + // From a debugging perspective, it is more important to have no missing events. + if (interruptible && JvmtiExport::should_post_monitor_waited() && node.TState != ObjectWaiter::TS_ENTER) { - if (was_notified && has_successor(current)) { - // In this part of the monitor wait-notify-reenter protocol it - // is possible (and normal) for another thread to do a fastpath - // monitor enter-exit while this thread is still trying to get - // to the reenter portion of the protocol. - // - // The ObjectMonitor was notified and the current thread is - // the successor which also means that an unpark() has already - // been done. The JVMTI_EVENT_MONITOR_WAITED event handler can - // consume the unpark() that was done when the successor was - // set because the same ParkEvent is shared between Java - // monitors and JVM/TI RawMonitors (for now). - // - // We redo the unpark() to ensure forward progress, i.e., we - // don't want all pending threads hanging (parked) with none - // entering the unlocked monitor. - current->_ParkEvent->unpark(); + // Process suspend requests now if any, before posting the event. + { + ThreadBlockInVM tbvm(current, true); + } + // Re-check the condition as the monitor waited events can be disabled whilst thread was suspended. + if (JvmtiExport::should_post_monitor_waited()) { + JvmtiExport::post_monitor_waited(current, this, ret == OS_TIMEOUT); } } @@ -1986,8 +1959,30 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { NoPreemptMark npm(current); enter(current); } else { + // This means the thread has been un-parked and added to the entry_list + // in notify_internal, i.e. notified while waiting. guarantee(v == ObjectWaiter::TS_ENTER, "invariant"); - reenter_internal(current, &node); + ExitOnSuspend eos(this); + { + ThreadBlockInVMPreprocess tbivs(current, eos, true /* allow_suspend */); + reenter_internal(current, &node); + // We can go to a safepoint at the end of this block. If we + // do a thread dump during that safepoint, then this thread will show + // as having "-locked" the monitor, but the OS and java.lang.Thread + // states will still report that the thread is blocked trying to + // acquire it. + // If there is a suspend request, ExitOnSuspend will exit the OM + // and set the OM as pending, the thread will not be reported as + // having "-locked" the monitor. + } + if (eos.exited()) { + // ExitOnSuspend exit the OM + assert(!has_owner(current), "invariant"); + guarantee(node.TState == ObjectWaiter::TS_RUN, "invariant"); + current->set_current_pending_monitor(nullptr); + enter(current, false /* post_jvmti_events */); + } + assert(has_owner(current), "invariant"); node.wait_reenter_end(this); } @@ -2041,6 +2036,8 @@ bool ObjectMonitor::notify_internal(JavaThread* current) { ObjectWaiter* iterator = dequeue_waiter(); if (iterator != nullptr) { guarantee(iterator->TState == ObjectWaiter::TS_WAIT, "invariant"); + iterator->_notifier_tid = JFR_THREAD_ID(current); + did_notify = true; if (iterator->is_vthread()) { oop vthread = iterator->vthread(); @@ -2056,45 +2053,55 @@ bool ObjectMonitor::notify_internal(JavaThread* current) { old_state == java_lang_VirtualThread::TIMED_WAIT) { java_lang_VirtualThread::cmpxchg_state(vthread, old_state, java_lang_VirtualThread::BLOCKED); } - // Increment counter *before* adding the vthread to the _entry_list. - // Adding to _entry_list uses Atomic::cmpxchg() which already provides - // a fence that prevents reordering of the stores. - inc_unmounted_vthreads(); + if (!JvmtiExport::should_post_monitor_waited()) { + // Increment counter *before* adding the vthread to the _entry_list. + // Adding to _entry_list uses Atomic::cmpxchg() which already provides + // a fence that prevents reordering of the stores. + inc_unmounted_vthreads(); + add_to_entry_list(current, iterator); + } else { + iterator->TState = ObjectWaiter::TS_RUN; + if (java_lang_VirtualThread::set_onWaitingList(vthread, vthread_list_head())) { + ParkEvent* pe = ObjectMonitor::vthread_unparker_ParkEvent(); + pe->unpark(); + } + } + } else { + if (!JvmtiExport::should_post_monitor_waited()) { + add_to_entry_list(current, iterator); + // Read counter *after* adding the thread to the _entry_list. + // Adding to _entry_list uses Atomic::cmpxchg() which already provides + // a fence that prevents this load from floating up previous store. + if (has_unmounted_vthreads()) { + // Wake up the thread to alleviate some deadlock cases where the successor + // that will be picked up when this thread releases the monitor is an unmounted + // virtual thread that cannot run due to having run out of carriers. Upon waking + // up, the thread will call reenter_internal() which will use timed-park in case + // there is contention and there are still vthreads in the _entry_list. + // If the target was interrupted or the wait timed-out at the same time, it could + // have reached reenter_internal and read a false value of has_unmounted_vthreads() + // before we added it to the _entry_list above. To deal with that case, we set _do_timed_park + // which will be read by the target on the next loop iteration in reenter_internal. + iterator->_do_timed_park = true; + JavaThread* t = iterator->thread(); + t->_ParkEvent->unpark(); + } + iterator->wait_reenter_begin(this); + } else { + iterator->TState = ObjectWaiter::TS_RUN; + JavaThread* t = iterator->thread(); + assert(t != nullptr, ""); + t->_ParkEvent->unpark(); + } } - iterator->_notifier_tid = JFR_THREAD_ID(current); - did_notify = true; - add_to_entry_list(current, iterator); - // _wait_set_lock protects the wait queue, not the entry_list. We could // move the add-to-entry_list operation, above, outside the critical section // protected by _wait_set_lock. In practice that's not useful. With the - // exception of wait() timeouts and interrupts the monitor owner + // exception of wait() timeouts and interrupts the monitor owner // is the only thread that grabs _wait_set_lock. There's almost no contention // on _wait_set_lock so it's not profitable to reduce the length of the // critical section. - - if (!iterator->is_vthread()) { - iterator->wait_reenter_begin(this); - - // Read counter *after* adding the thread to the _entry_list. - // Adding to _entry_list uses Atomic::cmpxchg() which already provides - // a fence that prevents this load from floating up previous store. - if (has_unmounted_vthreads()) { - // Wake up the thread to alleviate some deadlock cases where the successor - // that will be picked up when this thread releases the monitor is an unmounted - // virtual thread that cannot run due to having run out of carriers. Upon waking - // up, the thread will call reenter_internal() which will use timed-park in case - // there is contention and there are still vthreads in the _entry_list. - // If the target was interrupted or the wait timed-out at the same time, it could - // have reached reenter_internal and read a false value of has_unmounted_vthreads() - // before we added it to the _entry_list above. To deal with that case, we set _do_timed_park - // which will be read by the target on the next loop iteration in reenter_internal. - iterator->_do_timed_park = true; - JavaThread* t = iterator->thread(); - t->_ParkEvent->unpark(); - } - } } return did_notify; } @@ -2221,19 +2228,22 @@ bool ObjectMonitor::vthread_wait_reenter(JavaThread* current, ObjectWaiter* node // The first time we run after being preempted on Object.wait() we // need to check if we were interrupted or the wait timed-out, and // in that case remove ourselves from the _wait_set queue. + bool was_notified = true; if (node->TState == ObjectWaiter::TS_WAIT) { SpinCriticalSection scs(&_wait_set_lock); if (node->TState == ObjectWaiter::TS_WAIT) { dequeue_specific_waiter(node); // unlink from wait_set node->TState = ObjectWaiter::TS_RUN; + was_notified = false; } } // If this was an interrupted case, set the _interrupted boolean so that // once we re-acquire the monitor we know if we need to throw IE or not. ObjectWaiter::TStates state = node->TState; - bool was_notified = state == ObjectWaiter::TS_ENTER; - assert(was_notified || state == ObjectWaiter::TS_RUN, ""); + assert(was_notified || state == ObjectWaiter::TS_RUN, + "was not notified and is not in the right state: state = %s", + node->getTStateName(state)); node->_interrupted = node->_interruptible && !was_notified && current->is_interrupted(false); // Post JFR and JVMTI events. If non-interruptible we are in @@ -2246,7 +2256,10 @@ bool ObjectMonitor::vthread_wait_reenter(JavaThread* current, ObjectWaiter* node // Mark that we are at reenter so that we don't call this method again. node->_at_reenter = true; - if (!was_notified) { + // We check the state rather than was_notified because, when JVMTI + // monitor_waited event is enabled, the notifier only unparks the waiter + // without adding it to the entry_list. + if (state == ObjectWaiter::TS_RUN) { bool acquired = vthread_monitor_enter(current, node); if (acquired) { guarantee(_recursions == 0, "invariant"); @@ -2537,6 +2550,23 @@ ObjectWaiter::ObjectWaiter(JavaThread* current) { _active = false; } +const char* ObjectWaiter::getTStateName(ObjectWaiter::TStates state) { + switch (state) { + case ObjectWaiter::TS_UNDEF: + return "TS_UNDEF"; + case ObjectWaiter::TS_READY: + return "TS_READY"; + case ObjectWaiter::TS_RUN: + return "TS_RUN"; + case ObjectWaiter::TS_WAIT: + return "TS_WAIT"; + case ObjectWaiter::TS_ENTER: + return "TS_ENTER"; + default: + ShouldNotReachHere(); + } +} + ObjectWaiter::ObjectWaiter(oop vthread, ObjectMonitor* mon) : ObjectWaiter(nullptr) { assert(oopDesc::is_oop(vthread), ""); _vthread = OopHandle(JavaThread::thread_oop_storage(), vthread); diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index 53b64f1e8a5..574a652f230 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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,7 +40,6 @@ class ParkEvent; class BasicLock; class ContinuationWrapper; - class ObjectWaiter : public CHeapObj { public: enum TStates : uint8_t { TS_UNDEF, TS_READY, TS_RUN, TS_WAIT, TS_ENTER }; @@ -72,7 +71,7 @@ class ObjectWaiter : public CHeapObj { oop vthread() const; void wait_reenter_begin(ObjectMonitor *mon); void wait_reenter_end(ObjectMonitor *mon); - + const char* getTStateName(TStates state); void set_bad_pointers() { #ifdef ASSERT this->_prev = (ObjectWaiter*) badAddressVal; @@ -352,7 +351,6 @@ class ObjectMonitor : public CHeapObj { // returns false and throws IllegalMonitorStateException (IMSE). bool check_owner(TRAPS); - private: class ExitOnSuspend { protected: ObjectMonitor* _om; @@ -362,23 +360,16 @@ class ObjectMonitor : public CHeapObj { void operator()(JavaThread* current); bool exited() { return _om_exited; } }; - class ClearSuccOnSuspend { - protected: - ObjectMonitor* _om; - public: - ClearSuccOnSuspend(ObjectMonitor* om) : _om(om) {} - void operator()(JavaThread* current); - }; bool enter_is_async_deflating(); - void notify_contended_enter(JavaThread *current); + void notify_contended_enter(JavaThread *current, bool post_jvmti_events = true); public: void enter_for_with_contention_mark(JavaThread* locking_thread, ObjectMonitorContentionMark& contention_mark); bool enter_for(JavaThread* locking_thread); - bool enter(JavaThread* current); + bool enter(JavaThread* current, bool post_jvmti_events = true); bool try_enter(JavaThread* current, bool check_for_recursion = true); bool spin_enter(JavaThread* current); - void enter_with_contention_mark(JavaThread* current, ObjectMonitorContentionMark& contention_mark); + void enter_with_contention_mark(JavaThread* current, ObjectMonitorContentionMark& contention_mark, bool post_jvmti_events = true); void exit(JavaThread* current, bool not_suspended = true); bool resume_operation(JavaThread* current, ObjectWaiter* node, ContinuationWrapper& cont); void wait(jlong millis, bool interruptible, TRAPS); diff --git a/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWait.java b/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWait.java deleted file mode 100644 index 3a747a3e86b..00000000000 --- a/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWait.java +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright (c) 2001, 2021, 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 4413752 8262881 - * @summary Test SuspendThread with ObjectMonitor wait. - * @requires vm.jvmti - * @library /test/lib - * @compile SuspendWithObjectMonitorWait.java - * @run main/othervm/native -agentlib:SuspendWithObjectMonitorWait SuspendWithObjectMonitorWait - */ - -import java.io.PrintStream; - -// -// main waiter resumer -// ================= ================== =================== -// launch waiter -// waiter running -// launch resumer enter threadLock -// threadLock.wait() resumer running -// enter threadLock : wait for notify -// threadLock.notify wait finishes : -// : reenter blocks : -// suspend waiter : -// exit threadLock : : -// : : -// : : : -// notify resumer : wait finishes -// join resumer : enter threadLock -// : resume waiter -// : : exit threadLock -// : reenter threadLock : -// : resumer exits -// join waiter : -// waiter exits -// - -public class SuspendWithObjectMonitorWait { - private static final String AGENT_LIB = "SuspendWithObjectMonitorWait"; - private static final int exit_delta = 95; - - private static final int DEF_TIME_MAX = 60; // default max # secs to test - private static final int JOIN_MAX = 30; // max # secs to wait for join - - public static final int TS_INIT = 1; // initial testState - public static final int TS_WAITER_RUNNING = 2; // waiter is running - public static final int TS_RESUMER_RUNNING = 3; // resumer is running - public static final int TS_READY_TO_NOTIFY = 4; // ready to notify threadLock - public static final int TS_CALL_SUSPEND = 5; // call suspend on contender - public static final int TS_READY_TO_RESUME = 6; // ready to resume waiter - public static final int TS_CALL_RESUME = 7; // call resume on waiter - public static final int TS_WAITER_DONE = 8; // waiter has run; done - - public static Object barrierLaunch = new Object(); // controls thread launch - public static Object barrierResumer = new Object(); // controls resumer - public static Object threadLock = new Object(); // testing object - - public static long count = 0; - public static boolean printDebug = false; - public volatile static int testState; - - private static void log(String msg) { System.out.println(msg); } - - native static int suspendThread(SuspendWithObjectMonitorWaitWorker thr); - native static int wait4ContendedEnter(SuspendWithObjectMonitorWaitWorker thr); - - public static void main(String[] args) throws Exception { - try { - System.loadLibrary(AGENT_LIB); - log("Loaded library: " + AGENT_LIB); - } catch (UnsatisfiedLinkError ule) { - log("Failed to load library: " + AGENT_LIB); - log("java.library.path: " + System.getProperty("java.library.path")); - throw ule; - } - - int timeMax = 0; - if (args.length == 0) { - timeMax = DEF_TIME_MAX; - } else { - int argIndex = 0; - int argsLeft = args.length; - if (args[0].equals("-p")) { - printDebug = true; - argIndex = 1; - argsLeft--; - } - if (argsLeft == 0) { - timeMax = DEF_TIME_MAX; - } else if (argsLeft == 1) { - try { - timeMax = Integer.parseUnsignedInt(args[argIndex]); - } catch (NumberFormatException nfe) { - System.err.println("'" + args[argIndex] + - "': invalid timeMax value."); - usage(); - } - } else { - usage(); - } - } - - System.exit(run(timeMax, System.out) + exit_delta); - } - - public static void logDebug(String mesg) { - if (printDebug) { - System.err.println(Thread.currentThread().getName() + ": " + mesg); - } - } - - public static void usage() { - System.err.println("Usage: " + AGENT_LIB + " [-p][time_max]"); - System.err.println("where:"); - System.err.println(" -p ::= print debug info"); - System.err.println(" time_max ::= max looping time in seconds"); - System.err.println(" (default is " + DEF_TIME_MAX + - " seconds)"); - System.exit(1); - } - - public static int run(int timeMax, PrintStream out) { - return (new SuspendWithObjectMonitorWait()).doWork(timeMax, out); - } - - public static void checkTestState(int exp) { - if (testState != exp) { - System.err.println("Failure at " + count + " loops."); - throw new InternalError("Unexpected test state value: " - + "expected=" + exp + " actual=" + testState); - } - } - - public int doWork(int timeMax, PrintStream out) { - SuspendWithObjectMonitorWaitWorker waiter; // waiter thread - SuspendWithObjectMonitorWaitWorker resumer; // resumer thread - - System.out.println("About to execute for " + timeMax + " seconds."); - - long start_time = System.currentTimeMillis(); - while (System.currentTimeMillis() < start_time + (timeMax * 1000)) { - count++; - testState = TS_INIT; // starting the test loop - - // launch the waiter thread - synchronized (barrierLaunch) { - waiter = new SuspendWithObjectMonitorWaitWorker("waiter"); - waiter.start(); - - while (testState != TS_WAITER_RUNNING) { - try { - barrierLaunch.wait(0); // wait until it is running - } catch (InterruptedException ex) { - } - } - } - - // launch the resumer thread - synchronized (barrierLaunch) { - resumer = new SuspendWithObjectMonitorWaitWorker("resumer", waiter); - resumer.start(); - - while (testState != TS_RESUMER_RUNNING) { - try { - barrierLaunch.wait(0); // wait until it is running - } catch (InterruptedException ex) { - } - } - } - - checkTestState(TS_RESUMER_RUNNING); - - // The waiter thread was synchronized on threadLock before it - // set TS_WAITER_RUNNING and notified barrierLaunch above so - // we cannot enter threadLock until the waiter thread calls - // threadLock.wait(). - synchronized (threadLock) { - // notify waiter thread so it can try to reenter threadLock - testState = TS_READY_TO_NOTIFY; - threadLock.notify(); - - // wait for the waiter thread to block - logDebug("before contended enter wait"); - int retCode = wait4ContendedEnter(waiter); - if (retCode != 0) { - throw new RuntimeException("error in JVMTI GetThreadState: " - + "retCode=" + retCode); - } - logDebug("done contended enter wait"); - - checkTestState(TS_READY_TO_NOTIFY); - testState = TS_CALL_SUSPEND; - logDebug("before suspend thread"); - retCode = suspendThread(waiter); - if (retCode != 0) { - throw new RuntimeException("error in JVMTI SuspendThread: " - + "retCode=" + retCode); - } - logDebug("suspended thread"); - } - - // - // At this point, all of the child threads are running - // and we can get to meat of the test: - // - // - suspended threadLock waiter (trying to reenter) - // - a threadLock enter in the resumer thread - // - resumption of the waiter thread - // - a threadLock enter in the freshly resumed waiter thread - // - - synchronized (barrierResumer) { - checkTestState(TS_CALL_SUSPEND); - - // tell resumer thread to resume waiter thread - testState = TS_READY_TO_RESUME; - barrierResumer.notify(); - - // Can't call checkTestState() here because the - // resumer thread may have already resumed the - // waiter thread. - } - - try { - resumer.join(JOIN_MAX * 1000); - if (resumer.isAlive()) { - System.err.println("Failure at " + count + " loops."); - throw new InternalError("resumer thread is stuck"); - } - waiter.join(JOIN_MAX * 1000); - if (waiter.isAlive()) { - System.err.println("Failure at " + count + " loops."); - throw new InternalError("waiter thread is stuck"); - } - } catch (InterruptedException ex) { - } - - checkTestState(TS_WAITER_DONE); - } - - System.out.println("Executed " + count + " loops in " + timeMax + - " seconds."); - - return 0; - } -} - -class SuspendWithObjectMonitorWaitWorker extends Thread { - private SuspendWithObjectMonitorWaitWorker target; // target for resume operation - - public SuspendWithObjectMonitorWaitWorker(String name) { - super(name); - } - - public SuspendWithObjectMonitorWaitWorker(String name, SuspendWithObjectMonitorWaitWorker target) { - super(name); - this.target = target; - } - - native static int resumeThread(SuspendWithObjectMonitorWaitWorker thr); - - public void run() { - SuspendWithObjectMonitorWait.logDebug("thread running"); - - // - // Launch the waiter thread: - // - grab the threadLock - // - threadLock.wait() - // - releases threadLock - // - if (getName().equals("waiter")) { - // grab threadLock before we tell main we are running - SuspendWithObjectMonitorWait.logDebug("before enter threadLock"); - synchronized(SuspendWithObjectMonitorWait.threadLock) { - SuspendWithObjectMonitorWait.logDebug("enter threadLock"); - - SuspendWithObjectMonitorWait.checkTestState(SuspendWithObjectMonitorWait.TS_INIT); - - synchronized(SuspendWithObjectMonitorWait.barrierLaunch) { - // tell main we are running - SuspendWithObjectMonitorWait.testState = SuspendWithObjectMonitorWait.TS_WAITER_RUNNING; - SuspendWithObjectMonitorWait.barrierLaunch.notify(); - } - - SuspendWithObjectMonitorWait.logDebug("before wait"); - - // TS_READY_TO_NOTIFY is set after the main thread has - // entered threadLock so a spurious wakeup can't get the - // waiter thread out of this threadLock.wait(0) call: - while (SuspendWithObjectMonitorWait.testState <= SuspendWithObjectMonitorWait.TS_READY_TO_NOTIFY) { - try { - SuspendWithObjectMonitorWait.threadLock.wait(0); - } catch (InterruptedException ex) { - } - } - - SuspendWithObjectMonitorWait.logDebug("after wait"); - - SuspendWithObjectMonitorWait.checkTestState(SuspendWithObjectMonitorWait.TS_CALL_RESUME); - SuspendWithObjectMonitorWait.testState = SuspendWithObjectMonitorWait.TS_WAITER_DONE; - - SuspendWithObjectMonitorWait.logDebug("exit threadLock"); - } - } - // - // Launch the resumer thread: - // - tries to grab the threadLock (should not block!) - // - grabs threadLock - // - resumes the waiter thread - // - releases threadLock - // - else if (getName().equals("resumer")) { - synchronized(SuspendWithObjectMonitorWait.barrierResumer) { - synchronized(SuspendWithObjectMonitorWait.barrierLaunch) { - // tell main we are running - SuspendWithObjectMonitorWait.testState = SuspendWithObjectMonitorWait.TS_RESUMER_RUNNING; - SuspendWithObjectMonitorWait.barrierLaunch.notify(); - } - SuspendWithObjectMonitorWait.logDebug("thread waiting"); - while (SuspendWithObjectMonitorWait.testState != SuspendWithObjectMonitorWait.TS_READY_TO_RESUME) { - try { - // wait for main to tell us when to continue - SuspendWithObjectMonitorWait.barrierResumer.wait(0); - } catch (InterruptedException ex) { - } - } - } - - SuspendWithObjectMonitorWait.logDebug("before enter threadLock"); - synchronized(SuspendWithObjectMonitorWait.threadLock) { - SuspendWithObjectMonitorWait.logDebug("enter threadLock"); - - SuspendWithObjectMonitorWait.checkTestState(SuspendWithObjectMonitorWait.TS_READY_TO_RESUME); - SuspendWithObjectMonitorWait.testState = SuspendWithObjectMonitorWait.TS_CALL_RESUME; - - // resume the waiter thread so waiter.join() can work - SuspendWithObjectMonitorWait.logDebug("before resume thread"); - int retCode = resumeThread(target); - if (retCode != 0) { - throw new RuntimeException("error in JVMTI ResumeThread: " + - "retCode=" + retCode); - } - SuspendWithObjectMonitorWait.logDebug("resumed thread"); - - SuspendWithObjectMonitorWait.logDebug("exit threadLock"); - } - } - } -} diff --git a/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitBase.java b/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitBase.java new file mode 100644 index 00000000000..5443e4005fe --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitBase.java @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2001, 2026, 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.PrintStream; + +public class SuspendWithObjectMonitorWaitBase { + protected static final String AGENT_LIB = "SuspendWithObjectMonitorWait"; + protected static final int exit_delta = 95; + + protected static final int DEF_TIME_MAX = 60; // default max # secs to test + protected static final int JOIN_MAX = 30; // max # secs to wait for join + + public static final int TS_INIT = 1; // initial testState + public static final int TS_WAITER_RUNNING = 2; // waiter is running + public static final int TS_RESUMER_RUNNING = 3; // resumer is running + public static final int TS_READY_TO_NOTIFY = 4; // ready to notify threadLock + public static final int TS_CALL_SUSPEND = 5; // call suspend on contender + public static final int TS_READY_TO_RESUME = 6; // ready to resume waiter + public static final int TS_CALL_RESUME = 7; // call resume on waiter + public static final int TS_WAITER_DONE = 8; // waiter has run; done + + public static Object barrierLaunch = new Object(); // controls thread launch + public static Object barrierResumer = new Object(); // controls resumer + public static Object threadLock = new Object(); // testing object + + public static long count = 0; + public static boolean printDebug = false; + public volatile static int testState; + + protected static void log(String msg) { System.out.println(msg); } + + native static int suspendThread(SuspendWithObjectMonitorWaitWorker thr); + native static int wait4ContendedEnter(SuspendWithObjectMonitorWaitWorker thr); + + public static void logDebug(String mesg) { + if (printDebug) { + System.err.println(Thread.currentThread().getName() + ": " + mesg); + } + } + + public static void usage() { + System.err.println("Usage: " + AGENT_LIB + " test_case [-p] [time_max]"); + System.err.println("where:"); + System.err.println(" test_case ::= 1 | 2 | 3"); + System.err.println(" -p ::= print debug info"); + System.err.println(" time_max ::= max looping time in seconds"); + System.err.println(" (default is " + DEF_TIME_MAX + + " seconds)"); + System.exit(1); + } + + public static void checkTestState(int exp) { + if (testState != exp) { + System.err.println("Failure at " + count + " loops."); + throw new InternalError("Unexpected test state value: " + + "expected=" + exp + " actual=" + testState); + } + } + + public SuspendWithObjectMonitorWaitWorker launchWaiter(long waitTimeout) { + SuspendWithObjectMonitorWaitWorker waiter; + // launch the waiter thread + synchronized (barrierLaunch) { + waiter = new SuspendWithObjectMonitorWaitWorker("waiter", waitTimeout); + waiter.start(); + + while (testState != TS_WAITER_RUNNING) { + try { + barrierLaunch.wait(0); // wait until it is running + } catch (InterruptedException ex) { + } + } + } + return waiter; + } + + public SuspendWithObjectMonitorWaitWorker launchResumer(SuspendWithObjectMonitorWaitWorker waiter) { + SuspendWithObjectMonitorWaitWorker resumer; + synchronized (barrierLaunch) { + resumer = new SuspendWithObjectMonitorWaitWorker("resumer", waiter); + resumer.start(); + + while (testState != TS_RESUMER_RUNNING) { + try { + barrierLaunch.wait(0); // wait until it is running + } catch (InterruptedException ex) { + } + } + } + return resumer; + } + + public void barrierResumerNotify() { + synchronized (barrierResumer) { + checkTestState(TS_CALL_SUSPEND); + + // tell resumer thread to resume waiter thread + testState = TS_READY_TO_RESUME; + barrierResumer.notify(); + + // Can't call checkTestState() here because the + // resumer thread may have already resumed the + // waiter thread. + } + } + + public void shutDown(SuspendWithObjectMonitorWaitWorker resumer, SuspendWithObjectMonitorWaitWorker waiter) { + try { + resumer.join(JOIN_MAX * 1000); + if (resumer.isAlive()) { + System.err.println("Failure at " + count + " loops."); + throw new InternalError("resumer thread is stuck"); + } + waiter.join(JOIN_MAX * 1000); + if (waiter.isAlive()) { + System.err.println("Failure at " + count + " loops."); + throw new InternalError("waiter thread is stuck"); + } + } catch (InterruptedException ex) { + } + } + + public int run(int timeMax, PrintStream out) { + return 0; + } + + public static void main(String[] args) throws Exception { + if (args.length == 0) { + System.err.println("Invalid number of arguments, there should be at least a test_case given."); + usage(); + } + + if (args.length > 3) { + System.err.println("Invalid number of arguments, there are too many arguments."); + usage(); + } + + try { + System.loadLibrary(AGENT_LIB); + log("Loaded library: " + AGENT_LIB); + } catch (UnsatisfiedLinkError ule) { + log("Failed to load library: " + AGENT_LIB); + log("java.library.path: " + System.getProperty("java.library.path")); + throw ule; + } + + int testCase = 0; + int timeMax = 0; + for (int argIndex = 0; argIndex < args.length; argIndex++) { + if (args[argIndex].equals("-p")) { + // Handle optional -p arg regardless of position. + printDebug = true; + continue; + } + + if (testCase == 0) { + try { + // testCase must be the first non-optional arg. + testCase = Integer.parseUnsignedInt(args[argIndex]); + log("testCase = " + testCase); + } catch (NumberFormatException nfe) { + System.err.println("'" + args[argIndex] + + "': invalid test_case value."); + usage(); + } + if (testCase < 1 || testCase > 3) { + System.err.println("Invalid test_case value: '" + testCase + "'"); + usage(); + } + continue; + } + + if (argIndex < args.length) { + // timeMax is an optional arg. + try { + timeMax = Integer.parseUnsignedInt(args[argIndex]); + } catch (NumberFormatException nfe) { + System.err.println("'" + args[argIndex] + + "': invalid time_max value."); + usage(); + } + } else { + timeMax = DEF_TIME_MAX; + } + } + + if (timeMax == 0) { + timeMax = DEF_TIME_MAX; + } + log("timeMax = " + timeMax); + + if (testCase == 0) { + // Just -p was given. + System.err.println("Invalid number of arguments, no test_case given."); + usage(); + } + + SuspendWithObjectMonitorWaitBase test = null; + switch (testCase) { + case 1: + test = new SuspendWithObjectMonitorWaitDefault(); + break; + case 2: + test = new SuspendWithObjectMonitorWaitReentryPartFirst(); + break; + case 3: + test = new SuspendWithObjectMonitorWaitReentryPartSecond(); + break; + default: + // Impossible + break; + } + int result = test.run(timeMax, System.out); + System.exit(result + exit_delta); + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitDefault.java b/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitDefault.java new file mode 100644 index 00000000000..b2c1f108de5 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitDefault.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2001, 2026, 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 4413752 8262881 + * @summary Test SuspendThread with ObjectMonitor wait. + * @requires vm.jvmti + * @library /test/lib + * @compile SuspendWithObjectMonitorWaitDefault.java + * @run main/othervm/native -agentlib:SuspendWithObjectMonitorWait SuspendWithObjectMonitorWaitDefault 1 + */ + +import java.io.PrintStream; + +// +// SuspendWithObjectMonitorWaitDefault algorithm: +// +// main waiter resumer +// ================= ================== =================== +// launch waiter +// waiter running +// launch resumer enter threadLock +// threadLock.wait() resumer running +// enter threadLock : wait for notify +// threadLock.notify wait finishes : +// : reenter blocks : +// suspend waiter : +// exit threadLock : : +// : : +// : : : +// notify resumer : wait finishes +// join resumer : enter threadLock +// : resume waiter +// : : exit threadLock +// : reenter threadLock : +// : resumer exits +// join waiter : +// waiter exits +// + +public class SuspendWithObjectMonitorWaitDefault extends SuspendWithObjectMonitorWaitBase { + + @Override + public int run(int timeMax, PrintStream out) { + return doWork1(timeMax, out); + } + + // Default scenario, the resumer thread is always able to grab the threadLock once notified by the main thread. + public int doWork1(int timeMax, PrintStream out) { + SuspendWithObjectMonitorWaitWorker waiter; // waiter thread + SuspendWithObjectMonitorWaitWorker resumer; // resumer thread + + System.out.println("Test 1: About to execute for " + timeMax + " seconds."); + + long start_time = System.currentTimeMillis(); + while (System.currentTimeMillis() < start_time + (timeMax * 1000)) { + count++; + testState = TS_INIT; // starting the test loop + + // launch the waiter thread + waiter = launchWaiter(0); + + // launch the resumer thread + resumer = launchResumer(waiter); + + checkTestState(TS_RESUMER_RUNNING); + + // The waiter thread was synchronized on threadLock before it + // set TS_WAITER_RUNNING and notified barrierLaunch above so + // we cannot enter threadLock until the waiter thread calls + // threadLock.wait(). + synchronized (threadLock) { + // notify waiter thread so it can try to reenter threadLock + testState = TS_READY_TO_NOTIFY; + threadLock.notify(); + + // wait for the waiter thread to block + logDebug("before contended enter wait"); + int retCode = wait4ContendedEnter(waiter); + if (retCode != 0) { + throw new RuntimeException("error in JVMTI GetThreadState: " + + "retCode=" + retCode); + } + logDebug("done contended enter wait"); + + checkTestState(TS_READY_TO_NOTIFY); + testState = TS_CALL_SUSPEND; + logDebug("before suspend thread"); + retCode = suspendThread(waiter); + if (retCode != 0) { + throw new RuntimeException("error in JVMTI SuspendThread: " + + "retCode=" + retCode); + } + logDebug("suspended thread"); + } + + // + // At this point, all of the child threads are running + // and we can get to meat of the test: + // + // - suspended threadLock waiter (trying to reenter) + // - a threadLock enter in the resumer thread + // - resumption of the waiter thread + // - a threadLock enter in the freshly resumed waiter thread + // + barrierResumerNotify(); + + shutDown(waiter ,resumer); + checkTestState(TS_WAITER_DONE); + } + + System.out.println("Executed " + count + " loops in " + timeMax + + " seconds."); + + return 0; + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitReentryPartFirst.java b/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitReentryPartFirst.java new file mode 100644 index 00000000000..b331b338f47 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitReentryPartFirst.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2001, 2026, 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 4413752 8262881 + * @summary Test SuspendThread with ObjectMonitor wait. + * @requires vm.jvmti + * @library /test/lib + * @compile SuspendWithObjectMonitorWaitReentryPartFirst.java + * @run main/othervm/native -agentlib:SuspendWithObjectMonitorWait SuspendWithObjectMonitorWaitReentryPartFirst 2 + */ + +import java.io.PrintStream; + +// +// SuspendWithObjectMonitorWaitReentryPartFirst algorithm: +// +// main waiter resumer +// ================= ================== =================== +// launch waiter +// waiter running +// launch resumer enter threadLock +// threadLock.wait() resumer running +// enter threadLock : wait for notify +// threadLock.notify wait finishes : +// : reenter blocks : +// suspend waiter : +// : : +// : : : +// notify resumer : wait finishes +// delay 1-second : : +// exit threadLock : : +// join resumer : enter threadLock +// : resume waiter +// : : exit threadLock +// : reenter threadLock : +// : resumer exits +// join waiter : +// waiter exits +// +// Note: The sleep(1-second) in main along with the delayed exit +// of threadLock in main forces the resumer thread to reach +// "enter threadLock" and block. This difference from the default scenario +// forces the resumer thread to be contending for threadLock +// while the waiter thread is in threadLock.wait() increasing +// stress on the monitor sub-system. +// + +public class SuspendWithObjectMonitorWaitReentryPartFirst extends SuspendWithObjectMonitorWaitBase { + + @Override + public int run(int timeMax, PrintStream out) { + return doWork2(timeMax, out); + } + + // Notify the resumer while holding the threadLock. + public int doWork2(int timeMax, PrintStream out) { + SuspendWithObjectMonitorWaitWorker waiter; // waiter thread + SuspendWithObjectMonitorWaitWorker resumer; // resumer thread + + System.out.println("Test 2: About to execute for " + timeMax + " seconds."); + + long start_time = System.currentTimeMillis(); + while (System.currentTimeMillis() < start_time + (timeMax * 1000)) { + count++; + testState = TS_INIT; // starting the test loop + + // launch the waiter thread + waiter = launchWaiter(0); + + // launch the resumer thread + resumer = launchResumer(waiter); + + checkTestState(TS_RESUMER_RUNNING); + + // The waiter thread was synchronized on threadLock before it + // set TS_WAITER_RUNNING and notified barrierLaunch above so + // we cannot enter threadLock until the waiter thread calls + // threadLock.wait(). + synchronized (threadLock) { + // notify waiter thread so it can try to reenter threadLock + testState = TS_READY_TO_NOTIFY; + threadLock.notify(); + + // wait for the waiter thread to block + logDebug("before contended enter wait"); + int retCode = wait4ContendedEnter(waiter); + if (retCode != 0) { + throw new RuntimeException("error in JVMTI GetThreadState: " + + "retCode=" + retCode); + } + logDebug("done contended enter wait"); + + checkTestState(TS_READY_TO_NOTIFY); + testState = TS_CALL_SUSPEND; + logDebug("before suspend thread"); + retCode = suspendThread(waiter); + if (retCode != 0) { + throw new RuntimeException("error in JVMTI SuspendThread: " + + "retCode=" + retCode); + } + logDebug("suspended thread"); + + // + // At this point, all of the child threads are running + // and we can get to meat of the test: + // + // - suspended threadLock waiter (trying to reenter) + // - a blocked threadLock enter in the resumer thread while the + // threadLock is held by the main thread. + // - resumption of the waiter thread + // - a threadLock enter in the freshly resumed waiter thread + // + barrierResumerNotify(); + try { + // Delay for 1-second while holding the threadLock to force the + // resumer thread to block on entering the threadLock. + Thread.sleep(1000); + } catch (Exception e) {} + } + + shutDown(waiter ,resumer); + checkTestState(TS_WAITER_DONE); + } + + System.out.println("Executed " + count + " loops in " + timeMax + + " seconds."); + + return 0; + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitReentryPartSecond.java b/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitReentryPartSecond.java new file mode 100644 index 00000000000..92ab5a88eb6 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitReentryPartSecond.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2001, 2026, 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 4413752 8262881 + * @summary Test SuspendThread with ObjectMonitor wait. + * @requires vm.jvmti + * @library /test/lib + * @compile SuspendWithObjectMonitorWaitReentryPartSecond.java + * @run main/othervm/native -agentlib:SuspendWithObjectMonitorWait SuspendWithObjectMonitorWaitReentryPartSecond 3 + */ + +import java.io.PrintStream; + +// +// SuspendWithObjectMonitorWaitReentryPartSecond algorithm: +// +// main waiter resumer +// =================== ====================== =================== +// launch waiter +// waiter running +// launch resumer enter threadLock +// while !READY_TO_NOTIFY resumer running +// : threadLock.wait(1) wait for notify +// enter threadLock : : +// set READY_TO_NOTIFY : +// threadLock.notify wait finishes : +// : delay 200ms reenter blocks : +// suspend waiter : +// : : +// : : : +// notify resumer : wait finishes +// delay 1-second : : +// exit threadLock : : +// join resumer : enter threadLock +// : resume waiter +// : : exit threadLock +// : reenter threadLock : +// : resumer exits +// join waiter : +// waiter exits +// +// Note: The sleep(1-second) in main along with the delayed exit +// of threadLock in main forces the resumer thread to reach +// "enter threadLock" and block. This difference from the default scenario +// forces the resumer thread to be contending for threadLock +// while the waiter thread is in the threadLock.wait(1) tight +// loop increasing stress on the monitor sub-system. +// +// Note: sleep(200ms) here while holding the threadLock to allow the +// waiter thread's timed wait to finish before we attempt to +// suspend the waiter thread. +// + +public class SuspendWithObjectMonitorWaitReentryPartSecond extends SuspendWithObjectMonitorWaitBase { + + @Override + public int run(int timeMax, PrintStream out) { + return doWork3(timeMax, out); + } + + // Suspend on the re-entry path of wait. + public int doWork3(int timeMax, PrintStream out) { + SuspendWithObjectMonitorWaitWorker waiter; // waiter thread + SuspendWithObjectMonitorWaitWorker resumer; // resumer thread + + System.out.println("Test 3: About to execute for " + timeMax + " seconds."); + + long start_time = System.currentTimeMillis(); + while (System.currentTimeMillis() < start_time + (timeMax * 1000)) { + count++; + testState = TS_INIT; // starting the test loop + + // launch the waiter thread + waiter = launchWaiter(100); + + // launch the resumer thread + resumer = launchResumer(waiter); + + checkTestState(TS_RESUMER_RUNNING); + + // The waiter thread was synchronized on threadLock before it + // set TS_WAITER_RUNNING and notified barrierLaunch above so + // we cannot enter threadLock until the waiter thread calls + // threadLock.wait(). + synchronized (threadLock) { + // notify waiter thread so it can try to reenter threadLock + testState = TS_READY_TO_NOTIFY; + threadLock.notify(); + + try { + Thread.sleep(200); + } catch (Exception e) {} + + // wait for the waiter thread to block + logDebug("before contended enter wait"); + int retCode = wait4ContendedEnter(waiter); + if (retCode != 0) { + throw new RuntimeException("error in JVMTI GetThreadState: " + + "retCode=" + retCode); + } + logDebug("done contended enter wait"); + + checkTestState(TS_READY_TO_NOTIFY); + testState = TS_CALL_SUSPEND; + logDebug("before suspend thread"); + retCode = suspendThread(waiter); + if (retCode != 0) { + throw new RuntimeException("error in JVMTI SuspendThread: " + + "retCode=" + retCode); + } + logDebug("suspended thread"); + + // + // At this point, all of the child threads are running + // and we can get to meat of the test: + // + // - suspended threadLock waiter (trying to reenter) + // - a blocked threadLock enter in the resumer thread while the + // threadLock is held by the main thread. + // - resumption of the waiter thread + // - a threadLock enter in the freshly resumed waiter thread + // + barrierResumerNotify(); + try { + // Delay for 1-second while holding the threadLock to force the + // resumer thread to block on entering the threadLock. + Thread.sleep(1000); + } catch (Exception e) {} + } + + shutDown(waiter ,resumer); + checkTestState(TS_WAITER_DONE); + } + + System.out.println("Executed " + count + " loops in " + timeMax + + " seconds."); + + return 0; + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitWorker.java b/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitWorker.java new file mode 100644 index 00000000000..2bf41168d5a --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWaitWorker.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2001, 2026, 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. + */ + +public class SuspendWithObjectMonitorWaitWorker extends Thread { + private SuspendWithObjectMonitorWaitWorker target; // target for resume operation + private final long waitTimeout; + + public SuspendWithObjectMonitorWaitWorker(String name, long waitTimeout) { + super(name); + this.waitTimeout = waitTimeout; + } + + public SuspendWithObjectMonitorWaitWorker(String name, SuspendWithObjectMonitorWaitWorker target) { + super(name); + this.target = target; + this.waitTimeout = 0; + } + + native static int resumeThread(SuspendWithObjectMonitorWaitWorker thr); + + public void run() { + SuspendWithObjectMonitorWaitBase.logDebug("thread running"); + + // + // Launch the waiter thread: + // - grab the threadLock + // - threadLock.wait() + // - releases threadLock + // + if (getName().equals("waiter")) { + // grab threadLock before we tell main we are running + SuspendWithObjectMonitorWaitBase.logDebug("before enter threadLock"); + synchronized(SuspendWithObjectMonitorWaitBase.threadLock) { + SuspendWithObjectMonitorWaitBase.logDebug("enter threadLock"); + + SuspendWithObjectMonitorWaitBase.checkTestState(SuspendWithObjectMonitorWaitBase.TS_INIT); + + synchronized(SuspendWithObjectMonitorWaitBase.barrierLaunch) { + // tell main we are running + SuspendWithObjectMonitorWaitBase.testState = SuspendWithObjectMonitorWaitBase.TS_WAITER_RUNNING; + SuspendWithObjectMonitorWaitBase.barrierLaunch.notify(); + } + + SuspendWithObjectMonitorWaitBase.logDebug("before wait"); + + // TS_READY_TO_NOTIFY is set after the main thread has + // entered threadLock so a spurious wakeup can't get the + // waiter thread out of this threadLock.wait(0) call: + while (SuspendWithObjectMonitorWaitBase.testState <= SuspendWithObjectMonitorWaitBase.TS_READY_TO_NOTIFY) { + try { + SuspendWithObjectMonitorWaitBase.threadLock.wait(waitTimeout); + } catch (InterruptedException ex) { + } + } + + SuspendWithObjectMonitorWaitBase.logDebug("after wait"); + + SuspendWithObjectMonitorWaitBase.checkTestState(SuspendWithObjectMonitorWaitBase.TS_CALL_RESUME); + SuspendWithObjectMonitorWaitBase.testState = SuspendWithObjectMonitorWaitBase.TS_WAITER_DONE; + + SuspendWithObjectMonitorWaitBase.logDebug("exit threadLock"); + } + } + // + // Launch the resumer thread: + // - tries to grab the threadLock (should not block with doWork1!) + // - grabs threadLock + // - resumes the waiter thread + // - releases threadLock + // + else if (getName().equals("resumer")) { + synchronized(SuspendWithObjectMonitorWaitBase.barrierResumer) { + synchronized(SuspendWithObjectMonitorWaitBase.barrierLaunch) { + // tell main we are running + SuspendWithObjectMonitorWaitBase.testState = SuspendWithObjectMonitorWaitBase.TS_RESUMER_RUNNING; + SuspendWithObjectMonitorWaitBase.barrierLaunch.notify(); + } + SuspendWithObjectMonitorWaitBase.logDebug("thread waiting"); + while (SuspendWithObjectMonitorWaitBase.testState != SuspendWithObjectMonitorWaitBase.TS_READY_TO_RESUME) { + try { + // wait for main to tell us when to continue + SuspendWithObjectMonitorWaitBase.barrierResumer.wait(0); + } catch (InterruptedException ex) { + } + } + } + + SuspendWithObjectMonitorWaitBase.logDebug("before enter threadLock"); + synchronized(SuspendWithObjectMonitorWaitBase.threadLock) { + SuspendWithObjectMonitorWaitBase.logDebug("enter threadLock"); + + SuspendWithObjectMonitorWaitBase.checkTestState(SuspendWithObjectMonitorWaitBase.TS_READY_TO_RESUME); + SuspendWithObjectMonitorWaitBase.testState = SuspendWithObjectMonitorWaitBase.TS_CALL_RESUME; + + // resume the waiter thread so waiter.join() can work + SuspendWithObjectMonitorWaitBase.logDebug("before resume thread"); + int retCode = resumeThread(target); + if (retCode != 0) { + throw new RuntimeException("error in JVMTI ResumeThread: " + + "retCode=" + retCode); + } + SuspendWithObjectMonitorWaitBase.logDebug("resumed thread"); + + SuspendWithObjectMonitorWaitBase.logDebug("exit threadLock"); + } + } + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/libSuspendWithObjectMonitorWait.cpp b/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/libSuspendWithObjectMonitorWait.cpp index 3706cba76dc..bea70c4925f 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/libSuspendWithObjectMonitorWait.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/libSuspendWithObjectMonitorWait.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ static jvmtiEnv* jvmti = nullptr; } while (0) JNIEXPORT int JNICALL -Java_SuspendWithObjectMonitorWait_suspendThread(JNIEnv *jni, jclass cls, jthread thr) { +Java_SuspendWithObjectMonitorWaitBase_suspendThread(JNIEnv *jni, jclass cls, jthread thr) { return jvmti->SuspendThread(thr); } @@ -46,7 +46,7 @@ Java_SuspendWithObjectMonitorWaitWorker_resumeThread(JNIEnv *jni, jclass cls, jt } JNIEXPORT jint JNICALL -Java_SuspendWithObjectMonitorWait_wait4ContendedEnter(JNIEnv *jni, jclass cls, jthread thr) { +Java_SuspendWithObjectMonitorWaitBase_wait4ContendedEnter(JNIEnv *jni, jclass cls, jthread thr) { jvmtiError err; jint thread_state; do { From 5e248603813a46221c97f1c05311b06f21387bd7 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 2 Feb 2026 09:59:40 +0000 Subject: [PATCH 281/328] 8376115: G1: Convert G1CMRootRegions to use Atomic Reviewed-by: kbarrett, iwalulya --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 32 +++++++++++--------- src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 12 ++++---- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 29de5a12599..5f096c2b9d7 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -382,12 +382,12 @@ G1CMRootMemRegions::~G1CMRootMemRegions() { } void G1CMRootMemRegions::reset() { - _num_root_regions = 0; + _num_root_regions.store_relaxed(0); } void G1CMRootMemRegions::add(HeapWord* start, HeapWord* end) { assert_at_safepoint(); - size_t idx = AtomicAccess::fetch_then_add(&_num_root_regions, 1u); + size_t idx = _num_root_regions.fetch_then_add(1u); assert(idx < _max_regions, "Trying to add more root MemRegions than there is space %zu", _max_regions); assert(start != nullptr && end != nullptr && start <= end, "Start (" PTR_FORMAT ") should be less or equal to " "end (" PTR_FORMAT ")", p2i(start), p2i(end)); @@ -398,36 +398,38 @@ void G1CMRootMemRegions::add(HeapWord* start, HeapWord* end) { void G1CMRootMemRegions::prepare_for_scan() { assert(!scan_in_progress(), "pre-condition"); - _scan_in_progress = _num_root_regions > 0; + _scan_in_progress.store_relaxed(num_root_regions() > 0); - _claimed_root_regions = 0; - _should_abort = false; + _claimed_root_regions.store_relaxed(0); + _should_abort.store_relaxed(false); } const MemRegion* G1CMRootMemRegions::claim_next() { - if (_should_abort) { + if (_should_abort.load_relaxed()) { // If someone has set the should_abort flag, we return null to // force the caller to bail out of their loop. return nullptr; } - if (_claimed_root_regions >= _num_root_regions) { + uint local_num_root_regions = num_root_regions(); + if (_claimed_root_regions.load_relaxed() >= local_num_root_regions) { return nullptr; } - size_t claimed_index = AtomicAccess::fetch_then_add(&_claimed_root_regions, 1u); - if (claimed_index < _num_root_regions) { + size_t claimed_index = _claimed_root_regions.fetch_then_add(1u); + if (claimed_index < local_num_root_regions) { return &_root_regions[claimed_index]; } return nullptr; } uint G1CMRootMemRegions::num_root_regions() const { - return (uint)_num_root_regions; + return (uint)_num_root_regions.load_relaxed(); } bool G1CMRootMemRegions::contains(const MemRegion mr) const { - for (uint i = 0; i < _num_root_regions; i++) { + uint local_num_root_regions = num_root_regions(); + for (uint i = 0; i < local_num_root_regions; i++) { if (_root_regions[i].equals(mr)) { return true; } @@ -437,7 +439,7 @@ bool G1CMRootMemRegions::contains(const MemRegion mr) const { void G1CMRootMemRegions::notify_scan_done() { MutexLocker x(G1RootRegionScan_lock, Mutex::_no_safepoint_check_flag); - _scan_in_progress = false; + _scan_in_progress.store_relaxed(false); G1RootRegionScan_lock->notify_all(); } @@ -448,10 +450,10 @@ void G1CMRootMemRegions::cancel_scan() { void G1CMRootMemRegions::scan_finished() { assert(scan_in_progress(), "pre-condition"); - if (!_should_abort) { - assert(_claimed_root_regions >= num_root_regions(), + if (!_should_abort.load_relaxed()) { + assert(_claimed_root_regions.load_relaxed() >= num_root_regions(), "we should have claimed all root regions, claimed %zu, length = %u", - _claimed_root_regions, num_root_regions()); + _claimed_root_regions.load_relaxed(), num_root_regions()); } notify_scan_done(); diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 367568aeff4..3a4cbf1b83e 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -290,12 +290,12 @@ class G1CMRootMemRegions { MemRegion* _root_regions; size_t const _max_regions; - volatile size_t _num_root_regions; // Actual number of root regions. + Atomic _num_root_regions; // Actual number of root regions. - volatile size_t _claimed_root_regions; // Number of root regions currently claimed. + Atomic _claimed_root_regions; // Number of root regions currently claimed. - volatile bool _scan_in_progress; - volatile bool _should_abort; + Atomic _scan_in_progress; + Atomic _should_abort; void notify_scan_done(); @@ -312,11 +312,11 @@ public: void prepare_for_scan(); // Forces get_next() to return null so that the iteration aborts early. - void abort() { _should_abort = true; } + void abort() { _should_abort.store_relaxed(true); } // Return true if the CM thread are actively scanning root regions, // false otherwise. - bool scan_in_progress() { return _scan_in_progress; } + bool scan_in_progress() { return _scan_in_progress.load_relaxed(); } // Claim the next root MemRegion to scan atomically, or return null if // all have been claimed. From 7ccf1757859d25572d681c8e083b97ec4b6e0b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Maillard?= Date: Mon, 2 Feb 2026 10:10:21 +0000 Subject: [PATCH 282/328] 8371536: C2: VerifyIterativeGVN should assert on first detected failure Reviewed-by: epeter, mhaessig, chagedorn --- src/hotspot/share/opto/phaseX.cpp | 223 +++++++++++++++++------------- src/hotspot/share/opto/phaseX.hpp | 20 ++- 2 files changed, 141 insertions(+), 102 deletions(-) diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 52badca8050..ce24c46590d 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -532,6 +532,10 @@ void PhaseValues::init_con_caches() { memset(_zcons,0,sizeof(_zcons)); } +PhaseIterGVN* PhaseValues::is_IterGVN() { + return (_phase == PhaseValuesType::iter_gvn || _phase == PhaseValuesType::ccp) ? static_cast(this) : nullptr; +} + //--------------------------------find_int_type-------------------------------- const TypeInt* PhaseValues::find_int_type(Node* n) { if (n == nullptr) return nullptr; @@ -812,7 +816,7 @@ void PhaseGVN::dump_infinite_loop_info(Node* n, const char* where) { PhaseIterGVN::PhaseIterGVN(PhaseIterGVN* igvn) : _delay_transform(igvn->_delay_transform), _worklist(*C->igvn_worklist()) { - _iterGVN = true; + _phase = PhaseValuesType::iter_gvn; assert(&_worklist == &igvn->_worklist, "sanity"); } @@ -821,7 +825,7 @@ PhaseIterGVN::PhaseIterGVN(PhaseIterGVN* igvn) : _delay_transform(igvn->_delay_t PhaseIterGVN::PhaseIterGVN() : _delay_transform(false), _worklist(*C->igvn_worklist()) { - _iterGVN = true; + _phase = PhaseValuesType::iter_gvn; uint max; // Dead nodes in the hash table inherited from GVN were not treated as @@ -1090,16 +1094,28 @@ void PhaseIterGVN::verify_optimize() { is_verify_invariants()) { ResourceMark rm; Unique_Node_List worklist; - bool failure = false; // BFS all nodes, starting at root worklist.push(C->root()); for (uint j = 0; j < worklist.size(); ++j) { Node* n = worklist.at(j); - if (is_verify_Value()) { failure |= verify_Value_for(n); } - if (is_verify_Ideal()) { failure |= verify_Ideal_for(n, false); } - if (is_verify_Ideal()) { failure |= verify_Ideal_for(n, true); } - if (is_verify_Identity()) { failure |= verify_Identity_for(n); } - if (is_verify_invariants()) { failure |= verify_node_invariants_for(n); } + // If we get an assert here, check why the reported node was not processed again in IGVN. + // We should either make sure that this node is properly added back to the IGVN worklist + // in PhaseIterGVN::add_users_to_worklist to update it again or add an exception + // in the verification methods below if that is not possible for some reason (like Load nodes). + if (is_verify_Value()) { + verify_Value_for(n); + } + if (is_verify_Ideal()) { + verify_Ideal_for(n, false); + verify_Ideal_for(n, true); + } + if (is_verify_Identity()) { + verify_Identity_for(n); + } + if (is_verify_invariants()) { + verify_node_invariants_for(n); + } + // traverse all inputs and outputs for (uint i = 0; i < n->req(); i++) { if (n->in(i) != nullptr) { @@ -1110,11 +1126,6 @@ void PhaseIterGVN::verify_optimize() { worklist.push(n->fast_out(i)); } } - // If we get this assert, check why the reported nodes were not processed again in IGVN. - // We should either make sure that these nodes are properly added back to the IGVN worklist - // in PhaseIterGVN::add_users_to_worklist to update them again or add an exception - // in the verification code above if that is not possible for some reason (like Load nodes). - assert(!failure, "Missed optimization opportunity/broken graph in PhaseIterGVN"); } verify_empty_worklist(nullptr); @@ -1139,18 +1150,18 @@ void PhaseIterGVN::verify_empty_worklist(Node* node) { assert(false, "igvn worklist must still be empty after verify"); } -// Check that type(n) == n->Value(), return true if we have a failure. +// Check that type(n) == n->Value(), asserts if we have a failure. // We have a list of exceptions, see detailed comments in code. // (1) Integer "widen" changes, but the range is the same. // (2) LoadNode performs deep traversals. Load is not notified for changes far away. // (3) CmpPNode performs deep traversals if it compares oopptr. CmpP is not notified for changes far away. -bool PhaseIterGVN::verify_Value_for(Node* n, bool strict) { +void PhaseIterGVN::verify_Value_for(const Node* n, bool strict) { // If we assert inside type(n), because the type is still a null, then maybe // the node never went through gvn.transform, which would be a bug. const Type* told = type(n); const Type* tnew = n->Value(this); if (told == tnew) { - return false; + return; } // Exception (1) // Integer "widen" changes, but range is the same. @@ -1159,7 +1170,7 @@ bool PhaseIterGVN::verify_Value_for(Node* n, bool strict) { const TypeInteger* t1 = tnew->is_integer(tnew->basic_type()); if (t0->lo_as_long() == t1->lo_as_long() && t0->hi_as_long() == t1->hi_as_long()) { - return false; // ignore integer widen + return; // ignore integer widen } } // Exception (2) @@ -1168,7 +1179,7 @@ bool PhaseIterGVN::verify_Value_for(Node* n, bool strict) { // MemNode::can_see_stored_value looks up through many memory nodes, // which means we would need to notify modifications from far up in // the inputs all the way down to the LoadNode. We don't do that. - return false; + return; } // Exception (3) // CmpPNode performs deep traversals if it compares oopptr. CmpP is not notified for changes far away. @@ -1184,10 +1195,10 @@ bool PhaseIterGVN::verify_Value_for(Node* n, bool strict) { // control sub of the allocation. The problems is that sometimes dominates answers // false conservatively, and later it can determine that it is indeed true. Loops with // Region heads can lead to giving up, whereas LoopNodes can be skipped easier, and - // so the traversal becomes more powerful. This is difficult to remidy, we would have + // so the traversal becomes more powerful. This is difficult to remedy, we would have // to notify the CmpP of CFG updates. Luckily, we recompute CmpP::Value during CCP // after loop-opts, so that should take care of many of these cases. - return false; + return; } stringStream ss; // Print as a block without tty lock. @@ -1201,13 +1212,24 @@ bool PhaseIterGVN::verify_Value_for(Node* n, bool strict) { tnew->dump_on(&ss); ss.cr(); tty->print_cr("%s", ss.as_string()); - return true; + + switch (_phase) { + case PhaseValuesType::iter_gvn: + assert(false, "Missed Value optimization opportunity in PhaseIterGVN for %s",n->Name()); + break; + case PhaseValuesType::ccp: + assert(false, "PhaseCCP not at fixpoint: analysis result may be unsound for %s", n->Name()); + break; + default: + assert(false, "Unexpected phase"); + break; + } } // Check that all Ideal optimizations that could be done were done. -// Returns true if it found missed optimization opportunities and -// false otherwise (no missed optimization, or skipped verification). -bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { +// Asserts if it found missed optimization opportunities or encountered unexpected changes, and +// returns normally otherwise (no missed optimization, or skipped verification). +void PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // First, we check a list of exceptions, where we skip verification, // because there are known cases where Ideal can optimize after IGVN. // Some may be expected and cannot be fixed, and others should be fixed. @@ -1221,7 +1243,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Found with: // java -XX:VerifyIterativeGVN=0100 -Xbatch --version case Op_RangeCheck: - return false; + return; // IfNode::Ideal does: // Node* prev_dom = search_identical(dist, igvn); @@ -1232,7 +1254,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Found with: // java -XX:VerifyIterativeGVN=0100 -Xcomp --version case Op_If: - return false; + return; // IfNode::simple_subsuming // Looks for dominating test that subsumes the current test. @@ -1242,7 +1264,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java#id1 // -XX:VerifyIterativeGVN=1110 case Op_CountedLoopEnd: - return false; + return; // LongCountedLoopEndNode::Ideal // Probably same issue as above. @@ -1251,7 +1273,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // compiler/predicates/assertion/TestAssertionPredicates.java#NoLoopPredicationXbatch // -XX:StressLongCountedLoop=2000000 -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 case Op_LongCountedLoopEnd: - return false; + return; // RegionNode::Ideal does "Skip around the useless IF diamond". // 245 IfTrue === 244 @@ -1270,7 +1292,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Found with: // java -XX:VerifyIterativeGVN=0100 -Xcomp --version case Op_Region: - return false; + return; // In AddNode::Ideal, we call "commute", which swaps the inputs so // that smaller idx are first. Tracking it back, it led me to @@ -1349,7 +1371,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { case Op_MulHF: case Op_MaxHF: case Op_MinHF: - return false; + return; // In MulNode::Ideal the edges can be swapped to help value numbering: // @@ -1373,7 +1395,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // compiler/intrinsics/bigInteger/MontgomeryMultiplyTest.java // -XX:VerifyIterativeGVN=1110 case Op_AndL: - return false; + return; // SubLNode::Ideal does transform like: // Convert "c1 - (y+c0)" into "(c1-c0) - y" @@ -1405,7 +1427,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Found with: // java -XX:VerifyIterativeGVN=0100 -Xcomp --version case Op_SubL: - return false; + return; // SubINode::Ideal does // Convert "x - (y+c0)" into "(x-y) - c0" AND @@ -1417,7 +1439,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // test/hotspot/jtreg/compiler/c2/IVTest.java // -XX:VerifyIterativeGVN=1110 case Op_SubI: - return false; + return; // AddNode::IdealIL does transform like: // Convert x + (con - y) into "(x - y) + con" @@ -1446,7 +1468,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Found with: // java -XX:VerifyIterativeGVN=0100 -Xcomp --version case Op_AddL: - return false; + return; // SubTypeCheckNode::Ideal calls SubTypeCheckNode::verify_helper, which does // Node* cmp = phase->transform(new CmpPNode(subklass, in(SuperKlass))); @@ -1471,7 +1493,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Found with: // java -XX:VerifyIterativeGVN=0100 -Xbatch --version case Op_SubTypeCheck: - return false; + return; // LoopLimitNode::Ideal when stride is constant power-of-2, we can do a lowering // to other nodes: Conv, Add, Sub, Mul, And ... @@ -1491,7 +1513,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Fond with: // java -XX:VerifyIterativeGVN=0100 -Xcomp --version case Op_LoopLimit: - return false; + return; // PhiNode::Ideal calls split_flow_path, which tries to do this: // "This optimization tries to find two or more inputs of phi with the same constant @@ -1514,7 +1536,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Found with: // java -XX:VerifyIterativeGVN=0100 -Xcomp --version case Op_Phi: - return false; + return; // MemBarNode::Ideal does "Eliminate volatile MemBars for scalar replaced objects". // For examle "The allocated object does not escape". @@ -1527,7 +1549,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Found with: // java -XX:VerifyIterativeGVN=0100 -Xcomp --version case Op_MemBarStoreStore: - return false; + return; // ConvI2LNode::Ideal converts // 648 AddI === _ 583 645 [[ 661 ]] @@ -1543,7 +1565,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Found with: // java -XX:VerifyIterativeGVN=0100 -Xcomp --version case Op_ConvI2L: - return false; + return; // AddNode::IdealIL can do this transform (and similar other ones): // Convert "a*b+a*c into a*(b+c) @@ -1557,7 +1579,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java // -XX:VerifyIterativeGVN=1110 case Op_AddI: - return false; + return; // ArrayCopyNode::Ideal // calls ArrayCopyNode::prepare_array_copy @@ -1583,7 +1605,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // compiler/arraycopy/TestArrayCopyAsLoadsStores.java // -XX:VerifyIterativeGVN=1110 case Op_ArrayCopy: - return false; + return; // CastLLNode::Ideal // calls ConstraintCastNode::optimize_integer_cast -> pushes CastLL through SubL @@ -1595,7 +1617,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // compiler/c2/TestMergeStoresMemorySegment.java#byte-array // -XX:VerifyIterativeGVN=1110 case Op_CastLL: - return false; + return; // Similar case happens to CastII // @@ -1603,7 +1625,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // compiler/c2/TestScalarReplacementMaxLiveNodes.java // -XX:VerifyIterativeGVN=1110 case Op_CastII: - return false; + return; // MaxLNode::Ideal // calls AddNode::Ideal @@ -1618,7 +1640,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // -XX:VerifyIterativeGVN=1110 case Op_MaxL: case Op_MinL: - return false; + return; // OrINode::Ideal // calls AddNode::Ideal @@ -1632,7 +1654,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // -XX:VerifyIterativeGVN=1110 case Op_OrI: case Op_OrL: - return false; + return; // Bool -> constant folded to 1. // Issue with notification? @@ -1641,7 +1663,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // compiler/c2/irTests/TestVectorizationMismatchedAccess.java // -XX:VerifyIterativeGVN=1110 case Op_Bool: - return false; + return; // LShiftLNode::Ideal // Looks at pattern: "(x + x) << c0", converts it to "x << (c0 + 1)" @@ -1651,7 +1673,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // compiler/conversions/TestMoveConvI2LOrCastIIThruAddIs.java // -ea -esa -XX:CompileThreshold=100 -XX:+UnlockExperimentalVMOptions -server -XX:-TieredCompilation -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 case Op_LShiftL: - return false; + return; // LShiftINode::Ideal // pattern: ((x + con1) << con2) -> x << con2 + con1 << con2 @@ -1664,18 +1686,18 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // compiler/escapeAnalysis/Test6689060.java // -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 -ea -esa -XX:CompileThreshold=100 -XX:+UnlockExperimentalVMOptions -server -XX:-TieredCompilation -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 case Op_LShiftI: - return false; + return; // AddPNode::Ideal seems to do set_req without removing lock first. // Found with various vector tests tier1-tier3. case Op_AddP: - return false; + return; // StrIndexOfNode::Ideal // Found in tier1-3. case Op_StrIndexOf: case Op_StrIndexOfChar: - return false; + return; // StrEqualsNode::Identity // @@ -1684,7 +1706,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // -XX:+UnlockExperimentalVMOptions -XX:LockingMode=1 -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 // Note: The -XX:LockingMode option is not available anymore. case Op_StrEquals: - return false; + return; // AryEqNode::Ideal // Not investigated. Reshapes itself and adds lots of nodes to the worklist. @@ -1693,22 +1715,22 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // vmTestbase/vm/mlvm/meth/stress/compiler/i2c_c2i/Test.java // -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -XX:+StressUnstableIfTraps -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 case Op_AryEq: - return false; + return; // MergeMemNode::Ideal // Found in tier1-3. Did not investigate further yet. case Op_MergeMem: - return false; + return; // URShiftINode::Ideal // Found in tier1-3. Did not investigate further yet. case Op_URShiftI: - return false; + return; // CMoveINode::Ideal // Found in tier1-3. Did not investigate further yet. case Op_CMoveI: - return false; + return; // CmpPNode::Ideal calls isa_const_java_mirror // and generates new constant nodes, even if no progress is made. @@ -1719,14 +1741,14 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Found with: // java -XX:VerifyIterativeGVN=1110 -Xcomp --version case Op_CmpP: - return false; + return; // MinINode::Ideal // Did not investigate, but there are some patterns that might // need more notification. case Op_MinI: case Op_MaxI: // preemptively removed it as well. - return false; + return; } if (n->is_Load()) { @@ -1742,7 +1764,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Found with: // test/hotspot/jtreg/compiler/arraycopy/TestCloneAccess.java // -XX:VerifyIterativeGVN=1110 - return false; + return; } if (n->is_Store()) { @@ -1756,7 +1778,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // // Found with: // java -XX:VerifyIterativeGVN=0100 -Xcomp --version - return false; + return; } if (n->is_Vector()) { @@ -1775,7 +1797,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Found with: // compiler/vectorapi/TestMaskedMacroLogicVector.java // -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 -XX:+UseParallelGC -XX:+UseNUMA - return false; + return; } if (n->is_Region()) { @@ -1794,7 +1816,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Found with: // compiler/eliminateAutobox/TestShortBoxing.java // -ea -esa -XX:CompileThreshold=100 -XX:+UnlockExperimentalVMOptions -server -XX:-TieredCompilation -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 - return false; + return; } if (n->is_CallJava()) { @@ -1826,13 +1848,19 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Found with: // compiler/loopopts/superword/TestDependencyOffsets.java#vanilla-U // -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 - return false; + return; } // The number of nodes shoud not increase. uint old_unique = C->unique(); // The hash of a node should not change, this would indicate different inputs uint old_hash = n->hash(); + // Remove 'n' from hash table in case it gets modified. We want to avoid + // hitting the "Need to remove from hash before changing edges" assert if + // a change occurs. Instead, we would like to proceed with the optimization, + // return and finally hit the assert in PhaseIterGVN::verify_optimize to get + // a more meaningful message + _table.hash_delete(n); Node* i = n->Ideal(this, can_reshape); // If there was no new Idealization, we are probably happy. if (i == nullptr) { @@ -1843,7 +1871,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { ss.print_cr(" old_unique = %d, unique = %d", old_unique, C->unique()); n->dump_bfs(1, nullptr, "", &ss); tty->print_cr("%s", ss.as_string()); - return true; + assert(false, "Unexpected new unused nodes from applying Ideal optimization on %s", n->Name()); } if (old_hash != n->hash()) { @@ -1853,13 +1881,14 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { ss.print_cr(" old_hash = %d, hash = %d", old_hash, n->hash()); n->dump_bfs(1, nullptr, "", &ss); tty->print_cr("%s", ss.as_string()); - return true; + assert(false, "Unexpected hash change from applying Ideal optimization on %s", n->Name()); } verify_empty_worklist(n); // Everything is good. - return false; + hash_find_insert(n); + return; } // We just saw a new Idealization which was not done during IGVN. @@ -1876,13 +1905,14 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { ss.print_cr("The result after Ideal:"); i->dump_bfs(1, nullptr, "", &ss); tty->print_cr("%s", ss.as_string()); - return true; + + assert(false, "Missed Ideal optimization opportunity in PhaseIterGVN for %s", n->Name()); } // Check that all Identity optimizations that could be done were done. -// Returns true if it found missed optimization opportunities and -// false otherwise (no missed optimization, or skipped verification). -bool PhaseIterGVN::verify_Identity_for(Node* n) { +// Asserts if it found missed optimization opportunities, and +// returns normally otherwise (no missed optimization, or skipped verification). +void PhaseIterGVN::verify_Identity_for(Node* n) { // First, we check a list of exceptions, where we skip verification, // because there are known cases where Ideal can optimize after IGVN. // Some may be expected and cannot be fixed, and others should be fixed. @@ -1901,7 +1931,7 @@ bool PhaseIterGVN::verify_Identity_for(Node* n) { // Found with: // java -XX:VerifyIterativeGVN=1000 -Xcomp --version case Op_SafePoint: - return false; + return; // MergeMemNode::Identity replaces the MergeMem with its base_memory if it // does not record any other memory splits. @@ -1912,7 +1942,7 @@ bool PhaseIterGVN::verify_Identity_for(Node* n) { // Found with: // java -XX:VerifyIterativeGVN=1000 -Xcomp --version case Op_MergeMem: - return false; + return; // ConstraintCastNode::Identity finds casts that are the same, except that // the control is "higher up", i.e. dominates. The call goes via @@ -1926,7 +1956,7 @@ bool PhaseIterGVN::verify_Identity_for(Node* n) { case Op_CastPP: case Op_CastII: case Op_CastLL: - return false; + return; // Same issue for CheckCastPP, uses ConstraintCastNode::Identity and // checks dominator, which may be changed, but too far up for notification @@ -1936,7 +1966,7 @@ bool PhaseIterGVN::verify_Identity_for(Node* n) { // compiler/c2/irTests/TestSkeletonPredicates.java // -XX:VerifyIterativeGVN=1110 case Op_CheckCastPP: - return false; + return; // In SubNode::Identity, we do: // Convert "(X+Y) - Y" into X and "(X+Y) - X" into Y @@ -1954,7 +1984,7 @@ bool PhaseIterGVN::verify_Identity_for(Node* n) { // java -XX:VerifyIterativeGVN=1000 -Xcomp --version case Op_SubI: case Op_SubL: - return false; + return; // PhiNode::Identity checks for patterns like: // r = (x != con) ? x : con; @@ -1968,7 +1998,7 @@ bool PhaseIterGVN::verify_Identity_for(Node* n) { // test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithG1.java // -XX:VerifyIterativeGVN=1110 case Op_Phi: - return false; + return; // ConvI2LNode::Identity does // convert I2L(L2I(x)) => x @@ -1979,7 +2009,7 @@ bool PhaseIterGVN::verify_Identity_for(Node* n) { // compiler/loopopts/superword/TestDependencyOffsets.java#vanilla-A // -XX:VerifyIterativeGVN=1110 case Op_ConvI2L: - return false; + return; // MaxNode::find_identity_operation // Finds patterns like Max(A, Max(A, B)) -> Max(A, B) @@ -1999,7 +2029,7 @@ bool PhaseIterGVN::verify_Identity_for(Node* n) { case Op_MinHF: case Op_MaxD: case Op_MinD: - return false; + return; // AddINode::Identity @@ -2013,12 +2043,12 @@ bool PhaseIterGVN::verify_Identity_for(Node* n) { // -ea -esa -XX:CompileThreshold=100 -XX:+UnlockExperimentalVMOptions -server -XX:-TieredCompilation -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 case Op_AddI: case Op_AddL: - return false; + return; // AbsINode::Identity // Not investigated yet. case Op_AbsI: - return false; + return; } if (n->is_Load()) { @@ -2032,7 +2062,7 @@ bool PhaseIterGVN::verify_Identity_for(Node* n) { // // Found with: // java -XX:VerifyIterativeGVN=1000 -Xcomp --version - return false; + return; } if (n->is_Store()) { @@ -2043,20 +2073,20 @@ bool PhaseIterGVN::verify_Identity_for(Node* n) { // Found with: // applications/ctw/modules/java_base_2.java // -ea -esa -XX:CompileThreshold=100 -XX:+UnlockExperimentalVMOptions -server -XX:-TieredCompilation -Djava.awt.headless=true -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 - return false; + return; } if (n->is_Vector()) { // Found with tier1-3. Not investigated yet. // The observed issue was with AndVNode::Identity - return false; + return; } Node* i = n->Identity(this); // If we cannot find any other Identity, we are happy. if (i == n) { verify_empty_worklist(n); - return false; + return; } // The verification just found a new Identity that was not found during IGVN. @@ -2068,11 +2098,12 @@ bool PhaseIterGVN::verify_Identity_for(Node* n) { ss.print_cr("New node:"); i->dump_bfs(1, nullptr, "", &ss); tty->print_cr("%s", ss.as_string()); - return true; + + assert(false, "Missed Identity optimization opportunity in PhaseIterGVN for %s", n->Name()); } // Some other verifications that are not specific to a particular transformation. -bool PhaseIterGVN::verify_node_invariants_for(const Node* n) { +void PhaseIterGVN::verify_node_invariants_for(const Node* n) { if (n->is_AddP()) { if (!n->as_AddP()->address_input_has_same_base()) { stringStream ss; // Print as a block without tty lock. @@ -2080,10 +2111,10 @@ bool PhaseIterGVN::verify_node_invariants_for(const Node* n) { ss.print_cr("Base pointers must match for AddP chain:"); n->dump_bfs(2, nullptr, "", &ss); tty->print_cr("%s", ss.as_string()); - return true; + + assert(false, "Broken node invariant for %s", n->Name()); } } - return false; } #endif @@ -2794,6 +2825,7 @@ uint PhaseCCP::_total_constants = 0; PhaseCCP::PhaseCCP( PhaseIterGVN *igvn ) : PhaseIterGVN(igvn) { NOT_PRODUCT( clear_constants(); ) assert( _worklist.size() == 0, "" ); + _phase = PhaseValuesType::ccp; analyze(); } @@ -2914,17 +2946,18 @@ bool PhaseCCP::needs_revisit(Node* n) const { // Note for CCP the non-convergence can lead to unsound analysis and mis-compilation. // Therefore, we are verifying Value convergence strictly. void PhaseCCP::verify_analyze(Unique_Node_List& worklist_verify) { - bool failure = false; while (worklist_verify.size()) { Node* n = worklist_verify.pop(); - failure |= verify_Value_for(n, /* strict = */ true); + + // An assert in verify_Value_for means that PhaseCCP is not at fixpoint + // and that the analysis result may be unsound. + // If this happens, check why the reported nodes were not processed again in CCP. + // We should either make sure that these nodes are properly added back to the CCP worklist + // in PhaseCCP::push_child_nodes_to_worklist() to update their type in the same round, + // or that they are added in PhaseCCP::needs_revisit() so that analysis revisits + // them at the end of the round. + verify_Value_for(n, true); } - // If we get this assert, check why the reported nodes were not processed again in CCP. - // We should either make sure that these nodes are properly added back to the CCP worklist - // in PhaseCCP::push_child_nodes_to_worklist() to update their type in the same round, - // or that they are added in PhaseCCP::needs_revisit() so that analysis revisits - // them at the end of the round. - assert(!failure, "PhaseCCP not at fixpoint: analysis result may be unsound."); } #endif diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp index 3f75aab8980..ce02f456c00 100644 --- a/src/hotspot/share/opto/phaseX.hpp +++ b/src/hotspot/share/opto/phaseX.hpp @@ -224,7 +224,13 @@ public: // 3) NodeHash table, to find identical nodes (and remove/update the hash of a node on modification). class PhaseValues : public PhaseTransform { protected: - bool _iterGVN; + enum class PhaseValuesType { + gvn, + iter_gvn, + ccp + }; + + PhaseValuesType _phase; // Hash table for value-numbering. Reference to "C->node_hash()", NodeHash &_table; @@ -247,7 +253,7 @@ protected: void init_con_caches(); public: - PhaseValues() : PhaseTransform(GVN), _iterGVN(false), + PhaseValues() : PhaseTransform(GVN), _phase(PhaseValuesType::gvn), _table(*C->node_hash()), _types(*C->types()) { NOT_PRODUCT( clear_new_values(); ) @@ -256,7 +262,7 @@ public: init_con_caches(); } NOT_PRODUCT(~PhaseValues();) - PhaseIterGVN* is_IterGVN() { return (_iterGVN) ? (PhaseIterGVN*)this : nullptr; } + PhaseIterGVN* is_IterGVN(); // Some Ideal and other transforms delete --> modify --> insert values bool hash_delete(Node* n) { return _table.hash_delete(n); } @@ -490,10 +496,10 @@ public: void optimize(); #ifdef ASSERT void verify_optimize(); - bool verify_Value_for(Node* n, bool strict = false); - bool verify_Ideal_for(Node* n, bool can_reshape); - bool verify_Identity_for(Node* n); - bool verify_node_invariants_for(const Node* n); + void verify_Value_for(const Node* n, bool strict = false); + void verify_Ideal_for(Node* n, bool can_reshape); + void verify_Identity_for(Node* n); + void verify_node_invariants_for(const Node* n); void verify_empty_worklist(Node* n); #endif From 90a43f8445de4e66da6ae113c2b4d40ee88c4a73 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Mon, 2 Feb 2026 10:11:34 +0000 Subject: [PATCH 283/328] 8376325: [IR Framework] Detect and report overloads Reviewed-by: chagedorn, dfenacci --- .../lib/ir_framework/test/TestVM.java | 5 + .../ir_framework/tests/TestBadFormat.java | 5 +- .../ir_framework/tests/TestBasics.java | 272 ++++++++---------- .../ir_framework/tests/TestControls.java | 91 ++---- 4 files changed, 153 insertions(+), 220 deletions(-) diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java index c2580e087f0..14551141cd7 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java @@ -588,6 +588,11 @@ public class TestVM { } private void checkTestAnnotations(Method m, Test testAnno) { + List overloads = Arrays.stream(testClass.getDeclaredMethods()).filter(other -> !m.equals(other) && m.getName().equals(other.getName())).toList(); + TestFormat.check(overloads.isEmpty(), + "Cannot overload @Test methods, but method " + m + " has " + overloads.size() + " overload" + (overloads.size() == 1 ? "" : "s") + ":" + + overloads.stream().map(String::valueOf).collect(Collectors.joining("\n - ", "\n - ", "")) + ); TestFormat.check(!testMethodMap.containsKey(m.getName()), "Cannot overload two @Test methods: " + m + ", " + testMethodMap.get(m.getName())); TestFormat.check(testAnno != null, m + " must be a method with a @Test annotation"); diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java index 200866375af..da8fd6489b8 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -276,9 +276,10 @@ class BadArgumentsAnnotation { } } +// Since all the methods are failing, the class doesn't specify any @Test methods, which is another failure. +@ClassFail class BadOverloadedMethod { - @FailCount(0) // Combined with both sameName() below @Test public void sameName() {} diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBasics.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBasics.java index b5006290047..8efdcb4f021 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBasics.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBasics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,8 @@ import compiler.lib.ir_framework.test.TestVM; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.stream.Stream; /* @@ -44,7 +46,7 @@ import java.util.stream.Stream; public class TestBasics { private static boolean wasExecuted = false; private boolean lastToggleBoolean = true; - private final static int[] executed = new int[100]; + private final static HashMap executed = HashMap.newHashMap(100); private final static int[] executedOnce = new int[5]; private long[] nonFloatingRandomNumbers = new long[10]; private double[] floatingRandomNumbers = new double[10]; @@ -60,12 +62,12 @@ public class TestBasics { if (wasExecuted) { throw new RuntimeException("Executed non @Test method or a method that was not intended to be run"); } - for (int i = 0; i < executed.length; i++) { - int value = executed[i]; + for (Map.Entry entry : executed.entrySet()) { + int value = entry.getValue(); if (value != TestVM.WARMUP_ITERATIONS + 1) { // Warmups + 1 C2 compiled invocation - throw new RuntimeException("Test " + i + " was executed " + value + " times instead stead of " - + (TestVM.WARMUP_ITERATIONS + 1) + " times." ); + throw new RuntimeException("Test " + entry.getKey() + " was executed " + value + " times instead stead of " + + (TestVM.WARMUP_ITERATIONS + 1) + " times." ); } } @@ -88,12 +90,6 @@ public class TestBasics { randomBooleans = new Boolean[64]; } - // Base test, no arguments, directly invoked. - @Test - public void test() { - executed[0]++; - } - // Not a test public void noTest() { wasExecuted = true; @@ -109,24 +105,19 @@ public class TestBasics { wasExecuted = true; } - // Can overload a @Test if it is not a @Test itself. - public static void test(double i) { - wasExecuted = true; - } - @Test public static void staticTest() { - executed[1]++; + executed.merge("staticTest", 1, Integer::sum); } @Test public final void finalTest() { - executed[2]++; + executed.merge("finalTest", 1, Integer::sum); } @Test public int returnValueTest() { - executed[3]++; + executed.merge("returnValueTest", 1, Integer::sum); return 4; } @@ -135,7 +126,7 @@ public class TestBasics { @Test @Arguments(values = Argument.DEFAULT) public void byteDefaultArgument(byte x) { - executed[4]++; + executed.merge("byteDefaultArgument", 1, Integer::sum); if (x != 0) { throw new RuntimeException("Must be 0"); } @@ -144,7 +135,7 @@ public class TestBasics { @Test @Arguments(values = Argument.DEFAULT) public void shortDefaultArgument(short x) { - executed[5]++; + executed.merge("shortDefaultArgument", 1, Integer::sum); if (x != 0) { throw new RuntimeException("Must be 0"); } @@ -153,7 +144,7 @@ public class TestBasics { @Test @Arguments(values = Argument.DEFAULT) public void intDefaultArgument(int x) { - executed[6]++; + executed.merge("intDefaultArgument", 1, Integer::sum); if (x != 0) { throw new RuntimeException("Must be 0"); } @@ -162,7 +153,7 @@ public class TestBasics { @Test @Arguments(values = Argument.DEFAULT) public void longDefaultArgument(long x) { - executed[7]++; + executed.merge("longDefaultArgument", 1, Integer::sum); if (x != 0L) { throw new RuntimeException("Must be 0"); } @@ -171,7 +162,7 @@ public class TestBasics { @Test @Arguments(values = Argument.DEFAULT) public void floatDefaultArgument(float x) { - executed[8]++; + executed.merge("floatDefaultArgument", 1, Integer::sum); if (x != 0.0f) { throw new RuntimeException("Must be 0.0"); } @@ -180,7 +171,7 @@ public class TestBasics { @Test @Arguments(values = Argument.DEFAULT) public void doubleDefaultArgument(double x) { - executed[9]++; + executed.merge("doubleDefaultArgument", 1, Integer::sum); if (x != 0.0f) { throw new RuntimeException("Must be 0.0"); } @@ -189,7 +180,7 @@ public class TestBasics { @Test @Arguments(values = Argument.DEFAULT) public void charDefaultArgument(char x) { - executed[10]++; + executed.merge("charDefaultArgument", 1, Integer::sum); if (x != '\u0000') { throw new RuntimeException("Must be \u0000"); } @@ -198,7 +189,7 @@ public class TestBasics { @Test @Arguments(values = Argument.DEFAULT) public void booleanDefaultArgument(boolean x) { - executed[11]++; + executed.merge("booleanDefaultArgument", 1, Integer::sum); if (x) { throw new RuntimeException("Must be false"); } @@ -207,7 +198,7 @@ public class TestBasics { @Test @Arguments(values = Argument.DEFAULT) public void stringObjectDefaultArgument(String x) { - executed[12]++; + executed.merge("stringObjectDefaultArgument", 1, Integer::sum); if (x == null || x.length() != 0) { throw new RuntimeException("Default string object must be non-null and having a length of zero"); } @@ -216,7 +207,7 @@ public class TestBasics { @Test @Arguments(values = Argument.DEFAULT) public void defaultObjectDefaultArgument(DefaultObject x) { - executed[13]++; + executed.merge("defaultObjectDefaultArgument", 1, Integer::sum); if (x == null || x.i != 4) { throw new RuntimeException("Default object must not be null and its i field must be 4"); } @@ -225,7 +216,7 @@ public class TestBasics { @Test @Arguments(values = Argument.NUMBER_42) public void byte42(byte x) { - executed[14]++; + executed.merge("byte42", 1, Integer::sum); if (x != 42) { throw new RuntimeException("Must be 42"); } @@ -234,7 +225,7 @@ public class TestBasics { @Test @Arguments(values = Argument.NUMBER_42) public void short42(short x) { - executed[15]++; + executed.merge("short42", 1, Integer::sum); if (x != 42) { throw new RuntimeException("Must be 42"); } @@ -243,7 +234,7 @@ public class TestBasics { @Test @Arguments(values = Argument.NUMBER_42) public void int42(int x) { - executed[16]++; + executed.merge("int42", 1, Integer::sum); if (x != 42) { throw new RuntimeException("Must be 42"); } @@ -252,7 +243,7 @@ public class TestBasics { @Test @Arguments(values = Argument.NUMBER_42) public void long42(long x) { - executed[17]++; + executed.merge("long42", 1, Integer::sum); if (x != 42) { throw new RuntimeException("Must be 42"); } @@ -261,7 +252,7 @@ public class TestBasics { @Test @Arguments(values = Argument.NUMBER_42) public void float42(float x) { - executed[18]++; + executed.merge("float42", 1, Integer::sum); if (x != 42.0) { throw new RuntimeException("Must be 42"); } @@ -270,7 +261,7 @@ public class TestBasics { @Test @Arguments(values = Argument.NUMBER_42) public void double42(double x) { - executed[19]++; + executed.merge("double42", 1, Integer::sum); if (x != 42.0) { throw new RuntimeException("Must be 42"); } @@ -279,7 +270,7 @@ public class TestBasics { @Test @Arguments(values = Argument.FALSE) public void booleanFalse(boolean x) { - executed[20]++; + executed.merge("booleanFalse", 1, Integer::sum); if (x) { throw new RuntimeException("Must be false"); } @@ -288,7 +279,7 @@ public class TestBasics { @Test @Arguments(values = Argument.TRUE) public void booleanTrue(boolean x) { - executed[21]++; + executed.merge("booleanTrue", 1, Integer::sum); if (!x) { throw new RuntimeException("Must be true"); } @@ -297,37 +288,37 @@ public class TestBasics { @Test @Arguments(values = Argument.RANDOM_ONCE) public void randomByte(byte x) { - executed[22]++; + executed.merge("randomByte", 1, Integer::sum); } @Test @Arguments(values = Argument.RANDOM_ONCE) public void randomShort(short x) { - executed[23]++; + executed.merge("randomShort", 1, Integer::sum); } @Test @Arguments(values = Argument.RANDOM_ONCE) public void randomInt(int x) { - executed[24]++; + executed.merge("randomInt", 1, Integer::sum); } @Test @Arguments(values = Argument.RANDOM_ONCE) public void randomLong(long x) { - executed[25]++; + executed.merge("randomLong", 1, Integer::sum); } @Test @Arguments(values = Argument.RANDOM_ONCE) public void randomFloat(float x) { - executed[26]++; + executed.merge("randomFloat", 1, Integer::sum); } @Test @Arguments(values = Argument.RANDOM_ONCE) public void randomDouble(double x) { - executed[27]++; + executed.merge("randomDouble", 1, Integer::sum); } // Not executed @@ -338,13 +329,13 @@ public class TestBasics { @Test @Arguments(values = Argument.RANDOM_ONCE) public void randomBoolean(boolean x) { - executed[28]++; + executed.merge("randomBoolean", 1, Integer::sum); } @Test @Arguments(values = Argument.BOOLEAN_TOGGLE_FIRST_FALSE) public void booleanToggleFirstFalse(boolean x) { - if (executed[29] == 0) { + if (!executed.containsKey("booleanToggleFirstFalse")) { // First invocation if (x) { throw new RuntimeException("BOOLEAN_TOGGLE_FIRST_FALSE must be false on first invocation"); @@ -353,63 +344,63 @@ public class TestBasics { throw new RuntimeException("BOOLEAN_TOGGLE_FIRST_FALSE did not toggle"); } lastToggleBoolean = x; - executed[29]++; + executed.merge("booleanToggleFirstFalse", 1, Integer::sum); } @Test @Arguments(values = Argument.RANDOM_EACH) public void randomEachByte(byte x) { - checkNonFloatingRandomNumber(x, executed[30]); - executed[30]++; + checkNonFloatingRandomNumber(x, executed.getOrDefault("randomEachByte", 0)); + executed.merge("randomEachByte", 1, Integer::sum); } @Test @Arguments(values = Argument.RANDOM_EACH) public void randomEachShort(short x) { - checkNonFloatingRandomNumber(x, executed[31]); - executed[31]++; + checkNonFloatingRandomNumber(x, executed.getOrDefault("randomEachShort", 0)); + executed.merge("randomEachShort", 1, Integer::sum); } @Test @Arguments(values = Argument.RANDOM_EACH) public void randomEachInt(int x) { - checkNonFloatingRandomNumber(x, executed[32]); - executed[32]++; + checkNonFloatingRandomNumber(x, executed.getOrDefault("randomEachInt", 0)); + executed.merge("randomEachInt", 1, Integer::sum); } @Test @Arguments(values = Argument.RANDOM_EACH) public void randomEachLong(long x) { - checkNonFloatingRandomNumber(x, executed[33]); - executed[33]++; + checkNonFloatingRandomNumber(x, executed.getOrDefault("randomEachLong", 0)); + executed.merge("randomEachLong", 1, Integer::sum); } @Test @Arguments(values = Argument.RANDOM_EACH) public void randomEachChar(char x) { - checkNonFloatingRandomNumber(x, executed[34]); - executed[34]++; + checkNonFloatingRandomNumber(x, executed.getOrDefault("randomEachChar", 0)); + executed.merge("randomEachChar", 1, Integer::sum); } @Test @Arguments(values = Argument.RANDOM_EACH) public void randomEachFloat(float x) { - checkFloatingRandomNumber(x, executed[35]); - executed[35]++; + checkFloatingRandomNumber(x, executed.getOrDefault("randomEachFloat", 0)); + executed.merge("randomEachFloat", 1, Integer::sum); } @Test @Arguments(values = Argument.RANDOM_EACH) public void randomEachDouble(double x) { - checkFloatingRandomNumber(x, executed[36]); - executed[36]++; + checkFloatingRandomNumber(x, executed.getOrDefault("randomEachDouble", 0)); + executed.merge("randomEachDouble", 1, Integer::sum); } @Test @Arguments(values = Argument.RANDOM_EACH) public void randomEachBoolean(boolean x) { - checkRandomBoolean(x, executed[37]); - executed[37]++; + checkRandomBoolean(x, executed.getOrDefault("randomEachBoolean", 0)); + executed.merge("randomEachBoolean", 1, Integer::sum); } private void checkNonFloatingRandomNumber(long x, int invocationCount) { @@ -461,7 +452,7 @@ public class TestBasics { @Test @Arguments(values = Argument.NUMBER_MINUS_42) public void byteMinus42(byte x) { - executed[38]++; + executed.merge("byteMinus42", 1, Integer::sum); if (x != -42) { throw new RuntimeException("Must be -42"); } @@ -470,7 +461,7 @@ public class TestBasics { @Test @Arguments(values = Argument.NUMBER_MINUS_42) public void shortMinus42(short x) { - executed[39]++; + executed.merge("shortMinus42", 1, Integer::sum); if (x != -42) { throw new RuntimeException("Must be -42"); } @@ -479,7 +470,7 @@ public class TestBasics { @Test @Arguments(values = Argument.NUMBER_MINUS_42) public void intMinus42(int x) { - executed[40]++; + executed.merge("intMinus42", 1, Integer::sum); if (x != -42) { throw new RuntimeException("Must be -42"); } @@ -488,7 +479,7 @@ public class TestBasics { @Test @Arguments(values = Argument.NUMBER_MINUS_42) public void longMinus42(long x) { - executed[41]++; + executed.merge("longMinus42", 1, Integer::sum); if (x != -42) { throw new RuntimeException("Must be -42"); } @@ -497,7 +488,7 @@ public class TestBasics { @Test @Arguments(values = Argument.NUMBER_MINUS_42) public void floatMinus42(float x) { - executed[42]++; + executed.merge("floatMinus42", 1, Integer::sum); if (x != -42.0) { throw new RuntimeException("Must be -42"); } @@ -506,7 +497,7 @@ public class TestBasics { @Test @Arguments(values = Argument.NUMBER_MINUS_42) public void doubleMinus42(double x) { - executed[43]++; + executed.merge("doubleMinus42", 1, Integer::sum); if (x != -42.0) { throw new RuntimeException("Must be -42"); } @@ -515,7 +506,7 @@ public class TestBasics { @Test @Arguments(values = Argument.MIN) public void byteMin(byte x) { - executed[79]++; + executed.merge("byteMin", 1, Integer::sum); if (x != Byte.MIN_VALUE) { throw new RuntimeException("Must be MIN_VALUE"); } @@ -524,7 +515,7 @@ public class TestBasics { @Test @Arguments(values = Argument.MIN) public void charMin(char x) { - executed[80]++; + executed.merge("charMin", 1, Integer::sum); if (x != Character.MIN_VALUE) { throw new RuntimeException("Must be MIN_VALUE"); } @@ -533,7 +524,7 @@ public class TestBasics { @Test @Arguments(values = Argument.MIN) public void shortMin(short x) { - executed[81]++; + executed.merge("shortMin", 1, Integer::sum); if (x != Short.MIN_VALUE) { throw new RuntimeException("Must be MIN_VALUE"); } @@ -542,7 +533,7 @@ public class TestBasics { @Test @Arguments(values = Argument.MIN) public void intMin(int x) { - executed[82]++; + executed.merge("intMin", 1, Integer::sum); if (x != Integer.MIN_VALUE) { throw new RuntimeException("Must be MIN_VALUE"); } @@ -551,7 +542,7 @@ public class TestBasics { @Test @Arguments(values = Argument.MIN) public void longMin(long x) { - executed[83]++; + executed.merge("longMin", 1, Integer::sum); if (x != Long.MIN_VALUE) { throw new RuntimeException("Must be MIN_VALUE"); } @@ -560,7 +551,7 @@ public class TestBasics { @Test @Arguments(values = Argument.MIN) public void floatMin(float x) { - executed[84]++; + executed.merge("floatMin", 1, Integer::sum); if (x != Float.MIN_VALUE) { throw new RuntimeException("Must be MIN_VALUE"); } @@ -569,7 +560,7 @@ public class TestBasics { @Test @Arguments(values = Argument.MIN) public void doubleMin(double x) { - executed[85]++; + executed.merge("doubleMin", 1, Integer::sum); if (x != Double.MIN_VALUE) { throw new RuntimeException("Must be MIN_VALUE"); } @@ -578,7 +569,7 @@ public class TestBasics { @Test @Arguments(values = Argument.MAX) public void byteMax(byte x) { - executed[86]++; + executed.merge("byteMax", 1, Integer::sum); if (x != Byte.MAX_VALUE) { throw new RuntimeException("Must be MAX_VALUE"); } @@ -587,7 +578,7 @@ public class TestBasics { @Test @Arguments(values = Argument.MAX) public void charMax(char x) { - executed[87]++; + executed.merge("charMax", 1, Integer::sum); if (x != Character.MAX_VALUE) { throw new RuntimeException("Must be MAX_VALUE"); } @@ -596,7 +587,7 @@ public class TestBasics { @Test @Arguments(values = Argument.MAX) public void shortMax(short x) { - executed[88]++; + executed.merge("shortMax", 1, Integer::sum); if (x != Short.MAX_VALUE) { throw new RuntimeException("Must be MAX_VALUE"); } @@ -605,7 +596,7 @@ public class TestBasics { @Test @Arguments(values = Argument.MAX) public void intMax(int x) { - executed[89]++; + executed.merge("intMax", 1, Integer::sum); if (x != Integer.MAX_VALUE) { throw new RuntimeException("Must be MAX_VALUE"); } @@ -614,7 +605,7 @@ public class TestBasics { @Test @Arguments(values = Argument.MAX) public void longMax(long x) { - executed[90]++; + executed.merge("longMax", 1, Integer::sum); if (x != Long.MAX_VALUE) { throw new RuntimeException("Must be MAX_VALUE"); } @@ -623,7 +614,7 @@ public class TestBasics { @Test @Arguments(values = Argument.MAX) public void floatMax(float x) { - executed[91]++; + executed.merge("floatMax", 1, Integer::sum); if (x != Float.MAX_VALUE) { throw new RuntimeException("Must be MAX_VALUE"); } @@ -632,7 +623,7 @@ public class TestBasics { @Test @Arguments(values = Argument.MAX) public void doubleMax(double x) { - executed[78]++; + executed.merge("doubleMax", 1, Integer::sum); if (x != Double.MAX_VALUE) { throw new RuntimeException("Must be MAX_VALUE"); } @@ -641,7 +632,7 @@ public class TestBasics { @Test @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) public void twoArgsDefault1(byte x, short y) { - executed[44]++; + executed.merge("twoArgsDefault1", 1, Integer::sum); if (x != 0 || y != 0) { throw new RuntimeException("Both must be 0"); } @@ -650,7 +641,7 @@ public class TestBasics { @Test @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) public void twoArgsDefault2(int x, short y) { - executed[45]++; + executed.merge("twoArgsDefault2", 1, Integer::sum); if (x != 0 || y != 0) { throw new RuntimeException("Both must be 0"); } @@ -659,7 +650,7 @@ public class TestBasics { @Test @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) public void twoArgsDefault3(short x, long y) { - executed[46]++; + executed.merge("twoArgsDefault3", 1, Integer::sum); if (x != 0 || y != 0) { throw new RuntimeException("Both must be 0"); } @@ -668,7 +659,7 @@ public class TestBasics { @Test @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) public void twoArgsDefault4(float x, boolean y) { - executed[47]++; + executed.merge("twoArgsDefault4", 1, Integer::sum); if (x != 0.0 || y) { throw new RuntimeException("Must be 0 and false"); } @@ -677,7 +668,7 @@ public class TestBasics { @Test @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) public void twoArgsDefault5(boolean x, char y) { - executed[48]++; + executed.merge("twoArgsDefault5", 1, Integer::sum); if (x || y != '\u0000') { throw new RuntimeException("Must be false and \u0000"); } @@ -686,7 +677,7 @@ public class TestBasics { @Test @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) public void twoArgsDefault6(char x, byte y) { - executed[49]++; + executed.merge("twoArgsDefault6", 1, Integer::sum); if (x != '\u0000' || y != 0) { throw new RuntimeException("Must be\u0000 and 0"); } @@ -695,7 +686,7 @@ public class TestBasics { @Test @Arguments(values = {Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) public void twoArgsRandomOnce(char x, byte y) { - executed[50]++; + executed.merge("twoArgsRandomOnce", 1, Integer::sum); } @Test @@ -707,7 +698,7 @@ public class TestBasics { if (Stream.of(a, b, c, d, e, f, g, h).allMatch(i -> i == a)) { throw new RuntimeException("RANDOM_ONCE does not produce random values for different arguments"); } - executed[51]++; + executed.merge("checkRandomOnceDifferentArgs", 1, Integer::sum); } @Test @@ -716,7 +707,7 @@ public class TestBasics { Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) public void checkMixedRandoms1(byte a, short b, int c, long d, char e, boolean f, float g, double h) { - executed[52]++; + executed.merge("checkMixedRandoms1", 1, Integer::sum); } @Test @@ -725,7 +716,7 @@ public class TestBasics { Argument.RANDOM_EACH, Argument.RANDOM_EACH, Argument.RANDOM_EACH, Argument.RANDOM_EACH}) public void checkMixedRandoms2(byte a, short b, int c, long d, char e, boolean f, float g, double h) { - executed[53]++; + executed.merge("checkMixedRandoms2", 1, Integer::sum); } @Test @@ -734,7 +725,7 @@ public class TestBasics { Argument.RANDOM_ONCE, Argument.RANDOM_EACH, Argument.RANDOM_EACH, Argument.RANDOM_ONCE}) public void checkMixedRandoms3(byte a, short b, int c, long d, char e, boolean f, float g, double h) { - executed[54]++; + executed.merge("checkMixedRandoms3", 1, Integer::sum); } @Test @@ -745,7 +736,7 @@ public class TestBasics { if (a != 42 || b != 42 || c != 42 || d != 42 || e != 42.0 || f != 42.0) { throw new RuntimeException("Must all be 42"); } - executed[55]++; + executed.merge("check42Mix1", 1, Integer::sum); } @Test @@ -756,7 +747,7 @@ public class TestBasics { if (a != -42 || b != -42 || c != -42 || d != -42 || e != -42.0 || f != -42.0) { throw new RuntimeException("Must all be -42"); } - executed[56]++; + executed.merge("check42Mix2", 1, Integer::sum); } @Test @@ -767,14 +758,14 @@ public class TestBasics { if (a != -42 || b != 42 || c != -42 || d != -42 || e != 42.0 || f != -42.0) { throw new RuntimeException("Do not match the right 42 version"); } - executed[57]++; + executed.merge("check42Mix3", 1, Integer::sum); } @Test @Arguments(values = Argument.BOOLEAN_TOGGLE_FIRST_TRUE) public void booleanToggleFirstTrue(boolean x) { - if (executed[58] == 0) { + if (executed.getOrDefault("booleanToggleFirstTrue", 0) == 0) { // First invocation if (!x) { throw new RuntimeException("BOOLEAN_TOGGLE_FIRST_FALSE must be false on first invocation"); @@ -783,13 +774,13 @@ public class TestBasics { throw new RuntimeException("BOOLEAN_TOGGLE_FIRST_FALSE did not toggle"); } lastToggleBoolean = x; - executed[58]++; + executed.merge("booleanToggleFirstTrue", 1, Integer::sum); } @Test @Arguments(values = {Argument.BOOLEAN_TOGGLE_FIRST_FALSE, Argument.BOOLEAN_TOGGLE_FIRST_TRUE}) public void checkTwoToggles(boolean b1, boolean b2) { - if (executed[59] == 0) { + if (executed.getOrDefault("checkTwoToggles", 0) == 0) { // First invocation if (b1 || !b2) { throw new RuntimeException("BOOLEAN_TOGGLES have wrong initial value"); @@ -800,14 +791,14 @@ public class TestBasics { throw new RuntimeException("Booleans did not toggle"); } lastToggleBoolean = b1; - executed[59]++; + executed.merge("checkTwoToggles", 1, Integer::sum); } @Test @Arguments(values = {Argument.BOOLEAN_TOGGLE_FIRST_FALSE, Argument.FALSE, Argument.TRUE, Argument.BOOLEAN_TOGGLE_FIRST_TRUE}) public void booleanMix(boolean b1, boolean b2, boolean b3, boolean b4) { - if (executed[60] == 0) { + if (executed.getOrDefault("booleanMix", 0) == 0) { // First invocation if (b1 || b2 || !b3 || !b4) { throw new RuntimeException("BOOLEAN_TOGGLES have wrong initial value"); @@ -818,7 +809,7 @@ public class TestBasics { throw new RuntimeException("Booleans did not toggle"); } lastToggleBoolean = b1; - executed[60]++; + executed.merge("booleanMix", 1, Integer::sum); } /* @@ -827,19 +818,19 @@ public class TestBasics { @Test public int testCheck() { - executed[63]++; + executed.merge("testCheck", 1, Integer::sum); return 1; } // Checked test. Check invoked after invoking "testCheck". Perform some more things after invocation. @Check(test = "testCheck") public void checkTestCheck() { - executed[64]++; // Executed on each invocation + executed.merge("checkTestCheck", 1, Integer::sum); // Executed on each invocation } @Test public int testCheckReturn() { - executed[65]++; + executed.merge("testCheckReturn", 1, Integer::sum); return 2; } @@ -849,13 +840,13 @@ public class TestBasics { if (returnValue != 2) { throw new RuntimeException("Must be 2"); } - executed[66]++; // Executed on each invocation + executed.merge("checkTestCheckReturn", 1, Integer::sum); // Executed on each invocation } @Test @Arguments(values = Argument.NUMBER_42) public short testCheckWithArgs(short x) { - executed[94]++; + executed.merge("testCheckWithArgs", 1, Integer::sum); return x; } @@ -864,25 +855,25 @@ public class TestBasics { if (returnValue != 42) { throw new RuntimeException("Must be 42"); } - executed[95]++; // Executed on each invocation + executed.merge("checkTestCheckWithArgs", 1, Integer::sum); // Executed on each invocation } @Test public int testCheckTestInfo() { - executed[67]++; + executed.merge("testCheckTestInfo", 1, Integer::sum); return 3; } // Checked test with info object about test. @Check(test = "testCheckTestInfo") public void checkTestCheckTestInfo(TestInfo testInfo) { - executed[68]++; // Executed on each invocation + executed.merge("checkTestCheckTestInfo(TestInfo)", 1, Integer::sum); // Executed on each invocation } @Test public int testCheckBoth() { - executed[69]++; + executed.merge("testCheckBoth", 1, Integer::sum); return 4; } @@ -892,12 +883,12 @@ public class TestBasics { if (returnValue != 4) { throw new RuntimeException("Must be 4"); } - executed[70]++; // Executed on each invocation + executed.merge("checkTestCheckTestInfo(int, TestInfo)", 1, Integer::sum); // Executed on each invocation } @Test public int testCheckOnce() { - executed[71]++; + executed.merge("testCheckOnce", 1, Integer::sum); return 1; } @@ -909,7 +900,7 @@ public class TestBasics { @Test public int testCheckReturnOnce() { - executed[72]++; + executed.merge("testCheckReturnOnce", 1, Integer::sum); return 2; } @@ -923,7 +914,7 @@ public class TestBasics { @Test public int testCheckTestInfoOnce() { - executed[73]++; + executed.merge("testCheckTestInfoOnce", 1, Integer::sum); return 3; } @@ -934,7 +925,7 @@ public class TestBasics { @Test public int testCheckBothOnce() { - executed[74]++; + executed.merge("testCheckBothOnce", 1, Integer::sum); return 4; } @@ -946,42 +937,9 @@ public class TestBasics { executedOnce[3]++; // Executed once } - @Test - public void sameName() { - executed[76]++; - } - - // Allowed to overload test method if not test method itself - public void sameName(boolean a) { - wasExecuted = true; - } - - // Allowed to overload test method if not test method itself - @Check(test = "sameName") - public void sameName(TestInfo info) { - executed[77]++; - } - - - /* - * Custom run tests. - */ - - @Test - public void sameName2() { - executed[92]++; - } - - // Allowed to overload test method if not test method itself - @Run(test = "sameName2") - public void sameName2(RunInfo info) { - executed[93]++; - sameName2(); - } - @Test public void testRun() { - executed[61]++; + executed.merge("testRun", 1, Integer::sum); } // Custom run test. This method is invoked each time instead of @Test method. This method responsible for calling @@ -993,7 +951,7 @@ public class TestBasics { @Test public void testRunNoTestInfo(int i) { // Argument allowed when run by @Run - executed[62]++; + executed.merge("testRunNoTestInfo", 1, Integer::sum); } @Run(test = "testRunNoTestInfo") @@ -1025,7 +983,7 @@ public class TestBasics { @Test public void testRunOnce2() { - executed[75]++; + executed.merge("testRunOnce2", 1, Integer::sum); } @Run(test = "testRunOnce2", mode = RunMode.STANDALONE) @@ -1037,12 +995,12 @@ public class TestBasics { @Test public void testRunMultiple() { - executed[96]++; + executed.merge("testRunMultiple", 1, Integer::sum); } @Test public void testRunMultiple2() { - executed[97]++; + executed.merge("testRunMultiple2", 1, Integer::sum); } @Test @@ -1059,12 +1017,12 @@ public class TestBasics { @Test public void testRunMultiple3() { - executed[98]++; + executed.merge("testRunMultiple3", 1, Integer::sum); } @Test public void testRunMultiple4() { - executed[99]++; + executed.merge("testRunMultiple4", 1, Integer::sum); } @Test diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestControls.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestControls.java index 7fa834b3e55..05b7007c9bd 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestControls.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestControls.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import jdk.test.lib.Asserts; import jdk.test.whitebox.WhiteBox; import java.lang.reflect.Method; +import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -46,7 +47,7 @@ import java.util.regex.Pattern; */ public class TestControls { - static int[] executed = new int[15]; + static HashMap executed = HashMap.newHashMap(15); static boolean wasExecuted = false; static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); @@ -56,31 +57,21 @@ public class TestControls { Method runTestsOnSameVM = TestVM.class.getDeclaredMethod("runTestsOnSameVM", Class.class); runTestsOnSameVM.setAccessible(true); runTestsOnSameVM.invoke(null, new Object[]{ null }); - final int defaultIterations = TestVM.WARMUP_ITERATIONS + 1; - Asserts.assertEQ(executed[0], 1001); - Asserts.assertEQ(executed[1], 101); - Asserts.assertEQ(executed[2], 10000); - Asserts.assertEQ(executed[3], 10000); - Asserts.assertEQ(executed[4], defaultIterations); - Asserts.assertEQ(executed[5], defaultIterations); - Asserts.assertEQ(executed[6], 5001); - Asserts.assertEQ(executed[7], 5001); - Asserts.assertEQ(executed[8], 1); - Asserts.assertEQ(executed[9], 5000); - Asserts.assertEQ(executed[10], 1); - Asserts.assertEQ(executed[11], 2); - Asserts.assertEQ(executed[12], 1); - Asserts.assertEQ(executed[13], 1); + Asserts.assertEQ(executed.get("test1"), 1001); + Asserts.assertEQ(executed.get("test2"), 101); + Asserts.assertEQ(executed.get("testDontCompile"), 10000); + Asserts.assertEQ(executed.get("dontCompile"), 10000); + Asserts.assertEQ(executed.get("testCompileAtLevel1"), 5001); + Asserts.assertEQ(executed.get("dontCompile2"), 5001); + Asserts.assertEQ(executed.get("runTestDontCompile2A"), 1); + Asserts.assertEQ(executed.get("runTestDontCompile2B"), 5000); + Asserts.assertEQ(executed.get("noWarmup"), 1); + Asserts.assertEQ(executed.get("noWarmup2"), 2); + Asserts.assertEQ(executed.get("runNoWarmup2"), 1); + Asserts.assertEQ(executed.get("runTestCompilation"), 1); Asserts.assertFalse(wasExecuted); final long started = System.currentTimeMillis(); long elapsed = 0; - Method overloadDouble = TestControls.class.getDeclaredMethod("overload", double.class); - Method overloadInt = TestControls.class.getDeclaredMethod("overload", int.class); - while (!(TestFramework.isC2Compiled(overloadInt) && TestFramework.isCompiledAtLevel(overloadDouble, CompLevel.C1_LIMITED_PROFILE)) && elapsed < 5000) { - elapsed = System.currentTimeMillis() - started; - } - TestFramework.assertCompiledAtLevel(TestControls.class.getDeclaredMethod("overload", double.class), CompLevel.C1_LIMITED_PROFILE); - TestFramework.assertCompiledByC2(TestControls.class.getDeclaredMethod("overload", int.class)); TestFramework framework = new TestFramework(ClassInitializerTest.class); framework.addFlags("-XX:+PrintCompilation").addHelperClasses(ClassInitializerHelper.class).start(); @@ -99,15 +90,15 @@ public class TestControls { @Test @Warmup(1000) public void test1() { - executed[0]++; + executed.merge("test1", 1, Integer::sum); } @Check(test = "test1") public void check1(TestInfo info) { - if (executed[0] <= 1000) { + if (executed.getOrDefault("test1", 0) <= 1000) { Asserts.assertTrue(info.isWarmUp()); } else { - Asserts.assertTrue(!info.isWarmUp() && executed[0] == 1001); + Asserts.assertTrue(!info.isWarmUp() && executed.getOrDefault("test1", 0) == 1001); TestFramework.assertCompiledByC2(info.getTest()); } } @@ -115,45 +106,23 @@ public class TestControls { @Test @Warmup(100) public void test2() { - executed[1]++; + executed.merge("test2", 1, Integer::sum); } @Check(test = "test2", when = CheckAt.COMPILED) public void check2(TestInfo info) { - Asserts.assertTrue(!info.isWarmUp() && executed[1] == 101); + Asserts.assertTrue(!info.isWarmUp() && executed.getOrDefault("test2", 0) == 101); TestFramework.assertCompiledByC2(info.getTest()); } - @Test - public void overload() { - executed[4]++; - } - - @ForceCompile - @DontInline - public static void overload(int i) { - wasExecuted = true; - } - - @ForceCompile(CompLevel.C1_LIMITED_PROFILE) - @ForceInline - public static void overload(double i) { - wasExecuted = true; - } - - @Check(test = "overload") - public void checkOverload() { - executed[5]++; - } - @Test public void testDontCompile() { - executed[2]++; + executed.merge("testDontCompile", 1, Integer::sum); } @DontCompile public static void dontCompile() { - executed[3]++; + executed.merge("dontCompile", 1, Integer::sum); } @Run(test = "testDontCompile", mode = RunMode.STANDALONE) @@ -167,12 +136,12 @@ public class TestControls { @Test public void testCompileAtLevel1() { - executed[6]++; + executed.merge("testCompileAtLevel1", 1, Integer::sum); } @DontCompile(Compiler.ANY) public static void dontCompile2() { - executed[7]++; + executed.merge("dontCompile2", 1, Integer::sum); } @Run(test = "testCompileAtLevel1") @@ -181,23 +150,23 @@ public class TestControls { dontCompile2(); testCompileAtLevel1(); if (!info.isWarmUp()) { - executed[8]++; + executed.merge("runTestDontCompile2A", 1, Integer::sum); int compLevel = WHITE_BOX.getMethodCompilationLevel(TestControls.class.getDeclaredMethod("dontCompile2"), false); Asserts.assertLessThan(compLevel, CompLevel.C1_LIMITED_PROFILE.getValue()); } else { - executed[9]++; + executed.merge("runTestDontCompile2B", 1, Integer::sum); } } @Test @Warmup(0) public void noWarmup() { - executed[10]++; + executed.merge("noWarmup", 1, Integer::sum); } @Test public void noWarmup2() { - executed[11]++; + executed.merge("noWarmup2", 1, Integer::sum); } @Run(test = "noWarmup2") @@ -206,7 +175,7 @@ public class TestControls { noWarmup2(); noWarmup2(); Asserts.assertTrue(!info.isWarmUp()); - executed[12]++; + executed.merge("runNoWarmup2", 1, Integer::sum); } @Test @@ -301,7 +270,7 @@ public class TestControls { TestFramework.assertCompiledAtLevel(info.getTestClassMethod("forceC1DontC2"), CompLevel.C1_SIMPLE); TestFramework.assertCompiledAtLevel(info.getTestClassMethod("forceC2DontC1"), CompLevel.C2); - executed[13]++; + executed.merge("runTestCompilation", 1, Integer::sum); } } From e370b8a1d834a0a6ebcd1d5946a5533c015ed960 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 2 Feb 2026 10:32:51 +0000 Subject: [PATCH 284/328] 8376570: GrowableArray::remove_{till,range} should work on empty list Reviewed-by: kbarrett, iwalulya --- src/hotspot/share/utilities/growableArray.hpp | 12 +- .../gtest/utilities/test_growableArray.cpp | 117 +++++++++++++++++- 2 files changed, 122 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/utilities/growableArray.hpp b/src/hotspot/share/utilities/growableArray.hpp index 1823a2ba861..e300bea6993 100644 --- a/src/hotspot/share/utilities/growableArray.hpp +++ b/src/hotspot/share/utilities/growableArray.hpp @@ -493,16 +493,16 @@ public: return false; } - // Remove all elements up to the index (exclusive). The order is preserved. - void remove_till(int idx) { - remove_range(0, idx); + // Remove all elements in the range [0; end). The order is preserved. + void remove_till(int end) { + remove_range(0, end); } - // Remove all elements in the range [start - end). The order is preserved. + // Remove all elements in the range [start; end). The order is preserved. void remove_range(int start, int end) { assert(0 <= start, "illegal start index %d", start); - assert(start < end && end <= this->_len, - "erase called with invalid range (%d, %d) for length %d", + assert(start <= end && end <= this->_len, + "erase called with invalid range [%d, %d) for length %d", start, end, this->_len); for (int i = start, j = end; j < this->length(); i++, j++) { diff --git a/test/hotspot/gtest/utilities/test_growableArray.cpp b/test/hotspot/gtest/utilities/test_growableArray.cpp index 45fc9498d27..6958da18ac3 100644 --- a/test/hotspot/gtest/utilities/test_growableArray.cpp +++ b/test/hotspot/gtest/utilities/test_growableArray.cpp @@ -232,12 +232,111 @@ protected: } } + template + static void test_remove_range(ArrayClass* a) { + // Seed initial + for (int i = 0; i < 10; i++) { + a->append(i); + } + ASSERT_EQ(a->length(), 10); + + // Remove empty range from the non-empty list, should not modify the list. + a->remove_range(0, 0); + ASSERT_EQ(a->length(), 10); + + // Remove one element from head, should result in [1 ... 9] + a->remove_range(0, 1); + ASSERT_EQ(a->length(), 9); + for (int i = 0; i < a->length(); i++) { + ASSERT_EQ(a->at(i), i + 1); + } + + // Remove one element from tail, should result in [1 ... 8] + a->remove_range(8, 9); + ASSERT_EQ(a->length(), 8); + for (int i = 0; i < a->length(); i++) { + ASSERT_EQ(a->at(i), i + 1); + } + + // Remove another empty range from the non-empty list, should not modify + a->remove_range(1, 1); + ASSERT_EQ(a->length(), 8); + + // Remove some elements from the middle, should result in [1 2 7 8] + a->remove_range(2, 6); + ASSERT_EQ(a->length(), 4); + ASSERT_EQ(a->at(0), 1); + ASSERT_EQ(a->at(1), 2); + ASSERT_EQ(a->at(2), 7); + ASSERT_EQ(a->at(3), 8); + + // Remove the rest of the elements one by one + a->remove_range(0, 1); + ASSERT_EQ(a->length(), 3); + ASSERT_EQ(a->at(0), 2); + ASSERT_EQ(a->at(1), 7); + ASSERT_EQ(a->at(2), 8); + + a->remove_range(0, 1); + ASSERT_EQ(a->length(), 2); + ASSERT_EQ(a->at(0), 7); + ASSERT_EQ(a->at(1), 8); + + a->remove_range(0, 1); + ASSERT_EQ(a->length(), 1); + ASSERT_EQ(a->at(0), 8); + + a->remove_range(0, 1); + ASSERT_EQ(a->length(), 0); + + // Remove elements from empty list with empty range, should be accepted + a->remove_range(0, 0); + ASSERT_EQ(a->length(), 0); + } + + template + static void test_remove_till(ArrayClass* a) { + // Seed initial + for (int i = 0; i < 10; i++) { + a->append(i); + } + ASSERT_EQ(a->length(), 10); + + // Remove empty range from non-empty list, should work + a->remove_till(0); + ASSERT_EQ(a->length(), 10); + + // Remove one element from head, should result in [1 ... 9] + a->remove_till(1); + ASSERT_EQ(a->length(), 9); + for (int i = 0; i < a->length(); i++) { + ASSERT_EQ(a->at(i), i + 1); + } + + // Remove two elements from head, should result in [3 ... 9] + a->remove_till(2); + ASSERT_EQ(a->length(), 7); + for (int i = 0; i < a->length(); i++) { + ASSERT_EQ(a->at(i), i + 3); + } + + // Remove remaining elements, should result in [] + a->remove_till(a->length()); + ASSERT_EQ(a->length(), 0); + + // Remove empty range from empty list, should work + a->remove_till(0); + ASSERT_EQ(a->length(), 0); + } + // Supported by all GrowableArrays enum TestEnum { Append, Clear, Capacity, - Iterator + Iterator, + RemoveRange, + RemoveTill }; template @@ -259,6 +358,14 @@ protected: test_iterator(a); break; + case RemoveRange: + test_remove_range(a); + break; + + case RemoveTill: + test_remove_till(a); + break; + default: fatal("Missing dispatch"); break; @@ -451,6 +558,14 @@ TEST_VM_F(GrowableArrayTest, iterator) { with_all_types_all_0(Iterator); } +TEST_VM_F(GrowableArrayTest, remove_range) { + with_all_types_all_0(RemoveRange); +} + +TEST_VM_F(GrowableArrayTest, remove_till) { + with_all_types_all_0(RemoveTill); +} + TEST_VM_F(GrowableArrayTest, copy) { with_no_cheap_array_append1(Copy1); } From 17f25b5ac46daed362f15005d65c5ee771328214 Mon Sep 17 00:00:00 2001 From: David Briemann Date: Mon, 2 Feb 2026 11:31:17 +0000 Subject: [PATCH 285/328] 8375536: PPC64: Implement special MachNodes for floating point CMove Reviewed-by: mdoerr, rrich --- src/hotspot/cpu/aarch64/aarch64.ad | 4 +- src/hotspot/cpu/ppc/assembler_ppc.hpp | 6 ++ src/hotspot/cpu/ppc/assembler_ppc.inline.hpp | 4 + src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp | 34 +++++++++ src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp | 2 + src/hotspot/cpu/ppc/matcher_ppc.hpp | 6 +- src/hotspot/cpu/ppc/ppc.ad | 76 ++++++++++++++++--- 7 files changed, 114 insertions(+), 18 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index b9252cc56ff..a9ca91d9309 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -1229,7 +1229,7 @@ public: // predicate controlling addressing modes bool size_fits_all_mem_uses(AddPNode* addp, int shift); - // Convert BootTest condition to Assembler condition. + // Convert BoolTest condition to Assembler condition. // Replicate the logic of cmpOpOper::ccode() and cmpOpUOper::ccode(). Assembler::Condition to_assembler_cond(BoolTest::mask cond); %} @@ -2579,7 +2579,7 @@ bool size_fits_all_mem_uses(AddPNode* addp, int shift) { return true; } -// Convert BootTest condition to Assembler condition. +// Convert BoolTest condition to Assembler condition. // Replicate the logic of cmpOpOper::ccode() and cmpOpUOper::ccode(). Assembler::Condition to_assembler_cond(BoolTest::mask cond) { Assembler::Condition result; diff --git a/src/hotspot/cpu/ppc/assembler_ppc.hpp b/src/hotspot/cpu/ppc/assembler_ppc.hpp index 15e38411482..23775a3a52e 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp @@ -568,6 +568,9 @@ class Assembler : public AbstractAssembler { XSCVDPHP_OPCODE= (60u << OPCODE_SHIFT | 347u << 2 | 17u << 16), // XX2-FORM XXPERM_OPCODE = (60u << OPCODE_SHIFT | 26u << 3), XXSEL_OPCODE = (60u << OPCODE_SHIFT | 3u << 4), + XSCMPEQDP_OPCODE=(60u << OPCODE_SHIFT | 3u << 3), + XSCMPGEDP_OPCODE=(60u << OPCODE_SHIFT | 19u << 3), + XSCMPGTDP_OPCODE=(60u << OPCODE_SHIFT | 11u << 3), XXSPLTIB_OPCODE= (60u << OPCODE_SHIFT | 360u << 1), XVDIVDP_OPCODE = (60u << OPCODE_SHIFT | 120u << 3), XVABSSP_OPCODE = (60u << OPCODE_SHIFT | 409u << 2), @@ -2424,6 +2427,9 @@ class Assembler : public AbstractAssembler { inline void xscvdphp( VectorSRegister d, VectorSRegister b); inline void xxland( VectorSRegister d, VectorSRegister a, VectorSRegister b); inline void xxsel( VectorSRegister d, VectorSRegister a, VectorSRegister b, VectorSRegister c); + inline void xscmpeqdp(VectorSRegister t, VectorSRegister a, VectorSRegister b); // Requires Power9 + inline void xscmpgedp(VectorSRegister t, VectorSRegister a, VectorSRegister b); // Requires Power9 + inline void xscmpgtdp(VectorSRegister t, VectorSRegister a, VectorSRegister b); // Requires Power9 inline void xxspltib( VectorSRegister d, int ui8); inline void xvdivsp( VectorSRegister d, VectorSRegister a, VectorSRegister b); inline void xvdivdp( VectorSRegister d, VectorSRegister a, VectorSRegister b); diff --git a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp index 7e49ec7455d..4cda782067e 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp @@ -923,6 +923,10 @@ inline void Assembler::xxmrghw( VectorSRegister d, VectorSRegister a, VectorSReg inline void Assembler::xxmrglw( VectorSRegister d, VectorSRegister a, VectorSRegister b) { emit_int32( XXMRGHW_OPCODE | vsrt(d) | vsra(a) | vsrb(b)); } inline void Assembler::xxsel( VectorSRegister d, VectorSRegister a, VectorSRegister b, VectorSRegister c) { emit_int32( XXSEL_OPCODE | vsrt(d) | vsra(a) | vsrb(b) | vsrc(c)); } +inline void Assembler::xscmpeqdp(VectorSRegister t, VectorSRegister a, VectorSRegister b) { emit_int32( XSCMPEQDP_OPCODE | vsrt(t) | vsra(a) | vsrb(b) );} +inline void Assembler::xscmpgedp(VectorSRegister t, VectorSRegister a, VectorSRegister b) { emit_int32( XSCMPGEDP_OPCODE | vsrt(t) | vsra(a) | vsrb(b) );} +inline void Assembler::xscmpgtdp(VectorSRegister t, VectorSRegister a, VectorSRegister b) { emit_int32( XSCMPGTDP_OPCODE | vsrt(t) | vsra(a) | vsrb(b) );} + // VSX Extended Mnemonics inline void Assembler::xxspltd( VectorSRegister d, VectorSRegister a, int x) { xxpermdi(d, a, a, x ? 3 : 0); } inline void Assembler::xxmrghd( VectorSRegister d, VectorSRegister a, VectorSRegister b) { xxpermdi(d, a, b, 0); } diff --git a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp index edf348fdc50..73b6b132895 100644 --- a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp @@ -664,3 +664,37 @@ void C2_MacroAssembler::reduceI(int opcode, Register dst, Register iSrc, VectorR fn_scalar_op(opcode, dst, iSrc, R0); // dst <- op(iSrc, R0) } +// Works for single and double precision floats. +// dst = (op1 cmp(cc) op2) ? src1 : src2; +// Unordered semantics are the same as for CmpF3Node/CmpD3Node which implement the fcmpl/dcmpl bytecodes. +// Comparing unordered values has the same result as when src1 is less than src2. +// So dst = src1 for <, <=, != and dst = src2 for >, >=, ==. +void C2_MacroAssembler::cmovF(int cc, VectorSRegister dst, VectorSRegister op1, VectorSRegister op2, + VectorSRegister src1, VectorSRegister src2, VectorSRegister tmp) { + // See operand cmpOp() for details. + bool invert_cond = (cc & 8) == 0; // invert reflects bcondCRbiIs0 + auto cmp = (Assembler::Condition)(cc & 3); + + switch(cmp) { + case Assembler::Condition::equal: + // Use false_result if "unordered". + xscmpeqdp(tmp, op1, op2); + break; + case Assembler::Condition::greater: + // Use false_result if "unordered". + xscmpgtdp(tmp, op1, op2); + break; + case Assembler::Condition::less: + // Use true_result if "unordered". + xscmpgedp(tmp, op1, op2); + invert_cond = !invert_cond; + break; + default: + assert(false, "unsupported compare condition: %d", cc); + ShouldNotReachHere(); + } + + VectorSRegister true_result = invert_cond ? src2 : src1; + VectorSRegister false_result = invert_cond ? src1 : src2; + xxsel(dst, false_result, true_result, tmp); +} diff --git a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp index 5a114294c1f..e0dffec8396 100644 --- a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp @@ -74,5 +74,7 @@ void count_positives(Register src, Register cnt, Register result, Register tmp1, Register tmp2); void reduceI(int opcode, Register dst, Register iSrc, VectorRegister vSrc, VectorRegister vTmp1, VectorRegister vTmp2); + void cmovF(int cc, VectorSRegister dst, VectorSRegister op1, VectorSRegister op2, + VectorSRegister src1, VectorSRegister src2, VectorSRegister tmp); #endif // CPU_PPC_C2_MACROASSEMBLER_PPC_HPP diff --git a/src/hotspot/cpu/ppc/matcher_ppc.hpp b/src/hotspot/cpu/ppc/matcher_ppc.hpp index aad41fb7b1c..b50de6323de 100644 --- a/src/hotspot/cpu/ppc/matcher_ppc.hpp +++ b/src/hotspot/cpu/ppc/matcher_ppc.hpp @@ -64,12 +64,10 @@ return true; } - // Use conditional move (CMOVL) on Power7. static constexpr int long_cmove_cost() { return 0; } // this only makes long cmoves more expensive than int cmoves - // Suppress CMOVF. Conditional move available (sort of) on PPC64 only from P7 onwards. Not exploited yet. - // fsel doesn't accept a condition register as input, so this would be slightly different. - static int float_cmove_cost() { return ConditionalMoveLimit; } + // Suppress CMOVF for Power8 because there are no fast nodes. + static int float_cmove_cost() { return (PowerArchitecturePPC64 >= 9) ? 0 : ConditionalMoveLimit; } // This affects two different things: // - how Decode nodes are matched diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 2a0a9149bb3..d926fabd353 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -3024,7 +3024,6 @@ encode %{ %} enc_class postalloc_expand_encode_oop(iRegNdst dst, iRegPdst src, flagsReg crx) %{ - // use isel instruction with Power 7 cmpP_reg_imm16Node *n_compare = new cmpP_reg_imm16Node(); encodeP_subNode *n_sub_base = new encodeP_subNode(); encodeP_shiftNode *n_shift = new encodeP_shiftNode(); @@ -3099,7 +3098,6 @@ encode %{ n_shift->_opnds[1] = op_src; n_shift->_bottom_type = _bottom_type; - // use isel instruction with Power 7 decodeN_addNode *n_add_base = new decodeN_addNode(); n_add_base->add_req(n_region, n_shift); n_add_base->_opnds[0] = op_dst; @@ -6618,7 +6616,6 @@ instruct cond_sub_base(iRegNdst dst, flagsRegSrc crx, iRegPsrc src1) %{ ins_pipe(pipe_class_default); %} -// Power 7 can use isel instruction instruct cond_set_0_oop(iRegNdst dst, flagsRegSrc crx, iRegPsrc src1) %{ // The match rule is needed to make it a 'MachTypeNode'! match(Set dst (EncodeP (Binary crx src1))); @@ -7293,7 +7290,6 @@ instruct cmovF_reg(cmpOp cmp, flagsRegSrc crx, regF dst, regF src) %{ ins_variable_size_depending_on_alignment(true); format %{ "CMOVEF $cmp, $crx, $dst, $src\n\t" %} - // Worst case is branch + move + stop, no stop without scheduler. size(8); ins_encode %{ Label done; @@ -7313,7 +7309,6 @@ instruct cmovD_reg(cmpOp cmp, flagsRegSrc crx, regD dst, regD src) %{ ins_variable_size_depending_on_alignment(true); format %{ "CMOVEF $cmp, $crx, $dst, $src\n\t" %} - // Worst case is branch + move + stop, no stop without scheduler. size(8); ins_encode %{ Label done; @@ -7326,6 +7321,70 @@ instruct cmovD_reg(cmpOp cmp, flagsRegSrc crx, regD dst, regD src) %{ ins_pipe(pipe_class_default); %} +instruct cmovF_cmpF(cmpOp cop, regF op1, regF op2, regF dst, regF false_result, regF true_result, regD tmp) %{ + match(Set dst (CMoveF (Binary cop (CmpF op1 op2)) (Binary false_result true_result))); + predicate(PowerArchitecturePPC64 >= 9); + effect(TEMP tmp); + ins_cost(2*DEFAULT_COST); + format %{ "cmovF_cmpF $dst = ($op1 $cop $op2) ? $true_result : $false_result\n\t" %} + size(8); + ins_encode %{ + __ cmovF($cop$$cmpcode, $dst$$FloatRegister->to_vsr(), + $op1$$FloatRegister->to_vsr(), $op2$$FloatRegister->to_vsr(), + $true_result$$FloatRegister->to_vsr(), $false_result$$FloatRegister->to_vsr(), + $tmp$$FloatRegister->to_vsr()); + %} + ins_pipe(pipe_class_default); +%} + +instruct cmovF_cmpD(cmpOp cop, regD op1, regD op2, regF dst, regF false_result, regF true_result, regD tmp) %{ + match(Set dst (CMoveF (Binary cop (CmpD op1 op2)) (Binary false_result true_result))); + predicate(PowerArchitecturePPC64 >= 9); + effect(TEMP tmp); + ins_cost(2*DEFAULT_COST); + format %{ "cmovF_cmpD $dst = ($op1 $cop $op2) ? $true_result : $false_result\n\t" %} + size(8); + ins_encode %{ + __ cmovF($cop$$cmpcode, $dst$$FloatRegister->to_vsr(), + $op1$$FloatRegister->to_vsr(), $op2$$FloatRegister->to_vsr(), + $true_result$$FloatRegister->to_vsr(), $false_result$$FloatRegister->to_vsr(), + $tmp$$FloatRegister->to_vsr()); + %} + ins_pipe(pipe_class_default); +%} + +instruct cmovD_cmpD(cmpOp cop, regD op1, regD op2, regD dst, regD false_result, regD true_result, regD tmp) %{ + match(Set dst (CMoveD (Binary cop (CmpD op1 op2)) (Binary false_result true_result))); + predicate(PowerArchitecturePPC64 >= 9); + effect(TEMP tmp); + ins_cost(2*DEFAULT_COST); + format %{ "cmovD_cmpD $dst = ($op1 $cop $op2) ? $true_result : $false_result\n\t" %} + size(8); + ins_encode %{ + __ cmovF($cop$$cmpcode, $dst$$FloatRegister->to_vsr(), + $op1$$FloatRegister->to_vsr(), $op2$$FloatRegister->to_vsr(), + $true_result$$FloatRegister->to_vsr(), $false_result$$FloatRegister->to_vsr(), + $tmp$$FloatRegister->to_vsr()); + %} + ins_pipe(pipe_class_default); +%} + +instruct cmovD_cmpF(cmpOp cop, regF op1, regF op2, regD dst, regD false_result, regD true_result, regD tmp) %{ + match(Set dst (CMoveD (Binary cop (CmpF op1 op2)) (Binary false_result true_result))); + predicate(PowerArchitecturePPC64 >= 9); + effect(TEMP tmp); + ins_cost(2*DEFAULT_COST); + format %{ "cmovD_cmpF $dst = ($op1 $cop $op2) ? $true_result : $false_result\n\t" %} + size(8); + ins_encode %{ + __ cmovF($cop$$cmpcode, $dst$$FloatRegister->to_vsr(), + $op1$$FloatRegister->to_vsr(), $op2$$FloatRegister->to_vsr(), + $true_result$$FloatRegister->to_vsr(), $false_result$$FloatRegister->to_vsr(), + $tmp$$FloatRegister->to_vsr()); + %} + ins_pipe(pipe_class_default); +%} + //----------Compare-And-Swap--------------------------------------------------- // CompareAndSwap{P,I,L} have more than one output, therefore "CmpI @@ -8492,7 +8551,6 @@ instruct cmovI_bne_negI_reg(iRegIdst dst, flagsRegSrc crx, iRegIsrc src1) %{ ins_variable_size_depending_on_alignment(true); format %{ "CMOVE $dst, neg($src1), $crx" %} - // Worst case is branch + move + stop, no stop without scheduler. size(8); ins_encode %{ Label done; @@ -8551,7 +8609,6 @@ instruct cmovL_bne_negL_reg(iRegLdst dst, flagsRegSrc crx, iRegLsrc src1) %{ ins_variable_size_depending_on_alignment(true); format %{ "CMOVE $dst, neg($src1), $crx" %} - // Worst case is branch + move + stop, no stop without scheduler. size(8); ins_encode %{ Label done; @@ -10262,7 +10319,6 @@ instruct cmovI_bso_stackSlotL(iRegIdst dst, flagsRegSrc crx, stackSlotL src) %{ ins_variable_size_depending_on_alignment(true); format %{ "cmovI $crx, $dst, $src" %} - // Worst case is branch + move + stop, no stop without scheduler. size(8); ins_encode( enc_cmove_bso_stackSlotL(dst, crx, src) ); ins_pipe(pipe_class_default); @@ -10276,7 +10332,6 @@ instruct cmovI_bso_reg(iRegIdst dst, flagsRegSrc crx, regD src) %{ ins_variable_size_depending_on_alignment(true); format %{ "cmovI $crx, $dst, $src" %} - // Worst case is branch + move + stop, no stop without scheduler. size(8); ins_encode( enc_cmove_bso_reg(dst, crx, src) ); ins_pipe(pipe_class_default); @@ -10439,7 +10494,6 @@ instruct cmovL_bso_stackSlotL(iRegLdst dst, flagsRegSrc crx, stackSlotL src) %{ ins_variable_size_depending_on_alignment(true); format %{ "cmovL $crx, $dst, $src" %} - // Worst case is branch + move + stop, no stop without scheduler. size(8); ins_encode( enc_cmove_bso_stackSlotL(dst, crx, src) ); ins_pipe(pipe_class_default); @@ -10453,7 +10507,6 @@ instruct cmovL_bso_reg(iRegLdst dst, flagsRegSrc crx, regD src) %{ ins_variable_size_depending_on_alignment(true); format %{ "cmovL $crx, $dst, $src" %} - // Worst case is branch + move + stop, no stop without scheduler. size(8); ins_encode( enc_cmove_bso_reg(dst, crx, src) ); ins_pipe(pipe_class_default); @@ -11080,7 +11133,6 @@ instruct cmov_bns_less(flagsReg crx) %{ ins_variable_size_depending_on_alignment(true); format %{ "cmov $crx" %} - // Worst case is branch + move + stop, no stop without scheduler. size(12); ins_encode %{ Label done; From 176422b885d2d045dd44b61b7fcdcb01be2d00a7 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Mon, 2 Feb 2026 11:43:30 +0000 Subject: [PATCH 286/328] 8370519: C2: Hit MemLimit when running with +VerifyLoopOptimizations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Benoît Maillard Reviewed-by: mhaessig, bmaillard, epeter --- src/hotspot/share/memory/arena.hpp | 3 +- src/hotspot/share/opto/loopnode.cpp | 24 +++- src/hotspot/share/opto/loopnode.hpp | 28 ++-- ...stVerifyLoopOptimizationsHighMemUsage.java | 126 ++++++++++++++++++ 4 files changed, 157 insertions(+), 24 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/TestVerifyLoopOptimizationsHighMemUsage.java diff --git a/src/hotspot/share/memory/arena.hpp b/src/hotspot/share/memory/arena.hpp index a8450b5543a..7d88c79ca52 100644 --- a/src/hotspot/share/memory/arena.hpp +++ b/src/hotspot/share/memory/arena.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,6 +101,7 @@ public: FN(ra, Resource areas) \ FN(node, C2 Node arena) \ FN(comp, C2 Compile arena) \ + FN(idealloop, C2 Ideal Loop arena) \ FN(type, C2 Type arena) \ FN(states, C2 Matcher States Arena) \ FN(reglive, C2 Register Allocation Live Arenas) \ diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index fab354e3e3d..d68505836d4 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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 @@ -3752,6 +3752,20 @@ void CountedLoopEndNode::dump_spec(outputStream *st) const { } #endif +IdealLoopTree::IdealLoopTree(PhaseIdealLoop* phase, Node* head, Node* tail): _parent(nullptr), _next(nullptr), _child(nullptr), + _head(head), _tail(tail), + _phase(phase), + _local_loop_unroll_limit(0), _local_loop_unroll_factor(0), + _body(phase->arena()), + _nest(0), _irreducible(0), _has_call(0), _has_sfpt(0), _rce_candidate(0), + _has_range_checks(0), _has_range_checks_computed(0), + _safepts(nullptr), + _required_safept(nullptr), + _allow_optimizations(true) { + precond(_head != nullptr); + precond(_tail != nullptr); +} + //============================================================================= //------------------------------is_member-------------------------------------- // Is 'l' a member of 'this'? @@ -5089,8 +5103,8 @@ void PhaseIdealLoop::build_and_optimize() { // Since nodes do not have a slot for immediate dominator, make // a persistent side array for that info indexed on node->_idx. _idom_size = C->unique(); - _idom = NEW_RESOURCE_ARRAY( Node*, _idom_size ); - _dom_depth = NEW_RESOURCE_ARRAY( uint, _idom_size ); + _idom = NEW_ARENA_ARRAY(&_arena, Node*, _idom_size); + _dom_depth = NEW_ARENA_ARRAY(&_arena, uint, _idom_size); _dom_stk = nullptr; // Allocated on demand in recompute_dom_depth memset( _dom_depth, 0, _idom_size * sizeof(uint) ); @@ -5691,8 +5705,8 @@ void PhaseIdealLoop::set_idom(Node* d, Node* n, uint dom_depth) { uint idx = d->_idx; if (idx >= _idom_size) { uint newsize = next_power_of_2(idx); - _idom = REALLOC_RESOURCE_ARRAY( Node*, _idom,_idom_size,newsize); - _dom_depth = REALLOC_RESOURCE_ARRAY( uint, _dom_depth,_idom_size,newsize); + _idom = REALLOC_ARENA_ARRAY(&_arena, Node*, _idom,_idom_size,newsize); + _dom_depth = REALLOC_ARENA_ARRAY(&_arena, uint, _dom_depth,_idom_size,newsize); memset( _dom_depth + _idom_size, 0, (newsize - _idom_size) * sizeof(uint) ); _idom_size = newsize; } diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 24976d76a51..5b06f0555ab 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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 @@ -669,21 +669,7 @@ public: Node_List* _required_safept; // A inner loop cannot delete these safepts; bool _allow_optimizations; // Allow loop optimizations - IdealLoopTree( PhaseIdealLoop* phase, Node *head, Node *tail ) - : _parent(nullptr), _next(nullptr), _child(nullptr), - _head(head), _tail(tail), - _phase(phase), - _local_loop_unroll_limit(0), _local_loop_unroll_factor(0), - _body(Compile::current()->comp_arena()), - _nest(0), _irreducible(0), _has_call(0), _has_sfpt(0), _rce_candidate(0), - _has_range_checks(0), _has_range_checks_computed(0), - _safepts(nullptr), - _required_safept(nullptr), - _allow_optimizations(true) - { - precond(_head != nullptr); - precond(_tail != nullptr); - } + IdealLoopTree(PhaseIdealLoop* phase, Node* head, Node* tail); // Is 'l' a member of 'this'? bool is_member(const IdealLoopTree *l) const; // Test for nested membership @@ -889,6 +875,8 @@ class PhaseIdealLoop : public PhaseTransform { friend class ShenandoahBarrierC2Support; friend class AutoNodeBudget; + Arena _arena; // For data whose lifetime is a single pass of loop optimizations + // Map loop membership for CFG nodes, and ctrl for non-CFG nodes. // // Exception: dead CFG nodes may instead have a ctrl/idom forwarding @@ -1049,6 +1037,8 @@ public: PhaseIterGVN &igvn() const { return _igvn; } + Arena* arena() { return &_arena; }; + bool has_node(const Node* n) const { guarantee(n != nullptr, "No Node."); return _loop_or_ctrl[n->_idx] != nullptr; @@ -1223,7 +1213,8 @@ private: // Compute the Ideal Node to Loop mapping PhaseIdealLoop(PhaseIterGVN& igvn, LoopOptsMode mode) : PhaseTransform(Ideal_Loop), - _loop_or_ctrl(igvn.C->comp_arena()), + _arena(mtCompiler, Arena::Tag::tag_idealloop), + _loop_or_ctrl(&_arena), _igvn(igvn), _verify_me(nullptr), _verify_only(false), @@ -1238,7 +1229,8 @@ private: // or only verify that the graph is valid if verify_me is null. PhaseIdealLoop(PhaseIterGVN& igvn, const PhaseIdealLoop* verify_me = nullptr) : PhaseTransform(Ideal_Loop), - _loop_or_ctrl(igvn.C->comp_arena()), + _arena(mtCompiler, Arena::Tag::tag_idealloop), + _loop_or_ctrl(&_arena), _igvn(igvn), _verify_me(verify_me), _verify_only(verify_me == nullptr), diff --git a/test/hotspot/jtreg/compiler/c2/TestVerifyLoopOptimizationsHighMemUsage.java b/test/hotspot/jtreg/compiler/c2/TestVerifyLoopOptimizationsHighMemUsage.java new file mode 100644 index 00000000000..ea7f3049ec3 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestVerifyLoopOptimizationsHighMemUsage.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2026, 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 + * @key stress randomness + * @bug 8370519 + * @summary C2: Hit MemLimit when running with +VerifyLoopOptimizations + * @run main/othervm -XX:CompileCommand=compileonly,${test.main.class}::* -XX:-TieredCompilation -Xbatch + * -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions + * -XX:+StressLoopPeeling -XX:+VerifyLoopOptimizations + * -XX:CompileCommand=memlimit,${test.main.class}::*,600M~crash + * -XX:StressSeed=3106998670 ${test.main.class} + * @run main ${test.main.class} + */ + +package compiler.c2; + +public class TestVerifyLoopOptimizationsHighMemUsage { + public static final int N = 400; + public static long instanceCount = -13L; + public static volatile short sFld = -16143; + public static int iFld = -159; + public static float fArrFld[] = new float[N]; + + public static long lMeth(int i1) { + int i2 = 11, i3 = 37085, i4 = 177, i5 = 190, i6 = -234, i7 = 13060, + iArr[] = new int[N]; + float f = 1.179F; + double d = 2.9685; + long lArr[] = new long[N]; + for (i2 = 15; i2 < 330; ++i2) + for (i4 = 1; i4 < 5; ++i4) { + fArrFld[i4 + 1] = (++i1); + for (i6 = 2; i6 > 1; i6 -= 3) + switch ((i2 * 5) + 54) { + case 156: + if (i4 != 0) + ; + case 168: + case 342: + case 283: + case 281: + case 328: + case 322: + case 228: + case 114: + case 207: + case 209: + case 354: + case 108: + i1 <<= i1; + case 398: + case 144: + case 218: + case 116: + case 296: + case 198: + case 173: + case 105: + case 120: + case 248: + case 140: + case 352: + try { + } catch (ArithmeticException a_e) { + } + case 404: + i5 += (i6 ^ instanceCount); + case 370: + case 211: + case 231: + try { + } catch (ArithmeticException a_e) { + } + case 251: + case 179: + f += (((i6 * sFld) + i4) - + iFld); + } + } + long meth_res = i1 + i2 + i3 + i4 + i5 + i6 + i7 + Float.floatToIntBits(f) + + Double.doubleToLongBits(d) + +checkSum(iArr) + + checkSum(lArr); + return meth_res; + } + + public static long checkSum(int[] a) { + long sum = 0; + for (int j = 0; j < a.length; j++) + sum += (a[j] / (j + 1) + a[j] % (j + 1)); + return sum; + } + + public static long checkSum(long[] a) { + long sum = 0; + for (int j = 0; j < a.length; j++) + sum += (a[j] / (j + 1) + a[j] % (j + 1)); + return sum; + } + + public static void main(String[] strArr) { + for (int i = 0; i < 10; i++) + lMeth(-159); + } +} From 173c3f9852672f6c917e975383172c8878ba7e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Mon, 2 Feb 2026 14:57:14 +0000 Subject: [PATCH 287/328] 8376479: Http3 test server thread deadlock in ThrowingPublishersInRequest Co-authored-by: Volkan Yazici Reviewed-by: dfuchs --- .../test/lib/http3/Http3ServerExchange.java | 4 +- .../test/lib/http3/Http3ServerStreamImpl.java | 87 ++++++++----------- 2 files changed, 36 insertions(+), 55 deletions(-) diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3ServerExchange.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3ServerExchange.java index c127abf3c0f..1c61f00d164 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3ServerExchange.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3ServerExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, 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 @@ -175,7 +175,7 @@ public final class Http3ServerExchange implements Http2TestExchange { } serverStream.writer.reset(Http3Error.H3_INTERNAL_ERROR.code()); } - is.close(io); + is.resetStream(io); os.closeInternal(); close(); } diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3ServerStreamImpl.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3ServerStreamImpl.java index c5a8709346c..ebe92fa3bac 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3ServerStreamImpl.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3ServerStreamImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import java.util.Objects; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; @@ -264,7 +265,7 @@ final class Http3ServerStreamImpl { // nothing to do - let the response be sent to the client, but throw an // exception if `is` is used again. exchangeCF.thenApply(en -> { - en.is.close(new IOException("stopSendingRequested")); + en.is.resetStream(new IOException("stopSendingRequested")); return en; }); return; @@ -292,38 +293,37 @@ final class Http3ServerStreamImpl { } class RequestBodyInputStream extends InputStream { - volatile IOException error; - volatile boolean closed; + // Non-null if the stream is terminated. + // Points to an IOException on error, or Boolean.TRUE on EOF. + private final AtomicReference closeReason = new AtomicReference<>(); // uses an unbounded blocking queue in which the readrLoop // publishes the DataFrames payload... ByteBuffer current; - // Use lock to avoid pinned threads on the blocking queue - final ReentrantLock lock = new ReentrantLock(); ByteBuffer current() throws IOException { - lock.lock(); - try { - while (true) { - if (current != null && current.hasRemaining()) { - return current; - } - if (current == QuicStreamReader.EOF) return current; - try { - if (debug.on()) - debug.log("Taking buffer from queue"); - // Blocking call - current = requestBodyQueue.take(); - } catch (InterruptedException e) { - var io = new InterruptedIOException(); - Thread.currentThread().interrupt(); - io.initCause(e); - close(io); - var error = this.error; - if (error != null) throw error; + while (true) { + Object reason = closeReason.get(); + if (reason != null) { + if (reason == Boolean.TRUE) { + throw new IOException("Stream is closed"); + } else { + throw new IOException((IOException)reason); } } - } finally { - lock.unlock(); + if (current != null && (current.hasRemaining() || current == QuicStreamReader.EOF)) { + return current; + } + try { + if (debug.on()) + debug.log("Taking buffer from queue"); + // Blocking call + current = requestBodyQueue.take(); + } catch (InterruptedException e) { + var io = new InterruptedIOException(); + Thread.currentThread().interrupt(); + io.initCause(e); + throw io; + } } } @@ -331,9 +331,7 @@ final class Http3ServerStreamImpl { public int read() throws IOException { ByteBuffer buffer = current(); if (buffer == QuicStreamReader.EOF) { - var error = this.error; - if (error == null) return -1; - throw error; + return -1; } return buffer.get() & 0xFF; } @@ -345,11 +343,7 @@ final class Http3ServerStreamImpl { while (remaining > 0) { ByteBuffer buffer = current(); if (buffer == QuicStreamReader.EOF) { - if (len == remaining) { - var error = this.error; - if (error == null) return -1; - throw error; - } else return len - remaining; + return len == remaining ? -1 : len - remaining; } int count = Math.min(buffer.remaining(), remaining); buffer.get(b, off + (len - remaining), count); @@ -360,33 +354,20 @@ final class Http3ServerStreamImpl { @Override public void close() throws IOException { - lock.lock(); - try { - if (closed) return; - closed = true; - - } finally { - lock.unlock(); - } + if (closeReason.getAndSet(Boolean.TRUE) == Boolean.TRUE) return; if (debug.on()) debug.log("Closing request body input stream"); requestBodyQueue.add(QuicStreamReader.EOF); + stream.requestStopSending(Http3Error.H3_NO_ERROR.code()); } - void close(IOException io) { - lock.lock(); - try { - if (closed) return; - closed = true; - error = io; - } finally { - lock.unlock(); - } + void resetStream(IOException io) { + if (!closeReason.compareAndSet(null, io)) return; if (debug.on()) { debug.log("Closing request body input stream: " + io); } - requestBodyQueue.clear(); requestBodyQueue.add(QuicStreamReader.EOF); + stream.requestStopSending(Http3Error.H3_NO_ERROR.code()); } } From b7128b7c30f3de2c1dcee2be567bb25d407c71a2 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 2 Feb 2026 15:16:35 +0000 Subject: [PATCH 288/328] 8376357: Parallel: Convert MutableSpace classes to use Atomic Reviewed-by: dholmes, iwalulya --- .../share/gc/parallel/mutableNUMASpace.cpp | 6 ++--- .../share/gc/parallel/mutableSpace.cpp | 17 +++++--------- .../share/gc/parallel/mutableSpace.hpp | 22 +++++++++---------- .../gc/parallel/vmStructs_parallelgc.hpp | 4 ++-- 4 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp index e0b1edf2efc..c5d112ffbc1 100644 --- a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp +++ b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2026, 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,7 +31,7 @@ #include "memory/allocation.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.hpp" -#include "runtime/atomicAccess.hpp" +#include "runtime/atomic.hpp" #include "runtime/java.hpp" #include "runtime/javaThread.hpp" #include "runtime/os.inline.hpp" @@ -489,7 +489,7 @@ HeapWord* MutableNUMASpace::cas_allocate(size_t size) { if (p != nullptr) { HeapWord* cur_top, *cur_chunk_top = p + size; while ((cur_top = top()) < cur_chunk_top) { // Keep _top updated. - if (AtomicAccess::cmpxchg(top_addr(), cur_top, cur_chunk_top) == cur_top) { + if (top_addr()->compare_set(cur_top, cur_chunk_top)) { break; } } diff --git a/src/hotspot/share/gc/parallel/mutableSpace.cpp b/src/hotspot/share/gc/parallel/mutableSpace.cpp index fc42fc1eab2..d99db493989 100644 --- a/src/hotspot/share/gc/parallel/mutableSpace.cpp +++ b/src/hotspot/share/gc/parallel/mutableSpace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ #include "memory/iterator.inline.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/javaThread.hpp" #include "runtime/safepoint.hpp" #include "utilities/align.hpp" @@ -123,7 +122,7 @@ void MutableSpace::initialize(MemRegion mr, // makes the new space available for allocation by other threads. So this // assignment must follow all other configuration and initialization that // might be done for expansion. - AtomicAccess::release_store(end_addr(), mr.end()); + _end.release_store(mr.end()); if (clear_space) { clear(mangle_space); @@ -140,7 +139,7 @@ void MutableSpace::clear(bool mangle_space) { #ifndef PRODUCT void MutableSpace::mangle_unused_area() { - mangle_region(MemRegion(_top, _end)); + mangle_region(MemRegion(top(), end())); } void MutableSpace::mangle_region(MemRegion mr) { @@ -155,14 +154,10 @@ HeapWord* MutableSpace::cas_allocate(size_t size) { // If end is read first, other threads may advance end and top such that // current top > old end and current top + size > current end. Then // pointer_delta underflows, allowing installation of top > current end. - HeapWord* obj = AtomicAccess::load_acquire(top_addr()); + HeapWord* obj = _top.load_acquire(); if (pointer_delta(end(), obj) >= size) { HeapWord* new_top = obj + size; - HeapWord* result = AtomicAccess::cmpxchg(top_addr(), obj, new_top); - // result can be one of two: - // the old top value: the exchange succeeded - // otherwise: the new value of the top is returned. - if (result != obj) { + if (!_top.compare_set(obj, new_top)) { continue; // another thread beat us to the allocation, try again } assert(is_object_aligned(obj) && is_object_aligned(new_top), @@ -177,7 +172,7 @@ HeapWord* MutableSpace::cas_allocate(size_t size) { // Try to deallocate previous allocation. Returns true upon success. bool MutableSpace::cas_deallocate(HeapWord *obj, size_t size) { HeapWord* expected_top = obj + size; - return AtomicAccess::cmpxchg(top_addr(), expected_top, obj) == expected_top; + return _top.compare_set(expected_top, obj); } void MutableSpace::oop_iterate(OopIterateClosure* cl) { diff --git a/src/hotspot/share/gc/parallel/mutableSpace.hpp b/src/hotspot/share/gc/parallel/mutableSpace.hpp index 9d3894e2489..28df19a7c4b 100644 --- a/src/hotspot/share/gc/parallel/mutableSpace.hpp +++ b/src/hotspot/share/gc/parallel/mutableSpace.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "memory/allocation.hpp" #include "memory/iterator.hpp" #include "memory/memRegion.hpp" +#include "runtime/atomic.hpp" #include "utilities/copy.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" @@ -53,8 +54,8 @@ class MutableSpace: public CHeapObj { MemRegion _last_setup_region; size_t _page_size; HeapWord* _bottom; - HeapWord* volatile _top; - HeapWord* _end; + Atomic _top; + Atomic _end; void numa_setup_pages(MemRegion mr, bool clear_space); @@ -64,21 +65,20 @@ class MutableSpace: public CHeapObj { protected: size_t page_size() const { return _page_size; } + Atomic* top_addr() { return &_top; } + public: virtual ~MutableSpace() = default; MutableSpace(size_t page_size); // Accessors HeapWord* bottom() const { return _bottom; } - HeapWord* top() const { return _top; } - HeapWord* end() const { return _end; } + HeapWord* top() const { return _top.load_relaxed(); } + HeapWord* end() const { return _end.load_relaxed(); } void set_bottom(HeapWord* value) { _bottom = value; } - virtual void set_top(HeapWord* value) { _top = value; } - void set_end(HeapWord* value) { _end = value; } - - HeapWord* volatile* top_addr() { return &_top; } - HeapWord** end_addr() { return &_end; } + virtual void set_top(HeapWord* value) { _top.store_relaxed(value); } + void set_end(HeapWord* value) { _end.store_relaxed(value); } MemRegion region() const { return MemRegion(bottom(), end()); } @@ -110,7 +110,7 @@ public: // Boolean queries. bool is_empty() const { return used_in_words() == 0; } bool not_empty() const { return used_in_words() > 0; } - bool contains(const void* p) const { return _bottom <= p && p < _end; } + bool contains(const void* p) const { return _bottom <= p && p < end(); } // Size computations. Sizes are in bytes. size_t used_in_bytes() const { return used_in_words() * HeapWordSize; } diff --git a/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp b/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp index f69219a1f40..f8dabc4539e 100644 --- a/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp +++ b/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp @@ -47,8 +47,8 @@ nonstatic_field(PSVirtualSpace, _committed_high_addr, char*) \ \ nonstatic_field(MutableSpace, _bottom, HeapWord*) \ - nonstatic_field(MutableSpace, _end, HeapWord*) \ - volatile_nonstatic_field(MutableSpace, _top, HeapWord*) \ + nonstatic_field(MutableSpace, _end, Atomic) \ + volatile_nonstatic_field(MutableSpace, _top, Atomic) \ \ nonstatic_field(PSYoungGen, _reserved, MemRegion) \ nonstatic_field(PSYoungGen, _virtual_space, PSVirtualSpace*) \ From 903b3fe19596adaeac7cfb0d749b6e83f668f52f Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 2 Feb 2026 15:19:15 +0000 Subject: [PATCH 289/328] 8375438: G1: Convert G1HeapRegion related classes to use Atomic Reviewed-by: shade, iwalulya --- src/hotspot/share/gc/g1/g1HeapRegion.cpp | 14 +++---- src/hotspot/share/gc/g1/g1HeapRegion.hpp | 21 ++++++----- .../share/gc/g1/g1HeapRegion.inline.hpp | 37 ++++++++++++------- .../share/gc/g1/g1HeapRegionManager.cpp | 13 ++++--- .../share/gc/g1/g1HeapRegionManager.hpp | 5 ++- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 1 + src/hotspot/share/gc/g1/vmStructs_g1.hpp | 5 ++- src/hotspot/share/runtime/vmStructs.cpp | 2 + 8 files changed, 57 insertions(+), 41 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.cpp b/src/hotspot/share/gc/g1/g1HeapRegion.cpp index 361e19d4be5..2052a3ce156 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -44,7 +44,7 @@ #include "oops/access.inline.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" +#include "runtime/atomic.hpp" #include "runtime/globals_extension.hpp" #include "utilities/powerOfTwo.hpp" @@ -131,8 +131,8 @@ void G1HeapRegion::hr_clear(bool clear_space) { G1CollectedHeap::heap()->concurrent_mark()->reset_top_at_mark_start(this); - _parsable_bottom = bottom(); - _garbage_bytes = 0; + _parsable_bottom.store_relaxed(bottom()); + _garbage_bytes.store_relaxed(0); _incoming_refs = 0; if (clear_space) clear(SpaceDecorator::Mangle); @@ -294,12 +294,12 @@ void G1HeapRegion::report_region_type_change(G1HeapRegionTraceType::Type to) { // young gen regions never have their PB set to anything other than bottom. assert(parsable_bottom_acquire() == bottom(), "must be"); - _garbage_bytes = 0; + _garbage_bytes.store_relaxed(0); _incoming_refs = 0; } void G1HeapRegion::note_self_forward_chunk_done(size_t garbage_bytes) { - AtomicAccess::add(&_garbage_bytes, garbage_bytes, memory_order_relaxed); + _garbage_bytes.add_then_fetch(garbage_bytes, memory_order_relaxed); } // Code roots support @@ -448,7 +448,7 @@ void G1HeapRegion::print_on(outputStream* st) const { st->print("|-"); } } - st->print("|%3zu", AtomicAccess::load(&_pinned_object_count)); + st->print("|%3zu", _pinned_object_count.load_relaxed()); st->print_cr(""); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.hpp index fe915b0dafe..2b4b640d52b 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -33,6 +33,7 @@ #include "gc/shared/ageTable.hpp" #include "gc/shared/spaceDecorator.hpp" #include "gc/shared/verifyOption.hpp" +#include "runtime/atomic.hpp" #include "runtime/mutex.hpp" #include "utilities/macros.hpp" @@ -73,7 +74,7 @@ class G1HeapRegion : public CHeapObj { HeapWord* const _bottom; HeapWord* const _end; - HeapWord* volatile _top; + Atomic _top; G1BlockOffsetTable* _bot; @@ -89,8 +90,8 @@ public: HeapWord* bottom() const { return _bottom; } HeapWord* end() const { return _end; } - void set_top(HeapWord* value) { _top = value; } - HeapWord* top() const { return _top; } + void set_top(HeapWord* value) { _top.store_relaxed(value); } + HeapWord* top() const { return _top.load_relaxed(); } // See the comment above in the declaration of _pre_dummy_top for an // explanation of what it is. @@ -231,10 +232,10 @@ private: // // Below this limit the marking bitmap must be used to determine size and // liveness. - HeapWord* volatile _parsable_bottom; + Atomic _parsable_bottom; // Amount of dead data in the region. - size_t _garbage_bytes; + Atomic _garbage_bytes; // Approximate number of references to this regions at the end of concurrent // marking. We we do not mark through all objects, so this is an estimate. @@ -249,7 +250,7 @@ private: uint _node_index; // Number of objects in this region that are currently pinned. - volatile size_t _pinned_object_count; + Atomic _pinned_object_count; void report_region_type_change(G1HeapRegionTraceType::Type to); @@ -331,7 +332,7 @@ public: } // A lower bound on the amount of garbage bytes in the region. - size_t garbage_bytes() const { return _garbage_bytes; } + size_t garbage_bytes() const { return _garbage_bytes.load_relaxed(); } // Return the amount of bytes we'll reclaim if we collect this // region. This includes not only the known garbage bytes in the @@ -393,8 +394,8 @@ public: bool is_old_or_humongous() const { return _type.is_old_or_humongous(); } - size_t pinned_count() const { return AtomicAccess::load(&_pinned_object_count); } - bool has_pinned_objects() const { return pinned_count() > 0; } + inline size_t pinned_count() const; + inline bool has_pinned_objects() const; void set_free(); diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp index f25bf62c9be..4f242b7a537 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,6 @@ #include "gc/g1/g1Policy.hpp" #include "gc/g1/g1Predictions.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/init.hpp" #include "runtime/prefetch.inline.hpp" #include "runtime/safepoint.hpp" @@ -131,7 +130,7 @@ inline void G1HeapRegion::prepare_for_full_gc() { // After marking and class unloading the heap temporarily contains dead objects // with unloaded klasses. Moving parsable_bottom makes some (debug) code correctly // skip dead objects. - _parsable_bottom = top(); + _parsable_bottom.store_relaxed(top()); } inline void G1HeapRegion::reset_compacted_after_full_gc(HeapWord* new_top) { @@ -154,7 +153,7 @@ inline void G1HeapRegion::reset_after_full_gc_common() { // Everything above bottom() is parsable and live. reset_parsable_bottom(); - _garbage_bytes = 0; + _garbage_bytes.store_relaxed(0); _incoming_refs = 0; @@ -188,20 +187,22 @@ inline void G1HeapRegion::apply_to_marked_objects(G1CMBitMap* bitmap, ApplyToMar inline HeapWord* G1HeapRegion::par_allocate(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size) { + HeapWord* obj = top(); do { - HeapWord* obj = top(); size_t available = pointer_delta(end(), obj); size_t want_to_allocate = MIN2(available, desired_word_size); if (want_to_allocate >= min_word_size) { HeapWord* new_top = obj + want_to_allocate; - HeapWord* result = AtomicAccess::cmpxchg(&_top, obj, new_top); - // result can be one of two: - // the old top value: the exchange succeeded + HeapWord* result = _top.compare_exchange(obj, new_top); + // Result can be one of two: + // the old top value: the exchange succeeded, return. // otherwise: the new value of the top is returned. if (result == obj) { assert(is_object_aligned(obj) && is_object_aligned(new_top), "checking alignment"); *actual_word_size = want_to_allocate; return obj; + } else { + obj = result; } } else { return nullptr; @@ -254,27 +255,27 @@ inline void G1HeapRegion::update_bot_for_block(HeapWord* start, HeapWord* end) { inline HeapWord* G1HeapRegion::parsable_bottom() const { assert(!is_init_completed() || SafepointSynchronize::is_at_safepoint(), "only during initialization or safepoint"); - return _parsable_bottom; + return _parsable_bottom.load_relaxed(); } inline HeapWord* G1HeapRegion::parsable_bottom_acquire() const { - return AtomicAccess::load_acquire(&_parsable_bottom); + return _parsable_bottom.load_acquire(); } inline void G1HeapRegion::reset_parsable_bottom() { - AtomicAccess::release_store(&_parsable_bottom, bottom()); + _parsable_bottom.release_store(bottom()); } inline void G1HeapRegion::note_end_of_marking(HeapWord* top_at_mark_start, size_t marked_bytes, size_t incoming_refs) { assert_at_safepoint(); if (top_at_mark_start != bottom()) { - _garbage_bytes = byte_size(bottom(), top_at_mark_start) - marked_bytes; + _garbage_bytes.store_relaxed(byte_size(bottom(), top_at_mark_start) - marked_bytes); _incoming_refs = incoming_refs; } if (needs_scrubbing()) { - _parsable_bottom = top_at_mark_start; + _parsable_bottom.store_relaxed(top_at_mark_start); } } @@ -286,6 +287,14 @@ inline bool G1HeapRegion::needs_scrubbing() const { return is_old(); } +inline size_t G1HeapRegion::pinned_count() const { + return _pinned_object_count.load_relaxed(); +} + +inline bool G1HeapRegion::has_pinned_objects() const { + return pinned_count() > 0; +} + inline bool G1HeapRegion::in_collection_set() const { return G1CollectedHeap::heap()->is_in_cset(this); } @@ -511,7 +520,7 @@ inline void G1HeapRegion::record_surv_words_in_group(size_t words_survived) { inline void G1HeapRegion::add_pinned_object_count(size_t value) { assert(value != 0, "wasted effort"); assert(!is_free(), "trying to pin free region %u, adding %zu", hrm_index(), value); - AtomicAccess::add(&_pinned_object_count, value, memory_order_relaxed); + _pinned_object_count.add_then_fetch(value, memory_order_relaxed); } inline void G1HeapRegion::install_cset_group(G1CSetCandidateGroup* cset_group) { diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp index 795b6543bae..44897c8a277 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -713,8 +713,10 @@ void G1HeapRegionManager::verify_optional() { G1HeapRegionClaimer::G1HeapRegionClaimer(uint n_workers) : _n_workers(n_workers), _n_regions(G1CollectedHeap::heap()->_hrm._next_highest_used_hrm_index), _claims(nullptr) { - uint* new_claims = NEW_C_HEAP_ARRAY(uint, _n_regions, mtGC); - memset(new_claims, Unclaimed, sizeof(*_claims) * _n_regions); + Atomic* new_claims = NEW_C_HEAP_ARRAY(Atomic, _n_regions, mtGC); + for (uint i = 0; i < _n_regions; i++) { + new_claims[i].store_relaxed(Unclaimed); + } _claims = new_claims; } @@ -730,13 +732,12 @@ uint G1HeapRegionClaimer::offset_for_worker(uint worker_id) const { bool G1HeapRegionClaimer::is_region_claimed(uint region_index) const { assert(region_index < _n_regions, "Invalid index."); - return _claims[region_index] == Claimed; + return _claims[region_index].load_relaxed() == Claimed; } bool G1HeapRegionClaimer::claim_region(uint region_index) { assert(region_index < _n_regions, "Invalid index."); - uint old_val = AtomicAccess::cmpxchg(&_claims[region_index], Unclaimed, Claimed); - return old_val == Unclaimed; + return _claims[region_index].compare_set(Unclaimed, Claimed); } class G1RebuildFreeListTask : public WorkerTask { diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp index b4ce3b0a8be..eb593ff408e 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ #include "gc/g1/g1HeapRegionSet.hpp" #include "gc/g1/g1RegionToSpaceMapper.hpp" #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" #include "services/memoryUsage.hpp" class G1HeapRegion; @@ -294,7 +295,7 @@ public: class G1HeapRegionClaimer : public StackObj { uint _n_workers; uint _n_regions; - volatile uint* _claims; + Atomic* _claims; static const uint Unclaimed = 0; static const uint Claimed = 1; diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index 36cc44a8b7c..a9db9a7c269 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -36,6 +36,7 @@ #include "gc/g1/g1EvacFailureRegions.inline.hpp" #include "gc/g1/g1EvacInfo.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" +#include "gc/g1/g1HeapRegion.inline.hpp" #include "gc/g1/g1HeapRegionPrinter.hpp" #include "gc/g1/g1MonitoringSupport.hpp" #include "gc/g1/g1ParScanThreadState.inline.hpp" diff --git a/src/hotspot/share/gc/g1/vmStructs_g1.hpp b/src/hotspot/share/gc/g1/vmStructs_g1.hpp index 21c86d47a6b..af236ec8581 100644 --- a/src/hotspot/share/gc/g1/vmStructs_g1.hpp +++ b/src/hotspot/share/gc/g1/vmStructs_g1.hpp @@ -28,6 +28,7 @@ #include "gc/g1/g1CollectedHeap.hpp" #include "gc/g1/g1HeapRegion.hpp" #include "gc/g1/g1HeapRegionManager.hpp" +#include "runtime/atomic.hpp" #include "utilities/macros.hpp" #define VM_STRUCTS_G1GC(nonstatic_field, \ @@ -39,9 +40,9 @@ \ nonstatic_field(G1HeapRegion, _type, G1HeapRegionType) \ nonstatic_field(G1HeapRegion, _bottom, HeapWord* const) \ - nonstatic_field(G1HeapRegion, _top, HeapWord* volatile) \ + nonstatic_field(G1HeapRegion, _top, Atomic) \ nonstatic_field(G1HeapRegion, _end, HeapWord* const) \ - volatile_nonstatic_field(G1HeapRegion, _pinned_object_count, size_t) \ + volatile_nonstatic_field(G1HeapRegion, _pinned_object_count, Atomic)\ \ nonstatic_field(G1HeapRegionType, _tag, G1HeapRegionType::Tag volatile) \ \ diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 02572e16728..f65a3441bf4 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -79,6 +79,7 @@ #include "oops/typeArrayOop.hpp" #include "prims/jvmtiAgentThread.hpp" #include "runtime/arguments.hpp" +#include "runtime/atomic.hpp" #include "runtime/deoptimization.hpp" #include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" @@ -888,6 +889,7 @@ declare_unsigned_integer_type(unsigned short) \ declare_unsigned_integer_type(jushort) \ declare_unsigned_integer_type(unsigned long) \ + declare_unsigned_integer_type(Atomic) \ /* The compiler thinks this is a different type than */ \ /* unsigned short on Win32 */ \ declare_unsigned_integer_type(u1) \ From 9871e2d3f771ee2bc1b2473c0eb28a0bfc1c5456 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 2 Feb 2026 16:03:04 +0000 Subject: [PATCH 290/328] 8375535: G1: Convert CardTableBarrierSet and subclasses to use Atomic Reviewed-by: kbarrett, iwalulya --- src/hotspot/share/gc/g1/g1BarrierSet.cpp | 22 +++++++++---------- src/hotspot/share/gc/g1/g1BarrierSet.hpp | 7 +++--- .../share/gc/g1/g1BarrierSet.inline.hpp | 6 ++--- .../share/gc/shared/cardTableBarrierSet.cpp | 10 ++++----- .../share/gc/shared/cardTableBarrierSet.hpp | 11 ++++++---- .../gc/shared/cardTableBarrierSet.inline.hpp | 4 ++-- src/hotspot/share/gc/shared/vmStructs_gc.hpp | 4 +++- 7 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1BarrierSet.cpp b/src/hotspot/share/gc/g1/g1BarrierSet.cpp index 622651ce0d8..dee50500e07 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSet.cpp +++ b/src/hotspot/share/gc/g1/g1BarrierSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -64,13 +64,13 @@ G1BarrierSet::G1BarrierSet(G1CardTable* card_table, {} G1BarrierSet::~G1BarrierSet() { - delete _refinement_table; + delete refinement_table(); } void G1BarrierSet::swap_global_card_table() { - G1CardTable* temp = static_cast(_card_table); - _card_table = _refinement_table; - _refinement_table = temp; + G1CardTable* temp = static_cast(card_table()); + _card_table.store_relaxed(refinement_table()); + _refinement_table.store_relaxed(temp); } void G1BarrierSet::update_card_table_base(Thread* thread) { @@ -80,7 +80,7 @@ void G1BarrierSet::update_card_table_base(Thread* thread) { assert(thread->is_Java_thread(), "may only update card table base of JavaThreads, not %s", thread->name()); } #endif - G1ThreadLocalData::set_byte_map_base(thread, _card_table->byte_map_base()); + G1ThreadLocalData::set_byte_map_base(thread, card_table()->byte_map_base()); } template void @@ -135,10 +135,10 @@ void G1BarrierSet::write_region(MemRegion mr) { // marks next time. // If we write to the old card table (after the switching, then the refinement // table) the oncoming handshake will do the memory synchronization. - CardTable* card_table = AtomicAccess::load(&_card_table); + CardTable* local_card_table = card_table(); - volatile CardValue* byte = card_table->byte_for(mr.start()); - CardValue* last_byte = card_table->byte_for(mr.last()); + volatile CardValue* byte = local_card_table->byte_for(mr.start()); + CardValue* last_byte = local_card_table->byte_for(mr.last()); // Dirty cards only if necessary. for (; byte <= last_byte; byte++) { @@ -190,6 +190,6 @@ void G1BarrierSet::on_thread_detach(Thread* thread) { } void G1BarrierSet::print_on(outputStream* st) const { - _card_table->print_on(st, "Card"); - _refinement_table->print_on(st, "Refinement"); + card_table()->print_on(st, "Card"); + refinement_table()->print_on(st, "Refinement"); } diff --git a/src/hotspot/share/gc/g1/g1BarrierSet.hpp b/src/hotspot/share/gc/g1/g1BarrierSet.hpp index bf595973a32..406096acf10 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSet.hpp +++ b/src/hotspot/share/gc/g1/g1BarrierSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -29,6 +29,7 @@ #include "gc/shared/bufferNode.hpp" #include "gc/shared/cardTable.hpp" #include "gc/shared/cardTableBarrierSet.hpp" +#include "runtime/atomic.hpp" class G1CardTable; class Thread; @@ -66,7 +67,7 @@ class G1BarrierSet: public CardTableBarrierSet { BufferNode::Allocator _satb_mark_queue_buffer_allocator; G1SATBMarkQueueSet _satb_mark_queue_set; - G1CardTable* _refinement_table; + Atomic _refinement_table; public: G1BarrierSet(G1CardTable* card_table, G1CardTable* refinement_table); @@ -76,7 +77,7 @@ class G1BarrierSet: public CardTableBarrierSet { return barrier_set_cast(BarrierSet::barrier_set()); } - G1CardTable* refinement_table() const { return _refinement_table; } + G1CardTable* refinement_table() const { return _refinement_table.load_relaxed(); } // Swap the global card table references, without synchronization. void swap_global_card_table(); diff --git a/src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp b/src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp index 794e5db0634..54892c9191d 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,8 +73,8 @@ inline void G1BarrierSet::write_ref_field_post(T* field) { // Make sure that the card table reference is read only once. Otherwise the compiler // might reload that value in the two accesses below, that could cause writes to // the wrong card table. - CardTable* card_table = AtomicAccess::load(&_card_table); - CardValue* byte = card_table->byte_for(field); + CardTable* local_card_table = card_table(); + CardValue* byte = local_card_table->byte_for(field); if (*byte == G1CardTable::clean_card_val()) { *byte = G1CardTable::dirty_card_val(); } diff --git a/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp b/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp index 539e40820a8..d6541198858 100644 --- a/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp +++ b/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,15 +73,15 @@ CardTableBarrierSet::CardTableBarrierSet(CardTable* card_table) : {} CardTableBarrierSet::~CardTableBarrierSet() { - delete _card_table; + delete card_table(); } void CardTableBarrierSet::write_region(MemRegion mr) { - _card_table->dirty_MemRegion(mr); + card_table()->dirty_MemRegion(mr); } void CardTableBarrierSet::print_on(outputStream* st) const { - _card_table->print_on(st); + card_table()->print_on(st); } // Helper for ReduceInitialCardMarks. For performance, @@ -116,7 +116,7 @@ void CardTableBarrierSet::on_slowpath_allocation_exit(JavaThread* thread, oop ne if (!ReduceInitialCardMarks) { return; } - if (new_obj->is_typeArray() || _card_table->is_in_young(new_obj)) { + if (new_obj->is_typeArray() || card_table()->is_in_young(new_obj)) { // Arrays of non-references don't need a post-barrier. } else { MemRegion mr(cast_from_oop(new_obj), new_obj->size()); diff --git a/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp b/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp index c298bfcd0c2..3a9b46d9df8 100644 --- a/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp +++ b/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -29,6 +29,7 @@ #include "gc/shared/cardTable.hpp" #include "gc/shared/gc_globals.hpp" #include "memory/memRegion.hpp" +#include "runtime/atomic.hpp" #include "utilities/align.hpp" // This kind of "BarrierSet" allows a "CollectedHeap" to detect and @@ -49,7 +50,7 @@ class CardTableBarrierSet: public BarrierSet { protected: typedef CardTable::CardValue CardValue; - CardTable* _card_table; + Atomic _card_table; CardTableBarrierSet(BarrierSetAssembler* barrier_set_assembler, BarrierSetC1* barrier_set_c1, @@ -90,10 +91,12 @@ public: // at the address "start", which may not necessarily be HeapWord-aligned inline void write_ref_array(HeapWord* start, size_t count); - CardTable* card_table() const { return _card_table; } + CardTable* card_table() { return _card_table.load_relaxed(); } + CardTable* card_table() const { return _card_table.load_relaxed(); } + CardValue* card_table_base_const() const { assert(UseSerialGC || UseParallelGC, "Only these GCs have constant card table base"); - return _card_table->byte_map_base(); + return card_table()->byte_map_base(); } virtual void on_slowpath_allocation_exit(JavaThread* thread, oop new_obj); diff --git a/src/hotspot/share/gc/shared/cardTableBarrierSet.inline.hpp b/src/hotspot/share/gc/shared/cardTableBarrierSet.inline.hpp index ea539a70be5..f60a7f47a19 100644 --- a/src/hotspot/share/gc/shared/cardTableBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/shared/cardTableBarrierSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ template inline void CardTableBarrierSet::write_ref_field_post(T* field) { - volatile CardValue* byte = _card_table->byte_for(field); + volatile CardValue* byte = card_table()->byte_for(field); *byte = CardTable::dirty_card_val(); } diff --git a/src/hotspot/share/gc/shared/vmStructs_gc.hpp b/src/hotspot/share/gc/shared/vmStructs_gc.hpp index 6a29eb25b37..9348fd980f4 100644 --- a/src/hotspot/share/gc/shared/vmStructs_gc.hpp +++ b/src/hotspot/share/gc/shared/vmStructs_gc.hpp @@ -48,6 +48,7 @@ #if INCLUDE_ZGC #include "gc/z/vmStructs_z.hpp" #endif +#include "runtime/atomic.hpp" #define VM_STRUCTS_GC(nonstatic_field, \ volatile_static_field, \ @@ -88,7 +89,7 @@ nonstatic_field(CardTable, _byte_map_size, const size_t) \ nonstatic_field(CardTable, _byte_map, CardTable::CardValue*) \ nonstatic_field(CardTable, _byte_map_base, CardTable::CardValue*) \ - nonstatic_field(CardTableBarrierSet, _card_table, CardTable*) \ + nonstatic_field(CardTableBarrierSet, _card_table, Atomic) \ \ static_field(CollectedHeap, _lab_alignment_reserve, size_t) \ nonstatic_field(CollectedHeap, _reserved, MemRegion) \ @@ -149,6 +150,7 @@ \ declare_toplevel_type(BarrierSet*) \ declare_toplevel_type(CardTable*) \ + declare_toplevel_type(Atomic) \ declare_toplevel_type(CardTable*const) \ declare_toplevel_type(CardTableBarrierSet*) \ declare_toplevel_type(CardTableBarrierSet**) \ From 70f4984a4e1a43fd25169096ee0869361de2b9cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Galder=20Zamarre=C3=B1o?= Date: Mon, 2 Feb 2026 16:46:46 +0000 Subject: [PATCH 291/328] 8375640: MinMaxIdentity test fails on some machines after 8373134 Reviewed-by: mdoerr, mhaessig, amitkumar --- .../compiler/igvn/TestMinMaxIdentity.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/compiler/igvn/TestMinMaxIdentity.java b/test/hotspot/jtreg/compiler/igvn/TestMinMaxIdentity.java index d358359ff14..5b998caf65c 100644 --- a/test/hotspot/jtreg/compiler/igvn/TestMinMaxIdentity.java +++ b/test/hotspot/jtreg/compiler/igvn/TestMinMaxIdentity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 IBM Corporation. All rights reserved. + * Copyright (c) 2025, 2026 IBM Corporation. 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 @@ -122,8 +122,21 @@ public class TestMinMaxIdentity { let("arg2", arg2), """ @Test - @IR(counts = {IRNode.#op, "= 1"}, - phase = CompilePhase.BEFORE_MACRO_EXPANSION) + """, + type.isFloating() ? + """ + @IR(counts = {IRNode.#op, "= 1"}, + phase = CompilePhase.BEFORE_MACRO_EXPANSION, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + @IR(counts = {IRNode.#op, "= 1"}, + phase = CompilePhase.BEFORE_MACRO_EXPANSION, + applyIfPlatform = {"riscv64", "true"}) + """ : + """ + @IR(counts = {IRNode.#op, "= 1"}, + phase = CompilePhase.BEFORE_MACRO_EXPANSION) + """, + """ @Arguments(values = {Argument.NUMBER_42, Argument.NUMBER_42}) public #type $test(#type #arg1, #type #arg2) { int i; From b60249882cc511a7fc9cf9ae11e8beb1602ea10f Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 2 Feb 2026 16:57:47 +0000 Subject: [PATCH 292/328] 8376126: G1: Convert remaining volatiles in G1ConcurrentMark to Atomic Reviewed-by: iwalulya, kbarrett, stefank --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 70 +++++++++++-------- src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 32 ++++----- .../share/gc/g1/g1ConcurrentMark.inline.hpp | 14 ++-- .../share/gc/g1/g1RegionMarkStatsCache.hpp | 2 + 4 files changed, 64 insertions(+), 54 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 5f096c2b9d7..4ed0a3065bc 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -24,6 +24,7 @@ #include "classfile/classLoaderData.hpp" #include "classfile/classLoaderDataGraph.hpp" +#include "cppstdlib/new.hpp" #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1BatchedTask.hpp" #include "gc/g1/g1CardSetMemory.hpp" @@ -519,8 +520,8 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, _max_concurrent_workers(0), _region_mark_stats(NEW_C_HEAP_ARRAY(G1RegionMarkStats, _g1h->max_num_regions(), mtGC)), - _top_at_mark_starts(NEW_C_HEAP_ARRAY(HeapWord*, _g1h->max_num_regions(), mtGC)), - _top_at_rebuild_starts(NEW_C_HEAP_ARRAY(HeapWord*, _g1h->max_num_regions(), mtGC)), + _top_at_mark_starts(NEW_C_HEAP_ARRAY(Atomic, _g1h->max_num_regions(), mtGC)), + _top_at_rebuild_starts(NEW_C_HEAP_ARRAY(Atomic, _g1h->max_num_regions(), mtGC)), _needs_remembered_set_rebuild(false) { assert(G1CGC_lock != nullptr, "CGC_lock must be initialized"); @@ -564,6 +565,12 @@ void G1ConcurrentMark::fully_initialize() { _tasks[i] = new G1CMTask(i, this, task_queue, _region_mark_stats); } + for (uint i = 0; i < _g1h->max_num_regions(); i++) { + ::new (&_region_mark_stats[i]) G1RegionMarkStats{}; + ::new (&_top_at_mark_starts[i]) Atomic{}; + ::new (&_top_at_rebuild_starts[i]) Atomic{}; + } + reset_at_marking_complete(); } @@ -576,7 +583,7 @@ PartialArrayStateManager* G1ConcurrentMark::partial_array_state_manager() const } void G1ConcurrentMark::reset() { - _has_aborted = false; + _has_aborted.store_relaxed(false); reset_marking_for_restart(); @@ -588,7 +595,7 @@ void G1ConcurrentMark::reset() { uint max_num_regions = _g1h->max_num_regions(); for (uint i = 0; i < max_num_regions; i++) { - _top_at_rebuild_starts[i] = nullptr; + _top_at_rebuild_starts[i].store_relaxed(nullptr); _region_mark_stats[i].clear(); } @@ -600,7 +607,7 @@ void G1ConcurrentMark::clear_statistics(G1HeapRegion* r) { for (uint j = 0; j < _max_num_tasks; ++j) { _tasks[j]->clear_mark_stats_cache(region_idx); } - _top_at_rebuild_starts[region_idx] = nullptr; + _top_at_rebuild_starts[region_idx].store_relaxed(nullptr); _region_mark_stats[region_idx].clear(); } @@ -636,7 +643,7 @@ void G1ConcurrentMark::reset_marking_for_restart() { } clear_has_overflown(); - _finger = _heap.start(); + _finger.store_relaxed(_heap.start()); for (uint i = 0; i < _max_num_tasks; ++i) { G1CMTaskQueue* queue = _task_queues->queue(i); @@ -658,14 +665,14 @@ void G1ConcurrentMark::set_concurrency(uint active_tasks) { void G1ConcurrentMark::set_concurrency_and_phase(uint active_tasks, bool concurrent) { set_concurrency(active_tasks); - _concurrent = concurrent; + _concurrent.store_relaxed(concurrent); if (!concurrent) { // At this point we should be in a STW phase, and completed marking. assert_at_safepoint_on_vm_thread(); assert(out_of_regions(), "only way to get here: _finger: " PTR_FORMAT ", _heap_end: " PTR_FORMAT, - p2i(_finger), p2i(_heap.end())); + p2i(finger()), p2i(_heap.end())); } } @@ -696,8 +703,8 @@ void G1ConcurrentMark::reset_at_marking_complete() { } G1ConcurrentMark::~G1ConcurrentMark() { - FREE_C_HEAP_ARRAY(HeapWord*, _top_at_mark_starts); - FREE_C_HEAP_ARRAY(HeapWord*, _top_at_rebuild_starts); + FREE_C_HEAP_ARRAY(Atomic, _top_at_mark_starts); + FREE_C_HEAP_ARRAY(Atomic, _top_at_rebuild_starts); FREE_C_HEAP_ARRAY(G1RegionMarkStats, _region_mark_stats); // The G1ConcurrentMark instance is never freed. ShouldNotReachHere(); @@ -1164,7 +1171,7 @@ void G1ConcurrentMark::concurrent_cycle_start() { } uint G1ConcurrentMark::completed_mark_cycles() const { - return AtomicAccess::load(&_completed_mark_cycles); + return _completed_mark_cycles.load_relaxed(); } void G1ConcurrentMark::concurrent_cycle_end(bool mark_cycle_completed) { @@ -1173,7 +1180,7 @@ void G1ConcurrentMark::concurrent_cycle_end(bool mark_cycle_completed) { _g1h->trace_heap_after_gc(_gc_tracer_cm); if (mark_cycle_completed) { - AtomicAccess::inc(&_completed_mark_cycles, memory_order_relaxed); + _completed_mark_cycles.add_then_fetch(1u, memory_order_relaxed); } if (has_aborted()) { @@ -1187,7 +1194,7 @@ void G1ConcurrentMark::concurrent_cycle_end(bool mark_cycle_completed) { } void G1ConcurrentMark::mark_from_roots() { - _restart_for_overflow = false; + _restart_for_overflow.store_relaxed(false); uint active_workers = calc_active_marking_workers(); @@ -1356,7 +1363,7 @@ void G1ConcurrentMark::remark() { } } else { // We overflowed. Restart concurrent marking. - _restart_for_overflow = true; + _restart_for_overflow.store_relaxed(true); verify_during_pause(G1HeapVerifier::G1VerifyRemark, VerifyLocation::RemarkOverflow); @@ -1785,44 +1792,45 @@ void G1ConcurrentMark::clear_bitmap_for_region(G1HeapRegion* hr) { } G1HeapRegion* G1ConcurrentMark::claim_region(uint worker_id) { - // "checkpoint" the finger - HeapWord* finger = _finger; + // "Checkpoint" the finger. + HeapWord* local_finger = finger(); - while (finger < _heap.end()) { - assert(_g1h->is_in_reserved(finger), "invariant"); + while (local_finger < _heap.end()) { + assert(_g1h->is_in_reserved(local_finger), "invariant"); - G1HeapRegion* curr_region = _g1h->heap_region_containing_or_null(finger); + G1HeapRegion* curr_region = _g1h->heap_region_containing_or_null(local_finger); // Make sure that the reads below do not float before loading curr_region. OrderAccess::loadload(); // Above heap_region_containing may return null as we always scan claim // until the end of the heap. In this case, just jump to the next region. - HeapWord* end = curr_region != nullptr ? curr_region->end() : finger + G1HeapRegion::GrainWords; + HeapWord* end = curr_region != nullptr ? curr_region->end() : local_finger + G1HeapRegion::GrainWords; // Is the gap between reading the finger and doing the CAS too long? - HeapWord* res = AtomicAccess::cmpxchg(&_finger, finger, end); - if (res == finger && curr_region != nullptr) { - // we succeeded + HeapWord* res = _finger.compare_exchange(local_finger, end); + if (res == local_finger && curr_region != nullptr) { + // We succeeded. HeapWord* bottom = curr_region->bottom(); HeapWord* limit = top_at_mark_start(curr_region); log_trace(gc, marking)("Claim region %u bottom " PTR_FORMAT " tams " PTR_FORMAT, curr_region->hrm_index(), p2i(curr_region->bottom()), p2i(top_at_mark_start(curr_region))); - // notice that _finger == end cannot be guaranteed here since, - // someone else might have moved the finger even further - assert(_finger >= end, "the finger should have moved forward"); + // Notice that _finger == end cannot be guaranteed here since, + // someone else might have moved the finger even further. + assert(finger() >= end, "The finger should have moved forward"); if (limit > bottom) { return curr_region; } else { assert(limit == bottom, - "the region limit should be at bottom"); + "The region limit should be at bottom"); // We return null and the caller should try calling // claim_region() again. return nullptr; } } else { - assert(_finger > finger, "the finger should have moved forward"); - // read it again - finger = _finger; + // Read the finger again. + HeapWord* next_finger = finger(); + assert(next_finger > local_finger, "The finger should have moved forward " PTR_FORMAT " " PTR_FORMAT, p2i(local_finger), p2i(next_finger)); + local_finger = next_finger; } } @@ -1962,7 +1970,7 @@ bool G1ConcurrentMark::concurrent_cycle_abort() { void G1ConcurrentMark::abort_marking_threads() { assert(!_root_regions.scan_in_progress(), "still doing root region scan"); - _has_aborted = true; + _has_aborted.store_relaxed(true); _first_overflow_barrier_sync.abort(); _second_overflow_barrier_sync.abort(); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 3a4cbf1b83e..39d98db9876 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -368,7 +368,7 @@ class G1ConcurrentMark : public CHeapObj { // For grey objects G1CMMarkStack _global_mark_stack; // Grey objects behind global finger - HeapWord* volatile _finger; // The global finger, region aligned, + Atomic _finger; // The global finger, region aligned, // always pointing to the end of the // last claimed region @@ -395,19 +395,19 @@ class G1ConcurrentMark : public CHeapObj { WorkerThreadsBarrierSync _second_overflow_barrier_sync; // Number of completed mark cycles. - volatile uint _completed_mark_cycles; + Atomic _completed_mark_cycles; // This is set by any task, when an overflow on the global data // structures is detected - volatile bool _has_overflown; + Atomic _has_overflown; // True: marking is concurrent, false: we're in remark - volatile bool _concurrent; + Atomic _concurrent; // Set at the end of a Full GC so that marking aborts - volatile bool _has_aborted; + Atomic _has_aborted; // Used when remark aborts due to an overflow to indicate that // another concurrent marking phase should start - volatile bool _restart_for_overflow; + Atomic _restart_for_overflow; ConcurrentGCTimer* _gc_timer_cm; @@ -461,8 +461,8 @@ class G1ConcurrentMark : public CHeapObj { void print_and_reset_taskqueue_stats(); - HeapWord* finger() { return _finger; } - bool concurrent() { return _concurrent; } + HeapWord* finger() { return _finger.load_relaxed(); } + bool concurrent() { return _concurrent.load_relaxed(); } uint active_tasks() { return _num_active_tasks; } TaskTerminator* terminator() { return &_terminator; } @@ -487,7 +487,7 @@ class G1ConcurrentMark : public CHeapObj { // to satisfy an allocation without doing a GC. This is fine, because all // objects in those regions will be considered live anyway because of // SATB guarantees (i.e. their TAMS will be equal to bottom). - bool out_of_regions() { return _finger >= _heap.end(); } + bool out_of_regions() { return finger() >= _heap.end(); } // Returns the task with the given id G1CMTask* task(uint id) { @@ -499,10 +499,10 @@ class G1ConcurrentMark : public CHeapObj { // Access / manipulation of the overflow flag which is set to // indicate that the global stack has overflown - bool has_overflown() { return _has_overflown; } - void set_has_overflown() { _has_overflown = true; } - void clear_has_overflown() { _has_overflown = false; } - bool restart_for_overflow() { return _restart_for_overflow; } + bool has_overflown() { return _has_overflown.load_relaxed(); } + void set_has_overflown() { _has_overflown.store_relaxed(true); } + void clear_has_overflown() { _has_overflown.store_relaxed(false); } + bool restart_for_overflow() { return _restart_for_overflow.load_relaxed(); } // Methods to enter the two overflow sync barriers void enter_first_sync_barrier(uint worker_id); @@ -516,12 +516,12 @@ class G1ConcurrentMark : public CHeapObj { G1RegionMarkStats* _region_mark_stats; // Top pointer for each region at the start of marking. Must be valid for all committed // regions. - HeapWord* volatile* _top_at_mark_starts; + Atomic* _top_at_mark_starts; // Top pointer for each region at the start of the rebuild remembered set process // for regions which remembered sets need to be rebuilt. A null for a given region // means that this region does not be scanned during the rebuilding remembered // set phase at all. - HeapWord* volatile* _top_at_rebuild_starts; + Atomic* _top_at_rebuild_starts; // True when Remark pause selected regions for rebuilding. bool _needs_remembered_set_rebuild; public: @@ -679,7 +679,7 @@ public: uint completed_mark_cycles() const; - bool has_aborted() { return _has_aborted; } + bool has_aborted() { return _has_aborted.load_relaxed(); } void print_summary_info(); diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp index 2f4824e4cae..21167d5cae9 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp @@ -194,11 +194,11 @@ inline void G1CMTask::process_array_chunk(objArrayOop obj, size_t start, size_t inline void G1ConcurrentMark::update_top_at_mark_start(G1HeapRegion* r) { uint const region = r->hrm_index(); assert(region < _g1h->max_num_regions(), "Tried to access TAMS for region %u out of bounds", region); - _top_at_mark_starts[region] = r->top(); + _top_at_mark_starts[region].store_relaxed(r->top()); } inline void G1ConcurrentMark::reset_top_at_mark_start(G1HeapRegion* r) { - _top_at_mark_starts[r->hrm_index()] = r->bottom(); + _top_at_mark_starts[r->hrm_index()].store_relaxed(r->bottom()); } inline HeapWord* G1ConcurrentMark::top_at_mark_start(const G1HeapRegion* r) const { @@ -207,7 +207,7 @@ inline HeapWord* G1ConcurrentMark::top_at_mark_start(const G1HeapRegion* r) cons inline HeapWord* G1ConcurrentMark::top_at_mark_start(uint region) const { assert(region < _g1h->max_num_regions(), "Tried to access TARS for region %u out of bounds", region); - return _top_at_mark_starts[region]; + return _top_at_mark_starts[region].load_relaxed(); } inline bool G1ConcurrentMark::obj_allocated_since_mark_start(oop obj) const { @@ -217,7 +217,7 @@ inline bool G1ConcurrentMark::obj_allocated_since_mark_start(oop obj) const { } inline HeapWord* G1ConcurrentMark::top_at_rebuild_start(G1HeapRegion* r) const { - return _top_at_rebuild_starts[r->hrm_index()]; + return _top_at_rebuild_starts[r->hrm_index()].load_relaxed(); } inline void G1ConcurrentMark::update_top_at_rebuild_start(G1HeapRegion* r) { @@ -225,10 +225,10 @@ inline void G1ConcurrentMark::update_top_at_rebuild_start(G1HeapRegion* r) { uint const region = r->hrm_index(); assert(region < _g1h->max_num_regions(), "Tried to access TARS for region %u out of bounds", region); - assert(_top_at_rebuild_starts[region] == nullptr, + assert(top_at_rebuild_start(r) == nullptr, "TARS for region %u has already been set to " PTR_FORMAT " should be null", - region, p2i(_top_at_rebuild_starts[region])); - _top_at_rebuild_starts[region] = r->top(); + region, p2i(top_at_rebuild_start(r))); + _top_at_rebuild_starts[region].store_relaxed(r->top()); } inline void G1CMTask::update_liveness(oop const obj, const size_t obj_size) { diff --git a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.hpp b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.hpp index 4dcdd33846e..b8f13f4553d 100644 --- a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.hpp +++ b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.hpp @@ -44,6 +44,8 @@ struct G1RegionMarkStats { Atomic _live_words; Atomic _incoming_refs; + G1RegionMarkStats() : _live_words(0), _incoming_refs(0) { } + // Clear all members. void clear() { _live_words.store_relaxed(0); From 8023c41690aee648eef800b69e517136e1cd062c Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 2 Feb 2026 18:49:45 +0000 Subject: [PATCH 293/328] 8376703: Some coding in libjimage seems to be not called at all or not called from PRODUCT code Reviewed-by: alanb, rriggs --- .../share/native/libjimage/endian.cpp | 5 +- .../share/native/libjimage/endian.hpp | 5 +- .../native/libjimage/imageDecompressor.hpp | 1 - .../share/native/libjimage/imageFile.cpp | 48 +------------------ .../share/native/libjimage/imageFile.hpp | 18 +------ 5 files changed, 4 insertions(+), 73 deletions(-) diff --git a/src/java.base/share/native/libjimage/endian.cpp b/src/java.base/share/native/libjimage/endian.cpp index 5e13ffba34e..73d8aefe086 100644 --- a/src/java.base/share/native/libjimage/endian.cpp +++ b/src/java.base/share/native/libjimage/endian.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -104,6 +104,3 @@ void Endian::set_java(u1* p, u2 x) { p[1] = x & 0xff; } -Endian* Endian::get_native_handler() { - return NativeEndian::get_native(); -} diff --git a/src/java.base/share/native/libjimage/endian.hpp b/src/java.base/share/native/libjimage/endian.hpp index 42fbbb0e853..38e566b7524 100644 --- a/src/java.base/share/native/libjimage/endian.hpp +++ b/src/java.base/share/native/libjimage/endian.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -74,9 +74,6 @@ public: // Select an appropriate endian handler. static Endian* get_handler(bool big_endian); - // Return the native endian handler. - static Endian* get_native_handler(); - // get platform u2 from Java Big endian static u2 get_java(u1* x); // set platform u2 to Java Big endian diff --git a/src/java.base/share/native/libjimage/imageDecompressor.hpp b/src/java.base/share/native/libjimage/imageDecompressor.hpp index 057fa15917c..709e1a3bb21 100644 --- a/src/java.base/share/native/libjimage/imageDecompressor.hpp +++ b/src/java.base/share/native/libjimage/imageDecompressor.hpp @@ -111,7 +111,6 @@ protected: public: static void image_decompressor_init(); - static void image_decompressor_close(); static ImageDecompressor* get_decompressor(const char * decompressor_name) ; static void decompress_resource(u1* compressed, u1* uncompressed, u8 uncompressed_size, const ImageStrings* strings, Endian* _endian); diff --git a/src/java.base/share/native/libjimage/imageFile.cpp b/src/java.base/share/native/libjimage/imageFile.cpp index d97a8f95a60..e2479ba2c9e 100644 --- a/src/java.base/share/native/libjimage/imageFile.cpp +++ b/src/java.base/share/native/libjimage/imageFile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -180,16 +180,6 @@ void ImageFileReaderTable::remove(ImageFileReader* image) { } } -// Determine if image entry is in table. -bool ImageFileReaderTable::contains(ImageFileReader* image) { - for (u4 i = 0; i < _count; i++) { - if (_table[i] == image) { - return true; - } - } - return false; -} - // Table to manage multiple opens of an image file. ImageFileReaderTable ImageFileReader::_reader_table; @@ -261,25 +251,6 @@ void ImageFileReader::close(ImageFileReader *reader) { } } -// Return an id for the specified ImageFileReader. -u8 ImageFileReader::reader_to_ID(ImageFileReader *reader) { - // ID is just the cloaked reader address. - return (u8)reader; -} - -// Validate the image id. -bool ImageFileReader::id_check(u8 id) { - // Make sure the ID is a managed (_reader_table) reader. - SimpleCriticalSectionLock cs(&_reader_table_lock); - return _reader_table.contains((ImageFileReader*)id); -} - -// Return an id for the specified ImageFileReader. -ImageFileReader* ImageFileReader::id_to_reader(u8 id) { - assert(id_check(id) && "invalid image id"); - return (ImageFileReader*)id; -} - // Constructor initializes to a closed state. ImageFileReader::ImageFileReader(const char* name, bool big_endian) { // Copy the image file name. @@ -372,23 +343,6 @@ bool ImageFileReader::read_at(u1* data, u8 size, u8 offset) const { return (u8)osSupport::read(_fd, (char*)data, size, offset) == size; } -// Find the location attributes associated with the path. Returns true if -// the location is found, false otherwise. -bool ImageFileReader::find_location(const char* path, ImageLocation& location) const { - // Locate the entry in the index perfect hash table. - s4 index = ImageStrings::find(_endian, path, _redirect_table, table_length()); - // If is found. - if (index != ImageStrings::NOT_FOUND) { - // Get address of first byte of location attribute stream. - u1* data = get_location_data(index); - // Expand location attributes. - location.set_data(data); - // Make sure result is not a false positive. - return verify_location(location, path); - } - return false; -} - // Find the location index and size associated with the path. // Returns the location index and size if the location is found, 0 otherwise. u4 ImageFileReader::find_location_index(const char* path, u8 *size) const { diff --git a/src/java.base/share/native/libjimage/imageFile.hpp b/src/java.base/share/native/libjimage/imageFile.hpp index 5fb4ea3baaa..a4c8d159efa 100644 --- a/src/java.base/share/native/libjimage/imageFile.hpp +++ b/src/java.base/share/native/libjimage/imageFile.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -375,9 +375,6 @@ public: // Remove an image entry from the table. void remove(ImageFileReader* image); - - // Determine if image entry is in table. - bool contains(ImageFileReader* image); }; // Manage the image file. @@ -445,15 +442,6 @@ public: // Close an image file if the file is not in use elsewhere. static void close(ImageFileReader *reader); - // Return an id for the specified ImageFileReader. - static u8 reader_to_ID(ImageFileReader *reader); - - // Validate the image id. - static bool id_check(u8 id); - - // Return an id for the specified ImageFileReader. - static ImageFileReader* id_to_reader(u8 id); - // Open image file for read access. bool open(); @@ -545,10 +533,6 @@ public: return _endian->get(_offsets_table[index]); } - // Find the location attributes associated with the path. Returns true if - // the location is found, false otherwise. - bool find_location(const char* path, ImageLocation& location) const; - // Find the location index and size associated with the path. // Returns the location index and size if the location is found, // ImageFileReader::NOT_FOUND otherwise. From 5607a4620c97ad2650a2dd3f464d03955fe17ef1 Mon Sep 17 00:00:00 2001 From: Hendrik Schick Date: Mon, 2 Feb 2026 20:58:03 +0000 Subject: [PATCH 294/328] 8376954: Typos in CharacterRangeInfo and AsynchronousServerSocketChannel Reviewed-by: liach, bpb --- .../java/lang/classfile/attribute/CharacterRangeInfo.java | 6 +++--- .../java/nio/channels/AsynchronousServerSocketChannel.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java index f6f5f9928bc..e1cc52bfa1d 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, 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 @@ -124,7 +124,7 @@ public sealed interface CharacterRangeInfo *
  • {@link CharacterRange#FLAG_BRANCH_TRUE} A condition encoded * in the branch instruction immediately contained in the code range for * this item is not inverted towards the corresponding branch condition in - * the source code. I.e. actual jump occurs if and only if the the source + * the source code. I.e. actual jump occurs if and only if the source * code branch condition evaluates to true. Entries of this type are * produced only for conditions that are listed in the description of * CRT_FLOW_CONTROLLER flag. The source range for the entry contains flow @@ -136,7 +136,7 @@ public sealed interface CharacterRangeInfo *
  • {@link CharacterRange#FLAG_BRANCH_FALSE} A condition encoded * in the branch instruction immediately contained in the code range for * this item is inverted towards the corresponding branch condition in the - * source code. I.e. actual jump occurs if and only if the the source code + * source code. I.e. actual jump occurs if and only if the source code * branch condition evaluates to false. Entries of this type are produced * only for conditions that are listed in the description of * CRT_FLOW_CONTROLLER flag. The source range for the entry contains flow diff --git a/src/java.base/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java b/src/java.base/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java index 192b1f7958b..4e6cadc737c 100644 --- a/src/java.base/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java +++ b/src/java.base/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, 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 @@ -208,7 +208,7 @@ public abstract class AsynchronousServerSocketChannel *

    The {@code backlog} parameter is the maximum number of pending * connections on the socket. Its exact semantics are implementation specific. * In particular, an implementation may impose a maximum length or may choose - * to ignore the parameter altogther. If the {@code backlog} parameter has + * to ignore the parameter altogether. If the {@code backlog} parameter has * the value {@code 0}, or a negative value, then an implementation specific * default is used. * From 4db0f7f29154d6618c63a30ef2a86267c842ebb3 Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Mon, 2 Feb 2026 21:53:02 +0000 Subject: [PATCH 295/328] 8375057: Update HarfBuzz to 12.3.2 Reviewed-by: prr, kizune --- src/java.desktop/share/legal/harfbuzz.md | 2 +- .../native/libharfbuzz/OT/Color/COLR/COLR.hh | 92 +- .../native/libharfbuzz/OT/Color/CPAL/CPAL.hh | 1 + .../libharfbuzz/OT/Layout/Common/Coverage.hh | 58 +- .../OT/Layout/Common/CoverageFormat1.hh | 4 +- .../OT/Layout/Common/CoverageFormat2.hh | 2 +- .../native/libharfbuzz/OT/Layout/GDEF/GDEF.hh | 58 +- .../libharfbuzz/OT/Layout/GPOS/Anchor.hh | 14 +- .../OT/Layout/GPOS/AnchorFormat3.hh | 15 +- .../OT/Layout/GPOS/AnchorMatrix.hh | 7 + .../libharfbuzz/OT/Layout/GPOS/CursivePos.hh | 8 +- .../OT/Layout/GPOS/CursivePosFormat1.hh | 15 +- .../native/libharfbuzz/OT/Layout/GPOS/GPOS.hh | 66 +- .../OT/Layout/GPOS/LigatureArray.hh | 19 +- .../libharfbuzz/OT/Layout/GPOS/MarkArray.hh | 10 +- .../libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh | 8 +- .../OT/Layout/GPOS/MarkBasePosFormat1.hh | 33 +- .../libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh | 8 +- .../OT/Layout/GPOS/MarkLigPosFormat1.hh | 18 +- .../libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh | 8 +- .../OT/Layout/GPOS/MarkMarkPosFormat1.hh | 32 +- .../libharfbuzz/OT/Layout/GPOS/PairPos.hh | 8 +- .../OT/Layout/GPOS/PairPosFormat1.hh | 41 +- .../OT/Layout/GPOS/PairPosFormat2.hh | 52 +- .../libharfbuzz/OT/Layout/GPOS/SinglePos.hh | 14 +- .../libharfbuzz/OT/Layout/GPOS/ValueFormat.hh | 13 +- .../OT/Layout/GSUB/AlternateSet.hh | 13 + .../OT/Layout/GSUB/AlternateSubst.hh | 14 +- .../OT/Layout/GSUB/AlternateSubstFormat1.hh | 13 + .../libharfbuzz/OT/Layout/GSUB/Ligature.hh | 31 +- .../libharfbuzz/OT/Layout/GSUB/LigatureSet.hh | 30 +- .../OT/Layout/GSUB/LigatureSubst.hh | 14 +- .../OT/Layout/GSUB/LigatureSubstFormat1.hh | 52 +- .../OT/Layout/GSUB/MultipleSubst.hh | 14 +- .../OT/Layout/GSUB/ReverseChainSingleSubst.hh | 8 +- .../libharfbuzz/OT/Layout/GSUB/Sequence.hh | 2 +- .../libharfbuzz/OT/Layout/GSUB/SingleSubst.hh | 14 +- .../OT/Layout/GSUB/SingleSubstFormat1.hh | 15 + .../OT/Layout/GSUB/SingleSubstFormat2.hh | 11 + .../native/libharfbuzz/OT/Layout/types.hh | 7 +- .../native/libharfbuzz/OT/Var/VARC/VARC.cc | 421 + .../native/libharfbuzz/OT/Var/VARC/VARC.hh | 22 +- .../share/native/libharfbuzz/OT/glyf/Glyph.hh | 38 +- .../native/libharfbuzz/OT/glyf/SimpleGlyph.hh | 2 +- .../share/native/libharfbuzz/OT/glyf/glyf.hh | 149 +- .../libharfbuzz/graph/classdef-graph.hh | 4 +- .../libharfbuzz/graph/coverage-graph.hh | 72 +- .../share/native/libharfbuzz/graph/graph.hh | 336 +- .../libharfbuzz/graph/gsubgpos-context.hh | 1 + .../libharfbuzz/graph/gsubgpos-graph.hh | 116 +- .../libharfbuzz/graph/markbasepos-graph.hh | 12 +- .../native/libharfbuzz/graph/pairpos-graph.hh | 19 +- .../native/libharfbuzz/graph/serialize.hh | 45 +- .../native/libharfbuzz/graph/split-helpers.hh | 4 +- .../libharfbuzz/hb-aat-layout-common.hh | 134 +- .../libharfbuzz/hb-aat-layout-kerx-table.hh | 74 +- .../libharfbuzz/hb-aat-layout-morx-table.hh | 23 +- .../share/native/libharfbuzz/hb-algs.hh | 288 +- .../share/native/libharfbuzz/hb-alloc-pool.hh | 105 + .../share/native/libharfbuzz/hb-array.hh | 7 + .../share/native/libharfbuzz/hb-atomic.hh | 96 +- .../share/native/libharfbuzz/hb-bimap.hh | 2 +- .../share/native/libharfbuzz/hb-bit-page.hh | 33 +- .../libharfbuzz/hb-bit-set-invertible.hh | 2 +- .../share/native/libharfbuzz/hb-bit-set.hh | 13 +- .../hb-buffer-deserialize-text-unicode.hh | 10 +- .../native/libharfbuzz/hb-buffer-serialize.cc | 2 +- .../native/libharfbuzz/hb-buffer-verify.cc | 6 +- .../share/native/libharfbuzz/hb-buffer.cc | 36 +- .../share/native/libharfbuzz/hb-buffer.hh | 73 +- .../share/native/libharfbuzz/hb-cache.hh | 33 +- .../native/libharfbuzz/hb-cff2-interp-cs.hh | 4 +- .../share/native/libharfbuzz/hb-common.cc | 47 +- .../share/native/libharfbuzz/hb-config.hh | 16 +- .../share/native/libharfbuzz/hb-debug.hh | 48 +- .../share/native/libharfbuzz/hb-deprecated.h | 8 +- .../share/native/libharfbuzz/hb-draw.cc | 20 +- .../native/libharfbuzz/hb-face-builder.cc | 3 +- .../share/native/libharfbuzz/hb-face.cc | 5 +- .../share/native/libharfbuzz/hb-font.cc | 248 +- .../share/native/libharfbuzz/hb-font.h | 129 +- .../share/native/libharfbuzz/hb-font.hh | 365 +- .../{hb-pool.hh => hb-free-pool.hh} | 14 +- .../share/native/libharfbuzz/hb-ft.cc | 30 +- .../share/native/libharfbuzz/hb-geometry.hh | 249 +- .../share/native/libharfbuzz/hb-iter.hh | 11 +- .../share/native/libharfbuzz/hb-kern.hh | 2 +- .../share/native/libharfbuzz/hb-limits.hh | 8 +- .../share/native/libharfbuzz/hb-machinery.hh | 24 +- .../share/native/libharfbuzz/hb-map.hh | 51 +- .../native/libharfbuzz/hb-number-parser.hh | 8 +- .../share/native/libharfbuzz/hb-open-file.hh | 14 +- .../share/native/libharfbuzz/hb-open-type.hh | 203 +- .../native/libharfbuzz/hb-ot-cff-common.hh | 2 +- .../native/libharfbuzz/hb-ot-cff1-std-str.hh | 782 +- .../native/libharfbuzz/hb-ot-cff1-table.hh | 4 +- .../native/libharfbuzz/hb-ot-cff2-table.cc | 6 +- .../native/libharfbuzz/hb-ot-cmap-table.hh | 53 +- .../share/native/libharfbuzz/hb-ot-font.cc | 578 +- .../native/libharfbuzz/hb-ot-hmtx-table.hh | 79 +- .../native/libharfbuzz/hb-ot-kern-table.hh | 20 +- .../libharfbuzz/hb-ot-layout-base-table.hh | 20 +- .../native/libharfbuzz/hb-ot-layout-common.hh | 746 +- .../libharfbuzz/hb-ot-layout-gpos-table.hh | 10 +- .../libharfbuzz/hb-ot-layout-gsub-table.hh | 10 +- .../libharfbuzz/hb-ot-layout-gsubgpos.hh | 1174 ++- .../share/native/libharfbuzz/hb-ot-layout.cc | 162 +- .../share/native/libharfbuzz/hb-ot-layout.h | 6 + .../share/native/libharfbuzz/hb-ot-layout.hh | 32 +- .../native/libharfbuzz/hb-ot-math-table.hh | 6 +- .../native/libharfbuzz/hb-ot-post-macroman.hh | 516 +- .../libharfbuzz/hb-ot-shape-fallback.cc | 29 +- .../libharfbuzz/hb-ot-shape-normalize.cc | 12 +- .../libharfbuzz/hb-ot-shape-normalize.hh | 2 +- .../share/native/libharfbuzz/hb-ot-shape.cc | 216 +- .../share/native/libharfbuzz/hb-ot-shape.hh | 2 +- .../hb-ot-shaper-arabic-joining-list.hh | 8 +- .../libharfbuzz/hb-ot-shaper-arabic-table.hh | 22 +- .../native/libharfbuzz/hb-ot-shaper-arabic.cc | 2 +- .../native/libharfbuzz/hb-ot-shaper-hangul.cc | 2 +- .../libharfbuzz/hb-ot-shaper-indic-machine.hh | 14 +- .../libharfbuzz/hb-ot-shaper-indic-table.cc | 12 +- .../native/libharfbuzz/hb-ot-shaper-indic.cc | 48 +- .../libharfbuzz/hb-ot-shaper-khmer-machine.hh | 14 +- .../native/libharfbuzz/hb-ot-shaper-khmer.cc | 6 - .../hb-ot-shaper-myanmar-machine.hh | 14 +- .../native/libharfbuzz/hb-ot-shaper-thai.cc | 6 +- .../libharfbuzz/hb-ot-shaper-use-machine.hh | 14 +- .../libharfbuzz/hb-ot-shaper-use-table.hh | 727 +- .../hb-ot-shaper-vowel-constraints.cc | 4 +- .../share/native/libharfbuzz/hb-ot-shaper.hh | 6 + .../native/libharfbuzz/hb-ot-stat-table.hh | 20 +- .../native/libharfbuzz/hb-ot-tag-table.hh | 8 +- .../libharfbuzz/hb-ot-var-avar-table.hh | 178 +- .../native/libharfbuzz/hb-ot-var-common.hh | 717 +- .../libharfbuzz/hb-ot-var-cvar-table.hh | 7 +- .../libharfbuzz/hb-ot-var-fvar-table.hh | 25 +- .../libharfbuzz/hb-ot-var-gvar-table.hh | 165 +- .../libharfbuzz/hb-ot-var-hvar-table.hh | 101 +- .../share/native/libharfbuzz/hb-ot-var.cc | 20 +- .../native/libharfbuzz/hb-ot-vorg-table.hh | 1 + .../share/native/libharfbuzz/hb-outline.cc | 9 + .../share/native/libharfbuzz/hb-outline.hh | 1 + .../native/libharfbuzz/hb-paint-extents.cc | 14 +- .../native/libharfbuzz/hb-paint-extents.hh | 38 +- .../share/native/libharfbuzz/hb-paint.hh | 76 +- .../native/libharfbuzz/hb-priority-queue.hh | 12 +- .../share/native/libharfbuzz/hb-repacker.hh | 27 +- .../share/native/libharfbuzz/hb-sanitize.hh | 98 +- .../share/native/libharfbuzz/hb-script-list.h | 12 + .../share/native/libharfbuzz/hb-serialize.hh | 9 +- .../share/native/libharfbuzz/hb-set-digest.hh | 6 +- .../share/native/libharfbuzz/hb-shape.cc | 8 +- .../native/libharfbuzz/hb-shaper-list.hh | 8 + .../share/native/libharfbuzz/hb-static.cc | 23 - .../native/libharfbuzz/hb-string-array.hh | 12 +- .../libharfbuzz/hb-subset-cff-common.hh | 6 +- .../libharfbuzz/hb-subset-instancer-iup.hh | 15 + .../libharfbuzz/hb-subset-instancer-solver.cc | 38 +- .../libharfbuzz/hb-subset-instancer-solver.hh | 22 +- .../libharfbuzz/hb-subset-plan-member-list.hh | 4 + .../native/libharfbuzz/hb-subset-plan.cc | 19 +- .../native/libharfbuzz/hb-subset-plan.hh | 3 +- .../share/native/libharfbuzz/hb-subset.cc | 584 +- .../share/native/libharfbuzz/hb-subset.h | 5 + .../share/native/libharfbuzz/hb-subset.hh | 1 - .../share/native/libharfbuzz/hb-ucd-table.hh | 9165 ++++++++--------- .../libharfbuzz/hb-unicode-emoji-table.hh | 86 +- .../share/native/libharfbuzz/hb-unicode.hh | 51 + .../share/native/libharfbuzz/hb-utf.hh | 20 +- .../share/native/libharfbuzz/hb-vector.hh | 187 +- .../share/native/libharfbuzz/hb-version.h | 8 +- .../share/native/libharfbuzz/hb.hh | 29 +- 173 files changed, 11918 insertions(+), 9815 deletions(-) create mode 100644 src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.cc create mode 100644 src/java.desktop/share/native/libharfbuzz/hb-alloc-pool.hh rename src/java.desktop/share/native/libharfbuzz/{hb-pool.hh => hb-free-pool.hh} (92%) diff --git a/src/java.desktop/share/legal/harfbuzz.md b/src/java.desktop/share/legal/harfbuzz.md index e0c40705ed6..3aa5ca841d6 100644 --- a/src/java.desktop/share/legal/harfbuzz.md +++ b/src/java.desktop/share/legal/harfbuzz.md @@ -1,4 +1,4 @@ -## Harfbuzz 11.2.0 +## Harfbuzz 12.3.2 ### Harfbuzz License diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh index 73e6b4c305b..011b5ad5520 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh @@ -104,7 +104,7 @@ public: foreground (foreground_), instancer (instancer_) { - if (font->is_synthetic ()) + if (font->is_synthetic) { font = hb_font_create_sub_font (font); hb_font_set_synthetic_bold (font, 0, 0, true); @@ -178,7 +178,10 @@ struct hb_colrv1_closure_context_t : { glyphs->add (glyph_id); } void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers) - { layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); } + { + if (num_of_layers == 0) return; + layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); + } void add_palette_index (unsigned palette_index) { palette_indices->add (palette_index); } @@ -650,10 +653,10 @@ struct PaintColrLayers TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers.get (firstLayerIndex), - HB_SERIALIZE_ERROR_INT_OVERFLOW)); - return_trace (true); + uint32_t first_layer_index = numLayers ? c->plan->colrv1_layers.get (firstLayerIndex) : 0; + return_trace (c->serializer->check_assign (out->firstLayerIndex, first_layer_index, + HB_SERIALIZE_ERROR_INT_OVERFLOW)); } bool sanitize (hb_sanitize_context_t *c) const @@ -1075,9 +1078,9 @@ struct PaintTranslate float ddx = dx + c->instancer (varIdxBase, 0); float ddy = dy + c->instancer (varIdxBase, 1); - bool p1 = c->funcs->push_translate (c->data, ddx, ddy); + c->funcs->push_translate (c->data, ddx, ddy); c->recurse (this+src); - if (p1) c->funcs->pop_transform (c->data); + c->funcs->pop_transform (c->data); } HBUINT8 format; /* format = 14(noVar) or 15 (Var) */ @@ -1124,9 +1127,9 @@ struct PaintScale float sx = scaleX.to_float (c->instancer (varIdxBase, 0)); float sy = scaleY.to_float (c->instancer (varIdxBase, 1)); - bool p1 = c->funcs->push_scale (c->data, sx, sy); + c->funcs->push_scale (c->data, sx, sy); c->recurse (this+src); - if (p1) c->funcs->pop_transform (c->data); + c->funcs->pop_transform (c->data); } HBUINT8 format; /* format = 16 (noVar) or 17(Var) */ @@ -1177,13 +1180,9 @@ struct PaintScaleAroundCenter float tCenterX = centerX + c->instancer (varIdxBase, 2); float tCenterY = centerY + c->instancer (varIdxBase, 3); - bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY); - bool p2 = c->funcs->push_scale (c->data, sx, sy); - bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY); + c->funcs->push_scale_around_center (c->data, sx, sy, tCenterX, tCenterY); c->recurse (this+src); - if (p3) c->funcs->pop_transform (c->data); - if (p2) c->funcs->pop_transform (c->data); - if (p1) c->funcs->pop_transform (c->data); + c->funcs->pop_transform (c->data); } HBUINT8 format; /* format = 18 (noVar) or 19(Var) */ @@ -1228,9 +1227,9 @@ struct PaintScaleUniform TRACE_PAINT (this); float s = scale.to_float (c->instancer (varIdxBase, 0)); - bool p1 = c->funcs->push_scale (c->data, s, s); + c->funcs->push_scale (c->data, s, s); c->recurse (this+src); - if (p1) c->funcs->pop_transform (c->data); + c->funcs->pop_transform (c->data); } HBUINT8 format; /* format = 20 (noVar) or 21(Var) */ @@ -1278,13 +1277,9 @@ struct PaintScaleUniformAroundCenter float tCenterX = centerX + c->instancer (varIdxBase, 1); float tCenterY = centerY + c->instancer (varIdxBase, 2); - bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY); - bool p2 = c->funcs->push_scale (c->data, s, s); - bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY); + c->funcs->push_scale_around_center (c->data, s, s, tCenterX, tCenterY); c->recurse (this+src); - if (p3) c->funcs->pop_transform (c->data); - if (p2) c->funcs->pop_transform (c->data); - if (p1) c->funcs->pop_transform (c->data); + c->funcs->pop_transform (c->data); } HBUINT8 format; /* format = 22 (noVar) or 23(Var) */ @@ -1328,9 +1323,9 @@ struct PaintRotate TRACE_PAINT (this); float a = angle.to_float (c->instancer (varIdxBase, 0)); - bool p1 = c->funcs->push_rotate (c->data, a); + c->funcs->push_rotate (c->data, a); c->recurse (this+src); - if (p1) c->funcs->pop_transform (c->data); + c->funcs->pop_transform (c->data); } HBUINT8 format; /* format = 24 (noVar) or 25(Var) */ @@ -1378,13 +1373,9 @@ struct PaintRotateAroundCenter float tCenterX = centerX + c->instancer (varIdxBase, 1); float tCenterY = centerY + c->instancer (varIdxBase, 2); - bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY); - bool p2 = c->funcs->push_rotate (c->data, a); - bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY); + c->funcs->push_rotate_around_center (c->data, a, tCenterX, tCenterY); c->recurse (this+src); - if (p3) c->funcs->pop_transform (c->data); - if (p2) c->funcs->pop_transform (c->data); - if (p1) c->funcs->pop_transform (c->data); + c->funcs->pop_transform (c->data); } HBUINT8 format; /* format = 26 (noVar) or 27(Var) */ @@ -1432,9 +1423,9 @@ struct PaintSkew float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0)); float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1)); - bool p1 = c->funcs->push_skew (c->data, sx, sy); + c->funcs->push_skew (c->data, sx, sy); c->recurse (this+src); - if (p1) c->funcs->pop_transform (c->data); + c->funcs->pop_transform (c->data); } HBUINT8 format; /* format = 28(noVar) or 29 (Var) */ @@ -1485,13 +1476,9 @@ struct PaintSkewAroundCenter float tCenterX = centerX + c->instancer (varIdxBase, 2); float tCenterY = centerY + c->instancer (varIdxBase, 3); - bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY); - bool p2 = c->funcs->push_skew (c->data, sx, sy); - bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY); + c->funcs->push_skew_around_center (c->data, sx, sy, tCenterX, tCenterY); c->recurse (this+src); - if (p3) c->funcs->pop_transform (c->data); - if (p2) c->funcs->pop_transform (c->data); - if (p1) c->funcs->pop_transform (c->data); + c->funcs->pop_transform (c->data); } HBUINT8 format; /* format = 30(noVar) or 31 (Var) */ @@ -1626,7 +1613,7 @@ struct ClipBox const ItemVarStoreInstancer &instancer) const { TRACE_SUBSET (this); - switch (u.format) { + switch (u.format.v) { case 1: return_trace (u.format1.subset (c, instancer, VarIdx::NO_VARIATION)); case 2: return_trace (u.format2.subset (c, instancer)); default:return_trace (c->default_return_value ()); @@ -1635,7 +1622,7 @@ struct ClipBox void closurev1 (hb_colrv1_closure_context_t* c) const { - switch (u.format) { + switch (u.format.v) { case 2: u.format2.closurev1 (c); return; default:return; } @@ -1644,9 +1631,9 @@ struct ClipBox template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); default:return_trace (c->default_return_value ()); @@ -1657,7 +1644,7 @@ struct ClipBox const ItemVarStoreInstancer &instancer) const { ClipBoxData clip_box; - switch (u.format) { + switch (u.format.v) { case 1: u.format1.get_clip_box (clip_box, instancer); break; @@ -1677,7 +1664,7 @@ struct ClipBox protected: union { - HBUINT8 format; /* Format identifier */ + struct { HBUINT8 v; } format; /* Format identifier */ ClipBoxFormat1 format1; ClipBoxFormat2 format2; } u; @@ -1857,9 +1844,9 @@ struct Paint template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: return_trace (c->dispatch (u.paintformat1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.paintformat2, std::forward (ds)...)); case 3: return_trace (c->dispatch (u.paintformat3, std::forward (ds)...)); @@ -1898,7 +1885,7 @@ struct Paint protected: union { - HBUINT8 format; + struct { HBUINT8 v; } format; PaintColrLayers paintformat1; NoVariable paintformat2; Variable paintformat3; @@ -2073,7 +2060,7 @@ struct delta_set_index_map_subset_plan_t outer_bit_count = 1; inner_bit_count = 1; - if (unlikely (!output_map.resize (map_count, false))) return false; + if (unlikely (!output_map.resize_dirty (map_count))) return false; for (unsigned idx = 0; idx < map_count; idx++) { @@ -2693,7 +2680,8 @@ struct COLR { ItemVarStoreInstancer instancer (get_var_store_ptr (), get_delta_set_index_map_ptr (), - hb_array (font->coords, font->num_coords)); + hb_array (font->coords, + font->has_nonzero_coords ? font->num_coords : 0)); hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer); hb_decycler_node_t node (c.glyphs_decycler); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh index 51fc1b52af4..71417fdf3cf 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh @@ -307,6 +307,7 @@ struct CPAL if (first_color_to_layer_index.has (first_color_record_idx)) continue; first_color_index_for_layer.push (first_color_record_idx); + if (unlikely (!c->serializer->propagate_error (first_color_index_for_layer))) return_trace (false); first_color_to_layer_index.set (first_color_record_idx, first_color_index_for_layer.length - 1); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh index 35d73c7b858..28678856373 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh @@ -46,7 +46,7 @@ struct Coverage protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ CoverageFormat1_3 format1; CoverageFormat2_4 format2; #ifndef HB_NO_BEYOND_64K @@ -55,7 +55,7 @@ struct Coverage #endif } u; public: - DEFINE_SIZE_UNION (2, format); + DEFINE_SIZE_UNION (2, format.v); #ifndef HB_OPTIMIZE_SIZE HB_ALWAYS_INLINE @@ -63,9 +63,9 @@ struct Coverage bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return_trace (false); + if (!u.format.v.sanitize (c)) return_trace (false); hb_barrier (); - switch (u.format) + switch (u.format.v) { case 1: return_trace (u.format1.sanitize (c)); case 2: return_trace (u.format2.sanitize (c)); @@ -86,7 +86,7 @@ struct Coverage unsigned int get (hb_codepoint_t k) const { return get_coverage (k); } unsigned int get_coverage (hb_codepoint_t glyph_id) const { - switch (u.format) { + switch (u.format.v) { case 1: return u.format1.get_coverage (glyph_id); case 2: return u.format2.get_coverage (glyph_id); #ifndef HB_NO_BEYOND_64K @@ -97,18 +97,38 @@ struct Coverage } } unsigned int get_coverage (hb_codepoint_t glyph_id, - hb_ot_lookup_cache_t *cache) const + hb_ot_layout_mapping_cache_t *cache) const { unsigned coverage; - if (cache && cache->get (glyph_id, &coverage)) return coverage; + if (cache && cache->get (glyph_id, &coverage)) return coverage < cache->MAX_VALUE ? coverage : NOT_COVERED; coverage = get_coverage (glyph_id); - if (cache) cache->set (glyph_id, coverage); + if (cache) { + if (coverage == NOT_COVERED) + cache->set_unchecked (glyph_id, cache->MAX_VALUE); + else if (likely (coverage < cache->MAX_VALUE)) + cache->set_unchecked (glyph_id, coverage); + } + return coverage; + } + + unsigned int get_coverage_binary (hb_codepoint_t glyph_id, + hb_ot_layout_binary_cache_t *cache) const + { + unsigned coverage; + if (cache && cache->get (glyph_id, &coverage)) return coverage < cache->MAX_VALUE ? coverage : NOT_COVERED; + coverage = get_coverage (glyph_id); + if (cache) { + if (coverage == NOT_COVERED) + cache->set_unchecked (glyph_id, cache->MAX_VALUE); + else + cache->set_unchecked (glyph_id, 0); + } return coverage; } unsigned get_population () const { - switch (u.format) { + switch (u.format.v) { case 1: return u.format1.get_population (); case 2: return u.format2.get_population (); #ifndef HB_NO_BEYOND_64K @@ -140,11 +160,11 @@ struct Coverage last = g; if (g > max) max = g; } - u.format = !unsorted && count <= num_ranges * 3 ? 1 : 2; + u.format.v = !unsorted && count <= num_ranges * 3 ? 1 : 2; #ifndef HB_NO_BEYOND_64K if (max > 0xFFFFu) - u.format += 2; + u.format.v += 2; if (unlikely (max > 0xFFFFFFu)) #else if (unlikely (max > 0xFFFFu)) @@ -154,7 +174,7 @@ struct Coverage return_trace (false); } - switch (u.format) + switch (u.format.v) { case 1: return_trace (u.format1.serialize (c, glyphs)); case 2: return_trace (u.format2.serialize (c, glyphs)); @@ -185,7 +205,7 @@ struct Coverage bool intersects (const hb_set_t *glyphs) const { - switch (u.format) + switch (u.format.v) { case 1: return u.format1.intersects (glyphs); case 2: return u.format2.intersects (glyphs); @@ -198,7 +218,7 @@ struct Coverage } bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { - switch (u.format) + switch (u.format.v) { case 1: return u.format1.intersects_coverage (glyphs, index); case 2: return u.format2.intersects_coverage (glyphs, index); @@ -212,7 +232,7 @@ struct Coverage unsigned cost () const { - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return u.format1.cost (); case 2: hb_barrier (); return u.format2.cost (); #ifndef HB_NO_BEYOND_64K @@ -228,7 +248,7 @@ struct Coverage template bool collect_coverage (set_t *glyphs) const { - switch (u.format) + switch (u.format.v) { case 1: return u.format1.collect_coverage (glyphs); case 2: return u.format2.collect_coverage (glyphs); @@ -244,7 +264,7 @@ struct Coverage hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))> void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const { - switch (u.format) + switch (u.format.v) { case 1: return u.format1.intersect_set (glyphs, intersect_glyphs); case 2: return u.format2.intersect_set (glyphs, intersect_glyphs); @@ -262,7 +282,7 @@ struct Coverage iter_t (const Coverage &c_ = Null (Coverage)) { hb_memset (this, 0, sizeof (*this)); - format = c_.u.format; + format = c_.u.format.v; switch (format) { case 1: u.format1.init (c_.u.format1); return; @@ -332,7 +352,7 @@ struct Coverage } iter_t __end__ () const { - iter_t it = {}; + iter_t it; it.format = format; switch (format) { diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh index 97ea51089ec..122326e3024 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh @@ -41,11 +41,11 @@ struct CoverageFormat1_3 { friend struct Coverage; - protected: + public: HBUINT16 coverageFormat; /* Format identifier--format = 1 */ SortedArray16Of glyphArray; /* Array of GlyphIDs--in numerical order */ - public: + DEFINE_SIZE_ARRAY (4, glyphArray); private: diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh index 0c9bd09cbf7..8287c8d4d4d 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh @@ -40,7 +40,7 @@ struct CoverageFormat2_4 { friend struct Coverage; - protected: + public: HBUINT16 coverageFormat; /* Format identifier--format = 2 */ SortedArray16Of> rangeRecord; /* Array of glyph ranges--ordered by diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh index ceba37b0619..89e110990bc 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh @@ -252,7 +252,7 @@ struct CaretValue hb_codepoint_t glyph_id, const ItemVariationStore &var_store) const { - switch (u.format) { + switch (u.format.v) { case 1: return u.format1.get_caret_value (font, direction); case 2: return u.format2.get_caret_value (font, direction, glyph_id); case 3: return u.format3.get_caret_value (font, direction, var_store); @@ -263,9 +263,9 @@ struct CaretValue template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); case 3: return_trace (c->dispatch (u.format3, std::forward (ds)...)); @@ -275,7 +275,7 @@ struct CaretValue void collect_variation_indices (hb_collect_variation_indices_context_t *c) const { - switch (u.format) { + switch (u.format.v) { case 1: case 2: return; @@ -289,9 +289,9 @@ struct CaretValue bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return_trace (false); + if (!u.format.v.sanitize (c)) return_trace (false); hb_barrier (); - switch (u.format) { + switch (u.format.v) { case 1: return_trace (u.format1.sanitize (c)); case 2: return_trace (u.format2.sanitize (c)); case 3: return_trace (u.format3.sanitize (c)); @@ -301,13 +301,13 @@ struct CaretValue protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ CaretValueFormat1 format1; CaretValueFormat2 format2; CaretValueFormat3 format3; } u; public: - DEFINE_SIZE_UNION (2, format); + DEFINE_SIZE_UNION (2, format.v); }; struct LigGlyph @@ -519,7 +519,7 @@ struct MarkGlyphSets { bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const { - switch (u.format) { + switch (u.format.v) { case 1: return u.format1.covers (set_index, glyph_id); default:return false; } @@ -528,7 +528,7 @@ struct MarkGlyphSets template void collect_coverage (hb_vector_t &sets) const { - switch (u.format) { + switch (u.format.v) { case 1: u.format1.collect_coverage (sets); return; default:return; } @@ -537,7 +537,7 @@ struct MarkGlyphSets void collect_used_mark_sets (const hb_set_t& glyph_set, hb_set_t& used_mark_sets /* OUT */) const { - switch (u.format) { + switch (u.format.v) { case 1: u.format1.collect_used_mark_sets (glyph_set, used_mark_sets); return; default:return; } @@ -546,7 +546,7 @@ struct MarkGlyphSets bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - switch (u.format) { + switch (u.format.v) { case 1: return_trace (u.format1.subset (c)); default:return_trace (false); } @@ -555,9 +555,9 @@ struct MarkGlyphSets bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return_trace (false); + if (!u.format.v.sanitize (c)) return_trace (false); hb_barrier (); - switch (u.format) { + switch (u.format.v) { case 1: return_trace (u.format1.sanitize (c)); default:return_trace (true); } @@ -565,11 +565,11 @@ struct MarkGlyphSets protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ MarkGlyphSetsFormat1 format1; } u; public: - DEFINE_SIZE_UNION (2, format); + DEFINE_SIZE_UNION (2, format.v); }; @@ -977,7 +977,7 @@ struct GDEF } #ifndef HB_NO_GDEF_CACHE - table->get_mark_glyph_sets ().collect_coverage (mark_glyph_set_digests); + table->get_mark_glyph_sets ().collect_coverage (mark_glyph_sets); #endif } ~accelerator_t () { table.destroy (); } @@ -1002,18 +1002,34 @@ struct GDEF } + HB_ALWAYS_INLINE bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const { return #ifndef HB_NO_GDEF_CACHE - mark_glyph_set_digests[set_index].may_have (glyph_id) && + // We can access arrayZ directly because of sanitize_lookup_props() guarantee. + mark_glyph_sets.arrayZ[set_index].may_have (glyph_id) && #endif - table->mark_set_covers (set_index, glyph_id); + table->mark_set_covers (set_index, glyph_id) + ; + } + + unsigned sanitize_lookup_props (unsigned lookup_props) const + { +#ifndef HB_NO_GDEF_CACHE + if (lookup_props & LookupFlag::UseMarkFilteringSet && + (lookup_props >> 16) >= mark_glyph_sets.length) + { + // Invalid mark filtering set index; unset the flag. + lookup_props &= ~LookupFlag::UseMarkFilteringSet; + } +#endif + return lookup_props; } hb_blob_ptr_t table; #ifndef HB_NO_GDEF_CACHE - hb_vector_t mark_glyph_set_digests; + hb_vector_t mark_glyph_sets; mutable hb_cache_t<21, 3> glyph_props_cache; static_assert (sizeof (glyph_props_cache) == 512, ""); #endif diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Anchor.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Anchor.hh index 7802e397f4c..1938803fa7c 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Anchor.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Anchor.hh @@ -13,20 +13,20 @@ struct Anchor { protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ AnchorFormat1 format1; AnchorFormat2 format2; AnchorFormat3 format3; } u; public: - DEFINE_SIZE_UNION (2, format); + DEFINE_SIZE_UNION (2, format.v); bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return_trace (false); + if (!u.format.v.sanitize (c)) return_trace (false); hb_barrier (); - switch (u.format) { + switch (u.format.v) { case 1: return_trace (u.format1.sanitize (c)); case 2: return_trace (u.format2.sanitize (c)); case 3: return_trace (u.format3.sanitize (c)); @@ -38,7 +38,7 @@ struct Anchor float *x, float *y) const { *x = *y = 0; - switch (u.format) { + switch (u.format.v) { case 1: u.format1.get_anchor (c, glyph_id, x, y); return; case 2: u.format2.get_anchor (c, glyph_id, x, y); return; case 3: u.format3.get_anchor (c, glyph_id, x, y); return; @@ -49,7 +49,7 @@ struct Anchor bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - switch (u.format) { + switch (u.format.v) { case 1: return_trace (bool (reinterpret_cast (u.format1.copy (c->serializer)))); case 2: if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) @@ -66,7 +66,7 @@ struct Anchor void collect_variation_indices (hb_collect_variation_indices_context_t *c) const { - switch (u.format) { + switch (u.format.v) { case 1: case 2: return; case 3: diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh index 61bd90310a5..c49705bea0e 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh @@ -37,12 +37,12 @@ struct AnchorFormat3 *x = font->em_fscale_x (xCoordinate); *y = font->em_fscale_y (yCoordinate); - if ((font->x_ppem || font->num_coords) && xDeviceTable.sanitize (&c->sanitizer, this)) + if ((font->x_ppem || font->has_nonzero_coords) && xDeviceTable.sanitize (&c->sanitizer, this)) { hb_barrier (); *x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache); } - if ((font->y_ppem || font->num_coords) && yDeviceTable.sanitize (&c->sanitizer, this)) + if ((font->y_ppem || font->has_nonzero_coords) && yDeviceTable.sanitize (&c->sanitizer, this)) { hb_barrier (); *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache); @@ -91,10 +91,13 @@ struct AnchorFormat3 } } - /* in case that all axes are pinned or no variations after instantiation, - * both var_idxes will be mapped to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */ - if (x_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX && - y_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX) + + bool no_downgrade = (!xDeviceTable.is_null () && !(this+xDeviceTable).is_variation_device ()) || + x_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX || + y_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX || + (!yDeviceTable.is_null () && !(this+yDeviceTable).is_variation_device ()); + + if (!no_downgrade) return_trace (c->serializer->check_assign (out->format, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW)); if (!c->serializer->embed (xDeviceTable)) return_trace (false); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorMatrix.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorMatrix.hh index 9da9fff50ba..128ced6c176 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorMatrix.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorMatrix.hh @@ -77,6 +77,13 @@ struct AnchorMatrix return_trace (true); } + + bool offset_is_null (unsigned row, unsigned col, unsigned num_cols) const + { + if (unlikely (row >= rows || col >= num_cols)) return true; + auto &offset = matrixZ[row * num_cols + col]; + return offset.is_null (); + } }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePos.hh index 0105a9b8542..38a29dd9ed5 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePos.hh @@ -11,7 +11,7 @@ struct CursivePos { protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ CursivePosFormat1 format1; } u; @@ -19,9 +19,9 @@ struct CursivePos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); default:return_trace (c->default_return_value ()); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh index 361aaed658a..f5a09e07d73 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh @@ -50,8 +50,9 @@ struct EntryExitRecord DEFINE_SIZE_STATIC (4); }; -static void -reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent) { +static inline void +reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent) +{ int chain = pos[i].attach_chain(), type = pos[i].attach_type(); if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE))) return; @@ -130,7 +131,7 @@ struct CursivePosFormat1 unlikely (!this_record.entryAnchor.sanitize (&c->sanitizer, this))) return_trace (false); hb_barrier (); - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + auto &skippy_iter = c->iter_input; skippy_iter.reset_fast (buffer->idx); unsigned unsafe_from; if (unlikely (!skippy_iter.prev (&unsafe_from))) @@ -229,8 +230,13 @@ struct CursivePosFormat1 */ reverse_cursive_minor_offset (pos, child, c->direction, parent); - pos[child].attach_type() = ATTACH_TYPE_CURSIVE; pos[child].attach_chain() = (int) parent - (int) child; + if (pos[child].attach_chain() != (int) parent - (int) child) + { + pos[child].attach_chain() = 0; + goto overflow; + } + pos[child].attach_type() = ATTACH_TYPE_CURSIVE; buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) pos[child].y_offset = y_offset; @@ -256,6 +262,7 @@ struct CursivePosFormat1 i, j); } + overflow: buffer->idx++; return_trace (true); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh index ce3f74d8c3b..b80f606f7b5 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh @@ -80,9 +80,8 @@ propagate_attachment_offsets (hb_glyph_position_t *pos, { /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate * offset of glyph they are attached to. */ - int chain = pos[i].attach_chain(), type = pos[i].attach_type(); - if (likely (!chain)) - return; + int chain = pos[i].attach_chain(); + int type = pos[i].attach_type(); pos[i].attach_chain() = 0; @@ -94,7 +93,8 @@ propagate_attachment_offsets (hb_glyph_position_t *pos, if (unlikely (!nesting_level)) return; - propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1); + if (pos[j].attach_chain()) + propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1); assert (!!(type & GPOS_impl::ATTACH_TYPE_MARK) ^ !!(type & GPOS_impl::ATTACH_TYPE_CURSIVE)); @@ -110,17 +110,37 @@ propagate_attachment_offsets (hb_glyph_position_t *pos, pos[i].x_offset += pos[j].x_offset; pos[i].y_offset += pos[j].y_offset; - assert (j < i); - if (HB_DIRECTION_IS_FORWARD (direction)) - for (unsigned int k = j; k < i; k++) { - pos[i].x_offset -= pos[k].x_advance; - pos[i].y_offset -= pos[k].y_advance; - } - else - for (unsigned int k = j + 1; k < i + 1; k++) { - pos[i].x_offset += pos[k].x_advance; - pos[i].y_offset += pos[k].y_advance; - } + // i is the position of the mark; j is the base. + if (j < i) + { + /* This is the common case: mark follows base. + * And currently the only way in OpenType. */ + if (HB_DIRECTION_IS_FORWARD (direction)) + for (unsigned int k = j; k < i; k++) { + pos[i].x_offset -= pos[k].x_advance; + pos[i].y_offset -= pos[k].y_advance; + } + else + for (unsigned int k = j + 1; k < i + 1; k++) { + pos[i].x_offset += pos[k].x_advance; + pos[i].y_offset += pos[k].y_advance; + } + } + else // j > i + { + /* This can happen with `kerx`: a mark attaching + * to a base after it in the logical order. */ + if (HB_DIRECTION_IS_FORWARD (direction)) + for (unsigned int k = i; k < j; k++) { + pos[i].x_offset += pos[k].x_advance; + pos[i].y_offset += pos[k].y_advance; + } + else + for (unsigned int k = i + 1; k < j + 1; k++) { + pos[i].x_offset -= pos[k].x_advance; + pos[i].y_offset -= pos[k].y_advance; + } + } } } @@ -149,8 +169,20 @@ GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer) /* Handle attachments */ if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT) - for (unsigned i = 0; i < len; i++) - propagate_attachment_offsets (pos, len, i, direction); + { + auto *pos = buffer->pos; + // https://github.com/harfbuzz/harfbuzz/issues/5514 + if (HB_DIRECTION_IS_FORWARD (direction)) + { + for (unsigned i = 0; i < len; i++) + if (pos[i].attach_chain()) + propagate_attachment_offsets (pos, len, i, direction); + } else { + for (unsigned i = len; i-- > 0; ) + if (pos[i].attach_chain()) + propagate_attachment_offsets (pos, len, i, direction); + } + } if (unlikely (font->slant_xy) && HB_DIRECTION_IS_HORIZONTAL (direction)) diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh index eecdb95a95f..113b693dc3e 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh @@ -19,22 +19,30 @@ struct LigatureArray : List16OfOffset16To bool subset (hb_subset_context_t *c, Iterator coverage, unsigned class_count, - const hb_map_t *klass_mapping) const + const hb_map_t *klass_mapping, + hb_sorted_vector_t &new_coverage /* OUT */) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = c->plan->glyph_map_gsub; auto *out = c->serializer->start_embed (this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); bool ret = false; for (const auto _ : + hb_zip (coverage, *this) - | hb_filter (glyphset, hb_first)) + | hb_filter (glyph_map, hb_first)) { + const LigatureAttach& src = (this + _.second); + bool non_empty = + hb_range (src.rows * class_count) + | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); }) + | hb_map ([&] (const unsigned index) { return !src.offset_is_null (index / class_count, index % class_count, class_count); }) + | hb_any; + + if (!non_empty) continue; + auto *matrix = out->serialize_append (c->serializer); if (unlikely (!matrix)) return_trace (false); - const LigatureAttach& src = (this + _.second); auto indexes = + hb_range (src.rows * class_count) | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); }) @@ -44,6 +52,9 @@ struct LigatureArray : List16OfOffset16To this, src.rows, indexes); + + hb_codepoint_t new_gid = glyph_map.get (_.first); + new_coverage.push (new_gid); } return_trace (ret); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh index abae8f1c607..bddc5e7fe9e 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh @@ -47,10 +47,15 @@ struct MarkArray : Array16Of /* Array of MarkRecords--in Cove } hb_glyph_position_t &o = buffer->cur_pos(); + o.attach_chain() = (int) glyph_pos - (int) buffer->idx; + if (o.attach_chain() != (int) glyph_pos - (int) buffer->idx) + { + o.attach_chain() = 0; + goto overflow; + } + o.attach_type() = ATTACH_TYPE_MARK; o.x_offset = roundf (base_x - mark_x); o.y_offset = roundf (base_y - mark_y); - o.attach_type() = ATTACH_TYPE_MARK; - o.attach_chain() = (int) glyph_pos - (int) buffer->idx; buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) @@ -60,6 +65,7 @@ struct MarkArray : Array16Of /* Array of MarkRecords--in Cove c->buffer->idx, glyph_pos); } + overflow: buffer->idx++; return_trace (true); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh index b1d1118a86b..65f343bda8b 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh @@ -11,7 +11,7 @@ struct MarkBasePos { protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ MarkBasePosFormat1_2 format1; #ifndef HB_NO_BEYOND_64K MarkBasePosFormat1_2 format2; @@ -22,9 +22,9 @@ struct MarkBasePos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh index e633f7a1be1..ad071f327ea 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh @@ -119,7 +119,7 @@ struct MarkBasePosFormat1_2 /* Now we search backwards for a non-mark glyph. * We don't use skippy_iter.prev() to avoid O(n^2) behavior. */ - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + auto &skippy_iter = c->iter_input; skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); if (c->last_base_until > buffer->idx) @@ -209,19 +209,22 @@ struct MarkBasePosFormat1_2 ; new_coverage.reset (); - + base_iter - | hb_map (hb_first) - | hb_map (glyph_map) - | hb_sink (new_coverage) - ; - - if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ())) - return_trace (false); - hb_sorted_vector_t base_indexes; - for (const unsigned row : + base_iter - | hb_map (hb_second)) + auto &base_array = (this+baseArray); + for (const auto _ : + base_iter) { + unsigned row = _.second; + bool non_empty = + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return !base_array.offset_is_null (row, col, (unsigned) classCount); }) + | hb_any + ; + + if (!non_empty) continue; + + hb_codepoint_t new_g = glyph_map.get ( _.first); + new_coverage.push (new_g); + + hb_range ((unsigned) classCount) | hb_filter (klass_mapping) | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) @@ -229,8 +232,12 @@ struct MarkBasePosFormat1_2 ; } + if (!new_coverage) return_trace (false); + if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + return_trace (out->baseArray.serialize_subset (c, baseArray, this, - base_iter.len (), + new_coverage.length, base_indexes.iter ())); } }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh index b10102880c0..ee237eb479f 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh @@ -11,7 +11,7 @@ struct MarkLigPos { protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ MarkLigPosFormat1_2 format1; #ifndef HB_NO_BEYOND_64K MarkLigPosFormat1_2 format2; @@ -22,9 +22,9 @@ struct MarkLigPos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh index cf4cbae9a3f..509a26c2485 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh @@ -101,7 +101,7 @@ struct MarkLigPosFormat1_2 /* Now we search backwards for a non-mark glyph */ - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + auto &skippy_iter = c->iter_input; skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); if (c->last_base_until > buffer->idx) @@ -200,19 +200,13 @@ struct MarkLigPosFormat1_2 &klass_mapping))) return_trace (false); - auto new_ligature_coverage = - + hb_iter (this + ligatureCoverage) - | hb_take ((this + ligatureArray).len) - | hb_map_retains_sorting (glyph_map) - | hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; }) - ; - - if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage)) + hb_sorted_vector_t new_lig_coverage; + if (!out->ligatureArray.serialize_subset (c, ligatureArray, this, + hb_iter (this+ligatureCoverage), + classCount, &klass_mapping, new_lig_coverage)) return_trace (false); - return_trace (out->ligatureArray.serialize_subset (c, ligatureArray, this, - hb_iter (this+ligatureCoverage), - classCount, &klass_mapping)); + return_trace (out->ligatureCoverage.serialize_serialize (c->serializer, new_lig_coverage.iter ())); } }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh index e0d9eca0280..c06f013cdce 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh @@ -11,7 +11,7 @@ struct MarkMarkPos { protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ MarkMarkPosFormat1_2 format1; #ifndef HB_NO_BEYOND_64K MarkMarkPosFormat1_2 format2; @@ -22,9 +22,9 @@ struct MarkMarkPos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh index 6519e79b443..c93dbbb3f06 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh @@ -100,7 +100,7 @@ struct MarkMarkPosFormat1_2 if (likely (mark1_index == NOT_COVERED)) return_trace (false); /* now we search backwards for a suitable mark glyph until a non-mark glyph */ - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + auto &skippy_iter = c->iter_input; skippy_iter.reset_fast (buffer->idx); skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags); unsigned unsafe_from; @@ -196,19 +196,23 @@ struct MarkMarkPosFormat1_2 ; new_coverage.reset (); - + mark2_iter - | hb_map (hb_first) - | hb_map (glyph_map) - | hb_sink (new_coverage) - ; - - if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ())) - return_trace (false); - hb_sorted_vector_t mark2_indexes; - for (const unsigned row : + mark2_iter - | hb_map (hb_second)) + auto &mark2_array = (this+mark2Array); + for (const auto _ : + mark2_iter) { + unsigned row = _.second; + + bool non_empty = + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return !mark2_array.offset_is_null (row, col, (unsigned) classCount); }) + | hb_any + ; + + if (!non_empty) continue; + + hb_codepoint_t new_g = glyph_map.get ( _.first); + new_coverage.push (new_g); + + hb_range ((unsigned) classCount) | hb_filter (klass_mapping) | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) @@ -216,6 +220,10 @@ struct MarkMarkPosFormat1_2 ; } + if (!new_coverage) return_trace (false); + if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + return_trace (out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ())); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPos.hh index e3794ea9ed5..bf7fff7face 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPos.hh @@ -12,7 +12,7 @@ struct PairPos { protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ PairPosFormat1_3 format1; PairPosFormat2_4 format2; #ifndef HB_NO_BEYOND_64K @@ -25,9 +25,9 @@ struct PairPos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh index 2748882f527..1c067bde86f 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh @@ -103,52 +103,35 @@ struct PairPosFormat1_3 const Coverage &get_coverage () const { return this+coverage; } - unsigned cache_cost () const + struct external_cache_t { - return (this+coverage).cost (); - } - static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) + hb_ot_layout_mapping_cache_t coverage; + }; + void *external_cache_create () const { - switch (op) + external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t)); + if (likely (cache)) { - case hb_ot_lookup_cache_op_t::CREATE: - { - hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t)); - if (likely (cache)) - cache->clear (); - return cache; - } - case hb_ot_lookup_cache_op_t::ENTER: - return (void *) true; - case hb_ot_lookup_cache_op_t::LEAVE: - return nullptr; - case hb_ot_lookup_cache_op_t::DESTROY: - { - hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p; - hb_free (cache); - return nullptr; - } + cache->coverage.clear (); } - return nullptr; + return cache; } - bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } - bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); } - bool _apply (hb_ot_apply_context_t *c, bool cached) const + bool apply (hb_ot_apply_context_t *c, void *external_cache) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr; - unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache); + external_cache_t *cache = (external_cache_t *) external_cache; + unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache ? &cache->coverage : nullptr); #else unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); #endif if (index == NOT_COVERED) return_trace (false); - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + auto &skippy_iter = c->iter_input; skippy_iter.reset_fast (buffer->idx); unsigned unsafe_to; if (unlikely (!skippy_iter.next (&unsafe_to))) diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh index d85b1ac2c17..ce731450f41 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh @@ -123,63 +123,39 @@ struct PairPosFormat2_4 : ValueBase const Coverage &get_coverage () const { return this+coverage; } - struct pair_pos_cache_t + struct external_cache_t { - hb_ot_lookup_cache_t coverage; - hb_ot_lookup_cache_t first; - hb_ot_lookup_cache_t second; + hb_ot_layout_mapping_cache_t coverage; + hb_ot_layout_mapping_cache_t first; + hb_ot_layout_mapping_cache_t second; }; - - unsigned cache_cost () const + void *external_cache_create () const { - return (this+coverage).cost () + (this+classDef1).cost () + (this+classDef2).cost (); - } - static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) - { - switch (op) + external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t)); + if (likely (cache)) { - case hb_ot_lookup_cache_op_t::CREATE: - { - pair_pos_cache_t *cache = (pair_pos_cache_t *) hb_malloc (sizeof (pair_pos_cache_t)); - if (likely (cache)) - { - cache->coverage.clear (); - cache->first.clear (); - cache->second.clear (); - } - return cache; - } - case hb_ot_lookup_cache_op_t::ENTER: - return (void *) true; - case hb_ot_lookup_cache_op_t::LEAVE: - return nullptr; - case hb_ot_lookup_cache_op_t::DESTROY: - { - pair_pos_cache_t *cache = (pair_pos_cache_t *) p; - hb_free (cache); - return nullptr; - } + cache->coverage.clear (); + cache->first.clear (); + cache->second.clear (); } - return nullptr; + return cache; } - bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } - bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); } - bool _apply (hb_ot_apply_context_t *c, bool cached) const + bool apply (hb_ot_apply_context_t *c, void *external_cache) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - pair_pos_cache_t *cache = cached ? (pair_pos_cache_t *) c->lookup_accel->cache : nullptr; + external_cache_t *cache = (external_cache_t *) external_cache; unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache ? &cache->coverage : nullptr); #else unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); #endif if (index == NOT_COVERED) return_trace (false); - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + auto &skippy_iter = c->iter_input; skippy_iter.reset_fast (buffer->idx); unsigned unsafe_to; if (unlikely (!skippy_iter.next (&unsafe_to))) diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePos.hh index a0243a218c5..30fc1aacda8 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePos.hh @@ -12,7 +12,7 @@ struct SinglePos { protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ SinglePosFormat1 format1; SinglePosFormat2 format2; } u; @@ -41,7 +41,7 @@ struct SinglePos const hb_hashmap_t> *layout_variation_idx_delta_map, unsigned newFormat) { - if (unlikely (!c->extend_min (u.format))) return; + if (unlikely (!c->extend_min (u.format.v))) return; unsigned format = 2; ValueFormat new_format; new_format = newFormat; @@ -49,8 +49,8 @@ struct SinglePos if (glyph_val_iter_pairs) format = get_format (glyph_val_iter_pairs); - u.format = format; - switch (u.format) { + u.format.v = format; + switch (u.format.v) { case 1: u.format1.serialize (c, src, glyph_val_iter_pairs, @@ -70,9 +70,9 @@ struct SinglePos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); default:return_trace (c->default_return_value ()); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh index 731d1ffca1a..b961a5139d8 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh @@ -56,9 +56,14 @@ struct ValueFormat : HBUINT16 * PosTable (may be NULL) */ #endif - IntType& operator = (uint16_t i) { v = i; return *this; } + NumType& operator = (uint16_t i) { v = i; return *this; } - unsigned int get_len () const { return hb_popcount ((unsigned int) *this); } + // Note: spec says skip 2 bytes per bit in the valueformat. But reports + // from Microsoft developers indicate that only the fields that are + // currently defined are counted. We don't expect any new fields to + // be added to ValueFormat. As such, we use the faster hb_popcount8 + // that only processes the lowest 8 bits. + unsigned int get_len () const { return hb_popcount8 ((uint8_t) *this); } unsigned int get_size () const { return get_len () * Value::static_size; } hb_vector_t get_device_table_indices () const { @@ -111,8 +116,8 @@ struct ValueFormat : HBUINT16 if (!has_device ()) return ret; - bool use_x_device = font->x_ppem || font->num_coords; - bool use_y_device = font->y_ppem || font->num_coords; + bool use_x_device = font->x_ppem || font->has_nonzero_coords; + bool use_y_device = font->y_ppem || font->has_nonzero_coords; if (!use_x_device && !use_y_device) return ret; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSet.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSet.hh index b5d506f36f9..f13c5e7e251 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSet.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSet.hh @@ -91,6 +91,19 @@ struct AlternateSet return alternates.len; } + void + collect_alternates (hb_codepoint_t gid, + hb_map_t *alternate_count /* IN/OUT */, + hb_map_t *alternate_glyphs /* IN/OUT */) const + { + + hb_enumerate (alternates) + | hb_map ([gid] (hb_pair_t _) { return hb_pair (gid + (_.first << 24), _.second); }) + | hb_apply ([&] (const hb_pair_t &p) -> void + { _hb_collect_glyph_alternates_add (p.first, p.second, + alternate_count, alternate_glyphs); }) + ; + } + template bool serialize (hb_serialize_context_t *c, diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubst.hh index 8951f5a7a17..a43c75c8f4e 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubst.hh @@ -12,7 +12,7 @@ struct AlternateSubst { protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ AlternateSubstFormat1_2 format1; #ifndef HB_NO_BEYOND_64K AlternateSubstFormat1_2 format2; @@ -23,9 +23,9 @@ struct AlternateSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); @@ -42,10 +42,10 @@ struct AlternateSubst hb_array_t alternate_glyphs_list) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (u.format))) return_trace (false); + if (unlikely (!c->extend_min (u.format.v))) return_trace (false); unsigned int format = 1; - u.format = format; - switch (u.format) { + u.format.v = format; + switch (u.format.v) { case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list)); default:return_trace (false); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubstFormat1.hh index 421a6e06627..7a3a2511b7f 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubstFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubstFormat1.hh @@ -69,6 +69,19 @@ struct AlternateSubstFormat1_2 { return (this+alternateSet[(this+coverage).get_coverage (gid)]) .get_alternates (start_offset, alternate_count, alternate_glyphs); } + void + collect_glyph_alternates (hb_map_t *alternate_count /* IN/OUT */, + hb_map_t *alternate_glyphs /* IN/OUT */) const + { + + hb_iter (alternateSet) + | hb_map (hb_add (this)) + | hb_zip (this+coverage) + | hb_apply ([&] (const hb_pair_t &, hb_codepoint_t> _) { + _.first.collect_alternates (_.second, alternate_count, alternate_glyphs); + }) + ; + } + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh index 726da458fac..7bc98d31f32 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh @@ -44,6 +44,18 @@ struct Ligature c->output->add (ligGlyph); } + template + void collect_second (set_t &s) const + { + if (unlikely (!component.get_length ())) + { + // A ligature without any components. Anything matches. + s = set_t::full (); + return; + } + s.add (component.arrayZ[0]); + } + bool would_apply (hb_would_apply_context_t *c) const { if (c->len != component.lenP1) @@ -91,15 +103,6 @@ struct Ligature unsigned int total_component_count = 0; if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return false; - unsigned match_positions_stack[4]; - unsigned *match_positions = match_positions_stack; - if (unlikely (count > ARRAY_LENGTH (match_positions_stack))) - { - match_positions = (unsigned *) hb_malloc (hb_max (count, 1u) * sizeof (unsigned)); - if (unlikely (!match_positions)) - return_trace (false); - } - unsigned int match_end = 0; if (likely (!match_input (c, count, @@ -107,12 +110,9 @@ struct Ligature match_glyph, nullptr, &match_end, - match_positions, &total_component_count))) { c->buffer->unsafe_to_concat (c->buffer->idx, match_end); - if (match_positions != match_positions_stack) - hb_free (match_positions); return_trace (false); } @@ -129,10 +129,10 @@ struct Ligature match_end += delta; for (unsigned i = 0; i < count; i++) { - match_positions[i] += delta; + c->match_positions[i] += delta; if (i) *p++ = ','; - snprintf (p, sizeof(buf) - (p - buf), "%u", match_positions[i]); + snprintf (p, sizeof(buf) - (p - buf), "%u", c->match_positions[i]); p += strlen(p); } @@ -143,7 +143,6 @@ struct Ligature ligate_input (c, count, - match_positions, match_end, ligGlyph, total_component_count); @@ -156,8 +155,6 @@ struct Ligature pos); } - if (match_positions != match_positions_stack) - hb_free (match_positions); return_trace (true); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh index ff0ffce94d7..81c5c2bcfe4 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh @@ -11,11 +11,11 @@ namespace GSUB_impl { template struct LigatureSet { - protected: + public: Array16OfOffset16To> ligature; /* Array LigatureSet tables * ordered by preference */ - public: + DEFINE_SIZE_ARRAY (2, ligature); bool sanitize (hb_sanitize_context_t *c) const @@ -62,6 +62,15 @@ struct LigatureSet ; } + template + void collect_seconds (set_t &s) const + { + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_apply ([&s] (const Ligature &_) { _.collect_second (s); }) + ; + } + bool would_apply (hb_would_apply_context_t *c) const { return @@ -72,14 +81,14 @@ struct LigatureSet ; } - bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c, const hb_set_digest_t *seconds = nullptr) const { TRACE_APPLY (this); unsigned int num_ligs = ligature.len; #ifndef HB_NO_OT_RULESETS_FAST_PATH - if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 4) + if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 1) #endif { slow: @@ -91,21 +100,21 @@ struct LigatureSet return_trace (false); } - /* This version is optimized for speed by matching the first component + /* This version is optimized for speed by matching the second component * of the ligature here, instead of calling into the ligation code. * * This is replicated in ChainRuleSet and RuleSet. */ - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + auto &skippy_iter = c->iter_context; skippy_iter.reset (c->buffer->idx); skippy_iter.set_match_func (match_always, nullptr); skippy_iter.set_glyph_data ((HBUINT16 *) nullptr); unsigned unsafe_to; - hb_codepoint_t first = (unsigned) -1; + hb_codepoint_t second = (unsigned) -1; bool matched = skippy_iter.next (&unsafe_to); if (likely (matched)) { - first = c->buffer->info[skippy_iter.idx].codepoint; + second = c->buffer->info[skippy_iter.idx].codepoint; unsafe_to = skippy_iter.idx + 1; if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])) @@ -118,13 +127,14 @@ struct LigatureSet else goto slow; + if (seconds && !seconds->may_have (second)) + return_trace (false); bool unsafe_to_concat = false; - for (unsigned int i = 0; i < num_ligs; i++) { const auto &lig = this+ligature.arrayZ[i]; if (unlikely (lig.component.lenP1 <= 1) || - lig.component.arrayZ[0] == first) + lig.component.arrayZ[0] == second) { if (lig.apply (c)) { diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubst.hh index cffa910295f..22ce9b79d7f 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubst.hh @@ -12,7 +12,7 @@ struct LigatureSubst { protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ LigatureSubstFormat1_2 format1; #ifndef HB_NO_BEYOND_64K LigatureSubstFormat1_2 format2; @@ -23,9 +23,9 @@ struct LigatureSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); @@ -45,10 +45,10 @@ struct LigatureSubst hb_array_t component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (u.format))) return_trace (false); + if (unlikely (!c->extend_min (u.format.v))) return_trace (false); unsigned int format = 1; - u.format = format; - switch (u.format) { + u.format.v = format; + switch (u.format.v) { case 1: return_trace (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubstFormat1.hh index 6ae24b33754..909ddca220f 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubstFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubstFormat1.hh @@ -78,52 +78,44 @@ struct LigatureSubstFormat1_2 return lig_set.would_apply (c); } - unsigned cache_cost () const + struct external_cache_t { - return (this+coverage).cost (); - } - static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) + hb_ot_layout_mapping_cache_t coverage; + hb_set_digest_t seconds; + }; + void *external_cache_create () const { - switch (op) + external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t)); + if (likely (cache)) { - case hb_ot_lookup_cache_op_t::CREATE: - { - hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t)); - if (likely (cache)) - cache->clear (); - return cache; - } - case hb_ot_lookup_cache_op_t::ENTER: - return (void *) true; - case hb_ot_lookup_cache_op_t::LEAVE: - return nullptr; - case hb_ot_lookup_cache_op_t::DESTROY: - { - hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p; - hb_free (cache); - return nullptr; - } + cache->coverage.clear (); + + cache->seconds.init (); + + hb_iter (ligatureSet) + | hb_map (hb_add (this)) + | hb_apply ([cache] (const LigatureSet &_) { _.collect_seconds (cache->seconds); }) + ; } - return nullptr; + return cache; } - bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } - bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); } - bool _apply (hb_ot_apply_context_t *c, bool cached) const + bool apply (hb_ot_apply_context_t *c, void *external_cache) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr; - unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache); + external_cache_t *cache = (external_cache_t *) external_cache; + const hb_set_digest_t *seconds = cache ? &cache->seconds : nullptr; + unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache ? &cache->coverage : nullptr); #else - unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); + const hb_set_digest_t *seconds = nullptr; + unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); #endif if (index == NOT_COVERED) return_trace (false); const auto &lig_set = this+ligatureSet[index]; - return_trace (lig_set.apply (c)); + return_trace (lig_set.apply (c, seconds)); } bool serialize (hb_serialize_context_t *c, diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubst.hh index cf3d754e3cc..8fb663825b5 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubst.hh @@ -12,7 +12,7 @@ struct MultipleSubst { protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ MultipleSubstFormat1_2 format1; #ifndef HB_NO_BEYOND_64K MultipleSubstFormat1_2 format2; @@ -24,9 +24,9 @@ struct MultipleSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); @@ -41,10 +41,10 @@ struct MultipleSubst Iterator it) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (u.format))) return_trace (false); + if (unlikely (!c->extend_min (u.format.v))) return_trace (false); unsigned int format = 1; - u.format = format; - switch (u.format) { + u.format.v = format; + switch (u.format.v) { case 1: return_trace (u.format1.serialize (c, it)); default:return_trace (false); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubst.hh index 5ad463fea79..e33148d770b 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubst.hh @@ -12,7 +12,7 @@ struct ReverseChainSingleSubst { protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ ReverseChainSingleSubstFormat1 format1; } u; @@ -20,9 +20,9 @@ struct ReverseChainSingleSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); default:return_trace (c->default_return_value ()); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh index a5e93a98bef..b3295bee16d 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh @@ -115,7 +115,7 @@ struct Sequence for (unsigned i = c->buffer->idx - count; i < c->buffer->idx; i++) { - if (buf < p) + if (buf < p && sizeof(buf) - 1u > unsigned (p - buf)) *p++ = ','; snprintf (p, sizeof(buf) - (p - buf), "%u", i); p += strlen(p); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh index b84259e7f00..323eb4d0f90 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh @@ -13,7 +13,7 @@ struct SingleSubst { protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ SingleSubstFormat1_3 format1; SingleSubstFormat2_4 format2; #ifndef HB_NO_BEYOND_64K @@ -27,9 +27,9 @@ struct SingleSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K @@ -47,7 +47,7 @@ struct SingleSubst Iterator glyphs) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (u.format))) return_trace (false); + if (unlikely (!c->extend_min (u.format.v))) return_trace (false); unsigned format = 2; unsigned delta = 0; if (glyphs) @@ -71,8 +71,8 @@ struct SingleSubst if (!hb_all (++(+glyphs), delta, get_delta)) format += 1; } - u.format = format; - switch (u.format) { + u.format.v = format; + switch (u.format.v) { case 1: return_trace (u.format1.serialize (c, + glyphs | hb_map_retains_sorting (hb_first), diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat1.hh index be6cd820d28..5ee2c1d1f46 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat1.hh @@ -123,6 +123,21 @@ struct SingleSubstFormat1_3 return 1; } + void + collect_glyph_alternates (hb_map_t *alternate_count /* IN/OUT */, + hb_map_t *alternate_glyphs /* IN/OUT */) const + { + hb_codepoint_t d = deltaGlyphID; + hb_codepoint_t mask = get_mask (); + + + hb_iter (this+coverage) + | hb_map ([d, mask] (hb_codepoint_t g) { return hb_pair (g, (g + d) & mask); }) + | hb_apply ([&] (const hb_pair_t &p) -> void + { _hb_collect_glyph_alternates_add (p.first, p.second, + alternate_count, alternate_glyphs); }) + ; + } + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat2.hh index e9096460451..0d51d130fee 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat2.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat2.hh @@ -100,6 +100,17 @@ struct SingleSubstFormat2_4 return 1; } + void + collect_glyph_alternates (hb_map_t *alternate_count /* IN/OUT */, + hb_map_t *alternate_glyphs /* IN/OUT */) const + { + + hb_zip (this+coverage, substitute) + | hb_apply ([&] (const hb_pair_t &p) -> void + { _hb_collect_glyph_alternates_add (p.first, p.second, + alternate_count, alternate_glyphs); }) + ; + } + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/types.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/types.hh index 527f64114b4..5cf9eb368aa 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/types.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/types.hh @@ -29,8 +29,11 @@ #ifndef OT_LAYOUT_TYPES_HH #define OT_LAYOUT_TYPES_HH -using hb_ot_lookup_cache_t = hb_cache_t<15, 8, 7>; -static_assert (sizeof (hb_ot_lookup_cache_t) == 256, ""); +using hb_ot_layout_mapping_cache_t = hb_cache_t<16, 8, 8>; +static_assert (sizeof (hb_ot_layout_mapping_cache_t) == 512, ""); + +using hb_ot_layout_binary_cache_t = hb_cache_t<14, 1, 8>; +static_assert (sizeof (hb_ot_layout_binary_cache_t) == 256, ""); namespace OT { namespace Layout { diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.cc b/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.cc new file mode 100644 index 00000000000..f0e7f934579 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.cc @@ -0,0 +1,421 @@ +#include "VARC.hh" + +#ifndef HB_NO_VAR_COMPOSITES + +#include "../../../hb-draw.hh" +#include "../../../hb-ot-layout-common.hh" +#include "../../../hb-ot-layout-gdef-table.hh" + +namespace OT { + +//namespace Var { + + +#ifndef HB_NO_DRAW + +struct hb_transforming_pen_context_t +{ + hb_transform_t<> transform; + hb_draw_funcs_t *dfuncs; + void *data; + hb_draw_state_t *st; +}; + +static void +hb_transforming_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *data, + hb_draw_state_t *st, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; + + c->transform.transform_point (to_x, to_y); + + c->dfuncs->move_to (c->data, *c->st, to_x, to_y); +} + +static void +hb_transforming_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *data, + hb_draw_state_t *st, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; + + c->transform.transform_point (to_x, to_y); + + c->dfuncs->line_to (c->data, *c->st, to_x, to_y); +} + +static void +hb_transforming_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *data, + hb_draw_state_t *st, + float control_x, float control_y, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; + + c->transform.transform_point (control_x, control_y); + c->transform.transform_point (to_x, to_y); + + c->dfuncs->quadratic_to (c->data, *c->st, control_x, control_y, to_x, to_y); +} + +static void +hb_transforming_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *data, + hb_draw_state_t *st, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; + + c->transform.transform_point (control1_x, control1_y); + c->transform.transform_point (control2_x, control2_y); + c->transform.transform_point (to_x, to_y); + + c->dfuncs->cubic_to (c->data, *c->st, control1_x, control1_y, control2_x, control2_y, to_x, to_y); +} + +static void +hb_transforming_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *data, + hb_draw_state_t *st, + void *user_data HB_UNUSED) +{ + hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; + + c->dfuncs->close_path (c->data, *c->st); +} + +static inline void free_static_transforming_pen_funcs (); + +static struct hb_transforming_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t +{ + static hb_draw_funcs_t *create () + { + hb_draw_funcs_t *funcs = hb_draw_funcs_create (); + + hb_draw_funcs_set_move_to_func (funcs, hb_transforming_pen_move_to, nullptr, nullptr); + hb_draw_funcs_set_line_to_func (funcs, hb_transforming_pen_line_to, nullptr, nullptr); + hb_draw_funcs_set_quadratic_to_func (funcs, hb_transforming_pen_quadratic_to, nullptr, nullptr); + hb_draw_funcs_set_cubic_to_func (funcs, hb_transforming_pen_cubic_to, nullptr, nullptr); + hb_draw_funcs_set_close_path_func (funcs, hb_transforming_pen_close_path, nullptr, nullptr); + + hb_draw_funcs_make_immutable (funcs); + + hb_atexit (free_static_transforming_pen_funcs); + + return funcs; + } +} static_transforming_pen_funcs; + +static inline +void free_static_transforming_pen_funcs () +{ + static_transforming_pen_funcs.free_instance (); +} + +static hb_draw_funcs_t * +hb_transforming_pen_get_funcs () +{ + return static_transforming_pen_funcs.get_unconst (); +} + +hb_ubytes_t +VarComponent::get_path_at (const hb_varc_context_t &c, + hb_codepoint_t parent_gid, + hb_array_t coords, + hb_transform_t<> total_transform, + hb_ubytes_t total_record, + hb_scalar_cache_t *cache) const +{ + const unsigned char *end = total_record.arrayZ + total_record.length; + const unsigned char *record = total_record.arrayZ; + + auto &VARC = *c.font->face->table.VARC->table; + auto &varStore = &VARC+VARC.varStore; + +#define READ_UINT32VAR(name) \ + HB_STMT_START { \ + if (unlikely (unsigned (end - record) < HBUINT32VAR::min_size)) return hb_ubytes_t (); \ + hb_barrier (); \ + auto &varint = * (const HBUINT32VAR *) record; \ + unsigned size = varint.get_size (); \ + if (unlikely (unsigned (end - record) < size)) return hb_ubytes_t (); \ + name = (uint32_t) varint; \ + record += size; \ + } HB_STMT_END + + uint32_t flags; + READ_UINT32VAR (flags); + + // gid + + hb_codepoint_t gid = 0; + if (flags & (unsigned) flags_t::GID_IS_24BIT) + { + if (unlikely (unsigned (end - record) < HBGlyphID24::static_size)) + return hb_ubytes_t (); + hb_barrier (); + gid = * (const HBGlyphID24 *) record; + record += HBGlyphID24::static_size; + } + else + { + if (unlikely (unsigned (end - record) < HBGlyphID16::static_size)) + return hb_ubytes_t (); + hb_barrier (); + gid = * (const HBGlyphID16 *) record; + record += HBGlyphID16::static_size; + } + + // Condition + bool show = true; + if (flags & (unsigned) flags_t::HAVE_CONDITION) + { + unsigned conditionIndex; + READ_UINT32VAR (conditionIndex); + const auto &condition = (&VARC+VARC.conditionList)[conditionIndex]; + auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache); + show = condition.evaluate (coords.arrayZ, coords.length, &instancer); + } + + // Axis values + + auto &axisIndices = c.scratch.axisIndices; + axisIndices.clear (); + auto &axisValues = c.scratch.axisValues; + axisValues.clear (); + if (flags & (unsigned) flags_t::HAVE_AXES) + { + unsigned axisIndicesIndex; + READ_UINT32VAR (axisIndicesIndex); + axisIndices.extend ((&VARC+VARC.axisIndicesList)[axisIndicesIndex]); + axisValues.resize (axisIndices.length); + const HBUINT8 *p = (const HBUINT8 *) record; + TupleValues::decompile (p, axisValues, (const HBUINT8 *) end); + record = (const unsigned char *) p; + } + + // Apply variations if any + if (flags & (unsigned) flags_t::AXIS_VALUES_HAVE_VARIATION) + { + uint32_t axisValuesVarIdx; + READ_UINT32VAR (axisValuesVarIdx); + if (show && coords && !axisValues.in_error ()) + varStore.get_delta (axisValuesVarIdx, coords, axisValues.as_array (), cache); + } + + auto component_coords = coords; + /* Copying coords is expensive; so we have put an arbitrary + * limit on the max number of coords for now. */ + if ((flags & (unsigned) flags_t::RESET_UNSPECIFIED_AXES) || + coords.length > HB_VAR_COMPOSITE_MAX_AXES) + component_coords = hb_array (c.font->coords, c.font->num_coords); + + // Transform + + uint32_t transformVarIdx = VarIdx::NO_VARIATION; + if (flags & (unsigned) flags_t::TRANSFORM_HAS_VARIATION) + READ_UINT32VAR (transformVarIdx); + +#define PROCESS_TRANSFORM_COMPONENTS \ + HB_STMT_START { \ + PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TRANSLATE_X, translateX); \ + PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TRANSLATE_Y, translateY); \ + PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_ROTATION, rotation); \ + PROCESS_TRANSFORM_COMPONENT (F6DOT10, 1.0f, HAVE_SCALE_X, scaleX); \ + PROCESS_TRANSFORM_COMPONENT (F6DOT10, 1.0f, HAVE_SCALE_Y, scaleY); \ + PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_SKEW_X, skewX); \ + PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_SKEW_Y, skewY); \ + PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TCENTER_X, tCenterX); \ + PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TCENTER_Y, tCenterY); \ + } HB_STMT_END + + hb_transform_decomposed_t<> transform; + + // Read transform components +#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \ + if (flags & (unsigned) flags_t::flag) \ + { \ + static_assert (type::static_size == HBINT16::static_size, ""); \ + if (unlikely (unsigned (end - record) < HBINT16::static_size)) \ + return hb_ubytes_t (); \ + hb_barrier (); \ + transform.name = mult * * (const HBINT16 *) record; \ + record += HBINT16::static_size; \ + } + PROCESS_TRANSFORM_COMPONENTS; +#undef PROCESS_TRANSFORM_COMPONENT + + // Read reserved records + unsigned i = flags & (unsigned) flags_t::RESERVED_MASK; + while (i) + { + HB_UNUSED uint32_t discard; + READ_UINT32VAR (discard); + i &= i - 1; + } + + /* Parsing is over now. */ + + if (show) + { + // Only use coord_setter if there's actually any axis overrides. + coord_setter_t coord_setter (axisIndices ? component_coords : hb_array ()); + // Go backwards, to reduce coord_setter vector reallocations. + for (unsigned i = axisIndices.length; i; i--) + coord_setter[axisIndices[i - 1]] = axisValues[i - 1]; + if (axisIndices) + component_coords = coord_setter.get_coords (); + + // Apply transform variations if any + if (transformVarIdx != VarIdx::NO_VARIATION && coords) + { + float transformValues[9]; + unsigned numTransformValues = 0; +#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \ + if (flags & (unsigned) flags_t::flag) \ + transformValues[numTransformValues++] = transform.name / mult; + PROCESS_TRANSFORM_COMPONENTS; +#undef PROCESS_TRANSFORM_COMPONENT + varStore.get_delta (transformVarIdx, coords, hb_array (transformValues, numTransformValues), cache); + numTransformValues = 0; +#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \ + if (flags & (unsigned) flags_t::flag) \ + transform.name = transformValues[numTransformValues++] * mult; + PROCESS_TRANSFORM_COMPONENTS; +#undef PROCESS_TRANSFORM_COMPONENT + } + + // Divide them by their divisors +#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \ + if (flags & (unsigned) flags_t::flag) \ + { \ + HBINT16 int_v; \ + int_v = roundf (transform.name); \ + type typed_v = * (const type *) &int_v; \ + float float_v = (float) typed_v; \ + transform.name = float_v; \ + } + PROCESS_TRANSFORM_COMPONENTS; +#undef PROCESS_TRANSFORM_COMPONENT + + if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y)) + transform.scaleY = transform.scaleX; + + total_transform.transform (transform.to_transform ()); + total_transform.scale (c.font->x_mult ? 1.f / c.font->x_multf : 0.f, + c.font->y_mult ? 1.f / c.font->y_multf : 0.f); + + bool same_coords = component_coords.length == coords.length && + component_coords.arrayZ == coords.arrayZ; + + c.depth_left--; + VARC.get_path_at (c, gid, + component_coords, total_transform, + parent_gid, + same_coords ? cache : nullptr); + c.depth_left++; + } + +#undef PROCESS_TRANSFORM_COMPONENTS +#undef READ_UINT32VAR + + return hb_ubytes_t (record, end - record); +} + +bool +VARC::get_path_at (const hb_varc_context_t &c, + hb_codepoint_t glyph, + hb_array_t coords, + hb_transform_t<> transform, + hb_codepoint_t parent_glyph, + hb_scalar_cache_t *parent_cache) const +{ + // Don't recurse on the same glyph. + unsigned idx = glyph == parent_glyph ? + NOT_COVERED : + (this+coverage).get_coverage (glyph); + if (idx == NOT_COVERED) + { + if (c.draw_session) + { + // Build a transforming pen to apply the transform. + hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs (); + hb_transforming_pen_context_t context {transform, + c.draw_session->funcs, + c.draw_session->draw_data, + &c.draw_session->st}; + hb_draw_session_t transformer_session {transformer_funcs, &context}; + hb_draw_session_t &shape_draw_session = transform.is_identity () ? *c.draw_session : transformer_session; + + if (c.font->face->table.glyf->get_path_at (c.font, glyph, shape_draw_session, coords, c.scratch.glyf_scratch)) return true; +#ifndef HB_NO_CFF + if (c.font->face->table.cff2->get_path_at (c.font, glyph, shape_draw_session, coords)) return true; + if (c.font->face->table.cff1->get_path (c.font, glyph, shape_draw_session)) return true; // Doesn't have variations +#endif + return false; + } + else if (c.extents) + { + hb_glyph_extents_t glyph_extents; + if (!c.font->face->table.glyf->get_extents_at (c.font, glyph, &glyph_extents, coords)) +#ifndef HB_NO_CFF + if (!c.font->face->table.cff2->get_extents_at (c.font, glyph, &glyph_extents, coords)) + if (!c.font->face->table.cff1->get_extents (c.font, glyph, &glyph_extents)) // Doesn't have variations +#endif + return false; + + hb_extents_t<> comp_extents (glyph_extents); + transform.transform_extents (comp_extents); + c.extents->union_ (comp_extents); + } + return true; + } + + if (c.depth_left <= 0) + return true; + + if (c.edges_left <= 0) + return true; + (c.edges_left)--; + + hb_decycler_node_t node (c.decycler); + if (unlikely (!node.visit (glyph))) + return true; + + hb_ubytes_t record = (this+glyphRecords)[idx]; + + hb_scalar_cache_t static_cache; + hb_scalar_cache_t *cache = parent_cache ? + parent_cache : + (this+varStore).create_cache (&static_cache); + + transform.scale (c.font->x_multf, c.font->y_multf); + + VarCompositeGlyph::get_path_at (c, + glyph, + coords, transform, + record, + cache); + + if (cache != parent_cache) + (this+varStore).destroy_cache (cache, &static_cache); + + return true; +} + +#endif + +//} // namespace Var +} // namespace OT + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh b/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh index 2ea1b6bca32..6b40f044556 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh @@ -32,7 +32,7 @@ struct hb_varc_context_t { hb_font_t *font; hb_draw_session_t *draw_session; - hb_extents_t *extents; + hb_extents_t<> *extents; mutable hb_decycler_t decycler; mutable signed edges_left; mutable signed depth_left; @@ -65,9 +65,9 @@ struct VarComponent get_path_at (const hb_varc_context_t &c, hb_codepoint_t parent_gid, hb_array_t coords, - hb_transform_t transform, + hb_transform_t<> transform, hb_ubytes_t record, - VarRegionList::cache_t *cache = nullptr) const; + hb_scalar_cache_t *cache = nullptr) const; }; struct VarCompositeGlyph @@ -76,9 +76,9 @@ struct VarCompositeGlyph get_path_at (const hb_varc_context_t &c, hb_codepoint_t gid, hb_array_t coords, - hb_transform_t transform, + hb_transform_t<> transform, hb_ubytes_t record, - VarRegionList::cache_t *cache) + hb_scalar_cache_t *cache) { while (record) { @@ -104,9 +104,9 @@ struct VARC get_path_at (const hb_varc_context_t &c, hb_codepoint_t gid, hb_array_t coords, - hb_transform_t transform = HB_TRANSFORM_IDENTITY, + hb_transform_t<> transform = HB_TRANSFORM_IDENTITY, hb_codepoint_t parent_gid = HB_CODEPOINT_INVALID, - VarRegionList::cache_t *parent_cache = nullptr) const; + hb_scalar_cache_t *parent_cache = nullptr) const; bool get_path (hb_font_t *font, @@ -129,7 +129,7 @@ struct VARC bool get_extents (hb_font_t *font, hb_codepoint_t gid, - hb_extents_t *extents, + hb_extents_t<> *extents, hb_varc_scratch_t &scratch) const { hb_varc_context_t c {font, @@ -194,9 +194,10 @@ struct VARC hb_codepoint_t gid, hb_glyph_extents_t *extents) const { +#ifndef HB_NO_DRAW if (!table->has_data ()) return false; - hb_extents_t f_extents; + hb_extents_t<> f_extents; auto *scratch = acquire_scratch (); if (unlikely (!scratch)) return true; @@ -207,6 +208,9 @@ struct VARC *extents = f_extents.to_glyph_extents (font->x_scale < 0, font->y_scale < 0); return ret; +#else + return false; +#endif } private: diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh index 1805df262aa..8f5287e9457 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh @@ -102,17 +102,15 @@ struct Glyph if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; hb_array_t phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); { + // Duplicated code. int lsb = 0; - int h_delta = face->table.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ? - (int) header->xMin - lsb : 0; + face->table.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb); + int h_delta = (int) header->xMin - lsb; HB_UNUSED int tsb = 0; - int v_orig = (int) header->yMax + #ifndef HB_NO_VERTICAL - ((void) face->table.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb) -#else - 0 + face->table.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb); #endif - ; + int v_orig = (int) header->yMax + tsb; unsigned h_adv = face->table.hmtx->get_advance_without_var_unscaled (gid); unsigned v_adv = #ifndef HB_NO_VERTICAL @@ -314,6 +312,7 @@ struct Glyph bool use_my_metrics = true, bool phantom_only = false, hb_array_t coords = hb_array_t (), + hb_scalar_cache_t *gvar_cache = nullptr, unsigned int depth = 0, unsigned *edge_count = nullptr) const { @@ -328,7 +327,7 @@ struct Glyph head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth); } - if (!coords) + if (!coords && font->has_nonzero_coords) coords = hb_array (font->coords, font->num_coords); contour_point_vector_t &points = type == SIMPLE ? all_points : scratch.comp_points; @@ -357,17 +356,15 @@ struct Glyph if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; hb_array_t phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); { + // Duplicated code. int lsb = 0; - int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ? - (int) header->xMin - lsb : 0; + glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb); + int h_delta = (int) header->xMin - lsb; HB_UNUSED int tsb = 0; - int v_orig = (int) header->yMax + #ifndef HB_NO_VERTICAL - ((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb) -#else - 0 + glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb); #endif - ; + int v_orig = (int) header->yMax + tsb; unsigned h_adv = glyf_accelerator.hmtx->get_advance_without_var_unscaled (gid); unsigned v_adv = #ifndef HB_NO_VERTICAL @@ -383,7 +380,7 @@ struct Glyph } #ifndef HB_NO_VAR - if (coords) + if (hb_any (coords)) { #ifndef HB_NO_BEYOND_64K if (glyf_accelerator.GVAR->has_data ()) @@ -391,6 +388,7 @@ struct Glyph coords, points.as_array ().sub_array (old_length), scratch, + gvar_cache, phantom_only && type == SIMPLE); else #endif @@ -398,6 +396,7 @@ struct Glyph coords, points.as_array ().sub_array (old_length), scratch, + gvar_cache, phantom_only && type == SIMPLE); } #endif @@ -447,6 +446,7 @@ struct Glyph use_my_metrics, phantom_only, coords, + gvar_cache, depth + 1, edge_count))) { @@ -533,7 +533,11 @@ struct Glyph bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator, hb_glyph_extents_t *extents) const { - if (type == EMPTY) return true; /* Empty glyph; zero extents. */ + if (type == EMPTY) + { + *extents = {0, 0, 0, 0}; + return true; /* Empty glyph; zero extents. */ + } return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh index 601e1303792..507c94f7f3d 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh @@ -189,7 +189,7 @@ struct SimpleGlyph unsigned old_length = points.length; points.alloc (points.length + num_points + 4); // Allocate for phantom points, to avoid a possible copy - if (unlikely (!points.resize (points.length + num_points, false))) return false; + if (unlikely (!points.resize_dirty (points.length + num_points))) return false; auto points_ = points.as_array ().sub_array (old_length); if (!phantom_only) hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh index d9e5fedfa92..3fe2506bec9 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh @@ -220,7 +220,8 @@ struct glyf_accelerator_t template bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer, hb_array_t coords, - hb_glyf_scratch_t &scratch) const + hb_glyf_scratch_t &scratch, + hb_scalar_cache_t *gvar_cache = nullptr) const { if (gid >= num_glyphs) return false; @@ -228,7 +229,7 @@ struct glyf_accelerator_t all_points.resize (0); bool phantom_only = !consumer.is_consuming_contour_points (); - if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords))) + if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords, gvar_cache))) return false; unsigned count = all_points.length; @@ -371,28 +372,28 @@ struct glyf_accelerator_t contour_point_t *get_phantoms_sink () { return phantoms; } }; +#ifndef HB_NO_VAR unsigned - get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const + get_advance_with_var_unscaled (hb_codepoint_t gid, + hb_font_t *font, + bool is_vertical, + hb_glyf_scratch_t &scratch, + hb_scalar_cache_t *gvar_cache = nullptr) const { if (unlikely (gid >= num_glyphs)) return 0; bool success = false; contour_point_t phantoms[glyf_impl::PHANTOM_COUNT]; - if (font->num_coords) - { - hb_glyf_scratch_t scratch; - success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false), - hb_array (font->coords, font->num_coords), - scratch); - } - + success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false), + hb_array (font->coords, + font->has_nonzero_coords ? font->num_coords : 0), + scratch, gvar_cache); if (unlikely (!success)) - return -#ifndef HB_NO_VERTICAL - is_vertical ? vmtx->get_advance_without_var_unscaled (gid) : -#endif - hmtx->get_advance_without_var_unscaled (gid); + { + unsigned upem = font->face->get_upem (); + return is_vertical ? upem : upem / 2; + } float result = is_vertical ? phantoms[glyf_impl::PHANTOM_TOP].y - phantoms[glyf_impl::PHANTOM_BOTTOM].y @@ -400,40 +401,38 @@ struct glyf_accelerator_t return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2); } - bool get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical, int *lsb) const + float + get_v_origin_with_var_unscaled (hb_codepoint_t gid, + hb_font_t *font, + hb_glyf_scratch_t &scratch, + hb_scalar_cache_t *gvar_cache = nullptr) const { - if (unlikely (gid >= num_glyphs)) return false; + if (unlikely (gid >= num_glyphs)) return 0; + + bool success = false; - hb_glyph_extents_t extents; - hb_glyf_scratch_t scratch; contour_point_t phantoms[glyf_impl::PHANTOM_COUNT]; - if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms, false), - hb_array (font->coords, font->num_coords), - scratch))) - return false; + success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false), + hb_array (font->coords, + font->has_nonzero_coords ? font->num_coords : 0), + scratch, gvar_cache); + if (unlikely (!success)) + { + return font->face->get_upem (); + } - *lsb = is_vertical - ? roundf (phantoms[glyf_impl::PHANTOM_TOP].y) - extents.y_bearing - : roundf (phantoms[glyf_impl::PHANTOM_LEFT].x); - return true; + return phantoms[glyf_impl::PHANTOM_TOP].y; } #endif - - bool get_leading_bearing_without_var_unscaled (hb_codepoint_t gid, bool is_vertical, int *lsb) const - { - if (unlikely (gid >= num_glyphs)) return false; - if (is_vertical) return false; // TODO Humm, what to do here? - - *lsb = glyph_for_gid (gid).get_header ()->xMin; - return true; - } +#endif public: bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const - { return get_extents_at (font, gid, extents, hb_array (font->coords, font->num_coords)); } + { return get_extents_at (font, gid, extents, hb_array (font->coords, + font->has_nonzero_coords ? font->num_coords : 0)); } bool get_extents_at (hb_font_t *font, hb_codepoint_t gid, @@ -445,12 +444,15 @@ struct glyf_accelerator_t #ifndef HB_NO_VAR if (coords) { - hb_glyf_scratch_t scratch; - return get_points (font, - gid, - points_aggregator_t (font, extents, nullptr, true), - coords, - scratch); + hb_glyf_scratch_t *scratch = acquire_scratch (); + if (unlikely (!scratch)) return false; + bool ret = get_points (font, + gid, + points_aggregator_t (font, extents, nullptr, true), + coords, + *scratch); + release_scratch (scratch); + return ret; } #endif return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents); @@ -485,33 +487,20 @@ struct glyf_accelerator_t } bool - get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const + get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session, hb_scalar_cache_t *gvar_cache = nullptr) const { if (!has_data ()) return false; - hb_glyf_scratch_t *scratch; - - // Borrow the cached strach buffer. - { - scratch = cached_scratch.get_acquire (); - if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr))) - { - scratch = (hb_glyf_scratch_t *) hb_calloc (1, sizeof (hb_glyf_scratch_t)); - if (unlikely (!scratch)) - return true; - } - } + hb_glyf_scratch_t *scratch = acquire_scratch (); + if (unlikely (!scratch)) return true; bool ret = get_points (font, gid, glyf_impl::path_builder_t (font, draw_session), - hb_array (font->coords, font->num_coords), - *scratch); + hb_array (font->coords, + font->has_nonzero_coords ? font->num_coords : 0), + *scratch, + gvar_cache); - // Put it back. - if (!cached_scratch.cmpexch (nullptr, scratch)) - { - scratch->~hb_glyf_scratch_t (); - hb_free (scratch); - } + release_scratch (scratch); return ret; } @@ -519,12 +508,38 @@ struct glyf_accelerator_t bool get_path_at (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session, hb_array_t coords, - hb_glyf_scratch_t &scratch) const + hb_glyf_scratch_t &scratch, + hb_scalar_cache_t *gvar_cache = nullptr) const { if (!has_data ()) return false; return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session), coords, - scratch); + scratch, + gvar_cache); + } + + + hb_glyf_scratch_t *acquire_scratch () const + { + if (!has_data ()) return nullptr; + hb_glyf_scratch_t *scratch = cached_scratch.get_acquire (); + if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr))) + { + scratch = (hb_glyf_scratch_t *) hb_calloc (1, sizeof (hb_glyf_scratch_t)); + if (unlikely (!scratch)) + return nullptr; + } + return scratch; + } + void release_scratch (hb_glyf_scratch_t *scratch) const + { + if (!scratch) + return; + if (!cached_scratch.cmpexch (nullptr, scratch)) + { + scratch->~hb_glyf_scratch_t (); + hb_free (scratch); + } } #ifndef HB_NO_VAR diff --git a/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh index da6378820bb..d1f38b9de8a 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh @@ -74,7 +74,7 @@ struct ClassDef : public OT::ClassDef class_def_link->width = SmallTypes::size; class_def_link->objidx = class_def_prime_id; class_def_link->position = link_position; - class_def_prime_vertex.add_parent (parent_id); + class_def_prime_vertex.add_parent (parent_id, false); return true; } @@ -117,7 +117,7 @@ struct ClassDef : public OT::ClassDef int64_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < OT::ClassDef::min_size) return false; hb_barrier (); - switch (u.format) + switch (u.format.v) { case 1: return ((ClassDefFormat1*)this)->sanitize (vertex); case 2: return ((ClassDefFormat2*)this)->sanitize (vertex); diff --git a/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh index 61ca063e345..46c703524d9 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh @@ -32,29 +32,27 @@ namespace graph { -struct CoverageFormat1 : public OT::Layout::Common::CoverageFormat1_3 -{ - bool sanitize (graph_t::vertex_t& vertex) const - { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; - constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3::min_size; - if (vertex_len < min_size) return false; - hb_barrier (); - return vertex_len >= min_size + glyphArray.get_size () - glyphArray.len.get_size (); - } -}; +static bool sanitize ( + const OT::Layout::Common::CoverageFormat1_3* thiz, + graph_t::vertex_t& vertex +) { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3::min_size; + if (vertex_len < min_size) return false; + hb_barrier (); + return vertex_len >= min_size + thiz->glyphArray.get_size () - thiz->glyphArray.len.get_size (); +} -struct CoverageFormat2 : public OT::Layout::Common::CoverageFormat2_4 -{ - bool sanitize (graph_t::vertex_t& vertex) const - { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; - constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4::min_size; - if (vertex_len < min_size) return false; - hb_barrier (); - return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size (); - } -}; +static bool sanitize ( + const OT::Layout::Common::CoverageFormat2_4* thiz, + graph_t::vertex_t& vertex +) { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4::min_size; + if (vertex_len < min_size) return false; + hb_barrier (); + return vertex_len >= min_size + thiz->rangeRecord.get_size () - thiz->rangeRecord.len.get_size (); +} struct Coverage : public OT::Layout::Common::Coverage { @@ -98,11 +96,33 @@ struct Coverage : public OT::Layout::Common::Coverage coverage_link->width = SmallTypes::size; coverage_link->objidx = coverage_prime_id; coverage_link->position = link_position; - coverage_prime_vertex.add_parent (parent_id); + coverage_prime_vertex.add_parent (parent_id, false); return (Coverage*) coverage_prime_vertex.obj.head; } + // Filter an existing coverage table to glyphs at indices [start, end) and replace it with the filtered version. + static bool filter_coverage (gsubgpos_graph_context_t& c, + unsigned existing_coverage, + unsigned start, unsigned end) { + unsigned coverage_size = c.graph.vertices_[existing_coverage].table_size (); + auto& coverage_v = c.graph.vertices_[existing_coverage]; + Coverage* coverage_table = (Coverage*) coverage_v.obj.head; + if (!coverage_table || !coverage_table->sanitize (coverage_v)) + return false; + + auto new_coverage = + + hb_zip (coverage_table->iter (), hb_range ()) + | hb_filter ([&] (hb_pair_t p) { + return p.second >= start && p.second < end; + }) + | hb_map_retains_sorting (hb_first) + ; + + return make_coverage (c, new_coverage, existing_coverage, coverage_size * 2 + 100); + } + + // Replace the coverage table at dest obj with one covering 'glyphs'. template static bool make_coverage (gsubgpos_graph_context_t& c, It glyphs, @@ -141,10 +161,10 @@ struct Coverage : public OT::Layout::Common::Coverage int64_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < OT::Layout::Common::Coverage::min_size) return false; hb_barrier (); - switch (u.format) + switch (u.format.v) { - case 1: return ((CoverageFormat1*)this)->sanitize (vertex); - case 2: return ((CoverageFormat2*)this)->sanitize (vertex); + case 1: return graph::sanitize ((const OT::Layout::Common::CoverageFormat1_3*) this, vertex); + case 2: return graph::sanitize ((const OT::Layout::Common::CoverageFormat2_4*) this, vertex); #ifndef HB_NO_BEYOND_64K // Not currently supported case 3: diff --git a/src/java.desktop/share/native/libharfbuzz/graph/graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/graph.hh index ed1026f5866..78ae1a9dd5b 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/graph.hh @@ -50,6 +50,7 @@ struct graph_t private: unsigned incoming_edges_ = 0; unsigned single_parent = (unsigned) -1; + bool has_incoming_virtual_edges_ = false; hb_hashmap_t parents; public: @@ -66,6 +67,11 @@ struct graph_t return parents.in_error (); } + bool has_incoming_virtual_edges () const + { + return has_incoming_virtual_edges_; + } + bool link_positions_valid (unsigned num_objects, bool removed_nil) { hb_set_t assigned_bytes; @@ -121,7 +127,9 @@ struct graph_t } } - bool equals (const vertex_t& other, + bool equals (unsigned this_index, + unsigned other_index, + const vertex_t& other, const graph_t& graph, const graph_t& other_graph, unsigned depth) const @@ -129,8 +137,10 @@ struct graph_t if (!(as_bytes () == other.as_bytes ())) { DEBUG_MSG (SUBSET_REPACK, nullptr, - "vertex [%lu] bytes != [%lu] bytes, depth = %u", + "vertex %u [%lu bytes] != %u [%lu bytes], depth = %u", + this_index, (unsigned long) table_size (), + other_index, (unsigned long) other.table_size (), depth); @@ -162,6 +172,7 @@ struct graph_t hb_swap (a.single_parent, b.single_parent); hb_swap (a.parents, b.parents); hb_swap (a.incoming_edges_, b.incoming_edges_); + hb_swap (a.has_incoming_virtual_edges_, b.has_incoming_virtual_edges_); hb_swap (a.start, b.start); hb_swap (a.end, b.end); hb_swap (a.priority, b.priority); @@ -207,13 +218,16 @@ struct graph_t void reset_parents () { incoming_edges_ = 0; + has_incoming_virtual_edges_ = false; single_parent = (unsigned) -1; parents.reset (); } - void add_parent (unsigned parent_index) + void add_parent (unsigned parent_index, bool is_virtual) { assert (parent_index != (unsigned) -1); + has_incoming_virtual_edges_ |= is_virtual; + if (incoming_edges_ == 0) { single_parent = parent_index; @@ -408,7 +422,7 @@ struct graph_t link_a.bias != link_b.bias) return false; - if (!graph.vertices_[link_a.objidx].equals ( + if (!graph.vertices_[link_a.objidx].equals (link_a.objidx, link_b.objidx, other_graph.vertices_[link_b.objidx], graph, other_graph, depth + 1)) return false; @@ -456,8 +470,12 @@ struct graph_t num_roots_for_space_.push (1); bool removed_nil = false; vertices_.alloc (objects.length); - vertices_scratch_.alloc (objects.length); + ordering_.resize (objects.length); + ordering_scratch_.alloc (objects.length); + unsigned count = objects.length; + unsigned order = objects.length; + unsigned skip = 0; for (unsigned i = 0; i < count; i++) { // If this graph came from a serialization buffer object 0 is the @@ -465,6 +483,9 @@ struct graph_t if (i == 0 && !objects.arrayZ[i]) { removed_nil = true; + order--; + ordering_.resize(objects.length - 1); + skip++; continue; } @@ -474,6 +495,12 @@ struct graph_t check_success (v->link_positions_valid (count, removed_nil)); + // To start we set the ordering to match the provided objects + // list. Note: objects are provided to us in reverse order (ie. + // the last object is the root). + unsigned obj_idx = i - skip; + ordering_[--order] = obj_idx; + if (!removed_nil) continue; // Fix indices to account for removed nil object. for (auto& l : v->obj.all_links_writer ()) { @@ -490,17 +517,20 @@ struct graph_t bool operator== (const graph_t& other) const { - return root ().equals (other.root (), *this, other, 0); + return root ().equals (root_idx(), other.root_idx(), other.root (), *this, other, 0); } void print () const { - for (int i = vertices_.length - 1; i >= 0; i--) + for (unsigned id : ordering_) { - const auto& v = vertices_[i]; - printf("%d: %u [", i, (unsigned int)v.table_size()); + const auto& v = vertices_[id]; + printf("%u: %u [", id, (unsigned int)v.table_size()); for (const auto &l : v.obj.real_links) { printf("%u, ", l.objidx); } + for (const auto &l : v.obj.virtual_links) { + printf("v%u, ", l.objidx); + } printf("]\n"); } } @@ -516,6 +546,7 @@ struct graph_t { return !successful || vertices_.in_error () || + ordering_.in_error() || num_roots_for_space_.in_error (); } @@ -526,10 +557,10 @@ struct graph_t unsigned root_idx () const { - // Object graphs are in reverse order, the first object is at the end - // of the vector. Since the graph is topologically sorted it's safe to + // First element of ordering_ is the root. + // Since the graph is topologically sorted it's safe to // assume the first object has no incoming edges. - return vertices_.length - 1; + return ordering_[0]; } const hb_serialize_context_t::object_t& object (unsigned i) const @@ -556,7 +587,7 @@ struct graph_t link->width = 2; link->objidx = child_id; link->position = (char*) offset - (char*) v.obj.head; - vertices_[child_id].add_parent (parent_id); + vertices_[child_id].add_parent (parent_id, false); } /* @@ -587,55 +618,51 @@ struct graph_t hb_priority_queue_t queue; queue.alloc (vertices_.length); - hb_vector_t &sorted_graph = vertices_scratch_; - if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return; - hb_vector_t id_map; - if (unlikely (!check_success (id_map.resize (vertices_.length)))) return; + hb_vector_t &new_ordering = ordering_scratch_; + if (unlikely (!check_success (new_ordering.resize (vertices_.length)))) return; hb_vector_t removed_edges; if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return; update_parents (); queue.insert (root ().modified_distance (0), root_idx ()); - int new_id = root_idx (); unsigned order = 1; + unsigned pos = 0; while (!queue.in_error () && !queue.is_empty ()) { unsigned next_id = queue.pop_minimum().second; - sorted_graph[new_id] = std::move (vertices_[next_id]); - const vertex_t& next = sorted_graph[new_id]; - - if (unlikely (!check_success(new_id >= 0))) { + if (unlikely (!check_success(pos < new_ordering.length))) { // We are out of ids. Which means we've visited a node more than once. // This graph contains a cycle which is not allowed. DEBUG_MSG (SUBSET_REPACK, nullptr, "Invalid graph. Contains cycle."); return; } - - id_map[next_id] = new_id--; + new_ordering[pos++] = next_id; + const vertex_t& next = vertices_[next_id]; for (const auto& link : next.obj.all_links ()) { removed_edges[link.objidx]++; - if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx])) + const auto& v = vertices_[link.objidx]; + if (!(v.incoming_edges () - removed_edges[link.objidx])) // Add the order that the links were encountered to the priority. // This ensures that ties between priorities objects are broken in a consistent // way. More specifically this is set up so that if a set of objects have the same // distance they'll be added to the topological order in the order that they are // referenced from the parent object. - queue.insert (vertices_[link.objidx].modified_distance (order++), + queue.insert (v.modified_distance (order++), link.objidx); } } check_success (!queue.in_error ()); - check_success (!sorted_graph.in_error ()); + check_success (!new_ordering.in_error ()); - check_success (remap_all_obj_indices (id_map, &sorted_graph)); - vertices_ = std::move (sorted_graph); + hb_swap (ordering_, new_ordering); - if (!check_success (new_id == -1)) + if (!check_success (pos == vertices_.length)) { print_orphaned_nodes (); + } } /* @@ -645,8 +672,8 @@ struct graph_t */ void find_space_roots (hb_set_t& visited, hb_set_t& roots) { - int root_index = (int) root_idx (); - for (int i = root_index; i >= 0; i--) + unsigned root_index = root_idx (); + for (unsigned i : ordering_) { if (visited.has (i)) continue; @@ -829,7 +856,6 @@ struct graph_t if (subgraph.in_error ()) return false; - unsigned original_root_idx = root_idx (); hb_map_t index_map; bool made_changes = false; for (auto entry : subgraph.iter ()) @@ -852,14 +878,6 @@ struct graph_t if (!made_changes) return false; - if (original_root_idx != root_idx () - && parents.has (original_root_idx)) - { - // If the root idx has changed since parents was determined, update root idx in parents - parents.add (root_idx ()); - parents.del (original_root_idx); - } - auto new_subgraph = + subgraph.keys () | hb_map([&] (uint32_t node_idx) { @@ -943,12 +961,14 @@ struct graph_t /* * Moves the child of old_parent_idx pointed to by old_offset to a new * vertex at the new_offset. + * + * Returns the id of the child node that was moved. */ template - void move_child (unsigned old_parent_idx, - const O* old_offset, - unsigned new_parent_idx, - const O* new_offset) + unsigned move_child (unsigned old_parent_idx, + const O* old_offset, + unsigned new_parent_idx, + const O* new_offset) { distance_invalid = true; positions_invalid = true; @@ -965,10 +985,56 @@ struct graph_t new_link->position = (const char*) new_offset - (const char*) new_v.obj.head; auto& child = vertices_[child_id]; - child.add_parent (new_parent_idx); + child.add_parent (new_parent_idx, false); old_v.remove_real_link (child_id, old_offset); child.remove_parent (old_parent_idx); + + return child_id; + } + + /* + * Moves all outgoing links in old parent that have + * a link position between [old_post_start, old_pos_end) + * to the new parent. Links are placed serially in the new + * parent starting at new_pos_start. + */ + template + void move_children (unsigned old_parent_idx, + unsigned old_pos_start, + unsigned old_pos_end, + unsigned new_parent_idx, + unsigned new_pos_start) + { + distance_invalid = true; + positions_invalid = true; + + auto& old_v = vertices_[old_parent_idx]; + auto& new_v = vertices_[new_parent_idx]; + + hb_vector_t old_links; + for (const auto& l : old_v.obj.real_links) + { + if (l.position < old_pos_start || l.position >= old_pos_end) + { + old_links.push(l); + continue; + } + + unsigned array_pos = l.position - old_pos_start; + + unsigned child_id = l.objidx; + auto* new_link = new_v.obj.real_links.push (); + new_link->width = O::static_size; + new_link->objidx = child_id; + new_link->position = new_pos_start + array_pos; + + auto& child = vertices_[child_id]; + child.add_parent (new_parent_idx, false); + child.remove_parent (old_parent_idx); + } + + old_v.obj.real_links = std::move (old_links); } /* @@ -1000,8 +1066,11 @@ struct graph_t distance_invalid = true; auto* clone = vertices_.push (); + unsigned clone_idx = vertices_.length - 1; + ordering_.push(clone_idx); + auto& child = vertices_[node_idx]; - if (vertices_.in_error ()) { + if (vertices_.in_error () || ordering_.in_error()) { return -1; } @@ -1011,51 +1080,23 @@ struct graph_t clone->space = child.space; clone->reset_parents (); - unsigned clone_idx = vertices_.length - 2; for (const auto& l : child.obj.real_links) { clone->obj.real_links.push (l); - vertices_[l.objidx].add_parent (clone_idx); + vertices_[l.objidx].add_parent (clone_idx, false); } for (const auto& l : child.obj.virtual_links) { clone->obj.virtual_links.push (l); - vertices_[l.objidx].add_parent (clone_idx); + vertices_[l.objidx].add_parent (clone_idx, true); } check_success (!clone->obj.real_links.in_error ()); check_success (!clone->obj.virtual_links.in_error ()); - // The last object is the root of the graph, so swap back the root to the end. - // The root's obj idx does change, however since it's root nothing else refers to it. - // all other obj idx's will be unaffected. - hb_swap (vertices_[vertices_.length - 2], *clone); - - // Since the root moved, update the parents arrays of all children on the root. - for (const auto& l : root ().obj.all_links ()) - vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ()); - return clone_idx; } - /* - * Creates a copy of child and re-assigns the link from - * parent to the clone. The copy is a shallow copy, objects - * linked from child are not duplicated. - * - * Returns the index of the newly created duplicate. - * - * If the child_idx only has incoming edges from parent_idx, this - * will do nothing and return the original child_idx. - */ - unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx) - { - unsigned new_idx = duplicate (parent_idx, child_idx); - if (new_idx == (unsigned) -1) return child_idx; - return new_idx; - } - - /* * Creates a copy of child and re-assigns the link from * parent to the clone. The copy is a shallow copy, objects @@ -1073,10 +1114,15 @@ struct graph_t const auto& child = vertices_[child_idx]; unsigned links_to_child = child.incoming_edges_from_parent(parent_idx); - if (child.incoming_edges () <= links_to_child) + if (child.incoming_edges () <= links_to_child || child.has_incoming_virtual_edges()) { // Can't duplicate this node, doing so would orphan the original one as all remaining links // to child are from parent. + // + // We don't allow duplication of nodes with incoming virtual edges because we don't track + // the number of virtual vs real incoming edges. As a result we can't tell if a node + // with virtual edges may end up orphaned by duplication (ie. where one copy is only pointed + // to by virtual edges). DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %u => %u", parent_idx, child_idx); return -1; @@ -1091,12 +1137,15 @@ struct graph_t if (parent_idx == clone_idx) parent_idx++; auto& parent = vertices_[parent_idx]; + unsigned count = 0; + unsigned num_real = parent.obj.real_links.length; for (auto& l : parent.obj.all_links_writer ()) { + count++; if (l.objidx != child_idx) continue; - reassign_link (l, parent_idx, clone_idx); + reassign_link (l, parent_idx, clone_idx, count > num_real); } return clone_idx; @@ -1129,10 +1178,15 @@ struct graph_t links_to_child += child.incoming_edges_from_parent(parent_idx); } - if (child.incoming_edges () <= links_to_child) + if (child.incoming_edges () <= links_to_child || child.has_incoming_virtual_edges()) { // Can't duplicate this node, doing so would orphan the original one as all remaining links // to child are from parent. + // + // We don't allow duplication of nodes with incoming virtual edges because we don't track + // the number of virtual vs real incoming edges. As a result we can't tell if a node + // with virtual edges may end up orphaned by duplication (ie. where one copy is only pointed + // to by virtual edges). DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx); return -1; } @@ -1146,12 +1200,15 @@ struct graph_t // duplicate shifts the root node idx, so if parent_idx was root update it. if (parent_idx == clone_idx) parent_idx++; auto& parent = vertices_[parent_idx]; + unsigned count = 0; + unsigned num_real = parent.obj.real_links.length; for (auto& l : parent.obj.all_links_writer ()) { + count++; if (l.objidx != child_idx) continue; - reassign_link (l, parent_idx, clone_idx); + reassign_link (l, parent_idx, clone_idx, count > num_real); } } @@ -1168,7 +1225,10 @@ struct graph_t distance_invalid = true; auto* clone = vertices_.push (); - if (vertices_.in_error ()) { + unsigned clone_idx = vertices_.length - 1; + ordering_.push(clone_idx); + + if (vertices_.in_error () || ordering_.in_error()) { return -1; } @@ -1177,20 +1237,37 @@ struct graph_t clone->distance = 0; clone->space = 0; - unsigned clone_idx = vertices_.length - 2; - - // The last object is the root of the graph, so swap back the root to the end. - // The root's obj idx does change, however since it's root nothing else refers to it. - // all other obj idx's will be unaffected. - hb_swap (vertices_[vertices_.length - 2], *clone); - - // Since the root moved, update the parents arrays of all children on the root. - for (const auto& l : root ().obj.all_links ()) - vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ()); - return clone_idx; } + /* + * Creates a new child node and remap the old child to it. + * + * Returns the index of the newly created child. + * + */ + unsigned remap_child (unsigned parent_idx, unsigned old_child_idx) + { + unsigned new_child_idx = duplicate (old_child_idx); + if (new_child_idx == (unsigned) -1) return -1; + + auto& parent = vertices_[parent_idx]; + for (auto& l : parent.obj.real_links) + { + if (l.objidx != old_child_idx) + continue; + reassign_link (l, parent_idx, new_child_idx, false); + } + + for (auto& l : parent.obj.virtual_links) + { + if (l.objidx != old_child_idx) + continue; + reassign_link (l, parent_idx, new_child_idx, true); + } + return new_child_idx; + } + /* * Raises the sorting priority of all children. */ @@ -1279,6 +1356,7 @@ struct graph_t if (!DEBUG_ENABLED(SUBSET_REPACK)) return; DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected."); + parents_invalid = true; update_parents(); @@ -1348,7 +1426,8 @@ struct graph_t size_t total_size = 0; unsigned count = vertices_.length; for (unsigned i = 0; i < count; i++) { - size_t size = vertices_.arrayZ[i].obj.tail - vertices_.arrayZ[i].obj.head; + const auto& obj = vertices_.arrayZ[i].obj; + size_t size = obj.tail - obj.head; total_size += size; } return total_size; @@ -1398,8 +1477,11 @@ struct graph_t for (unsigned p = 0; p < count; p++) { - for (auto& l : vertices_.arrayZ[p].obj.all_links ()) - vertices_[l.objidx].add_parent (p); + for (auto& l : vertices_.arrayZ[p].obj.real_links) + vertices_[l.objidx].add_parent (p, false); + + for (auto& l : vertices_.arrayZ[p].obj.virtual_links) + vertices_[l.objidx].add_parent (p, true); } for (unsigned i = 0; i < count; i++) @@ -1418,7 +1500,7 @@ struct graph_t if (!positions_invalid) return; unsigned current_pos = 0; - for (int i = root_idx (); i >= 0; i--) + for (unsigned i : ordering_) { auto& v = vertices_[i]; v.start = current_pos; @@ -1450,11 +1532,11 @@ struct graph_t unsigned count = vertices_.length; for (unsigned i = 0; i < count; i++) vertices_.arrayZ[i].distance = hb_int_max (int64_t); - vertices_.tail ().distance = 0; + vertices_[root_idx ()].distance = 0; hb_priority_queue_t queue; queue.alloc (count); - queue.insert (0, vertices_.length - 1); + queue.insert (0, root_idx ()); hb_vector_t visited; visited.resize (vertices_.length); @@ -1464,22 +1546,23 @@ struct graph_t unsigned next_idx = queue.pop_minimum ().second; if (visited[next_idx]) continue; const auto& next = vertices_[next_idx]; - int64_t next_distance = vertices_[next_idx].distance; + int64_t next_distance = next.distance; visited[next_idx] = true; for (const auto& link : next.obj.all_links ()) { if (visited[link.objidx]) continue; - const auto& child = vertices_.arrayZ[link.objidx].obj; + auto& child_v = vertices_.arrayZ[link.objidx]; + const auto& child = child_v.obj; unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide int64_t child_weight = (child.tail - child.head) + - ((int64_t) 1 << (link_width * 8)) * (vertices_.arrayZ[link.objidx].space + 1); + ((int64_t) 1 << (link_width * 8)) * (child_v.space + 1); int64_t child_distance = next_distance + child_weight; - if (child_distance < vertices_.arrayZ[link.objidx].distance) + if (child_distance < child_v.distance) { - vertices_.arrayZ[link.objidx].distance = child_distance; + child_v.distance = child_distance; queue.insert (child_distance, link.objidx); } } @@ -1502,12 +1585,13 @@ struct graph_t */ void reassign_link (hb_serialize_context_t::object_t::link_t& link, unsigned parent_idx, - unsigned new_idx) + unsigned new_idx, + bool is_virtual) { unsigned old_idx = link.objidx; link.objidx = new_idx; vertices_[old_idx].remove_parent (parent_idx); - vertices_[new_idx].add_parent (parent_idx); + vertices_[new_idx].add_parent (parent_idx, is_virtual); } /* @@ -1521,36 +1605,21 @@ struct graph_t if (!id_map) return; for (unsigned i : subgraph) { - for (auto& link : vertices_[i].obj.all_links_writer ()) + auto& obj = vertices_[i].obj; + unsigned num_real = obj.real_links.length; + unsigned count = 0; + for (auto& link : obj.all_links_writer ()) { + count++; const uint32_t *v; if (!id_map.has (link.objidx, &v)) continue; - if (only_wide && !(link.width == 4 && !link.is_signed)) continue; + if (only_wide && (link.is_signed || (link.width != 4 && link.width != 3))) continue; - reassign_link (link, i, *v); + reassign_link (link, i, *v, count > num_real); } } } - /* - * Updates all objidx's in all links using the provided mapping. - */ - bool remap_all_obj_indices (const hb_vector_t& id_map, - hb_vector_t* sorted_graph) const - { - unsigned count = sorted_graph->length; - for (unsigned i = 0; i < count; i++) - { - if (!(*sorted_graph)[i].remap_parents (id_map)) - return false; - for (auto& link : sorted_graph->arrayZ[i].obj.all_links_writer ()) - { - link.objidx = id_map[link.objidx]; - } - } - return true; - } - /* * Finds all nodes in targets that are reachable from start_idx, nodes in visited will be skipped. * For this search the graph is treated as being undirected. @@ -1586,7 +1655,16 @@ struct graph_t public: // TODO(garretrieger): make private, will need to move most of offset overflow code into graph. hb_vector_t vertices_; - hb_vector_t vertices_scratch_; + + // Specifies the current topological ordering of this graph + // + // ordering_[pos] = obj index + // + // specifies that the 'pos'th spot is filled by the object + // given by obj index. + hb_vector_t ordering_; + hb_vector_t ordering_scratch_; + private: bool parents_invalid; bool distance_invalid; diff --git a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh index b25d538fe3d..8969d007879 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh @@ -41,6 +41,7 @@ struct gsubgpos_graph_context_t unsigned lookup_list_index; hb_hashmap_t lookups; hb_hashmap_t subtable_to_extension; + hb_hashmap_t> split_subtables; HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_, graph_t& graph_); diff --git a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh index 7ad2ba430b7..ea6bcd239a0 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh @@ -27,9 +27,11 @@ #include "graph.hh" #include "../hb-ot-layout-gsubgpos.hh" #include "../OT/Layout/GSUB/ExtensionSubst.hh" +#include "../OT/Layout/GSUB/SubstLookupSubTable.hh" #include "gsubgpos-context.hh" #include "pairpos-graph.hh" #include "markbasepos-graph.hh" +#include "ligature-graph.hh" #ifndef GRAPH_GSUBGPOS_GRAPH_HH #define GRAPH_GSUBGPOS_GRAPH_HH @@ -85,6 +87,12 @@ struct Lookup : public OT::Lookup return lookupType == extension_type (table_tag); } + bool use_mark_filtering_set () const + { + unsigned flag = lookupFlag; + return flag & 0x0010u; + } + bool make_extension (gsubgpos_graph_context_t& c, unsigned this_index) { @@ -120,22 +128,18 @@ struct Lookup : public OT::Lookup unsigned type = lookupType; bool is_ext = is_extension (c.table_tag); - if (c.table_tag != HB_OT_TAG_GPOS) + if (c.table_tag != HB_OT_TAG_GPOS && c.table_tag != HB_OT_TAG_GSUB) return true; - if (!is_ext && - type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair && - type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase) + if (!is_ext && !is_supported_gpos_type(type, c) && !is_supported_gsub_type(type, c)) return true; hb_vector_t>> all_new_subtables; for (unsigned i = 0; i < subTable.len; i++) { unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]); - unsigned parent_index = this_index; if (is_ext) { unsigned ext_subtable_index = subtable_index; - parent_index = ext_subtable_index; ExtensionFormat1* extension = (ExtensionFormat1*) c.graph.object (ext_subtable_index).head; @@ -144,26 +148,47 @@ struct Lookup : public OT::Lookup subtable_index = extension->get_subtable_index (c.graph, ext_subtable_index); type = extension->get_lookup_type (); - if (type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair - && type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase) + if (!is_supported_gpos_type(type, c) && !is_supported_gsub_type(type, c)) continue; } - hb_vector_t new_sub_tables; - switch (type) + hb_vector_t* split_result; + if (c.split_subtables.has (subtable_index, &split_result)) { - case 2: - new_sub_tables = split_subtable (c, parent_index, subtable_index); break; - case 4: - new_sub_tables = split_subtable (c, parent_index, subtable_index); break; - default: - break; + if (split_result->length == 0) + continue; + all_new_subtables.push (hb_pair(i, *split_result)); + } + else + { + hb_vector_t new_sub_tables; + + if (c.table_tag == HB_OT_TAG_GPOS) { + switch (type) + { + case 2: + new_sub_tables = split_subtable (c, subtable_index); break; + case 4: + new_sub_tables = split_subtable (c, subtable_index); break; + default: + break; + } + } else if (c.table_tag == HB_OT_TAG_GSUB) { + switch (type) + { + case 4: + new_sub_tables = split_subtable (c, subtable_index); break; + default: + break; + } + } + + if (new_sub_tables.in_error ()) return false; + + c.split_subtables.set (subtable_index, new_sub_tables); + if (new_sub_tables) + all_new_subtables.push (hb_pair (i, std::move (new_sub_tables))); } - if (new_sub_tables.in_error ()) return false; - if (!new_sub_tables) continue; - hb_pair_t>* entry = all_new_subtables.push (); - entry->first = i; - entry->second = std::move (new_sub_tables); } if (all_new_subtables) { @@ -175,30 +200,29 @@ struct Lookup : public OT::Lookup template hb_vector_t split_subtable (gsubgpos_graph_context_t& c, - unsigned parent_idx, unsigned objidx) { T* sub_table = (T*) c.graph.object (objidx).head; if (!sub_table || !sub_table->sanitize (c.graph.vertices_[objidx])) return hb_vector_t (); - return sub_table->split_subtables (c, parent_idx, objidx); + return sub_table->split_subtables (c, objidx); } bool add_sub_tables (gsubgpos_graph_context_t& c, unsigned this_index, unsigned type, - hb_vector_t>>& subtable_ids) + const hb_vector_t>>& subtable_ids) { bool is_ext = is_extension (c.table_tag); - auto& v = c.graph.vertices_[this_index]; + auto* v = &c.graph.vertices_[this_index]; fix_existing_subtable_links (c, this_index, subtable_ids); unsigned new_subtable_count = 0; for (const auto& p : subtable_ids) new_subtable_count += p.second.length; - size_t new_size = v.table_size () + size_t new_size = v->table_size () + new_subtable_count * OT::Offset16::static_size; char* buffer = (char*) hb_calloc (1, new_size); if (!buffer) return false; @@ -207,10 +231,13 @@ struct Lookup : public OT::Lookup hb_free (buffer); return false; } - hb_memcpy (buffer, v.obj.head, v.table_size()); + hb_memcpy (buffer, v->obj.head, v->table_size()); - v.obj.head = buffer; - v.obj.tail = buffer + new_size; + if (use_mark_filtering_set ()) + hb_memcpy (buffer + new_size - 2, v->obj.tail - 2, 2); + + v->obj.head = buffer; + v->obj.tail = buffer + new_size; Lookup* new_lookup = (Lookup*) buffer; @@ -226,21 +253,23 @@ struct Lookup : public OT::Lookup if (is_ext) { unsigned ext_id = create_extension_subtable (c, subtable_id, type); - c.graph.vertices_[subtable_id].add_parent (ext_id); + c.graph.vertices_[subtable_id].add_parent (ext_id, false); subtable_id = ext_id; + // the reference to v may have changed on adding a node, so reassign it. + v = &c.graph.vertices_[this_index]; } - auto* link = v.obj.real_links.push (); + auto* link = v->obj.real_links.push (); link->width = 2; link->objidx = subtable_id; link->position = (char*) &new_lookup->subTable[offset_index++] - (char*) new_lookup; - c.graph.vertices_[subtable_id].add_parent (this_index); + c.graph.vertices_[subtable_id].add_parent (this_index, false); } } // Repacker sort order depends on link order, which we've messed up so resort it. - v.obj.real_links.qsort (); + v->obj.real_links.qsort (); // The head location of the lookup has changed, invalidating the lookups map entry // in the context. Update the map. @@ -250,17 +279,15 @@ struct Lookup : public OT::Lookup void fix_existing_subtable_links (gsubgpos_graph_context_t& c, unsigned this_index, - hb_vector_t>>& subtable_ids) + const hb_vector_t>>& subtable_ids) { auto& v = c.graph.vertices_[this_index]; - Lookup* lookup = (Lookup*) v.obj.head; - unsigned shift = 0; for (const auto& p : subtable_ids) { unsigned insert_index = p.first + shift; unsigned pos_offset = p.second.length * OT::Offset16::static_size; - unsigned insert_offset = (char*) &lookup->subTable[insert_index] - (char*) lookup; + unsigned insert_offset = Lookup::min_size + insert_index * OT::Offset16::static_size; shift += p.second.length; for (auto& l : v.obj.all_links_writer ()) @@ -326,7 +353,7 @@ struct Lookup : public OT::Lookup // Make extension point at the subtable. auto& ext_vertex = c.graph.vertices_[ext_index]; - ext_vertex.add_parent (lookup_index); + ext_vertex.add_parent (lookup_index, false); if (!existing_ext_index) subtable_vertex.remap_parent (lookup_index, ext_index); @@ -334,6 +361,19 @@ struct Lookup : public OT::Lookup } private: + bool is_supported_gsub_type(unsigned type, gsubgpos_graph_context_t& c) const { + return (c.table_tag == HB_OT_TAG_GSUB) && ( + type == OT::Layout::GSUB_impl::SubstLookupSubTable::Type::Ligature + ); + } + + bool is_supported_gpos_type(unsigned type, gsubgpos_graph_context_t& c) const { + return (c.table_tag == HB_OT_TAG_GPOS) && ( + type == OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair || + type == OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase + ); + } + unsigned extension_type (hb_tag_t table_tag) const { switch (table_tag) diff --git a/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh index fb4166128a9..6d1a3d4ae4b 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh @@ -212,7 +212,6 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2 split_subtables (gsubgpos_graph_context_t& c, - unsigned parent_index, unsigned this_index) { hb_set_t visited; @@ -265,7 +264,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2 split_subtables (gsubgpos_graph_context_t& c, - unsigned parent_index, unsigned this_index) { - switch (u.format) { + switch (u.format.v) { case 1: - return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index); + return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, this_index); #ifndef HB_NO_BEYOND_64K case 2: HB_FALLTHROUGH; // Don't split 24bit MarkBasePos's. @@ -496,10 +494,10 @@ struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos bool sanitize (graph_t::vertex_t& vertex) const { int64_t vertex_len = vertex.obj.tail - vertex.obj.head; - if (vertex_len < u.format.get_size ()) return false; + if (vertex_len < u.format.v.get_size ()) return false; hb_barrier (); - switch (u.format) { + switch (u.format.v) { case 1: return ((MarkBasePosFormat1*)(&u.format1))->sanitize (vertex); #ifndef HB_NO_BEYOND_64K diff --git a/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh index fd46861de46..85950b63457 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh @@ -49,7 +49,6 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3 split_subtables (gsubgpos_graph_context_t& c, - unsigned parent_index, unsigned this_index) { hb_set_t visited; @@ -84,7 +83,7 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3 (split_context, split_points); @@ -207,7 +206,6 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4 split_subtables (gsubgpos_graph_context_t& c, - unsigned parent_index, unsigned this_index) { const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4::min_size; @@ -291,7 +289,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4width = SmallTypes::size; class_def_link->objidx = class_def_2_id; class_def_link->position = 10; - graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id); + graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id, false); graph.duplicate (pair_pos_prime_id, class_def_2_id); return pair_pos_prime_id; @@ -607,14 +605,13 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4 split_subtables (gsubgpos_graph_context_t& c, - unsigned parent_index, unsigned this_index) { - switch (u.format) { + switch (u.format.v) { case 1: - return ((PairPosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index); + return ((PairPosFormat1*)(&u.format1))->split_subtables (c, this_index); case 2: - return ((PairPosFormat2*)(&u.format2))->split_subtables (c, parent_index, this_index); + return ((PairPosFormat2*)(&u.format2))->split_subtables (c, this_index); #ifndef HB_NO_BEYOND_64K case 3: HB_FALLTHROUGH; case 4: HB_FALLTHROUGH; @@ -628,10 +625,10 @@ struct PairPos : public OT::Layout::GPOS_impl::PairPos bool sanitize (graph_t::vertex_t& vertex) const { int64_t vertex_len = vertex.obj.tail - vertex.obj.head; - if (vertex_len < u.format.get_size ()) return false; + if (vertex_len < u.format.v.get_size ()) return false; hb_barrier (); - switch (u.format) { + switch (u.format.v) { case 1: return ((PairPosFormat1*)(&u.format1))->sanitize (vertex); case 2: diff --git a/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh b/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh index 06e4bf44d8e..37fac8909e5 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh @@ -113,7 +113,7 @@ will_overflow (graph_t& graph, hb_hashmap_t record_set; const auto& vertices = graph.vertices_; - for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--) + for (unsigned parent_idx : graph.ordering_) { // Don't need to check virtual links for overflow for (const auto& link : vertices.arrayZ[parent_idx].obj.real_links) @@ -172,14 +172,16 @@ void print_overflows (graph_t& graph, template inline void serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link, char* head, + unsigned size, + const hb_vector_t& id_map, hb_serialize_context_t* c) { + assert(link.position + link.width <= size); + OT::Offset* offset = reinterpret_cast*> (head + link.position); *offset = 0; c->add_link (*offset, - // serializer has an extra nil object at the start of the - // object array. So all id's are +1 of what our id's are. - link.objidx + 1, + id_map[link.objidx], (hb_serialize_context_t::whence_t) link.whence, link.bias); } @@ -187,6 +189,8 @@ serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link, inline void serialize_link (const hb_serialize_context_t::object_t::link_t& link, char* head, + unsigned size, + const hb_vector_t& id_map, hb_serialize_context_t* c) { switch (link.width) @@ -197,21 +201,21 @@ void serialize_link (const hb_serialize_context_t::object_t::link_t& link, case 4: if (link.is_signed) { - serialize_link_of_type (link, head, c); + serialize_link_of_type (link, head, size, id_map, c); } else { - serialize_link_of_type (link, head, c); + serialize_link_of_type (link, head, size, id_map, c); } return; case 2: if (link.is_signed) { - serialize_link_of_type (link, head, c); + serialize_link_of_type (link, head, size, id_map, c); } else { - serialize_link_of_type (link, head, c); + serialize_link_of_type (link, head, size, id_map, c); } return; case 3: - serialize_link_of_type (link, head, c); + serialize_link_of_type (link, head, size, id_map, c); return; default: // Unexpected link width. @@ -237,25 +241,36 @@ inline hb_blob_t* serialize (const graph_t& graph) c.start_serialize (); const auto& vertices = graph.vertices_; - for (unsigned i = 0; i < vertices.length; i++) { + + // Objects are placed in the serializer in reverse order since children need + // to be inserted before their parents. + + // Maps from our obj id's to the id's used during this serialization. + hb_vector_t id_map; + id_map.resize(graph.ordering_.length); + for (int pos = graph.ordering_.length - 1; pos >= 0; pos--) { + unsigned i = graph.ordering_[pos]; c.push (); - size_t size = vertices[i].obj.tail - vertices[i].obj.head; + auto& v = vertices[i]; + + size_t size = v.obj.tail - v.obj.head; + char* start = c.allocate_size (size); if (!start) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Buffer out of space."); return nullptr; } - hb_memcpy (start, vertices[i].obj.head, size); + hb_memcpy (start, v.obj.head, size); // Only real links needs to be serialized. - for (const auto& link : vertices[i].obj.real_links) - serialize_link (link, start, &c); + for (const auto& link : v.obj.real_links) + serialize_link (link, start, size, id_map, &c); // All duplications are already encoded in the graph, so don't // enable sharing during packing. - c.pop_pack (false); + id_map[i] = c.pop_pack (false); } c.end_serialize (); diff --git a/src/java.desktop/share/native/libharfbuzz/graph/split-helpers.hh b/src/java.desktop/share/native/libharfbuzz/graph/split-helpers.hh index 61fd7c2d2ff..f1f86e332db 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/split-helpers.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/split-helpers.hh @@ -49,7 +49,7 @@ hb_vector_t actuate_subtable_split (Context& split_context, if (id == (unsigned) -1) { new_objects.reset (); - new_objects.allocated = -1; // mark error + new_objects.ensure_error (); return new_objects; } new_objects.push (id); @@ -58,7 +58,7 @@ hb_vector_t actuate_subtable_split (Context& split_context, if (!split_context.shrink (split_points[0])) { new_objects.reset (); - new_objects.allocated = -1; // mark error + new_objects.ensure_error (); } return new_objects; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh index d5a44bf473c..d2ce32616be 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh @@ -47,8 +47,7 @@ using namespace OT; struct ankr; -using hb_aat_class_cache_t = hb_cache_t<15, 8, 7>; -static_assert (sizeof (hb_aat_class_cache_t) == 256, ""); +using hb_aat_class_cache_t = hb_ot_layout_mapping_cache_t; struct hb_aat_scratch_t { @@ -79,7 +78,10 @@ struct hb_aat_scratch_t { hb_bit_set_t *s = buffer_glyph_set.get_acquire (); if (s && buffer_glyph_set.cmpexch (s, nullptr)) + { + s->clear (); return s; + } s = (hb_bit_set_t *) hb_calloc (1, sizeof (hb_bit_set_t)); if (unlikely (!s)) @@ -124,13 +126,14 @@ struct hb_aat_apply_context_t : const OT::GDEF &gdef; bool has_glyph_classes; const hb_sorted_vector_t *range_flags = nullptr; + hb_mask_t subtable_flags = 0; + bool buffer_is_reversed = false; + // Caches bool using_buffer_glyph_set = false; hb_bit_set_t *buffer_glyph_set = nullptr; - const hb_bit_set_t *left_set = nullptr; - const hb_bit_set_t *right_set = nullptr; - const hb_bit_set_t *machine_glyph_set = nullptr; + const hb_bit_set_t *first_set = nullptr; + const hb_bit_set_t *second_set = nullptr; hb_aat_class_cache_t *machine_class_cache = nullptr; - hb_mask_t subtable_flags = 0; /* Unused. For debug tracing only. */ unsigned int lookup_index; @@ -146,6 +149,12 @@ struct hb_aat_apply_context_t : void set_lookup_index (unsigned int i) { lookup_index = i; } + void reverse_buffer () + { + buffer->reverse (); + buffer_is_reversed = !buffer_is_reversed; + } + void setup_buffer_glyph_set () { using_buffer_glyph_set = buffer->len >= 4 && buffer_glyph_set; @@ -156,11 +165,11 @@ struct hb_aat_apply_context_t : bool buffer_intersects_machine () const { if (likely (using_buffer_glyph_set)) - return buffer_glyph_set->intersects (*machine_glyph_set); + return buffer_glyph_set->intersects (*first_set); // Faster for shorter buffers. for (unsigned i = 0; i < buffer->len; i++) - if (machine_glyph_set->has (buffer->info[i].codepoint)) + if (first_set->has (buffer->info[i].codepoint)) return true; return false; } @@ -639,6 +648,23 @@ struct LookupFormat10 glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1); } + template + void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const + { + if (unlikely (!glyphCount)) return; + if (firstGlyph == DELETED_GLYPH) return; + const HBUINT8 *p = valueArrayZ.arrayZ; + for (unsigned i = 0; i < glyphCount; i++) + { + unsigned int v = 0; + unsigned int count = valueSize; + for (unsigned int j = 0; j < count; j++) + v = (v << 8) | *p++; + if (filter (v)) + glyphs.add (firstGlyph + i); + } + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -666,7 +692,7 @@ struct Lookup { const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const { - switch (u.format) { + switch (u.format.v) { case 0: hb_barrier (); return u.format0.get_value (glyph_id, num_glyphs); case 2: hb_barrier (); return u.format2.get_value (glyph_id); case 4: hb_barrier (); return u.format4.get_value (glyph_id); @@ -678,7 +704,7 @@ struct Lookup const typename T::type get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const { - switch (u.format) { + switch (u.format.v) { /* Format 10 cannot return a pointer. */ case 10: hb_barrier (); return u.format10.get_value_or_null (glyph_id); default: @@ -690,7 +716,7 @@ struct Lookup template void collect_glyphs (set_t &glyphs, unsigned int num_glyphs) const { - switch (u.format) { + switch (u.format.v) { case 0: hb_barrier (); u.format0.collect_glyphs (glyphs, num_glyphs); return; case 2: hb_barrier (); u.format2.collect_glyphs (glyphs); return; case 4: hb_barrier (); u.format4.collect_glyphs (glyphs); return; @@ -703,12 +729,13 @@ struct Lookup template void collect_glyphs_filtered (set_t &glyphs, unsigned num_glyphs, const filter_t &filter) const { - switch (u.format) { + switch (u.format.v) { case 0: hb_barrier (); u.format0.collect_glyphs_filtered (glyphs, num_glyphs, filter); return; case 2: hb_barrier (); u.format2.collect_glyphs_filtered (glyphs, filter); return; case 4: hb_barrier (); u.format4.collect_glyphs_filtered (glyphs, filter); return; case 6: hb_barrier (); u.format6.collect_glyphs_filtered (glyphs, filter); return; case 8: hb_barrier (); u.format8.collect_glyphs_filtered (glyphs, filter); return; + case 10: hb_barrier (); u.format10.collect_glyphs_filtered (glyphs, filter); return; default:return; } } @@ -724,9 +751,9 @@ struct Lookup bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return_trace (false); + if (!u.format.v.sanitize (c)) return_trace (false); hb_barrier (); - switch (u.format) { + switch (u.format.v) { case 0: hb_barrier (); return_trace (u.format0.sanitize (c)); case 2: hb_barrier (); return_trace (u.format2.sanitize (c)); case 4: hb_barrier (); return_trace (u.format4.sanitize (c)); @@ -739,9 +766,9 @@ struct Lookup bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return_trace (false); + if (!u.format.v.sanitize (c)) return_trace (false); hb_barrier (); - switch (u.format) { + switch (u.format.v) { case 0: hb_barrier (); return_trace (u.format0.sanitize (c, base)); case 2: hb_barrier (); return_trace (u.format2.sanitize (c, base)); case 4: hb_barrier (); return_trace (u.format4.sanitize (c, base)); @@ -754,7 +781,7 @@ struct Lookup protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ LookupFormat0 format0; LookupFormat2 format2; LookupFormat4 format4; @@ -763,7 +790,7 @@ struct Lookup LookupFormat10 format10; } u; public: - DEFINE_SIZE_UNION (2, format); + DEFINE_SIZE_UNION (2, format.v); }; DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2); @@ -838,11 +865,6 @@ struct StateTable STATE_START_OF_LINE = 1, }; - template - void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const - { - (this+classTable).collect_glyphs (glyphs, num_glyphs); - } template void collect_initial_glyphs (set_t &glyphs, unsigned num_glyphs, const table_t &table) const { @@ -1082,6 +1104,8 @@ struct SubtableGlyphCoverage for (unsigned i = 0; i < subtable_count; i++) { uint32_t offset = (uint32_t) subtableOffsets[i]; + // A font file called SFNSDisplay.ttf has value 0xFFFFFFFF in the offsets. + // Just ignore it. if (offset == 0 || offset == 0xFFFFFFFF) continue; if (unlikely (!subtableOffsets[i].sanitize (c, this, bytes))) @@ -1192,11 +1216,24 @@ struct StateTableDriver int state = StateTableT::STATE_START_OF_TEXT; // If there's only one range, we already checked the flag. auto *last_range = ac->range_flags && (ac->range_flags->length > 1) ? &(*ac->range_flags)[0] : nullptr; + const bool start_state_safe_to_break_eot = + !c->table->is_actionable (machine.get_entry (StateTableT::STATE_START_OF_TEXT, CLASS_END_OF_TEXT)); for (buffer->idx = 0; buffer->successful;) { - /* This block is copied in NoncontextualSubtable::apply. Keep in sync. */ - if (last_range) + unsigned int klass = likely (buffer->idx < buffer->len) ? + machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_class_cache) : + (unsigned) CLASS_END_OF_TEXT; + resume: + DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx); + const EntryT &entry = machine.get_entry (state, klass); + const int next_state = machine.new_state (entry.newState); + + bool is_not_epsilon_transition = !(entry.flags & Flags::DontAdvance); + bool is_not_actionable = !c->table->is_actionable (entry); + + if (unlikely (last_range)) { + /* This block is copied in NoncontextualSubtable::apply. Keep in sync. */ auto *range = last_range; if (buffer->idx < buffer->len) { @@ -1211,7 +1248,7 @@ struct StateTableDriver } if (!(range->flags & ac->subtable_flags)) { - if (buffer->idx == buffer->len || unlikely (!buffer->successful)) + if (buffer->idx == buffer->len) break; state = StateTableT::STATE_START_OF_TEXT; @@ -1219,13 +1256,42 @@ struct StateTableDriver continue; } } + else + { + // Fast path for when transitioning from start-state to start-state with + // no action and advancing. Do so as long as the class remains the same. + // This is common with runs of non-actionable glyphs. - unsigned int klass = likely (buffer->idx < buffer->len) ? - machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_class_cache) : - (unsigned) CLASS_END_OF_TEXT; - DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx); - const EntryT &entry = machine.get_entry (state, klass); - const int next_state = machine.new_state (entry.newState); + bool is_null_transition = state == StateTableT::STATE_START_OF_TEXT && + next_state == StateTableT::STATE_START_OF_TEXT && + start_state_safe_to_break_eot && + is_not_actionable && + is_not_epsilon_transition && + !last_range; + + if (is_null_transition) + { + unsigned old_klass = klass; + do + { + c->transition (buffer, this, entry); + + if (buffer->idx == buffer->len || !buffer->successful) + break; + + (void) buffer->next_glyph (); + + klass = likely (buffer->idx < buffer->len) ? + machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_class_cache) : + (unsigned) CLASS_END_OF_TEXT; + } while (klass == old_klass); + + if (buffer->idx == buffer->len || !buffer->successful) + break; + + goto resume; + } + } /* Conditions under which it's guaranteed safe-to-break before current glyph: * @@ -1292,10 +1358,10 @@ struct StateTableDriver state = next_state; DEBUG_MSG (APPLY, nullptr, "s%d", state); - if (buffer->idx == buffer->len || unlikely (!buffer->successful)) + if (buffer->idx == buffer->len) break; - if (!(entry.flags & Flags::DontAdvance) || buffer->max_ops-- <= 0) + if (is_not_epsilon_transition || buffer->max_ops-- <= 0) (void) buffer->next_glyph (); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh index ca4f2243346..2a6b813972f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh @@ -120,12 +120,12 @@ struct KerxSubTableFormat0 } template - void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const + void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const { for (const KernPair& pair : pairs) { - left_set.add (pair.left); - right_set.add (pair.right); + first_set.add (pair.left); + second_set.add (pair.right); } } @@ -140,7 +140,7 @@ struct KerxSubTableFormat0 int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const { - if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0; + if (!(*c->first_set)[left] || !(*c->second_set)[right]) return 0; return table.get_kerning (left, right, c); } }; @@ -396,10 +396,10 @@ struct KerxSubTableFormat1 } template - void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const + void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const { - machine.collect_initial_glyphs (left_set, num_glyphs, *this); - //machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning + machine.collect_initial_glyphs (first_set, num_glyphs, *this); + //machine.collect_glyphs (second_set, num_glyphs); // second_set is unused for machine kerning } protected: @@ -451,10 +451,10 @@ struct KerxSubTableFormat2 } template - void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const + void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const { - (this+leftClassTable).collect_glyphs (left_set, num_glyphs); - (this+rightClassTable).collect_glyphs (right_set, num_glyphs); + (this+leftClassTable).collect_glyphs (first_set, num_glyphs); + (this+rightClassTable).collect_glyphs (second_set, num_glyphs); } struct accelerator_t @@ -468,7 +468,7 @@ struct KerxSubTableFormat2 int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const { - if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0; + if (!(*c->first_set)[left] || !(*c->second_set)[right]) return 0; return table.get_kerning (left, right, c); } }; @@ -629,6 +629,8 @@ struct KerxSubTableFormat4 } o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_MARK; o.attach_chain() = (int) mark - (int) buffer->idx; + if (c->buffer_is_reversed) + o.attach_chain() = -o.attach_chain(); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; } @@ -671,10 +673,10 @@ struct KerxSubTableFormat4 } template - void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const + void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const { - machine.collect_initial_glyphs (left_set, num_glyphs, *this); - //machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning + machine.collect_initial_glyphs (first_set, num_glyphs, *this); + //machine.collect_glyphs (second_set, num_glyphs); // second_set is unused for machine kerning } protected: @@ -762,19 +764,19 @@ struct KerxSubTableFormat6 } template - void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const + void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const { if (is_long ()) { const auto &t = u.l; - (this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs); - (this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs); + (this+t.rowIndexTable).collect_glyphs (first_set, num_glyphs); + (this+t.columnIndexTable).collect_glyphs (second_set, num_glyphs); } else { const auto &t = u.s; - (this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs); - (this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs); + (this+t.rowIndexTable).collect_glyphs (first_set, num_glyphs); + (this+t.columnIndexTable).collect_glyphs (second_set, num_glyphs); } } @@ -789,7 +791,7 @@ struct KerxSubTableFormat6 int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const { - if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0; + if (!(*c->first_set)[left] || !(*c->second_set)[right]) return 0; return table.get_kerning (left, right, c); } }; @@ -878,15 +880,15 @@ struct KerxSubTable } template - void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const + void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const { unsigned int subtable_type = get_type (); switch (subtable_type) { - case 0: u.format0.collect_glyphs (left_set, right_set, num_glyphs); return; - case 1: u.format1.collect_glyphs (left_set, right_set, num_glyphs); return; - case 2: u.format2.collect_glyphs (left_set, right_set, num_glyphs); return; - case 4: u.format4.collect_glyphs (left_set, right_set, num_glyphs); return; - case 6: u.format6.collect_glyphs (left_set, right_set, num_glyphs); return; + case 0: u.format0.collect_glyphs (first_set, second_set, num_glyphs); return; + case 1: u.format1.collect_glyphs (first_set, second_set, num_glyphs); return; + case 2: u.format2.collect_glyphs (first_set, second_set, num_glyphs); return; + case 4: u.format4.collect_glyphs (first_set, second_set, num_glyphs); return; + case 6: u.format6.collect_glyphs (first_set, second_set, num_glyphs); return; default: return; } } @@ -923,8 +925,8 @@ struct KerxSubTable struct kern_subtable_accelerator_data_t { - hb_bit_set_t left_set; - hb_bit_set_t right_set; + hb_bit_set_t first_set; + hb_bit_set_t second_set; mutable hb_aat_class_cache_t class_cache; }; @@ -1017,9 +1019,8 @@ struct KerxTable if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ()) goto skip; - c->left_set = &subtable_accel.left_set; - c->right_set = &subtable_accel.right_set; - c->machine_glyph_set = &subtable_accel.left_set; + c->first_set = &subtable_accel.first_set; + c->second_set = &subtable_accel.second_set; c->machine_class_cache = &subtable_accel.class_cache; if (!c->buffer_intersects_machine ()) @@ -1051,8 +1052,8 @@ struct KerxTable } } - if (reverse) - c->buffer->reverse (); + if (reverse != c->buffer_is_reversed) + c->reverse_buffer (); { /* See comment in sanitize() for conditional here. */ @@ -1060,15 +1061,14 @@ struct KerxTable ret |= st->dispatch (c); } - if (reverse) - c->buffer->reverse (); - (void) c->buffer->message (c->font, "end subtable %u", c->lookup_index); skip: st = &StructAfter (*st); c->set_lookup_index (c->lookup_index + 1); } + if (c->buffer_is_reversed) + c->reverse_buffer (); return ret; } @@ -1133,7 +1133,7 @@ struct KerxTable if (unlikely (accel_data.subtable_accels.in_error ())) return accel_data; - st->collect_glyphs (subtable_accel.left_set, subtable_accel.right_set, num_glyphs); + st->collect_glyphs (subtable_accel.first_set, subtable_accel.second_set, num_glyphs); subtable_accel.class_cache.clear (); st = &StructAfter (*st); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh index 92b07eec6e5..2cbb86c7566 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh @@ -487,7 +487,7 @@ struct LigatureSubtable if (entry.flags & LigatureEntryT::SetComponent) { /* Never mark same index twice, in case DontAdvance was used... */ - if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len) + if (unlikely (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len)) match_length--; match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len; @@ -640,7 +640,7 @@ struct NoncontextualSubtable for (unsigned int i = 0; i < count; i++) { /* This block copied from StateTableDriver::drive. Keep in sync. */ - if (last_range) + if (unlikely (last_range)) { auto *range = last_range; { @@ -1169,15 +1169,15 @@ struct Chain hb_map ([subtable_flags] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable_flags & (_.flags); }))) goto skip; - c->subtable_flags = subtable_flags; - c->machine_glyph_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t); - c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr; - if (!(coverage & ChainSubtable::AllDirections) && HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != bool (coverage & ChainSubtable::Vertical)) goto skip; + c->subtable_flags = subtable_flags; + c->first_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t); + c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr; + if (!c->buffer_intersects_machine ()) { (void) c->buffer->message (c->font, "skipped chainsubtable %u because no glyph matches", c->lookup_index); @@ -1219,22 +1219,21 @@ struct Chain if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index)) goto skip; - if (reverse) - c->buffer->reverse (); + if (reverse != c->buffer_is_reversed) + c->reverse_buffer (); subtable->apply (c); - if (reverse) - c->buffer->reverse (); - (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index); - if (unlikely (!c->buffer->successful)) return; + if (unlikely (!c->buffer->successful)) break; skip: subtable = &StructAfter> (*subtable); c->set_lookup_index (c->lookup_index + 1); } + if (c->buffer_is_reversed) + c->reverse_buffer (); } unsigned int get_size () const { return length; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-algs.hh b/src/java.desktop/share/native/libharfbuzz/hb-algs.hh index 6e250bfdef0..651ffcda01d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-algs.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-algs.hh @@ -78,129 +78,246 @@ /* - * Big-endian integers. + * Fixed-endian integers / floats. */ + /* Endian swap, used in Windows related backends */ static inline constexpr uint16_t hb_uint16_swap (uint16_t v) { return (v >> 8) | (v << 8); } static inline constexpr uint32_t hb_uint32_swap (uint32_t v) { return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); } -#ifndef HB_FAST_INT_ACCESS +template +struct __attribute__((packed)) hb_packed_t { Type v; }; + +#ifndef HB_FAST_NUM_ACCESS + #if defined(__OPTIMIZE__) && \ defined(__BYTE_ORDER) && \ (__BYTE_ORDER == __BIG_ENDIAN || \ (__BYTE_ORDER == __LITTLE_ENDIAN && \ hb_has_builtin(__builtin_bswap16) && \ - hb_has_builtin(__builtin_bswap32))) -#define HB_FAST_INT_ACCESS 1 + hb_has_builtin(__builtin_bswap32) && \ + hb_has_builtin(__builtin_bswap64))) +#define HB_FAST_NUM_ACCESS 1 #else -#define HB_FAST_INT_ACCESS 0 -#endif +#define HB_FAST_NUM_ACCESS 0 #endif -template -struct BEInt; -template -struct BEInt +// https://github.com/harfbuzz/harfbuzz/issues/5456 +#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ <= 12) +#undef HB_FAST_NUM_ACCESS +#define HB_FAST_NUM_ACCESS 0 +#endif + +#endif + +template +struct HBInt; +template +struct HBInt { public: - BEInt () = default; - constexpr BEInt (Type V) : v {uint8_t (V)} {} + HBInt () = default; + constexpr HBInt (Type V) : v {uint8_t (V)} {} constexpr operator Type () const { return v; } private: uint8_t v; }; -template -struct BEInt +template +struct HBInt { - struct __attribute__((packed)) packed_uint16_t { uint16_t v; }; - public: - BEInt () = default; + HBInt () = default; - BEInt (Type V) -#if HB_FAST_INT_ACCESS -#if __BYTE_ORDER == __LITTLE_ENDIAN - { ((packed_uint16_t *) v)->v = __builtin_bswap16 (V); } -#else /* __BYTE_ORDER == __BIG_ENDIAN */ - { ((packed_uint16_t *) v)->v = V; } -#endif + HBInt (Type V) +#if HB_FAST_NUM_ACCESS + { + if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) + ((hb_packed_t *) v)->v = V; + else + ((hb_packed_t *) v)->v = __builtin_bswap16 (V); + } #else - : v {uint8_t ((V >> 8) & 0xFF), - uint8_t ((V ) & 0xFF)} {} + : v {BE ? uint8_t ((V >> 8) & 0xFF) : uint8_t ((V ) & 0xFF), + BE ? uint8_t ((V ) & 0xFF) : uint8_t ((V >> 8) & 0xFF)} {} #endif - constexpr operator Type () const { -#if HB_FAST_INT_ACCESS -#if __BYTE_ORDER == __LITTLE_ENDIAN - return __builtin_bswap16 (((packed_uint16_t *) v)->v); -#else /* __BYTE_ORDER == __BIG_ENDIAN */ - return ((packed_uint16_t *) v)->v; -#endif + constexpr operator Type () const + { +#if HB_FAST_NUM_ACCESS + return (BE == (__BYTE_ORDER == __BIG_ENDIAN)) ? + ((const hb_packed_t *) v)->v + : + __builtin_bswap16 (((const hb_packed_t *) v)->v) + ; #else - return (v[0] << 8) - + (v[1] ); + return (BE ? (v[0] << 8) : (v[0] )) + + (BE ? (v[1] ) : (v[1] << 8)); #endif } private: uint8_t v[2]; }; -template -struct BEInt +template +struct HBInt { static_assert (!std::is_signed::value, ""); public: - BEInt () = default; - constexpr BEInt (Type V) : v {uint8_t ((V >> 16) & 0xFF), - uint8_t ((V >> 8) & 0xFF), - uint8_t ((V ) & 0xFF)} {} + HBInt () = default; + constexpr HBInt (Type V) : v {BE ? uint8_t ((V >> 16) & 0xFF) : uint8_t ((V >> 16) & 0xFF), + BE ? uint8_t ((V >> 8) & 0xFF) : uint8_t ((V >> 8) & 0xFF), + BE ? uint8_t ((V ) & 0xFF) : uint8_t ((V ) & 0xFF)} {} - constexpr operator Type () const { return (v[0] << 16) - + (v[1] << 8) - + (v[2] ); } + constexpr operator Type () const { return (BE ? (v[0] << 16) : (v[0] )) + + (BE ? (v[1] << 8) : (v[1] << 8)) + + (BE ? (v[2] ) : (v[2] << 16)); } private: uint8_t v[3]; }; -template -struct BEInt +template +struct HBInt { - struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; + template + friend struct HBFloat; public: - BEInt () = default; + HBInt () = default; - BEInt (Type V) -#if HB_FAST_INT_ACCESS -#if __BYTE_ORDER == __LITTLE_ENDIAN - { ((packed_uint32_t *) v)->v = __builtin_bswap32 (V); } -#else /* __BYTE_ORDER == __BIG_ENDIAN */ - { ((packed_uint32_t *) v)->v = V; } -#endif + HBInt (Type V) +#if HB_FAST_NUM_ACCESS + { + if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) + ((hb_packed_t *) v)->v = V; + else + ((hb_packed_t *) v)->v = __builtin_bswap32 (V); + } #else - : v {uint8_t ((V >> 24) & 0xFF), - uint8_t ((V >> 16) & 0xFF), - uint8_t ((V >> 8) & 0xFF), - uint8_t ((V ) & 0xFF)} {} + : v {BE ? uint8_t ((V >> 24) & 0xFF) : uint8_t ((V ) & 0xFF), + BE ? uint8_t ((V >> 16) & 0xFF) : uint8_t ((V >> 8) & 0xFF), + BE ? uint8_t ((V >> 8) & 0xFF) : uint8_t ((V >> 16) & 0xFF), + BE ? uint8_t ((V ) & 0xFF) : uint8_t ((V >> 24) & 0xFF)} {} #endif constexpr operator Type () const { -#if HB_FAST_INT_ACCESS -#if __BYTE_ORDER == __LITTLE_ENDIAN - return __builtin_bswap32 (((packed_uint32_t *) v)->v); -#else /* __BYTE_ORDER == __BIG_ENDIAN */ - return ((packed_uint32_t *) v)->v; -#endif +#if HB_FAST_NUM_ACCESS + return (BE == (__BYTE_ORDER == __BIG_ENDIAN)) ? + ((const hb_packed_t *) v)->v + : + __builtin_bswap32 (((const hb_packed_t *) v)->v) + ; #else - return (v[0] << 24) - + (v[1] << 16) - + (v[2] << 8) - + (v[3] ); + return (BE ? (v[0] << 24) : (v[0] )) + + (BE ? (v[1] << 16) : (v[1] << 8)) + + (BE ? (v[2] << 8) : (v[2] << 16)) + + (BE ? (v[3] ) : (v[3] << 24)); #endif } private: uint8_t v[4]; }; +template +struct HBInt +{ + template + friend struct HBFloat; + + public: + HBInt () = default; + + HBInt (Type V) +#if HB_FAST_NUM_ACCESS + { + if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) + ((hb_packed_t *) v)->v = V; + else + ((hb_packed_t *) v)->v = __builtin_bswap64 (V); + } +#else + : v {BE ? uint8_t ((V >> 56) & 0xFF) : uint8_t ((V ) & 0xFF), + BE ? uint8_t ((V >> 48) & 0xFF) : uint8_t ((V >> 8) & 0xFF), + BE ? uint8_t ((V >> 40) & 0xFF) : uint8_t ((V >> 16) & 0xFF), + BE ? uint8_t ((V >> 32) & 0xFF) : uint8_t ((V >> 24) & 0xFF), + BE ? uint8_t ((V >> 24) & 0xFF) : uint8_t ((V >> 32) & 0xFF), + BE ? uint8_t ((V >> 16) & 0xFF) : uint8_t ((V >> 40) & 0xFF), + BE ? uint8_t ((V >> 8) & 0xFF) : uint8_t ((V >> 48) & 0xFF), + BE ? uint8_t ((V ) & 0xFF) : uint8_t ((V >> 56) & 0xFF)} {} +#endif + + constexpr operator Type () const { +#if HB_FAST_NUM_ACCESS + return (BE == (__BYTE_ORDER == __BIG_ENDIAN)) ? + ((const hb_packed_t *) v)->v + : + __builtin_bswap64 (((const hb_packed_t *) v)->v) + ; +#else + return (BE ? (uint64_t (v[0]) << 56) : (uint64_t (v[0]) )) + + (BE ? (uint64_t (v[1]) << 48) : (uint64_t (v[1]) << 8)) + + (BE ? (uint64_t (v[2]) << 40) : (uint64_t (v[2]) << 16)) + + (BE ? (uint64_t (v[3]) << 32) : (uint64_t (v[3]) << 24)) + + (BE ? (uint64_t (v[4]) << 24) : (uint64_t (v[4]) << 32)) + + (BE ? (uint64_t (v[5]) << 16) : (uint64_t (v[5]) << 40)) + + (BE ? (uint64_t (v[6]) << 8) : (uint64_t (v[6]) << 48)) + + (BE ? (uint64_t (v[7]) ) : (uint64_t (v[7]) << 56)); +#endif + } + private: uint8_t v[8]; +}; /* Floats. */ +template +struct HBFloat +{ + using IntType = typename std::conditional::type; + + public: + HBFloat () = default; + + HBFloat (Type V) + { +#if HB_FAST_NUM_ACCESS + { + if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) + { + ((hb_packed_t *) v)->v = V; + return; + } + } +#endif + + union { + hb_packed_t f; + hb_packed_t i; + } u = {{V}}; + + const HBInt I = u.i.v; + for (unsigned i = 0; i < Bytes; i++) + v[i] = I.v[i]; + } + + /* c++14 constexpr */ operator Type () const + { +#if HB_FAST_NUM_ACCESS + { + if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) + return ((const hb_packed_t *) v)->v; + } +#endif + + HBInt I; + for (unsigned i = 0; i < Bytes; i++) + I.v[i] = v[i]; + + union { + hb_packed_t i; + hb_packed_t f; + } u = {{I}}; + + return u.f.v; + } + private: uint8_t v[Bytes]; +}; + + /* We want our rounding towards +infinity. */ static inline double _hb_roundf (double x) { return floor (x + .5); } @@ -210,6 +327,27 @@ _hb_roundf (float x) { return floorf (x + .5f); } #define roundf(x) _hb_roundf(x) +static inline void +hb_sincos (float rotation, float &s, float &c) +{ +#ifdef HAVE_SINCOSF + sincosf (rotation, &s, &c); +#else + c = cosf (rotation); + s = sinf (rotation); +#endif +} +static inline void +hb_sincos (double rotation, double &s, double &c) +{ +#ifdef HAVE_SINCOS + sincos (rotation, &s, &c); +#else + c = cos (rotation); + s = sin (rotation); +#endif +} + /* Encodes three unsigned integers in one 64-bit number. If the inputs have more than 21 bits, * values will be truncated / overlap, and might not decode exactly. */ @@ -734,6 +872,17 @@ HB_FUNCOBJ (hb_clamp); * Bithacks. */ +/* Return the number of 1 bits in a uint8_t; faster than hb_popcount() */ +static inline unsigned +hb_popcount8 (uint8_t v) +{ + static const uint8_t popcount4[16] = { + 0, 1, 1, 2, 1, 2, 2, 3, + 1, 2, 2, 3, 2, 3, 3, 4 + }; + return popcount4[v & 0xF] + popcount4[v >> 4]; +} + /* Return the number of 1 bits in v. */ template static inline unsigned int @@ -1070,6 +1219,7 @@ _hb_cmp_operator (const void *pkey, const void *pval) } template +HB_HOT static inline bool hb_bsearch_impl (unsigned *pos, /* Out */ const K& key, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-alloc-pool.hh b/src/java.desktop/share/native/libharfbuzz/hb-alloc-pool.hh new file mode 100644 index 00000000000..cb0d7aa7acd --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-alloc-pool.hh @@ -0,0 +1,105 @@ +/* + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Author(s): Behdad Esfahbod + */ + +#ifndef HB_ALLOC_POOL_HH +#define HB_ALLOC_POOL_HH + +#include "hb-vector.hh" + +/* Memory pool for persistent small- to medium-sized allocations. + * + * Some AI musings on this, not necessarily true: + * + * This is a very simple implementation, but it's good enough for our + * purposes. It's not thread-safe. It's not very fast. It's not + * very memory efficient. It's not very cache efficient. It's not + * very anything efficient. But it's simple and it works. And it's + * good enough for our purposes. If you need something more + * sophisticated, use a real allocator. Or use a real language. */ + +struct hb_alloc_pool_t +{ + unsigned ChunkSize = 65536 - 2 * sizeof (void *); + + void *alloc (size_t size, unsigned alignment = 2 * sizeof (void *)) + { + if (unlikely (chunks.in_error ())) return nullptr; + + assert (alignment > 0); + assert (alignment <= 2 * sizeof (void *)); + assert ((alignment & (alignment - 1)) == 0); /* power of two */ + + if (size > (ChunkSize) / 4) + { + /* Big chunk, allocate separately. */ + hb_vector_t chunk; + if (unlikely (!chunk.resize (size))) return nullptr; + void *ret = chunk.arrayZ; + chunks.push (std::move (chunk)); + if (chunks.in_error ()) return nullptr; + if (chunks.length > 1) + { + // Bring back the previous last chunk to the end, so that + // we can continue to allocate from it. + hb_swap (chunks.arrayZ[chunks.length - 1], chunks.arrayZ[chunks.length - 2]); + } + return ret; + } + + unsigned pad = (unsigned) ((alignment - ((uintptr_t) current_chunk.arrayZ & (alignment - 1))) & (alignment - 1)); + + // Small chunk, allocate from the last chunk. + if (current_chunk.length < pad + size) + { + chunks.push (); + if (unlikely (chunks.in_error ())) return nullptr; + hb_vector_t &chunk = chunks.arrayZ[chunks.length - 1]; + if (unlikely (!chunk.resize (ChunkSize))) return nullptr; + current_chunk = chunk; + pad = (unsigned) ((alignment - ((uintptr_t) current_chunk.arrayZ & (alignment - 1))) & (alignment - 1)); + } + + current_chunk += pad; + + assert (current_chunk.length >= size); + void *ret = current_chunk.arrayZ; + current_chunk += size; + return ret; + } + + void discard (void *p_, size_t size) + { + // Reclaim memory if we can. + char *p = (char *) p_; + if (current_chunk.arrayZ == p + size && current_chunk.backwards_length >= size) + current_chunk -= size; + } + + private: + hb_vector_t> chunks; + hb_array_t current_chunk; +}; + + +#endif /* HB_ALLOC_POOL_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-array.hh b/src/java.desktop/share/native/libharfbuzz/hb-array.hh index d65bbc5c711..71d3bcdf1ea 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-array.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-array.hh @@ -291,6 +291,13 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> && (unsigned int) (arrayZ + length - (const char *) p) >= size; } + template + bool check_end (const void *p) const + { + return (uintptr_t) (((const char *) p) - arrayZ) <= length; + } + /* Only call if you allocated the underlying array using hb_malloc() or similar. */ void fini () { hb_free ((void *) arrayZ); arrayZ = nullptr; length = 0; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh b/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh index 80bd90e87dc..05aaf5a155e 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh @@ -40,7 +40,6 @@ * Atomic integers and pointers. */ - /* We need external help for these */ #if defined(hb_atomic_int_impl_add) \ @@ -80,27 +79,11 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) #include +#define HB_STL_ATOMIC_IMPL + #define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire) #define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release) -#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel)) -#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast::type> *> (AI)->store ((V), std::memory_order_relaxed)) -#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast::type> *> (AI)->store ((V), std::memory_order_release)) -#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast::type> const *> (AI)->load (std::memory_order_relaxed)) -#define hb_atomic_int_impl_get(AI) (reinterpret_cast::type> const *> (AI)->load (std::memory_order_acquire)) - -#define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast *> (P)->store ((V), std::memory_order_relaxed)) -#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast const *> (P)->load (std::memory_order_relaxed)) -#define hb_atomic_ptr_impl_get(P) (reinterpret_cast *> (P)->load (std::memory_order_acquire)) -static inline bool -_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) -{ - const void *O = O_; // Need lvalue - return reinterpret_cast *> (P)->compare_exchange_weak (O, N, std::memory_order_acq_rel, std::memory_order_relaxed); -} -#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N)) - - #else /* defined(HB_NO_MT) */ #define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V)) @@ -159,6 +142,76 @@ inline T hb_atomic_int_impl_get (const T *AI) { T v = *AI; _hb_memory_r_barrie inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; } #endif +#ifdef HB_STL_ATOMIC_IMPL +template +struct hb_atomic_t +{ + hb_atomic_t () = default; + constexpr hb_atomic_t (T v) : v (v) {} + constexpr hb_atomic_t (const hb_atomic_t& o) : v (o.get_relaxed ()) {} + constexpr hb_atomic_t (hb_atomic_t&& o) : v (o.get_relaxed ()) { o.set_relaxed ({}); } + + hb_atomic_t &operator= (const hb_atomic_t& o) { set_relaxed (o.get_relaxed ()); return *this; } + hb_atomic_t &operator= (hb_atomic_t&& o){ set_relaxed (o.get_relaxed ()); o.set_relaxed ({}); return *this; } + hb_atomic_t &operator= (T v_) + { + set_relaxed (v_); + return *this; + } + operator T () const { return get_relaxed (); } + + void set_relaxed (T v_) { v.store (v_, std::memory_order_relaxed); } + void set_release (T v_) { v.store (v_, std::memory_order_release); } + T get_relaxed () const { return v.load (std::memory_order_relaxed); } + T get_acquire () const { return v.load (std::memory_order_acquire); } + T inc () { return v.fetch_add (1, std::memory_order_acq_rel); } + T dec () { return v.fetch_add (-1, std::memory_order_acq_rel); } + + int operator++ (int) { return inc (); } + int operator-- (int) { return dec (); } + + friend void swap (hb_atomic_t &a, hb_atomic_t &b) noexcept + { + T v = a.get_acquire (); + a.set_relaxed (b.get_acquire ()); + b.set_relaxed (v); + } + + std::atomic v = 0; +}; + +template +struct hb_atomic_t +{ + hb_atomic_t () = default; + constexpr hb_atomic_t (T *v) : v (v) {} + hb_atomic_t (const hb_atomic_t &other) = delete; + + void init (T *v_ = nullptr) { set_relaxed (v_); } + void set_relaxed (T *v_) { v.store (v_, std::memory_order_relaxed); } + T *get_relaxed () const { return v.load (std::memory_order_relaxed); } + T *get_acquire () const { return v.load (std::memory_order_acquire); } + bool cmpexch (T *old, T *new_) { return v.compare_exchange_weak (old, new_, std::memory_order_acq_rel, std::memory_order_relaxed); } + + operator bool () const { return get_acquire () != nullptr; } + T *operator->() const { return get_acquire (); } + template + operator C * () const + { + return get_acquire (); + } + + friend void swap (hb_atomic_t &a, hb_atomic_t &b) noexcept + { + T *p = a.get_acquire (); + a.set_relaxed (b.get_acquire ()); + b.set_relaxed (p); + } + + std::atomic v = nullptr; +}; + +#else template struct hb_atomic_t @@ -178,7 +231,6 @@ struct hb_atomic_t int operator ++ (int) { return inc (); } int operator -- (int) { return dec (); } - long operator |= (long v_) { set_relaxed (get_relaxed () | v_); return *this; } T v = 0; }; @@ -194,7 +246,7 @@ struct hb_atomic_t void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); } T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); } T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); } - bool cmpexch (const T *old, T *new_) { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); } + bool cmpexch (T *old, T *new_) { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); } operator bool () const { return get_acquire () != nullptr; } T * operator -> () const { return get_acquire (); } @@ -203,6 +255,8 @@ struct hb_atomic_t T *v = nullptr; }; +#endif + static inline bool hb_barrier () { _hb_compiler_memory_r_barrier (); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh b/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh index f541472544a..f9c0e8870ff 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh @@ -176,7 +176,7 @@ struct hb_inc_bimap_t { hb_codepoint_t count = get_population (); hb_vector_t work; - if (unlikely (!work.resize (count, false))) return; + if (unlikely (!work.resize_dirty (count))) return; for (hb_codepoint_t rhs = 0; rhs < count; rhs++) work.arrayZ[rhs] = back_map[rhs]; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh index 9562a9674a5..902db195507 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh @@ -142,6 +142,7 @@ struct hb_bit_page_t bool operator [] (hb_codepoint_t g) const { return get (g); } bool operator () (hb_codepoint_t g) const { return get (g); } + bool has (hb_codepoint_t g) const { return get (g); } void add_range (hb_codepoint_t a, hb_codepoint_t b) { @@ -290,7 +291,7 @@ struct hb_bit_page_t unsigned int j = m & ELT_MASK; const elt_t vv = v[i] & ~((elt_t (1) << j) - 1); - for (const elt_t *p = &vv; i < len (); p = &v[++i]) + for (const elt_t *p = &vv; i < len (); p = ((const elt_t *) &v[0]) + (++i)) if (*p) { *codepoint = i * ELT_BITS + elt_get_min (*p); @@ -346,6 +347,36 @@ struct hb_bit_page_t return 0; } + /* + * Iterator implementation. + */ + struct iter_t : hb_iter_with_fallback_t + { + static constexpr bool is_sorted_iterator = true; + iter_t (const hb_bit_page_t &s_ = Null (hb_bit_page_t), bool init = true) : s (&s_), v (INVALID) + { + if (init) + v = s->get_min (); + } + + typedef hb_codepoint_t __item_t__; + hb_codepoint_t __item__ () const { return v; } + bool __more__ () const { return v != INVALID; } + void __next__ () { + s->next (&v); + } + void __prev__ () { s->previous (&v); } + iter_t end () const { return iter_t (*s, false); } + bool operator != (const iter_t& o) const + { return v != o.v; } + + protected: + const hb_bit_page_t *s; + hb_codepoint_t v; + }; + iter_t iter () const { return iter_t (*this); } + operator iter_t () const { return iter (); } + static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID; typedef unsigned long long elt_t; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh index 740a2437671..4028dd63531 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh @@ -368,7 +368,7 @@ struct hb_bit_set_invertible_t unsigned __len__ () const { return l; } iter_t end () const { return iter_t (*s, false); } bool operator != (const iter_t& o) const - { return v != o.v || s != o.s; } + { return v != o.v; } protected: const hb_bit_set_invertible_t *s; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh index 799c3607599..f86d5750854 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh @@ -91,10 +91,10 @@ struct hb_bit_set_t if (pages.length < count && (unsigned) pages.allocated < count && count <= 2) exact_size = true; // Most sets are small and local - if (unlikely (!pages.resize (count, clear, exact_size) || - !page_map.resize (count, clear))) + if (unlikely (!pages.resize_full (count, clear, exact_size) || + !page_map.resize_full (count, clear, false))) { - pages.resize (page_map.length, clear, exact_size); + pages.resize_full (page_map.length, clear, exact_size); successful = false; return false; } @@ -108,10 +108,11 @@ struct hb_bit_set_t page_map.alloc (sz); } - void reset () + hb_bit_set_t& reset () { successful = true; clear (); + return *this; } void clear () @@ -394,7 +395,7 @@ struct hb_bit_set_t { if (unlikely (!successful)) return; unsigned int count = other.pages.length; - if (unlikely (!resize (count, false, exact_size))) + if (unlikely (!resize (count, false, exact_size))) return; population = other.population; @@ -922,7 +923,7 @@ struct hb_bit_set_t unsigned __len__ () const { return l; } iter_t end () const { return iter_t (*s, false); } bool operator != (const iter_t& o) const - { return s != o.s || v != o.v; } + { return v != o.v; } protected: const hb_bit_set_t *s; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh index 9e21beebd34..87c1524df6f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh @@ -32,7 +32,7 @@ #include "hb.hh" -#line 36 "hb-buffer-deserialize-text-unicode.hh" +#line 33 "hb-buffer-deserialize-text-unicode.hh" static const unsigned char _deserialize_text_unicode_trans_keys[] = { 0u, 0u, 43u, 102u, 48u, 102u, 48u, 124u, 48u, 57u, 62u, 124u, 48u, 124u, 60u, 117u, 85u, 117u, 85u, 117u, 0 @@ -150,12 +150,12 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer, hb_glyph_info_t info = {0}; const hb_glyph_position_t pos = {0}; -#line 154 "hb-buffer-deserialize-text-unicode.hh" +#line 147 "hb-buffer-deserialize-text-unicode.hh" { cs = deserialize_text_unicode_start; } -#line 159 "hb-buffer-deserialize-text-unicode.hh" +#line 150 "hb-buffer-deserialize-text-unicode.hh" { int _slen; int _trans; @@ -215,7 +215,7 @@ _resume: hb_memset (&info, 0, sizeof (info)); } break; -#line 219 "hb-buffer-deserialize-text-unicode.hh" +#line 203 "hb-buffer-deserialize-text-unicode.hh" } _again: @@ -238,7 +238,7 @@ _again: *end_ptr = p; } break; -#line 242 "hb-buffer-deserialize-text-unicode.hh" +#line 224 "hb-buffer-deserialize-text-unicode.hh" } } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc index 763172818c4..6787da6f65f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc @@ -427,7 +427,7 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer, * #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set. Then, * - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, `=` then #hb_glyph_info_t.cluster. * - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format: - * - If both #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not 0, `@x_offset,y_offset`. Then, + * - If #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not both 0, `@x_offset,y_offset`. Then, * - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then, * - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the #hb_glyph_extents_t in the format `` * diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc index 56299d9b7e0..0c9190bf6f8 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc @@ -163,7 +163,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, hb_buffer_append (fragment, text_buffer, text_start, text_end); if (!hb_shape_full (font, fragment, features, num_features, shapers) || - fragment->successful || fragment->shaping_failed) + fragment->successful) { hb_buffer_destroy (reconstruction); hb_buffer_destroy (fragment); @@ -313,11 +313,11 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, * Shape the two fragment streams. */ if (!hb_shape_full (font, fragments[0], features, num_features, shapers) || - !fragments[0]->successful || fragments[0]->shaping_failed) + !fragments[0]->successful) goto out; if (!hb_shape_full (font, fragments[1], features, num_features, shapers) || - !fragments[1]->successful || fragments[1]->shaping_failed) + !fragments[1]->successful) goto out; if (!forward) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc index c0600fd839b..8f6da312cdd 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc @@ -158,14 +158,15 @@ hb_segment_properties_overlay (hb_segment_properties_t *p, bool hb_buffer_t::enlarge (unsigned int size) { - if (unlikely (!successful)) - return false; if (unlikely (size > max_len)) { successful = false; return false; } + if (unlikely (!successful)) + return false; + unsigned int new_allocated = allocated; hb_glyph_position_t *new_pos = nullptr; hb_glyph_info_t *new_info = nullptr; @@ -226,6 +227,13 @@ hb_buffer_t::shift_forward (unsigned int count) assert (have_output); if (unlikely (!ensure (len + count))) return false; + max_ops -= len - idx; + if (unlikely (max_ops < 0)) + { + successful = false; + return false; + } + memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0])); if (idx + count > len) { @@ -297,7 +305,6 @@ hb_buffer_t::clear () props = default_props; successful = true; - shaping_failed = false; have_output = false; have_positions = false; @@ -320,7 +327,6 @@ hb_buffer_t::enter () { deallocate_var_all (); serial = 0; - shaping_failed = false; scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; unsigned mul; if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR, &mul))) @@ -339,7 +345,6 @@ hb_buffer_t::leave () max_ops = HB_BUFFER_MAX_OPS_DEFAULT; deallocate_var_all (); serial = 0; - // Intentionally not reseting shaping_failed, such that it can be inspected. } @@ -520,7 +525,19 @@ hb_buffer_t::set_masks (hb_mask_t value, hb_mask_t not_mask = ~mask; value &= mask; + max_ops -= len; + if (unlikely (max_ops < 0)) + successful = false; + unsigned int count = len; + + if (cluster_start == 0 && cluster_end == (unsigned int) -1) + { + for (unsigned int i = 0; i < count; i++) + info[i].mask = (info[i].mask & not_mask) | value; + return; + } + for (unsigned int i = 0; i < count; i++) if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end) info[i].mask = (info[i].mask & not_mask) | value; @@ -536,6 +553,10 @@ hb_buffer_t::merge_clusters_impl (unsigned int start, return; } + max_ops -= end - start; + if (unlikely (max_ops < 0)) + successful = false; + unsigned int cluster = info[start].cluster; for (unsigned int i = start + 1; i < end; i++) @@ -569,6 +590,10 @@ hb_buffer_t::merge_out_clusters (unsigned int start, if (unlikely (end - start < 2)) return; + max_ops -= end - start; + if (unlikely (max_ops < 0)) + successful = false; + unsigned int cluster = out_info[start].cluster; for (unsigned int i = start + 1; i < end; i++) @@ -726,7 +751,6 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) = HB_SEGMENT_PROPERTIES_DEFAULT, false, /* successful */ - true, /* shaping_failed */ false, /* have_output */ true /* have_positions */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh index 81c0f4a72e3..1c46981cc9c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh @@ -32,6 +32,7 @@ #include "hb.hh" #include "hb-unicode.hh" +#include "hb-set-digest.hh" static_assert ((sizeof (hb_glyph_info_t) == 20), ""); @@ -44,14 +45,14 @@ HB_MARK_AS_FLAG_T (hb_buffer_diff_flags_t); enum hb_buffer_scratch_flags_t { HB_BUFFER_SCRATCH_FLAG_DEFAULT = 0x00000000u, - HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII = 0x00000001u, + HB_BUFFER_SCRATCH_FLAG_HAS_FRACTION_SLASH = 0x00000001u, HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES = 0x00000002u, HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000004u, HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000008u, HB_BUFFER_SCRATCH_FLAG_HAS_CGJ = 0x00000010u, - HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS = 0x00000020u, - HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE = 0x00000040u, - HB_BUFFER_SCRATCH_FLAG_HAS_VARIATION_SELECTOR_FALLBACK= 0x00000080u, + HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE = 0x00000020u, + HB_BUFFER_SCRATCH_FLAG_HAS_VARIATION_SELECTOR_FALLBACK= 0x00000040u, + HB_BUFFER_SCRATCH_FLAG_HAS_CONTINUATIONS = 0x00000080u, /* Reserved for shapers' internal use. */ HB_BUFFER_SCRATCH_FLAG_SHAPER0 = 0x01000000u, @@ -90,7 +91,6 @@ struct hb_buffer_t hb_segment_properties_t props; /* Script, language, direction */ bool successful; /* Allocations successful */ - bool shaping_failed; /* Shaping failure */ bool have_output; /* Whether we have an output buffer going on */ bool have_positions; /* Whether we have positions */ @@ -110,6 +110,7 @@ struct hb_buffer_t hb_codepoint_t context[2][CONTEXT_LENGTH]; unsigned int context_len[2]; + hb_set_digest_t digest; /* Manually updated sometimes */ /* * Managed by enter / leave @@ -200,6 +201,12 @@ struct hb_buffer_t void collect_codepoints (set_t &d) const { d.clear (); d.add_array (&info[0].codepoint, len, sizeof (info[0])); } + void update_digest () + { + digest = hb_set_digest_t (); + collect_codepoints (digest); + } + HB_INTERNAL void similar (const hb_buffer_t &src); HB_INTERNAL void reset (); HB_INTERNAL void clear (); @@ -346,7 +353,7 @@ struct hb_buffer_t { if (out_info != info || out_len != idx) { - if (unlikely (!make_room_for (1, 1))) return false; + if (unlikely (!ensure (out_len + 1))) return false; out_info[out_len] = info[idx]; } out_len++; @@ -363,7 +370,7 @@ struct hb_buffer_t { if (out_info != info || out_len != idx) { - if (unlikely (!make_room_for (n, n))) return false; + if (unlikely (!ensure (out_len + n))) return false; memmove (out_info + out_len, info + idx, n * sizeof (out_info[0])); } out_len += n; @@ -404,22 +411,12 @@ struct hb_buffer_t /* Adds glyph flags in mask to infos with clusters between start and end. * The start index will be from out-buffer if from_out_buffer is true. * If interior is true, then the cluster having the minimum value is skipped. */ - void _set_glyph_flags (hb_mask_t mask, - unsigned start = 0, - unsigned end = (unsigned) -1, - bool interior = false, - bool from_out_buffer = false) + void _set_glyph_flags_impl (hb_mask_t mask, + unsigned start, + unsigned end, + bool interior, + bool from_out_buffer) { - end = hb_min (end, len); - - if (unlikely (end - start > 255)) - return; - - if (interior && !from_out_buffer && end - start < 2) - return; - - scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; - if (!from_out_buffer || !have_output) { if (!interior) @@ -456,6 +453,25 @@ struct hb_buffer_t } } + HB_ALWAYS_INLINE + void _set_glyph_flags (hb_mask_t mask, + unsigned start = 0, + unsigned end = (unsigned) -1, + bool interior = false, + bool from_out_buffer = false) + { + if (unlikely (end != (unsigned) -1 && end - start > 255)) + return; + + end = hb_min (end, len); + + if (interior && !from_out_buffer && end - start < 2) + return; + + _set_glyph_flags_impl (mask, start, end, interior, from_out_buffer); + } + + void unsafe_to_break (unsigned int start = 0, unsigned int end = -1) { _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT, @@ -606,6 +622,10 @@ struct hb_buffer_t if (unlikely (start == end)) return; + max_ops -= end - start; + if (unlikely (max_ops < 0)) + successful = false; + unsigned cluster_first = infos[start].cluster; unsigned cluster_last = infos[end - 1].cluster; @@ -614,10 +634,7 @@ struct hb_buffer_t { for (unsigned int i = start; i < end; i++) if (cluster != infos[i].cluster) - { - scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; infos[i].mask |= mask; - } return; } @@ -626,18 +643,12 @@ struct hb_buffer_t if (cluster == cluster_first) { for (unsigned int i = end; start < i && infos[i - 1].cluster != cluster_first; i--) - { - scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; infos[i - 1].mask |= mask; - } } else /* cluster == cluster_last */ { for (unsigned int i = start; i < end && infos[i].cluster != cluster_last; i++) - { - scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; infos[i].mask |= mask; - } } } unsigned diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cache.hh b/src/java.desktop/share/native/libharfbuzz/hb-cache.hh index 7d09ca89d7f..3609ccecc71 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cache.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cache.hh @@ -64,17 +64,23 @@ template , - hb_atomic_t>::type, - typename std::conditional::type + typename std::conditional, + typename std::conditional, + hb_atomic_t>::type>::type, + typename std::conditional::type>::type >::type; static_assert ((key_bits >= cache_bits), ""); static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), ""); + static constexpr unsigned MAX_VALUE = (1u << value_bits) - 1; + hb_cache_t () { clear (); } void clear () @@ -83,25 +89,32 @@ struct hb_cache_t v = -1; } + HB_HOT bool get (unsigned int key, unsigned int *value) const { unsigned int k = key & ((1u<> value_bits) != (key >> cache_bits)) return false; *value = v & ((1u<> key_bits) || (value >> value_bits))) - return false; /* Overflows */ + return; /* Overflows */ + set_unchecked (key, value); + } + + HB_HOT + void set_unchecked (unsigned int key, unsigned int value) + { unsigned int k = key & ((1u<>cache_bits)< cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd, const int *coords_=nullptr, unsigned int num_coords_=0) : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs), - cached_scalars_vector (&acc.cached_scalars_vector) + region_count (0), cached_scalars_vector (&acc.cached_scalars_vector) { coords = coords_; num_coords = num_coords_; varStore = acc.varStore; - do_blend = num_coords && coords && varStore->size; + do_blend = num_coords && varStore->size; set_ivs (acc.privateDicts[fd].ivs); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-common.cc b/src/java.desktop/share/native/libharfbuzz/hb-common.cc index 5c8546a378c..9eeae358a75 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-common.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-common.cc @@ -40,43 +40,6 @@ **/ -/* hb_options_t */ - -hb_atomic_t _hb_options; - -void -_hb_options_init () -{ - hb_options_union_t u; - u.i = 0; - u.opts.initialized = true; - - const char *c = getenv ("HB_OPTIONS"); - if (c) - { - while (*c) - { - const char *p = strchr (c, ':'); - if (!p) - p = c + strlen (c); - -#define OPTION(name, symbol) \ - if (0 == strncmp (c, name, p - c) && strlen (name) == static_cast(p - c)) do { u.opts.symbol = true; } while (0) - - OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible); - -#undef OPTION - - c = *p ? p + 1 : p; - } - - } - - /* This is idempotent and threadsafe. */ - _hb_options = u.i; -} - - /* hb_tag_t */ /** @@ -545,8 +508,11 @@ hb_script_to_iso15924_tag (hb_script_t script) * Fetches the #hb_direction_t of a script when it is * set horizontally. All right-to-left scripts will return * #HB_DIRECTION_RTL. All left-to-right scripts will return - * #HB_DIRECTION_LTR. Scripts that can be written either - * horizontally or vertically will return #HB_DIRECTION_INVALID. + * #HB_DIRECTION_LTR. + * + * Scripts that can be written either right-to-left or + * left-to-right will return #HB_DIRECTION_INVALID. + * * Unknown scripts will return #HB_DIRECTION_LTR. * * Return value: The horizontal #hb_direction_t of @script @@ -628,6 +594,9 @@ hb_script_get_horizontal_direction (hb_script_t script) /* Unicode-16.0 additions */ case HB_SCRIPT_GARAY: + /* Unicode-17.0 additions */ + case HB_SCRIPT_SIDETIC: + return HB_DIRECTION_RTL; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-config.hh b/src/java.desktop/share/native/libharfbuzz/hb-config.hh index 3956690da35..c522eeea2ea 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-config.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-config.hh @@ -38,7 +38,6 @@ #ifndef HB_EXPERIMENTAL_API #define HB_NO_BEYOND_64K #define HB_NO_CUBIC_GLYF -#define HB_NO_VAR_COMPOSITES #endif #ifdef HB_TINY @@ -91,7 +90,10 @@ #ifdef HB_MINI #define HB_NO_AAT #define HB_NO_LEGACY -#define HB_NO_BORING_EXPANSION +#define HB_NO_BEYOND_64K +#define HB_NO_CUBIC_GLYF +#define HB_NO_VAR_COMPOSITES +#define HB_NO_VAR_HVF #endif #ifdef __OPTIMIZE_SIZE__ @@ -109,12 +111,6 @@ /* Closure of options. */ -#ifdef HB_NO_BORING_EXPANSION -#define HB_NO_BEYOND_64K -#define HB_NO_CUBIC_GLYF -#define HB_NO_VAR_COMPOSITES -#endif - #ifdef HB_NO_VAR #define HB_NO_VAR_COMPOSITES #endif @@ -149,10 +145,6 @@ #define HB_NO_PAINT #endif -#ifdef HB_NO_GETENV -#define HB_NO_UNISCRIBE_BUG_COMPATIBLE -#endif - #ifdef HB_NO_LEGACY #define HB_NO_CMAP_LEGACY_SUBTABLES #define HB_NO_FALLBACK_SHAPE diff --git a/src/java.desktop/share/native/libharfbuzz/hb-debug.hh b/src/java.desktop/share/native/libharfbuzz/hb-debug.hh index 1e9a18b9326..87d30d9ded1 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-debug.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-debug.hh @@ -37,48 +37,6 @@ #endif -/* - * Global runtime options. - */ - -struct hb_options_t -{ - bool unused : 1; /* In-case sign bit is here. */ - bool initialized : 1; - bool uniscribe_bug_compatible : 1; -}; - -union hb_options_union_t { - unsigned i; - hb_options_t opts; -}; -static_assert ((sizeof (hb_atomic_t) >= sizeof (hb_options_union_t)), ""); - -HB_INTERNAL void -_hb_options_init (); - -extern HB_INTERNAL hb_atomic_t _hb_options; - -static inline hb_options_t -hb_options () -{ -#ifdef HB_NO_GETENV - return hb_options_t (); -#endif - /* Make a local copy, so we can access bitfield threadsafely. */ - hb_options_union_t u; - u.i = _hb_options; - - if (unlikely (!u.i)) - { - _hb_options_init (); - u.i = _hb_options; - } - - return u.opts; -} - - /* * Debug output (needs enabling at compile time.) */ @@ -394,6 +352,10 @@ struct hb_no_trace_t { #define HB_DEBUG_WASM (HB_DEBUG+0) #endif +#ifndef HB_DEBUG_KBTS +#define HB_DEBUG_KBTS (HB_DEBUG+0) +#endif + /* * With tracing. */ @@ -484,7 +446,7 @@ struct hb_no_trace_t { #ifndef HB_BUFFER_MESSAGE_MORE -#define HB_BUFFER_MESSAGE_MORE (HB_DEBUG+1) +#define HB_BUFFER_MESSAGE_MORE (HB_DEBUG+0) #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h b/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h index 927563c4c40..a87a53d0e30 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h @@ -287,7 +287,7 @@ typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. * * Since: 7.0.0 - * XDeprecated: REPLACEME: Use hb_font_draw_glyph_func_or_fail_t instead. + * Deprecated: 11.2.0: Use hb_font_draw_glyph_func_or_fail_t instead. **/ typedef void (*hb_font_draw_glyph_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t glyph, @@ -308,7 +308,7 @@ typedef void (*hb_font_draw_glyph_func_t) (hb_font_t *font, void *font_data, * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. * * Since: 7.0.0 - * XDeprecated: REPLACEME: Use hb_font_paint_glyph_or_fail_func_t instead. + * Deprecated: 11.2.0: Use hb_font_paint_glyph_or_fail_func_t instead. */ typedef hb_bool_t (*hb_font_paint_glyph_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t glyph, @@ -346,7 +346,7 @@ hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs, * Sets the implementation function for #hb_font_draw_glyph_func_t. * * Since: 7.0.0 - * XDeprecated: REPLACEME: Use hb_font_funcs_set_draw_glyph_or_fail_func instead. + * Deprecated: 11.2.0: Use hb_font_funcs_set_draw_glyph_or_fail_func instead. **/ HB_DEPRECATED_FOR (hb_font_funcs_set_draw_glyph_or_fail_func) HB_EXTERN void @@ -364,7 +364,7 @@ hb_font_funcs_set_draw_glyph_func (hb_font_funcs_t *ffuncs, * Sets the implementation function for #hb_font_paint_glyph_func_t. * * Since: 7.0.0 - * XDeprecated: REPLACEME: Use hb_font_funcs_set_paint_glyph_or_fail_func() instead. + * Deprecated: 11.2.0: Use hb_font_funcs_set_paint_glyph_or_fail_func() instead. */ HB_DEPRECATED_FOR (hb_font_funcs_set_paint_glyph_or_fail_func) HB_EXTERN void diff --git a/src/java.desktop/share/native/libharfbuzz/hb-draw.cc b/src/java.desktop/share/native/libharfbuzz/hb-draw.cc index 8764ffe7129..c243d12f7ae 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-draw.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-draw.cc @@ -63,14 +63,14 @@ hb_draw_quadratic_to_nil (hb_draw_funcs_t *dfuncs, void *draw_data, float to_x, float to_y, void *user_data HB_UNUSED) { -#define HB_ONE_THIRD 0.33333333f +#define HB_TWO_THIRD 0.66666666666666666666666667f dfuncs->emit_cubic_to (draw_data, *st, - (st->current_x + 2.f * control_x) * HB_ONE_THIRD, - (st->current_y + 2.f * control_y) * HB_ONE_THIRD, - (to_x + 2.f * control_x) * HB_ONE_THIRD, - (to_y + 2.f * control_y) * HB_ONE_THIRD, + st->current_x + (control_x - st->current_x) * HB_TWO_THIRD, + st->current_y + (control_y - st->current_y) * HB_TWO_THIRD, + to_x + (control_x - to_x) * HB_TWO_THIRD, + to_y + (control_y - to_y) * HB_TWO_THIRD, to_x, to_y); -#undef HB_ONE_THIRD +#undef HB_TWO_THIRD } static void @@ -467,7 +467,7 @@ hb_draw_extents_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED, float to_x, float to_y, void *user_data HB_UNUSED) { - hb_extents_t *extents = (hb_extents_t *) data; + hb_extents_t<> *extents = (hb_extents_t<> *) data; extents->add_point (to_x, to_y); } @@ -479,7 +479,7 @@ hb_draw_extents_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED, float to_x, float to_y, void *user_data HB_UNUSED) { - hb_extents_t *extents = (hb_extents_t *) data; + hb_extents_t<> *extents = (hb_extents_t<> *) data; extents->add_point (to_x, to_y); } @@ -492,7 +492,7 @@ hb_draw_extents_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, float to_x, float to_y, void *user_data HB_UNUSED) { - hb_extents_t *extents = (hb_extents_t *) data; + hb_extents_t<> *extents = (hb_extents_t<> *) data; extents->add_point (control_x, control_y); extents->add_point (to_x, to_y); @@ -507,7 +507,7 @@ hb_draw_extents_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, float to_x, float to_y, void *user_data HB_UNUSED) { - hb_extents_t *extents = (hb_extents_t *) data; + hb_extents_t<> *extents = (hb_extents_t<> *) data; extents->add_point (control1_x, control1_y); extents->add_point (control2_x, control2_y); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc b/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc index 6b7e1913024..c1feaac6280 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc @@ -169,8 +169,7 @@ _hb_face_builder_get_table_tags (const hb_face_t *face HB_UNUSED, if (unlikely (start_offset >= population)) { - if (table_count) - *table_count = 0; + *table_count = 0; return population; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-face.cc b/src/java.desktop/share/native/libharfbuzz/hb-face.cc index 9d59d7c9468..a0f497eea7f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-face.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-face.cc @@ -84,8 +84,7 @@ hb_face_count (hb_blob_t *blob) hb_sanitize_context_t c (blob); - const char *start = hb_blob_get_data (blob, nullptr); - auto *ot = reinterpret_cast (const_cast (start)); + auto *ot = blob->as (); if (unlikely (!ot->sanitize (&c))) return 0; @@ -329,7 +328,7 @@ hb_face_create_from_file_or_fail (const char *file_name, return face; } -static struct supported_face_loaders_t { +static const struct supported_face_loaders_t { char name[16]; hb_face_t * (*from_file) (const char *font_file, unsigned face_index); hb_face_t * (*from_blob) (hb_blob_t *blob, unsigned face_index); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.cc b/src/java.desktop/share/native/libharfbuzz/hb-font.cc index 849855e2c22..6c636e23567 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-font.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-font.cc @@ -246,7 +246,6 @@ hb_font_get_glyph_v_advance_nil (hb_font_t *font, hb_codepoint_t glyph HB_UNUSED, void *user_data HB_UNUSED) { - /* TODO use font_extents.ascender+descender */ return -font->y_scale; } @@ -352,6 +351,10 @@ hb_font_get_glyph_h_origin_default (hb_font_t *font, hb_position_t *y, void *user_data HB_UNUSED) { + if (font->has_glyph_h_origins_func_set ()) + { + return font->get_glyph_h_origins (1, &glyph, 0, x, 0, y, 0, false); + } hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y); if (ret) font->parent_scale_position (x, y); @@ -366,7 +369,6 @@ hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED, hb_position_t *y, void *user_data HB_UNUSED) { - *x = *y = 0; return false; } @@ -378,12 +380,100 @@ hb_font_get_glyph_v_origin_default (hb_font_t *font, hb_position_t *y, void *user_data HB_UNUSED) { + if (font->has_glyph_v_origins_func_set ()) + { + return font->get_glyph_v_origins (1, &glyph, 0, x, 0, y, 0, false); + } hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y); if (ret) font->parent_scale_position (x, y); return ret; } +#define hb_font_get_glyph_h_origins_nil hb_font_get_glyph_h_origins_default + +static hb_bool_t +hb_font_get_glyph_h_origins_default (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + unsigned int count, + const hb_codepoint_t *first_glyph HB_UNUSED, + unsigned glyph_stride HB_UNUSED, + hb_position_t *first_x, + unsigned x_stride, + hb_position_t *first_y, + unsigned y_stride, + void *user_data HB_UNUSED) +{ + if (font->has_glyph_h_origin_func_set ()) + { + for (unsigned int i = 0; i < count; i++) + { + font->get_glyph_h_origin (*first_glyph, first_x, first_y, false); + first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); + first_x = &StructAtOffsetUnaligned (first_x, x_stride); + first_y = &StructAtOffsetUnaligned (first_y, y_stride); + } + return true; + } + + hb_bool_t ret = font->parent->get_glyph_h_origins (count, + first_glyph, glyph_stride, + first_x, x_stride, + first_y, y_stride); + if (ret) + { + for (unsigned i = 0; i < count; i++) + { + font->parent_scale_position (first_x, first_y); + first_x = &StructAtOffsetUnaligned (first_x, x_stride); + first_y = &StructAtOffsetUnaligned (first_y, y_stride); + } + } + return ret; +} + +#define hb_font_get_glyph_v_origins_nil hb_font_get_glyph_v_origins_default + +static hb_bool_t +hb_font_get_glyph_v_origins_default (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + unsigned int count, + const hb_codepoint_t *first_glyph HB_UNUSED, + unsigned glyph_stride HB_UNUSED, + hb_position_t *first_x, + unsigned x_stride, + hb_position_t *first_y, + unsigned y_stride, + void *user_data HB_UNUSED) +{ + if (font->has_glyph_v_origin_func_set ()) + { + for (unsigned int i = 0; i < count; i++) + { + font->get_glyph_v_origin (*first_glyph, first_x, first_y, false); + first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); + first_x = &StructAtOffsetUnaligned (first_x, x_stride); + first_y = &StructAtOffsetUnaligned (first_y, y_stride); + } + return true; + } + + hb_bool_t ret = font->parent->get_glyph_v_origins (count, + first_glyph, glyph_stride, + first_x, x_stride, + first_y, y_stride); + if (ret) + { + for (unsigned i = 0; i < count; i++) + { + font->parent_scale_position (first_x, first_y); + first_x = &StructAtOffsetUnaligned (first_x, x_stride); + first_y = &StructAtOffsetUnaligned (first_y, y_stride); + } + } + return ret; +} + static hb_position_t hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, @@ -1256,6 +1346,77 @@ hb_font_get_glyph_v_origin (hb_font_t *font, return font->get_glyph_v_origin (glyph, x, y); } +/** + * hb_font_get_glyph_h_origins: + * @font: #hb_font_t to work upon + * @count: The number of glyph IDs in the sequence queried + * @first_glyph: The first glyph ID to query + * @glyph_stride: The stride between successive glyph IDs + * @first_x: (out): The first X coordinate of the origin retrieved + * @x_stride: The stride between successive X coordinates + * @first_y: (out): The first Y coordinate of the origin retrieved + * @y_stride: The stride between successive Y coordinates + * + * Fetches the (X,Y) coordinates of the origin for requested glyph IDs + * in the specified font, for horizontal text segments. + * + * Return value: `true` if data found, `false` otherwise + * + * Since: 11.3.0 + **/ +hb_bool_t +hb_font_get_glyph_h_origins (hb_font_t *font, + unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + hb_position_t *first_x, + unsigned int x_stride, + hb_position_t *first_y, + unsigned int y_stride) + +{ + return font->get_glyph_h_origins (count, + first_glyph, glyph_stride, + first_x, x_stride, + first_y, y_stride); +} + +/** + * hb_font_get_glyph_v_origins: + * @font: #hb_font_t to work upon + * @count: The number of glyph IDs in the sequence queried + * @first_glyph: The first glyph ID to query + * @glyph_stride: The stride between successive glyph IDs + * @first_x: (out): The first X coordinate of the origin retrieved + * @x_stride: The stride between successive X coordinates + * @first_y: (out): The first Y coordinate of the origin retrieved + * @y_stride: The stride between successive Y coordinates + * + * Fetches the (X,Y) coordinates of the origin for requested glyph IDs + * in the specified font, for vertical text segments. + * + * Return value: `true` if data found, `false` otherwise + * + * Since: 11.3.0 + **/ +hb_bool_t +hb_font_get_glyph_v_origins (hb_font_t *font, + unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + hb_position_t *first_x, + unsigned int x_stride, + hb_position_t *first_y, + unsigned int y_stride) + +{ + return font->get_glyph_v_origins (count, + first_glyph, glyph_stride, + first_x, x_stride, + first_y, y_stride); +} + + /** * hb_font_get_glyph_h_kerning: * @font: #hb_font_t to work upon @@ -1443,7 +1604,7 @@ hb_font_get_glyph_shape (hb_font_t *font, * * Return value: `true` if glyph was drawn, `false` otherwise * - * XSince: REPLACEME + * Since: 11.2.0 **/ hb_bool_t hb_font_draw_glyph_or_fail (hb_font_t *font, @@ -1480,7 +1641,7 @@ hb_font_draw_glyph_or_fail (hb_font_t *font, * * Return value: `true` if glyph was painted, `false` otherwise * - * XSince: REPLACEME + * Since: 11.2.0 */ hb_bool_t hb_font_paint_glyph_or_fail (hb_font_t *font, @@ -1883,6 +2044,7 @@ DEFINE_NULL_INSTANCE (hb_font_t) = 1000, /* x_scale */ 1000, /* y_scale */ + false, /* is_synthetic */ 0.f, /* x_embolden */ 0.f, /* y_embolden */ true, /* embolden_in_place */ @@ -1900,6 +2062,7 @@ DEFINE_NULL_INSTANCE (hb_font_t) = 0, /* ptem */ HB_FONT_NO_VAR_NAMED_INSTANCE, /* instance_index */ + false, /* has_nonzero_coords */ 0, /* num_coords */ nullptr, /* coords */ nullptr, /* design_coords */ @@ -1960,8 +2123,14 @@ hb_font_create (hb_face_t *face) hb_font_set_funcs_using (font, nullptr); #ifndef HB_NO_VAR - if (face && face->index >> 16) - hb_font_set_var_named_instance (font, (face->index >> 16) - 1); + // Initialize variations. + if (likely (face)) + { + if (face->index >> 16) + hb_font_set_var_named_instance (font, (face->index >> 16) - 1); + else + hb_font_set_variations (font, nullptr, 0); + } #endif return font; @@ -1979,6 +2148,7 @@ _hb_font_adopt_var_coords (hb_font_t *font, font->coords = coords; font->design_coords = design_coords; font->num_coords = coords_length; + font->has_nonzero_coords = hb_any (hb_array (coords, coords_length)); font->changed (); font->serial_coords = font->serial; @@ -2393,7 +2563,7 @@ hb_font_set_funcs_data (hb_font_t *font, font->changed (); } -static struct supported_font_funcs_t { +static const struct supported_font_funcs_t { char name[16]; void (*func) (hb_font_t *); } supported_font_funcs[] = @@ -2450,6 +2620,9 @@ hb_bool_t hb_font_set_funcs_using (hb_font_t *font, const char *name) { + if (unlikely (hb_object_is_immutable (font))) + return false; + bool retry = false; if (!name || !*name) @@ -2704,12 +2877,12 @@ hb_font_get_ptem (hb_font_t *font) * * Return value: `true` if the font is synthetic, `false` otherwise. * - * XSince: REPLACEME + * Since: 11.2.0 */ hb_bool_t hb_font_is_synthetic (hb_font_t *font) { - return font->is_synthetic (); + return font->is_synthetic; } /** @@ -2858,12 +3031,6 @@ hb_font_set_variations (hb_font_t *font, if (hb_object_is_immutable (font)) return; - if (!variations_length && font->instance_index == HB_FONT_NO_VAR_NAMED_INSTANCE) - { - hb_font_set_var_coords_normalized (font, nullptr, 0); - return; - } - const OT::fvar &fvar = *font->face->table.fvar; auto axes = fvar.get_axes (); const unsigned coords_length = axes.length; @@ -2970,7 +3137,6 @@ hb_font_set_variation (hb_font_t *font, hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized); _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); - } /** @@ -2991,11 +3157,16 @@ hb_font_set_variation (hb_font_t *font, void hb_font_set_var_coords_design (hb_font_t *font, const float *coords, - unsigned int coords_length) + unsigned int input_coords_length) { if (hb_object_is_immutable (font)) return; + const OT::fvar &fvar = *font->face->table.fvar; + auto axes = fvar.get_axes (); + const unsigned coords_length = axes.length; + + input_coords_length = hb_min (input_coords_length, coords_length); int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr; float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr; @@ -3006,8 +3177,11 @@ hb_font_set_var_coords_design (hb_font_t *font, return; } - if (coords_length) - hb_memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0])); + if (input_coords_length) + hb_memcpy (design_coords, coords, input_coords_length * sizeof (font->design_coords[0])); + // Fill in the rest with default values + for (unsigned int i = input_coords_length; i < coords_length; i++) + design_coords[i] = axes[i].get_default (); hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized); _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); @@ -3072,34 +3246,31 @@ hb_font_get_var_named_instance (hb_font_t *font) void hb_font_set_var_coords_normalized (hb_font_t *font, const int *coords, /* 2.14 normalized */ - unsigned int coords_length) + unsigned int input_coords_length) { if (hb_object_is_immutable (font)) return; + const OT::fvar &fvar = *font->face->table.fvar; + auto axes = fvar.get_axes (); + unsigned coords_length = axes.length; + + input_coords_length = hb_min (input_coords_length, coords_length); int *copy = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr; - int *unmapped = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr; float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (design_coords[0])) : nullptr; - if (unlikely (coords_length && !(copy && unmapped && design_coords))) + if (unlikely (coords_length && !(copy && design_coords))) { hb_free (copy); - hb_free (unmapped); hb_free (design_coords); return; } - if (coords_length) - { - hb_memcpy (copy, coords, coords_length * sizeof (coords[0])); - hb_memcpy (unmapped, coords, coords_length * sizeof (coords[0])); - } + if (input_coords_length) + hb_memcpy (copy, coords, input_coords_length * sizeof (coords[0])); - /* Best effort design coords simulation */ - font->face->table.avar->unmap_coords (unmapped, coords_length); for (unsigned int i = 0; i < coords_length; ++i) - design_coords[i] = font->face->table.fvar->unnormalize_axis_value (i, unmapped[i]); - hb_free (unmapped); + design_coords[i] = NAN; _hb_font_adopt_var_coords (font, copy, design_coords, coords_length); } @@ -3112,8 +3283,8 @@ hb_font_set_var_coords_normalized (hb_font_t *font, * Fetches the list of normalized variation coordinates currently * set on a font. * - * Note that this returned array may only contain values for some - * (or none) of the axes; omitted axes effectively have zero values. + * Note that if no variation coordinates are set, this function may + * return %NULL. * * Return value is valid as long as variation coordinates of the font * are not modified. @@ -3140,9 +3311,12 @@ hb_font_get_var_coords_normalized (hb_font_t *font, * Fetches the list of variation coordinates (in design-space units) currently * set on a font. * - * Note that this returned array may only contain values for some - * (or none) of the axes; omitted axes effectively have their default - * values. + * Note that if no variation coordinates are set, this function may + * return %NULL. + * + * If variations have been set on the font using normalized coordinates + * (i.e. via hb_font_set_var_coords_normalized()), the design coordinates will + * have NaN (Not a Number) values. * * Return value is valid as long as variation coordinates of the font * are not modified. diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.h b/src/java.desktop/share/native/libharfbuzz/hb-font.h index 4e267ba6a80..2d06b659278 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-font.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-font.h @@ -97,7 +97,7 @@ hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs); * @descender: The depth of typographic descenders. * @line_gap: The suggested line-spacing gap. * - * Font-wide extent values, measured in font units. + * Font-wide extent values, measured in scaled units. * * Note that typically @ascender is positive and @descender * negative, in coordinate systems that grow up. @@ -332,7 +332,7 @@ typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t; * * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. * - * This method should retrieve the (X,Y) coordinates (in font units) of the + * This method should retrieve the (X,Y) coordinates (in scaled units) of the * origin for a glyph. Each coordinate must be returned in an #hb_position_t * output parameter. * @@ -349,7 +349,7 @@ typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *fon * * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. * - * This method should retrieve the (X,Y) coordinates (in font units) of the + * This method should retrieve the (X,Y) coordinates (in scaled units) of the * origin for a glyph, for horizontal-direction text segments. Each * coordinate must be returned in an #hb_position_t output parameter. * @@ -361,13 +361,72 @@ typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t; * * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. * - * This method should retrieve the (X,Y) coordinates (in font units) of the + * This method should retrieve the (X,Y) coordinates (in scaled units) of the * origin for a glyph, for vertical-direction text segments. Each coordinate * must be returned in an #hb_position_t output parameter. * **/ typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t; +/** + * hb_font_get_glyph_origins_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @first_glyph: The first glyph ID to query + * @count: number of glyphs to query + * @glyph_stride: The stride between successive glyph IDs + * @first_x: (out): The first origin X coordinate retrieved + * @x_stride: The stride between successive origin X coordinates + * @first_y: (out): The first origin Y coordinate retrieved + * @y_stride: The stride between successive origin Y coordinates + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the (X,Y) coordinates (in scaled units) of the + * origin for each requested glyph. Each coordinate value must be returned in + * an #hb_position_t in the two output parameters. + * + * Return value: `true` if data found, `false` otherwise + * + * Since: 11.3.0 + **/ +typedef hb_bool_t (*hb_font_get_glyph_origins_func_t) (hb_font_t *font, void *font_data, + unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_x, + unsigned x_stride, + hb_position_t *first_y, + unsigned y_stride, + void *user_data); + +/** + * hb_font_get_glyph_h_origins_func_t: + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the (X,Y) coordinates (in scaled units) of the + * origin for requested glyph, for horizontal-direction text segments. Each + * coordinate must be returned in a the x/y #hb_position_t output parameters. + * + * Since: 11.3.0 + **/ +typedef hb_font_get_glyph_origins_func_t hb_font_get_glyph_h_origins_func_t; + +/** + * hb_font_get_glyph_v_origins_func_t: + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the (X,Y) coordinates (in scaled units) of the + * origin for requested glyph, for vertical-direction text segments. Each + * coordinate must be returned in a the x/y #hb_position_t output parameters. + * + * Since: 11.3.0 + **/ +typedef hb_font_get_glyph_origins_func_t hb_font_get_glyph_v_origins_func_t; + /** * hb_font_get_glyph_kerning_func_t: * @font: #hb_font_t to work upon @@ -428,7 +487,7 @@ typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *fo * * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. * - * This method should retrieve the (X,Y) coordinates (in font units) for a + * This method should retrieve the (X,Y) coordinates (in scaled units) for a * specified contour point in a glyph. Each coordinate must be returned as * an #hb_position_t output parameter. * @@ -498,7 +557,7 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void * * * Return value: `true` if glyph was drawn, `false` otherwise * - * XSince: REPLACEME + * Since: 11.2.0 **/ typedef hb_bool_t (*hb_font_draw_glyph_or_fail_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t glyph, @@ -520,7 +579,7 @@ typedef hb_bool_t (*hb_font_draw_glyph_or_fail_func_t) (hb_font_t *font, void *f * * Return value: `true` if glyph was painted, `false` otherwise * - * XSince: REPLACEME + * Since: 11.2.0 */ typedef hb_bool_t (*hb_font_paint_glyph_or_fail_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t glyph, @@ -707,6 +766,38 @@ hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_v_origin_func_t func, void *user_data, hb_destroy_func_t destroy); +/** + * hb_font_funcs_set_glyph_h_origins_func: + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets the implementation function for #hb_font_get_glyph_h_origins_func_t. + * + * Since: 11.3.0 + **/ +HB_EXTERN void +hb_font_funcs_set_glyph_h_origins_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_h_origins_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_font_funcs_set_glyph_v_origins_func: + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets the implementation function for #hb_font_get_glyph_v_origins_func_t. + * + * Since: 11.3.0 + **/ +HB_EXTERN void +hb_font_funcs_set_glyph_v_origins_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_v_origins_func_t func, + void *user_data, hb_destroy_func_t destroy); + /** * hb_font_funcs_set_glyph_h_kerning_func: * @ffuncs: A font-function structure @@ -796,7 +887,7 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs, * * Sets the implementation function for #hb_font_draw_glyph_or_fail_func_t. * - * XSince: REPLACEME + * Since: 11.2.0 **/ HB_EXTERN void hb_font_funcs_set_draw_glyph_or_fail_func (hb_font_funcs_t *ffuncs, @@ -812,7 +903,7 @@ hb_font_funcs_set_draw_glyph_or_fail_func (hb_font_funcs_t *ffuncs, * * Sets the implementation function for #hb_font_paint_glyph_or_fail_func_t. * - * XSince: REPLACEME + * Since: 11.2.0 */ HB_EXTERN void hb_font_funcs_set_paint_glyph_or_fail_func (hb_font_funcs_t *ffuncs, @@ -876,6 +967,26 @@ hb_font_get_glyph_v_origin (hb_font_t *font, hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y); +HB_EXTERN hb_bool_t +hb_font_get_glyph_h_origins (hb_font_t *font, + unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_x, + unsigned x_stride, + hb_position_t *first_y, + unsigned y_stride); + +HB_EXTERN hb_bool_t +hb_font_get_glyph_v_origins (hb_font_t *font, + unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_x, + unsigned x_stride, + hb_position_t *first_y, + unsigned y_stride); + HB_EXTERN hb_position_t hb_font_get_glyph_h_kerning (hb_font_t *font, hb_codepoint_t left_glyph, hb_codepoint_t right_glyph); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.hh b/src/java.desktop/share/native/libharfbuzz/hb-font.hh index 69d8d4b09df..9dd54466d7f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-font.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-font.hh @@ -55,6 +55,8 @@ HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_advances) \ HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_origin) \ HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_origin) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_origins) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_origins) \ HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_kerning) \ HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_kerning)) \ HB_FONT_FUNC_IMPLEMENT (get_,glyph_extents) \ @@ -118,6 +120,8 @@ struct hb_font_t int32_t x_scale; int32_t y_scale; + bool is_synthetic; + float x_embolden; float y_embolden; bool embolden_in_place; @@ -139,6 +143,7 @@ struct hb_font_t /* Font variation coordinates. */ unsigned int instance_index; + bool has_nonzero_coords; unsigned int num_coords; int *coords; float *design_coords; @@ -430,21 +435,127 @@ struct hb_font_t } hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + hb_position_t *x, hb_position_t *y, + bool synthetic = true) { *x = *y = 0; - return klass->get.f.glyph_h_origin (this, user_data, - glyph, x, y, - !klass->user_data ? nullptr : klass->user_data->glyph_h_origin); + bool ret = klass->get.f.glyph_h_origin (this, user_data, + glyph, x, y, + !klass->user_data ? nullptr : klass->user_data->glyph_h_origin); + + if (synthetic && ret) + { + /* Slant is ignored as it does not affect glyph origin */ + + /* Embolden */ + if (!embolden_in_place) + { + *x += x_scale < 0 ? -x_strength : x_strength; + *y += y_scale < 0 ? -y_strength : y_strength; + } + } + + return ret; } hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + hb_position_t *x, hb_position_t *y, + bool synthetic = true) { *x = *y = 0; - return klass->get.f.glyph_v_origin (this, user_data, - glyph, x, y, - !klass->user_data ? nullptr : klass->user_data->glyph_v_origin); + bool ret = klass->get.f.glyph_v_origin (this, user_data, + glyph, x, y, + !klass->user_data ? nullptr : klass->user_data->glyph_v_origin); + + if (synthetic && ret) + { + /* Slant is ignored as it does not affect glyph origin */ + + /* Embolden */ + if (!embolden_in_place) + { + *x += x_scale < 0 ? -x_strength : x_strength; + *y += y_scale < 0 ? -y_strength : y_strength; + } + } + + return ret; + } + + hb_bool_t get_glyph_h_origins (unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + hb_position_t *first_x, + unsigned int x_stride, + hb_position_t *first_y, + unsigned int y_stride, + bool synthetic = true) + + { + bool ret = klass->get.f.glyph_h_origins (this, user_data, + count, + first_glyph, glyph_stride, + first_x, x_stride, first_y, y_stride, + !klass->user_data ? nullptr : klass->user_data->glyph_h_origins); + + if (synthetic && ret) + { + hb_position_t x_shift = x_scale < 0 ? -x_strength : x_strength; + hb_position_t y_shift = y_scale < 0 ? -y_strength : y_strength; + for (unsigned i = 0; i < count; i++) + { + /* Slant is ignored as it does not affect glyph origin */ + + /* Embolden */ + if (!embolden_in_place) + { + *first_x += x_shift; + *first_y += y_shift; + } + first_x = &StructAtOffsetUnaligned (first_x, x_stride); + first_y = &StructAtOffsetUnaligned (first_y, y_stride); + } + } + + return ret; + } + + hb_bool_t get_glyph_v_origins (unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + hb_position_t *first_x, + unsigned int x_stride, + hb_position_t *first_y, + unsigned int y_stride, + bool synthetic = true) + + { + bool ret = klass->get.f.glyph_v_origins (this, user_data, + count, + first_glyph, glyph_stride, + first_x, x_stride, first_y, y_stride, + !klass->user_data ? nullptr : klass->user_data->glyph_v_origins); + + if (synthetic && is_synthetic && ret) + { + hb_position_t x_shift = x_scale < 0 ? -x_strength : x_strength; + hb_position_t y_shift = y_scale < 0 ? -y_strength : y_strength; + for (unsigned i = 0; i < count; i++) + { + /* Slant is ignored as it does not affect glyph origin */ + + /* Embolden */ + if (!embolden_in_place) + { + *first_x += x_shift; + *first_y += y_shift; + } + first_x = &StructAtOffsetUnaligned (first_x, x_stride); + first_y = &StructAtOffsetUnaligned (first_y, y_stride); + } + } + + return ret; } hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, @@ -486,7 +597,7 @@ struct hb_font_t extents, !klass->user_data ? nullptr : klass->user_data->glyph_extents); } - if (!is_synthetic () && + if (!is_synthetic && klass->get.f.glyph_extents (this, user_data, glyph, extents, @@ -496,6 +607,7 @@ struct hb_font_t /* Try getting extents from paint(), then draw(), *then* get_extents() * and apply synthetic settings in the last case. */ +#ifndef HB_NO_PAINT hb_paint_extents_context_t paint_extents; if (paint_glyph_or_fail (glyph, hb_paint_extents_get_funcs (), &paint_extents, @@ -504,14 +616,17 @@ struct hb_font_t *extents = paint_extents.get_extents ().to_glyph_extents (); return true; } +#endif - hb_extents_t draw_extents; +#ifndef HB_NO_DRAW + hb_extents_t<> draw_extents; if (draw_glyph_or_fail (glyph, hb_draw_extents_get_funcs (), &draw_extents)) { *extents = draw_extents.to_glyph_extents (); return true; } +#endif bool ret = klass->get.f.glyph_extents (this, user_data, glyph, @@ -575,6 +690,7 @@ struct hb_font_t hb_draw_funcs_t *draw_funcs, void *draw_data, bool synthetic = true) { +#ifndef HB_NO_DRAW #ifndef HB_NO_OUTLINE bool embolden = x_strength || y_strength; bool slanted = slant_xy; @@ -603,7 +719,13 @@ struct hb_font_t // Slant before embolden; produces nicer results. if (slanted) + { + hb_position_t xo = 0, yo = 0; + get_glyph_h_origin (glyph, &xo, &yo, false); + outline.translate (-xo, -yo); outline.slant (slant_xy); + outline.translate (xo, yo); + } if (embolden) { @@ -618,6 +740,8 @@ struct hb_font_t return true; #endif +#endif + return false; } bool paint_glyph_or_fail (hb_codepoint_t glyph, @@ -626,6 +750,7 @@ struct hb_font_t hb_color_t foreground, bool synthetic = true) { +#ifndef HB_NO_PAINT /* Slant */ if (synthetic && slant_xy) hb_paint_push_transform (paint_funcs, paint_data, @@ -643,6 +768,8 @@ struct hb_font_t hb_paint_pop_transform (paint_funcs, paint_data); return ret; +#endif + return false; } /* A bit higher-level, and with fallback */ @@ -704,6 +831,28 @@ struct hb_font_t get_glyph_v_advances (count, first_glyph, glyph_stride, first_advance, advance_stride); } + void apply_offset (hb_position_t *x, hb_position_t *y, + hb_position_t dx, hb_position_t dy, + signed mult) + { + assert (mult == -1 || mult == +1); + + *x += dx * mult; + *y += dy * mult; + } + void add_offset (hb_position_t *x, hb_position_t *y, + hb_position_t dx, hb_position_t dy) + { + *x += dx; + *y += dy; + } + void subtract_offset (hb_position_t *x, hb_position_t *y, + hb_position_t dx, hb_position_t dy) + { + *x -= dx; + *y -= dy; + } + void guess_v_origin_minus_h_origin (hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y) { @@ -714,6 +863,141 @@ struct hb_font_t *y = extents.ascender; } + void apply_glyph_h_origins_with_fallback (hb_buffer_t *buf, int mult) + { + bool has_ascender = false; + hb_position_t ascender = 0; + + struct { hb_position_t x, y; } origins[32]; + + unsigned int offset = 0; + unsigned int count = buf->len; + while (offset < count) + { + unsigned n = hb_min (count - offset, ARRAY_LENGTH (origins)); + if (!get_glyph_h_origins (n, + &buf->info[offset].codepoint, sizeof (hb_glyph_info_t), + &origins[0].x, sizeof (origins[0]), + &origins[0].y, sizeof (origins[0]))) + { + if (get_glyph_v_origins (n, + &buf->info[offset].codepoint, sizeof (hb_glyph_info_t), + &origins[0].x, sizeof (origins[0]), + &origins[0].y, sizeof (origins[0]))) + { + if (!has_ascender) + { + hb_font_extents_t extents; + get_h_extents_with_fallback (&extents); + ascender = extents.ascender; + has_ascender = true; + } + + /* We got the v_origins, adjust them to h_origins. */ + for (unsigned j = 0; j < n; j++) + { + hb_codepoint_t glyph = buf->info[offset + j].codepoint; + origins[j].x -= get_glyph_h_advance (glyph) / 2; + origins[j].y -= ascender; + } + } + else + { + for (unsigned j = 0; j < n; j++) + { + origins[j].x = 0; + origins[j].y = 0; + } + } + } + + assert (mult == -1 || mult == +1); + if (mult == +1) + for (unsigned j = 0; j < n; j++) + { + hb_glyph_position_t *pos = &buf->pos[offset + j]; + add_offset (&pos->x_offset, &pos->y_offset, + origins[j].x, origins[j].y); + } + else /* mult == -1 */ + for (unsigned j = 0; j < n; j++) + { + hb_glyph_position_t *pos = &buf->pos[offset + j]; + subtract_offset (&pos->x_offset, &pos->y_offset, + origins[j].x, origins[j].y); + } + + offset += n; + } + } + void apply_glyph_v_origins_with_fallback (hb_buffer_t *buf, int mult) + { + bool has_ascender = false; + hb_position_t ascender = 0; + + struct { hb_position_t x, y; } origins[32]; + + unsigned int offset = 0; + unsigned int count = buf->len; + while (offset < count) + { + unsigned n = hb_min (count - offset, ARRAY_LENGTH (origins)); + if (!get_glyph_v_origins (n, + &buf->info[offset].codepoint, sizeof (hb_glyph_info_t), + &origins[0].x, sizeof (origins[0]), + &origins[0].y, sizeof (origins[0]))) + { + if (get_glyph_h_origins (n, + &buf->info[offset].codepoint, sizeof (hb_glyph_info_t), + &origins[0].x, sizeof (origins[0]), + &origins[0].y, sizeof (origins[0]))) + { + if (!has_ascender) + { + hb_font_extents_t extents; + get_h_extents_with_fallback (&extents); + ascender = extents.ascender; + has_ascender = true; + } + + /* We got the h_origins, adjust them to v_origins. */ + for (unsigned j = 0; j < n; j++) + { + hb_codepoint_t glyph = buf->info[offset + j].codepoint; + origins[j].x += get_glyph_h_advance (glyph) / 2; + origins[j].y += ascender; + } + } + else + { + for (unsigned j = 0; j < n; j++) + { + origins[j].x = 0; + origins[j].y = 0; + } + } + } + + assert (mult == -1 || mult == +1); + if (mult == +1) + for (unsigned j = 0; j < n; j++) + { + hb_glyph_position_t *pos = &buf->pos[offset + j]; + add_offset (&pos->x_offset, &pos->y_offset, + origins[j].x, origins[j].y); + } + else /* mult == -1 */ + for (unsigned j = 0; j < n; j++) + { + hb_glyph_position_t *pos = &buf->pos[offset + j]; + subtract_offset (&pos->x_offset, &pos->y_offset, + origins[j].x, origins[j].y); + } + + offset += n; + } + } + void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y) { @@ -722,7 +1006,7 @@ struct hb_font_t { hb_position_t dx, dy; guess_v_origin_minus_h_origin (glyph, &dx, &dy); - *x -= dx; *y -= dy; + subtract_offset (x, y, dx, dy); } } void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph, @@ -733,7 +1017,7 @@ struct hb_font_t { hb_position_t dx, dy; guess_v_origin_minus_h_origin (glyph, &dx, &dy); - *x += dx; *y += dy; + add_offset (x, y, dx, dy); } } @@ -747,68 +1031,38 @@ struct hb_font_t get_glyph_v_origin_with_fallback (glyph, x, y); } - void add_glyph_h_origin (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + void add_glyph_h_origins (hb_buffer_t *buf) { - hb_position_t origin_x, origin_y; - - get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y); - - *x += origin_x; - *y += origin_y; + apply_glyph_h_origins_with_fallback (buf, +1); } - void add_glyph_v_origin (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + void add_glyph_v_origins (hb_buffer_t *buf) { - hb_position_t origin_x, origin_y; - - get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y); - - *x += origin_x; - *y += origin_y; + apply_glyph_v_origins_with_fallback (buf, +1); } void add_glyph_origin_for_direction (hb_codepoint_t glyph, hb_direction_t direction, hb_position_t *x, hb_position_t *y) { hb_position_t origin_x, origin_y; - get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y); - - *x += origin_x; - *y += origin_y; + add_offset (x, y, origin_x, origin_y); } - void subtract_glyph_h_origin (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + void subtract_glyph_h_origins (hb_buffer_t *buf) { - hb_position_t origin_x, origin_y; - - get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y); - - *x -= origin_x; - *y -= origin_y; + apply_glyph_h_origins_with_fallback (buf, -1); } - void subtract_glyph_v_origin (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + void subtract_glyph_v_origins (hb_buffer_t *buf) { - hb_position_t origin_x, origin_y; - - get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y); - - *x -= origin_x; - *y -= origin_y; + apply_glyph_v_origins_with_fallback (buf, -1); } void subtract_glyph_origin_for_direction (hb_codepoint_t glyph, hb_direction_t direction, hb_position_t *x, hb_position_t *y) { hb_position_t origin_x, origin_y; - get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y); - - *x -= origin_x; - *y -= origin_y; + subtract_offset (x, y, origin_x, origin_y); } void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, @@ -890,11 +1144,6 @@ struct hb_font_t return false; } - bool is_synthetic () const - { - return x_embolden || y_embolden || slant; - } - void changed () { float upem = face->get_upem (); @@ -906,6 +1155,8 @@ struct hb_font_t bool y_neg = y_scale < 0; y_mult = (y_neg ? -((int64_t) -y_scale << 16) : ((int64_t) y_scale << 16)) / upem; + is_synthetic = x_embolden || y_embolden || slant; + x_strength = roundf (abs (x_scale) * x_embolden); y_strength = roundf (abs (y_scale) * y_embolden); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-pool.hh b/src/java.desktop/share/native/libharfbuzz/hb-free-pool.hh similarity index 92% rename from src/java.desktop/share/native/libharfbuzz/hb-pool.hh rename to src/java.desktop/share/native/libharfbuzz/hb-free-pool.hh index 613c78d1973..3acd144a857 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-pool.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-free-pool.hh @@ -24,12 +24,12 @@ * Facebook Author(s): Behdad Esfahbod */ -#ifndef HB_POOL_HH -#define HB_POOL_HH +#ifndef HB_FREE_POOL_HH +#define HB_FREE_POOL_HH #include "hb.hh" -/* Memory pool for persistent allocation of small objects. +/* Memory pool for persistent alloc/free of small objects. * * Some AI musings on this, not necessarily true: * @@ -41,10 +41,10 @@ * sophisticated, use a real allocator. Or use a real language. */ template -struct hb_pool_t +struct hb_free_pool_t { - hb_pool_t () : next (nullptr) {} - ~hb_pool_t () + hb_free_pool_t () : next (nullptr) {} + ~hb_free_pool_t () { next = nullptr; @@ -104,4 +104,4 @@ struct hb_pool_t }; -#endif /* HB_POOL_HH */ +#endif /* HB_FREE_POOL_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ft.cc b/src/java.desktop/share/native/libharfbuzz/hb-ft.cc index e9c0e734a53..b90f966c57c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ft.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ft.cc @@ -143,6 +143,9 @@ _hb_ft_font_destroy (void *data) /* hb_font changed, update FT_Face. */ static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face) { + if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) + return; + hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data; float x_mult = 1.f, y_mult = 1.f; @@ -184,12 +187,14 @@ static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face) FT_Set_Transform (ft_face, &matrix, nullptr); ft_font->transform = true; } + else + FT_Set_Transform (ft_face, nullptr, nullptr); #if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR) - unsigned int num_coords; - const float *coords = hb_font_get_var_coords_design (font, &num_coords); - if (num_coords) + if (font->has_nonzero_coords) { + unsigned int num_coords; + const float *coords = hb_font_get_var_coords_design (font, &num_coords); FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (num_coords, sizeof (FT_Fixed)); if (ft_coords) { @@ -199,6 +204,12 @@ static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face) hb_free (ft_coords); } } + else if (font->num_coords) + { + // Some old versions of FreeType crash if we + // call this function on non-variable fonts. + FT_Set_Var_Design_Coordinates (ft_face, 0, nullptr); + } #endif } @@ -1093,6 +1104,10 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data FT_ULong length = 0; FT_Error error; + /* In new FreeType, a tag value of 1 loads the SFNT table directory. Reject it. */ + if (tag == 1) + return nullptr; + /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */ error = FT_Load_Sfnt_Table (ft_face, tag, 0, nullptr, &length); @@ -1366,7 +1381,7 @@ hb_ft_font_changed (hb_font_t *font) for (unsigned int i = 0; i < mm_var->num_axis; ++i) { - coords[i] = ft_coords[i] >>= 2; + coords[i] = (ft_coords[i] + 2) >> 2; nonzero = nonzero || coords[i]; } @@ -1717,7 +1732,12 @@ hb_ft_font_set_funcs (hb_font_t *font) ft_face->generic.finalizer = _release_blob; // And the FT_Library to the blob - hb_blob_set_user_data (blob, &ft_library_key, ft_library, destroy_ft_library, true); + if (unlikely (!hb_blob_set_user_data (blob, &ft_library_key, ft_library, destroy_ft_library, true))) + { + DEBUG_MSG (FT, font, "hb_blob_set_user_data() failed"); + FT_Done_Face (ft_face); + return; + } _hb_ft_font_set_funcs (font, ft_face, true); hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh b/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh index 795f29f6ab0..0de062df68e 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh @@ -26,7 +26,10 @@ #include "hb.hh" +#include "hb-algs.hh" + +template struct hb_extents_t { hb_extents_t () {} @@ -35,7 +38,7 @@ struct hb_extents_t ymin (hb_min (extents.y_bearing, extents.y_bearing + extents.height)), xmax (hb_max (extents.x_bearing, extents.x_bearing + extents.width)), ymax (hb_max (extents.y_bearing, extents.y_bearing + extents.height)) {} - hb_extents_t (float xmin, float ymin, float xmax, float ymax) : + hb_extents_t (Float xmin, Float ymin, Float xmax, Float ymax) : xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {} bool is_empty () const { return xmin >= xmax || ymin >= ymax; } @@ -69,7 +72,7 @@ struct hb_extents_t } void - add_point (float x, float y) + add_point (Float x, Float y) { if (unlikely (is_void ())) { @@ -97,62 +100,69 @@ struct hb_extents_t yneg ? y1 - y0 : y0 - y1}; } - float xmin = 0.f; - float ymin = 0.f; - float xmax = -1.f; - float ymax = -1.f; + Float xmin = 0; + Float ymin = 0; + Float xmax = -1; + Float ymax = -1; }; +template struct hb_transform_t { hb_transform_t () {} - hb_transform_t (float xx, float yx, - float xy, float yy, - float x0, float y0) : + hb_transform_t (Float xx, Float yx, + Float xy, Float yy, + Float x0, Float y0) : xx (xx), yx (yx), xy (xy), yy (yy), x0 (x0), y0 (y0) {} bool is_identity () const { - return xx == 1.f && yx == 0.f && - xy == 0.f && yy == 1.f && - x0 == 0.f && y0 == 0.f; + return xx == 1 && yx == 0 && + xy == 0 && yy == 1 && + x0 == 0 && y0 == 0; + } + bool is_translation () const + { + return xx == 1 && yx == 0 && + xy == 0 && yy == 1; } - void multiply (const hb_transform_t &o) + void multiply (const hb_transform_t &o, bool before=false) { - /* Copied from cairo, with "o" being "a" there and "this" being "b" there. */ - hb_transform_t r; - - r.xx = o.xx * xx + o.yx * xy; - r.yx = o.xx * yx + o.yx * yy; - - r.xy = o.xy * xx + o.yy * xy; - r.yy = o.xy * yx + o.yy * yy; - - r.x0 = o.x0 * xx + o.y0 * xy + x0; - r.y0 = o.x0 * yx + o.y0 * yy + y0; - - *this = r; + // Copied from cairo-matrix.c + const hb_transform_t &a = before ? o : *this; + const hb_transform_t &b = before ? *this : o; + *this = { + a.xx * b.xx + a.xy * b.yx, + a.yx * b.xx + a.yy * b.yx, + a.xx * b.xy + a.xy * b.yy, + a.yx * b.xy + a.yy * b.yy, + a.xx * b.x0 + a.xy * b.y0 + a.x0, + a.yx * b.x0 + a.yy * b.y0 + a.y0 + }; } - void transform_distance (float &dx, float &dy) const + HB_ALWAYS_INLINE + void transform_distance (Float &dx, Float &dy) const { - float new_x = xx * dx + xy * dy; - float new_y = yx * dx + yy * dy; + Float new_x = xx * dx + xy * dy; + Float new_y = yx * dx + yy * dy; dx = new_x; dy = new_y; } - void transform_point (float &x, float &y) const + HB_ALWAYS_INLINE + void transform_point (Float &x, Float &y) const { - transform_distance (x, y); - x += x0; - y += y0; + Float new_x = x0 + xx * x + xy * y; + Float new_y = y0 + yx * x + yy * y; + x = new_x; + y = new_y; } - void transform_extents (hb_extents_t &extents) const + void transform_extents (hb_extents_t &extents) const { - float quad_x[4], quad_y[4]; + Float quad_x[4], quad_y[4]; quad_x[0] = extents.xmin; quad_y[0] = extents.ymin; @@ -163,7 +173,7 @@ struct hb_transform_t quad_x[3] = extents.xmax; quad_y[3] = extents.ymax; - extents = hb_extents_t {}; + extents = hb_extents_t {}; for (unsigned i = 0; i < 4; i++) { transform_point (quad_x[i], quad_y[i]); @@ -171,20 +181,36 @@ struct hb_transform_t } } - void transform (const hb_transform_t &o) { multiply (o); } + void transform (const hb_transform_t &o, bool before=false) { multiply (o, before); } - void translate (float x, float y) + static hb_transform_t translation (Float x, Float y) { - if (x == 0.f && y == 0.f) - return; + return {1, 0, 0, 1, x, y}; + } + void translate (Float x, Float y, bool before=false) + { + if (before) + { + x0 += x; + y0 += y; + } + else + { + if (x == 0 && y == 0) + return; - x0 += xx * x + xy * y; - y0 += yx * x + yy * y; + x0 += xx * x + xy * y; + y0 += yx * x + yy * y; + } } - void scale (float scaleX, float scaleY) + static hb_transform_t scaling (Float scaleX, Float scaleY) { - if (scaleX == 1.f && scaleY == 1.f) + return {scaleX, 0, 0, scaleY, 0, 0}; + } + void scale (Float scaleX, Float scaleY) + { + if (scaleX == 1 && scaleY == 1) return; xx *= scaleX; @@ -192,52 +218,94 @@ struct hb_transform_t xy *= scaleY; yy *= scaleY; } - - void rotate (float rotation) + static hb_transform_t scaling_around_center (Float scaleX, Float scaleY, Float center_x, Float center_y) { - if (rotation == 0.f) + return {scaleX, 0, 0, scaleY, + center_x ? (1 - scaleX) * center_x : 0, + center_y ? (1 - scaleY) * center_y : 0}; + } + void scale_around_center (Float scaleX, Float scaleY, Float center_x, Float center_y) + { + if (scaleX == 1 && scaleY == 1) return; + transform (scaling_around_center (scaleX, scaleY, center_x, center_y)); + } + + static hb_transform_t rotation (Float radians) + { // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240 - rotation = rotation * HB_PI; - float c; - float s; -#ifdef HAVE_SINCOSF - sincosf (rotation, &s, &c); -#else - c = cosf (rotation); - s = sinf (rotation); -#endif - auto other = hb_transform_t{c, s, -s, c, 0.f, 0.f}; - transform (other); + Float c; + Float s; + hb_sincos (radians, s, c); + return {c, s, -s, c, 0, 0}; } - - void skew (float skewX, float skewY) + void rotate (Float radians, bool before=false) { - if (skewX == 0.f && skewY == 0.f) + if (radians == 0) return; - // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255 - skewX = skewX * HB_PI; - skewY = skewY * HB_PI; - auto other = hb_transform_t{1.f, - skewY ? tanf (skewY) : 0.f, - skewX ? tanf (skewX) : 0.f, - 1.f, - 0.f, 0.f}; - transform (other); + transform (rotation (radians), before); } - float xx = 1.f; - float yx = 0.f; - float xy = 0.f; - float yy = 1.f; - float x0 = 0.f; - float y0 = 0.f; + static hb_transform_t rotation_around_center (Float radians, Float center_x, Float center_y) + { + Float s, c; + hb_sincos (radians, s, c); + return { + c, s, -s, c, + (1 - c) * center_x + s * center_y, + -s * center_x + (1 - c) * center_y + }; + } + void rotate_around_center (Float radians, Float center_x, Float center_y, bool before=false) + { + if (radians == 0) + return; + + transform (rotation_around_center (radians, center_x, center_y), before); + } + + static hb_transform_t skewing (Float skewX, Float skewY) + { + return {1, skewY ? tanf (skewY) : 0, skewX ? tanf (skewX) : 0, 1, 0, 0}; + } + void skew (Float skewX, Float skewY) + { + if (skewX == 0 && skewY == 0) + return; + + transform (skewing (skewX, skewY)); + } + static hb_transform_t skewing_around_center (Float skewX, Float skewY, Float center_x, Float center_y) + { + skewX = skewX ? tanf (skewX) : 0; + skewY = skewY ? tanf (skewY) : 0; + return { + 1, skewY, skewX, 1, + center_y ? -skewX * center_y : 0, + center_x ? -skewY * center_x : 0 + }; + } + void skew_around_center (Float skewX, Float skewY, Float center_x, Float center_y) + { + if (skewX == 0 && skewY == 0) + return; + + transform (skewing_around_center (skewX, skewY, center_x, center_y)); + } + + Float xx = 1; + Float yx = 0; + Float xy = 0; + Float yy = 1; + Float x0 = 0; + Float y0 = 0; }; -#define HB_TRANSFORM_IDENTITY hb_transform_t{1.f, 0.f, 0.f, 1.f, 0.f, 0.f} +#define HB_TRANSFORM_IDENTITY {1, 0, 0, 1, 0, 0} +template struct hb_bounds_t { enum status_t { @@ -247,7 +315,7 @@ struct hb_bounds_t }; hb_bounds_t (status_t status = UNBOUNDED) : status (status) {} - hb_bounds_t (const hb_extents_t &extents) : + hb_bounds_t (const hb_extents_t &extents) : status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {} void union_ (const hb_bounds_t &o) @@ -281,20 +349,21 @@ struct hb_bounds_t } status_t status; - hb_extents_t extents; + hb_extents_t extents; }; +template struct hb_transform_decomposed_t { - float translateX = 0; - float translateY = 0; - float rotation = 0; // in degrees, counter-clockwise - float scaleX = 1; - float scaleY = 1; - float skewX = 0; // in degrees, counter-clockwise - float skewY = 0; // in degrees, counter-clockwise - float tCenterX = 0; - float tCenterY = 0; + Float translateX = 0; + Float translateY = 0; + Float rotation = 0; // in radians, counter-clockwise + Float scaleX = 1; + Float scaleY = 1; + Float skewX = 0; // in radians, counter-clockwise + Float skewY = 0; // in radians, counter-clockwise + Float tCenterX = 0; + Float tCenterY = 0; operator bool () const { @@ -305,9 +374,9 @@ struct hb_transform_decomposed_t tCenterX || tCenterY; } - hb_transform_t to_transform () const + hb_transform_t to_transform () const { - hb_transform_t t; + hb_transform_t t; t.translate (translateX + tCenterX, translateY + tCenterY); t.rotate (rotation); t.scale (scaleX, scaleY); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-iter.hh b/src/java.desktop/share/native/libharfbuzz/hb-iter.hh index 21d9544a74b..661e6771a4a 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-iter.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-iter.hh @@ -772,8 +772,9 @@ struct hb_iota_iter_t : template auto inc (hb_type_identity s, hb_priority<1>) - -> hb_void_t (s), hb_declval ()))> - { v = hb_invoke (std::forward (s), v); } + -> hb_void_t> (s), + hb_declval ()))> + { v = hb_invoke (std::forward> (s), v); } void inc (S s, hb_priority<0>) @@ -972,7 +973,7 @@ struct Proj&& f = hb_identity) const { for (auto it = hb_iter (c); it; ++it) - if (!hb_match (std::forward (p), hb_get (std::forward (f), *it))) + if (!hb_match (p, hb_get (f, *it))) return false; return true; } @@ -989,7 +990,7 @@ struct Proj&& f = hb_identity) const { for (auto it = hb_iter (c); it; ++it) - if (hb_match (std::forward (p), hb_get (std::forward (f), *it))) + if (hb_match (p, hb_get (f, *it))) return true; return false; } @@ -1006,7 +1007,7 @@ struct Proj&& f = hb_identity) const { for (auto it = hb_iter (c); it; ++it) - if (hb_match (std::forward (p), hb_get (std::forward (f), *it))) + if (hb_match (p, hb_get (f, *it))) return false; return true; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-kern.hh b/src/java.desktop/share/native/libharfbuzz/hb-kern.hh index 1f2c8d5811b..cf08c16689f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-kern.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-kern.hh @@ -70,7 +70,7 @@ struct hb_kern_machine_t continue; } - skippy_iter.reset (idx); + skippy_iter.reset_fast (idx); unsigned unsafe_to; if (!skippy_iter.next (&unsafe_to)) { diff --git a/src/java.desktop/share/native/libharfbuzz/hb-limits.hh b/src/java.desktop/share/native/libharfbuzz/hb-limits.hh index fbc7bbe764e..857e183737f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-limits.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-limits.hh @@ -29,20 +29,20 @@ #ifndef HB_BUFFER_MAX_LEN_FACTOR -#define HB_BUFFER_MAX_LEN_FACTOR 64 +#define HB_BUFFER_MAX_LEN_FACTOR 256 #endif #ifndef HB_BUFFER_MAX_LEN_MIN -#define HB_BUFFER_MAX_LEN_MIN 16384 +#define HB_BUFFER_MAX_LEN_MIN 65536 #endif #ifndef HB_BUFFER_MAX_LEN_DEFAULT #define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */ #endif #ifndef HB_BUFFER_MAX_OPS_FACTOR -#define HB_BUFFER_MAX_OPS_FACTOR 1024 +#define HB_BUFFER_MAX_OPS_FACTOR 4096 #endif #ifndef HB_BUFFER_MAX_OPS_MIN -#define HB_BUFFER_MAX_OPS_MIN 16384 +#define HB_BUFFER_MAX_OPS_MIN 65536 #endif #ifndef HB_BUFFER_MAX_OPS_DEFAULT #define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh b/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh index ffbb8f3d301..8fa32ea8eaa 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh @@ -66,13 +66,22 @@ static inline Type& StructAtOffsetUnaligned(void *P, unsigned int offset) } /* StructAfter(X) returns the struct T& that is placed after X. - * Works with X of variable size also. X must implement get_size() */ -template -static inline const Type& StructAfter(const TObject &X) -{ return StructAtOffset(&X, X.get_size()); } -template -static inline Type& StructAfter(TObject &X) -{ return StructAtOffset(&X, X.get_size()); } + * Works with X of variable size also. X must implement get_size(). + * Any extra arguments are forwarded to get_size, so for example + * it can work with UnsizedArrayOf<> as well. */ +template +static inline auto StructAfter(const TObject &X, Ts... args) HB_AUTO_RETURN(( + StructAtOffset(&X, X.get_size(std::forward (args)...)) +)) +/* The is_const shenanigans is to avoid ambiguous overload with gcc-8. + * It disables this path when TObject is const. + * See: https://github.com/harfbuzz/harfbuzz/issues/5429 */ +template +static inline auto StructAfter(TObject &X, Ts... args) HB_AUTO_RETURN(( + sizeof(int[std::is_const::value ? -1 : +1]) > 0 ? + StructAtOffset(&X, X.get_size(std::forward (args)...)) + : *reinterpret_cast (0) +)) /* @@ -132,7 +141,6 @@ static inline Type& StructAfter(TObject &X) DEFINE_SIZE_ARRAY(size, array) - /* * Lazy loaders. * diff --git a/src/java.desktop/share/native/libharfbuzz/hb-map.hh b/src/java.desktop/share/native/libharfbuzz/hb-map.hh index 76206342f57..4c76622df7a 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-map.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-map.hh @@ -47,11 +47,11 @@ struct hb_hashmap_t hb_hashmap_t () { init (); } ~hb_hashmap_t () { fini (); } - hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () + void _copy (const hb_hashmap_t& o) { if (unlikely (!o.mask)) return; - if (item_t::is_trivial) + if (hb_is_trivially_copy_assignable (item_t)) { items = (item_t *) hb_malloc (sizeof (item_t) * (o.mask + 1)); if (unlikely (!items)) @@ -70,8 +70,16 @@ struct hb_hashmap_t alloc (o.population); hb_copy (o, *this); } + + hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { _copy (o); } + hb_hashmap_t& operator= (const hb_hashmap_t& o) + { + reset (); + if (!items) { _copy (o); return *this; } + alloc (o.population); hb_copy (o, *this); return *this; + } + hb_hashmap_t (hb_hashmap_t&& o) noexcept : hb_hashmap_t () { hb_swap (*this, o); } - hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); alloc (o.population); hb_copy (o, *this); return *this; } hb_hashmap_t& operator= (hb_hashmap_t&& o) noexcept { hb_swap (*this, o); return *this; } hb_hashmap_t (std::initializer_list> lst) : hb_hashmap_t () @@ -130,10 +138,7 @@ struct hb_hashmap_t uint32_t total_hash () const { return (hash * 31u) + hb_hash (value); } - static constexpr bool is_trivial = hb_is_trivially_constructible(K) && - hb_is_trivially_destructible(K) && - hb_is_trivially_constructible(V) && - hb_is_trivially_destructible(V); + static constexpr bool is_trivially_constructible = (hb_is_trivially_constructible(K) && hb_is_trivially_constructible(V)); }; hb_object_header_t header; @@ -174,19 +179,19 @@ struct hb_hashmap_t if (likely (items)) { unsigned size = mask + 1; - if (!item_t::is_trivial) - for (unsigned i = 0; i < size; i++) - items[i].~item_t (); + for (unsigned i = 0; i < size; i++) + items[i].~item_t (); hb_free (items); items = nullptr; } population = occupancy = 0; } - void reset () + hb_hashmap_t& reset () { successful = true; clear (); + return *this; } bool in_error () const { return !successful; } @@ -197,7 +202,7 @@ struct hb_hashmap_t if (new_population != 0 && (new_population + new_population / 2) < mask) return true; - unsigned int power = hb_bit_storage (hb_max ((unsigned) population, new_population) * 2 + 8); + unsigned int power = hb_bit_storage (hb_max (hb_max ((unsigned) population, new_population) * 2, 4u)); unsigned int new_size = 1u << power; item_t *new_items = (item_t *) hb_malloc ((size_t) new_size * sizeof (item_t)); if (unlikely (!new_items)) @@ -205,7 +210,7 @@ struct hb_hashmap_t successful = false; return false; } - if (!item_t::is_trivial) + if (!item_t::is_trivially_constructible) for (auto &_ : hb_iter (new_items, new_size)) new (&_) item_t (); else @@ -231,9 +236,8 @@ struct hb_hashmap_t std::move (old_items[i].value)); } } - if (!item_t::is_trivial) - for (unsigned int i = 0; i < old_size; i++) - old_items[i].~item_t (); + for (unsigned int i = 0; i < old_size; i++) + old_items[i].~item_t (); hb_free (old_items); @@ -335,7 +339,13 @@ struct hb_hashmap_t bool has (const K &key, VV **vp = nullptr) const { if (!items) return false; - auto *item = fetch_item (key, hb_hash (key)); + return has_with_hash (key, hb_hash (key), vp); + } + template + bool has_with_hash (const K &key, uint32_t hash, VV **vp = nullptr) const + { + if (!items) return false; + auto *item = fetch_item (key, hash); if (item) { if (vp) *vp = std::addressof (item->value); @@ -481,10 +491,17 @@ struct hb_hashmap_t /* Sink interface. */ hb_hashmap_t& operator << (const hb_pair_t& v) { set (v.first, v.second); return *this; } + template hb_hashmap_t& operator << (const hb_pair_t& v) { set (v.first, std::move (v.second)); return *this; } + template hb_hashmap_t& operator << (const hb_pair_t& v) { set (std::move (v.first), v.second); return *this; } + template hb_hashmap_t& operator << (const hb_pair_t& v) { set (std::move (v.first), std::move (v.second)); return *this; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh b/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh index 9d2867e4835..07f3ebe0c7d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh @@ -31,7 +31,7 @@ #include "hb.hh" -#line 35 "hb-number-parser.hh" +#line 32 "hb-number-parser.hh" static const unsigned char _double_parser_trans_keys[] = { 0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u, 46u, 101u, 0 @@ -135,12 +135,12 @@ strtod_rl (const char *p, const char **end_ptr /* IN/OUT */) int cs; -#line 139 "hb-number-parser.hh" +#line 132 "hb-number-parser.hh" { cs = double_parser_start; } -#line 144 "hb-number-parser.hh" +#line 135 "hb-number-parser.hh" { int _slen; int _trans; @@ -198,7 +198,7 @@ _resume: exp_overflow = true; } break; -#line 202 "hb-number-parser.hh" +#line 187 "hb-number-parser.hh" } _again: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh b/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh index 382ee2ddaf2..538240b6416 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh @@ -465,11 +465,11 @@ struct OpenTypeFontFile Typ1Tag = HB_TAG ('t','y','p','1') /* Obsolete Apple Type1 font in SFNT container */ }; - hb_tag_t get_tag () const { return u.tag; } + hb_tag_t get_tag () const { return u.tag.v; } unsigned int get_face_count () const { - switch (u.tag) { + switch (u.tag.v) { case CFFTag: /* All the non-collection tags */ case TrueTag: case Typ1Tag: @@ -483,7 +483,7 @@ struct OpenTypeFontFile { if (base_offset) *base_offset = 0; - switch (u.tag) { + switch (u.tag.v) { /* Note: for non-collection SFNT data we ignore index. This is because * Apple dfont container is a container of SFNT's. So each SFNT is a * non-TTC, but the index is more than zero. */ @@ -512,9 +512,9 @@ struct OpenTypeFontFile bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!u.tag.sanitize (c))) return_trace (false); + if (unlikely (!u.tag.v.sanitize (c))) return_trace (false); hb_barrier (); - switch (u.tag) { + switch (u.tag.v) { case CFFTag: /* All the non-collection tags */ case TrueTag: case Typ1Tag: @@ -527,13 +527,13 @@ struct OpenTypeFontFile protected: union { - Tag tag; /* 4-byte identifier. */ + struct { Tag v; } tag; /* 4-byte identifier. */ OpenTypeFontFace fontFace; TTCHeader ttcHeader; ResourceForkHeader rfHeader; } u; public: - DEFINE_SIZE_UNION (4, tag); + DEFINE_SIZE_UNION (4, tag.v); }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh b/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh index 75d87f11ea5..ad831b66d56 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh @@ -54,35 +54,41 @@ namespace OT { */ /* Integer types in big-endian order and no alignment requirement */ -template -struct IntType +struct NumType { typedef Type type; - - IntType () = default; - explicit constexpr IntType (Type V) : v {V} {} - IntType& operator = (Type i) { v = i; return *this; } /* For reason we define cast out operator for signed/unsigned, instead of Type, see: * https://github.com/harfbuzz/harfbuzz/pull/2875/commits/09836013995cab2b9f07577a179ad7b024130467 */ - operator typename std::conditional::value, signed, unsigned>::type () const { return v; } + typedef typename std::conditional::value && sizeof (Type) <= sizeof(int), + typename std::conditional::value, signed, unsigned>::type, + Type>::type WideType; - bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; } - bool operator != (const IntType &o) const { return !(*this == o); } + NumType () = default; + explicit constexpr NumType (Type V) : v {V} {} + NumType& operator = (Type V) { v = V; return *this; } - IntType& operator += (unsigned count) { *this = *this + count; return *this; } - IntType& operator -= (unsigned count) { *this = *this - count; return *this; } - IntType& operator ++ () { *this += 1; return *this; } - IntType& operator -- () { *this -= 1; return *this; } - IntType operator ++ (int) { IntType c (*this); ++*this; return c; } - IntType operator -- (int) { IntType c (*this); --*this; return c; } + operator WideType () const { return v; } - HB_INTERNAL static int cmp (const IntType *a, const IntType *b) + bool operator == (const NumType &o) const { return (Type) v == (Type) o.v; } + bool operator != (const NumType &o) const { return !(*this == o); } + + NumType& operator += (WideType count) { *this = *this + count; return *this; } + NumType& operator -= (WideType count) { *this = *this - count; return *this; } + NumType& operator ++ () { *this += 1; return *this; } + NumType& operator -- () { *this -= 1; return *this; } + NumType operator ++ (int) { NumType c (*this); ++*this; return c; } + NumType operator -- (int) { NumType c (*this); --*this; return c; } + + uint32_t hash () const { return hb_array ((const char *) &v, sizeof (v)).hash (); } + HB_INTERNAL static int cmp (const NumType *a, const NumType *b) { return b->cmp (*a); } HB_INTERNAL static int cmp (const void *a, const void *b) { - IntType *pa = (IntType *) a; - IntType *pb = (IntType *) b; + NumType *pa = (NumType *) a; + NumType *pb = (NumType *) b; return pb->cmp (*pa); } @@ -99,20 +105,36 @@ struct IntType return_trace (c->check_struct (this)); } protected: - BEInt v; + typename std::conditional::value, + HBInt, + HBFloat>::type v; public: DEFINE_SIZE_STATIC (Size); }; -typedef IntType HBUINT8; /* 8-bit unsigned integer. */ -typedef IntType HBINT8; /* 8-bit signed integer. */ -typedef IntType HBUINT16; /* 16-bit unsigned integer. */ -typedef IntType HBINT16; /* 16-bit signed integer. */ -typedef IntType HBUINT32; /* 32-bit unsigned integer. */ -typedef IntType HBINT32; /* 32-bit signed integer. */ +typedef NumType HBUINT8; /* 8-bit big-endian unsigned integer. */ +typedef NumType HBINT8; /* 8-bit big-endian signed integer. */ +typedef NumType HBUINT16; /* 16-bit big-endian unsigned integer. */ +typedef NumType HBINT16; /* 16-bit big-endian signed integer. */ +typedef NumType HBUINT32; /* 32-bit big-endian unsigned integer. */ +typedef NumType HBINT32; /* 32-bit big-endian signed integer. */ +typedef NumType HBUINT64; /* 64-bit big-endian unsigned integer. */ +typedef NumType HBINT64; /* 64-bit big-endian signed integer. */ /* Note: we cannot defined a signed HBINT24 because there's no corresponding C type. * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */ -typedef IntType HBUINT24; /* 24-bit unsigned integer. */ +typedef NumType HBUINT24; /* 24-bit big-endian unsigned integer. */ + +typedef NumType HBUINT16LE; /* 16-bit little-endian unsigned integer. */ +typedef NumType HBINT16LE; /* 16-bit little-endian signed integer. */ +typedef NumType HBUINT32LE; /* 32-bit little-endian unsigned integer. */ +typedef NumType HBINT32LE; /* 32-bit little-endian signed integer. */ +typedef NumType HBUINT64LE; /* 64-bit little-endian unsigned integer. */ +typedef NumType HBINT64LE; /* 64-bit little-endian signed integer. */ + +typedef NumType HBFLOAT32BE; /* 32-bit little-endian floating point number. */ +typedef NumType HBFLOAT64BE; /* 64-bit little-endian floating point number. */ +typedef NumType HBFLOAT32LE; /* 32-bit little-endian floating point number. */ +typedef NumType HBFLOAT64LE; /* 64-bit little-endian floating point number. */ /* 15-bit unsigned number; top bit used for extension. */ struct HBUINT15 : HBUINT16 @@ -218,7 +240,7 @@ typedef HBUINT16 UFWORD; template struct HBFixed : Type { - static constexpr float shift = (float) (1 << fraction_bits); + static constexpr float mult = 1.f / (1 << fraction_bits); static_assert (Type::static_size * 8 > fraction_bits, ""); operator signed () const = delete; @@ -226,8 +248,8 @@ struct HBFixed : Type explicit operator float () const { return to_float (); } typename Type::type to_int () const { return Type::v; } void set_int (typename Type::type i ) { Type::v = i; } - float to_float (float offset = 0) const { return ((int32_t) Type::v + offset) / shift; } - void set_float (float f) { Type::v = roundf (f * shift); } + float to_float (float offset = 0) const { return ((int32_t) Type::v + offset) * mult; } + void set_float (float f) { Type::v = roundf (f / mult); } public: DEFINE_SIZE_STATIC (Type::static_size); }; @@ -504,16 +526,9 @@ struct OffsetTo : Offset return_trace (sanitize_shallow (c, base) && hb_barrier () && (this->is_null () || - c->dispatch (StructAtOffset (base, *this), std::forward (ds)...) || - neuter (c))); + c->dispatch (StructAtOffset (base, *this), std::forward (ds)...))); } - /* Set the offset to Null */ - bool neuter (hb_sanitize_context_t *c) const - { - if (!has_null) return false; - return c->try_set (this, 0); - } DEFINE_SIZE_STATIC (sizeof (OffsetType)); }; /* Partial specializations. */ @@ -1481,8 +1496,8 @@ struct TupleValues VALUE_RUN_COUNT_MASK = 0x3F }; - static unsigned compile (hb_array_t values, /* IN */ - hb_array_t encoded_bytes /* OUT */) + static unsigned compile_unsafe (hb_array_t values, /* IN */ + unsigned char *encoded_bytes /* OUT */) { unsigned num_values = values.length; unsigned encoded_len = 0; @@ -1491,24 +1506,23 @@ struct TupleValues { int val = values.arrayZ[i]; if (val == 0) - encoded_len += encode_value_run_as_zeroes (i, encoded_bytes.sub_array (encoded_len), values); - else if (val >= -128 && val <= 127) - encoded_len += encode_value_run_as_bytes (i, encoded_bytes.sub_array (encoded_len), values); - else if (val >= -32768 && val <= 32767) - encoded_len += encode_value_run_as_words (i, encoded_bytes.sub_array (encoded_len), values); + encoded_len += encode_value_run_as_zeroes (i, encoded_bytes + encoded_len, values); + else if ((int8_t) val == val) + encoded_len += encode_value_run_as_bytes (i, encoded_bytes + encoded_len, values); + else if ((int16_t) val == val) + encoded_len += encode_value_run_as_words (i, encoded_bytes + encoded_len, values); else - encoded_len += encode_value_run_as_longs (i, encoded_bytes.sub_array (encoded_len), values); + encoded_len += encode_value_run_as_longs (i, encoded_bytes + encoded_len, values); } return encoded_len; } static unsigned encode_value_run_as_zeroes (unsigned& i, - hb_array_t encoded_bytes, + unsigned char *it, hb_array_t values) { unsigned num_values = values.length; unsigned run_length = 0; - auto it = encoded_bytes.iter (); unsigned encoded_len = 0; while (i < num_values && values.arrayZ[i] == 0) { @@ -1532,7 +1546,7 @@ struct TupleValues } static unsigned encode_value_run_as_bytes (unsigned &i, - hb_array_t encoded_bytes, + unsigned char *it, hb_array_t values) { unsigned start = i; @@ -1540,7 +1554,7 @@ struct TupleValues while (i < num_values) { int val = values.arrayZ[i]; - if (val > 127 || val < -128) + if ((int8_t) val != val) break; /* from fonttools: if there're 2 or more zeros in a sequence, @@ -1553,7 +1567,6 @@ struct TupleValues unsigned run_length = i - start; unsigned encoded_len = 0; - auto it = encoded_bytes.iter (); while (run_length >= 64) { @@ -1561,10 +1574,9 @@ struct TupleValues encoded_len++; for (unsigned j = 0; j < 64; j++) - { - *it++ = static_cast (values.arrayZ[start + j]); - encoded_len++; - } + it[j] = static_cast (values.arrayZ[start + j]); + it += 64; + encoded_len += 64; start += 64; run_length -= 64; @@ -1575,18 +1587,16 @@ struct TupleValues *it++ = (VALUES_ARE_BYTES | (run_length - 1)); encoded_len++; - while (start < i) - { - *it++ = static_cast (values.arrayZ[start++]); - encoded_len++; - } + for (unsigned j = 0; j < run_length; j++) + it[j] = static_cast (values.arrayZ[start + j]); + encoded_len += run_length; } return encoded_len; } static unsigned encode_value_run_as_words (unsigned &i, - hb_array_t encoded_bytes, + unsigned char *it, hb_array_t values) { unsigned start = i; @@ -1595,22 +1605,24 @@ struct TupleValues { int val = values.arrayZ[i]; - /* start a new run for a single zero value*/ + if ((int16_t) val != val) + break; + + /* start a new run for a single zero value. */ if (val == 0) break; - /* from fonttools: continue word-encoded run if there's only one + /* From fonttools: continue word-encoded run if there's only one * single value in the range [-128, 127] because it is more compact. * Only start a new run when there're 2 continuous such values. */ - if (val >= -128 && val <= 127 && + if ((int8_t) val == val && i + 1 < num_values && - values.arrayZ[i+1] >= -128 && values.arrayZ[i+1] <= 127) + (int8_t) values.arrayZ[i+1] == values.arrayZ[i+1]) break; i++; } unsigned run_length = i - start; - auto it = encoded_bytes.iter (); unsigned encoded_len = 0; while (run_length >= 64) { @@ -1647,7 +1659,7 @@ struct TupleValues } static unsigned encode_value_run_as_longs (unsigned &i, - hb_array_t encoded_bytes, + unsigned char *it, hb_array_t values) { unsigned start = i; @@ -1656,14 +1668,13 @@ struct TupleValues { int val = values.arrayZ[i]; - if (val >= -32768 && val <= 32767) + if ((int16_t) val == val) break; i++; } unsigned run_length = i - start; - auto it = encoded_bytes.iter (); unsigned encoded_len = 0; while (run_length >= 64) { @@ -1704,10 +1715,14 @@ struct TupleValues } template +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif static bool decompile (const HBUINT8 *&p /* IN/OUT */, hb_vector_t &values /* IN/OUT */, const HBUINT8 *end, - bool consume_all = false) + bool consume_all = false, + unsigned start = 0) { unsigned i = 0; unsigned count = consume_all ? UINT_MAX : values.length; @@ -1720,19 +1735,24 @@ struct TupleValues unsigned run_count = (control & VALUE_RUN_COUNT_MASK) + 1; if (consume_all) { - if (unlikely (!values.resize (values.length + run_count, false))) + if (unlikely (!values.resize_dirty (values.length + run_count))) return false; } unsigned stop = i + run_count; if (unlikely (stop > count)) return false; + + unsigned skip = i < start ? hb_min (start - i, run_count) : 0; + i += skip; + if ((control & VALUES_SIZE_MASK) == VALUES_ARE_ZEROS) { - for (; i < stop; i++) - values.arrayZ[i] = 0; + hb_memset (&values.arrayZ[i], 0, (stop - i) * sizeof (T)); + i = stop; } else if ((control & VALUES_SIZE_MASK) == VALUES_ARE_WORDS) { if (unlikely (p + run_count * HBINT16::static_size > end)) return false; + p += skip * HBINT16::static_size; #ifndef HB_OPTIMIZE_SIZE for (; i + 3 < stop; i += 4) { @@ -1755,6 +1775,7 @@ struct TupleValues else if ((control & VALUES_SIZE_MASK) == VALUES_ARE_LONGS) { if (unlikely (p + run_count * HBINT32::static_size > end)) return false; + p += skip * HBINT32::static_size; for (; i < stop; i++) { values.arrayZ[i] = * (const HBINT32 *) p; @@ -1764,6 +1785,7 @@ struct TupleValues else if ((control & VALUES_SIZE_MASK) == VALUES_ARE_BYTES) { if (unlikely (p + run_count > end)) return false; + p += skip * HBINT8::static_size; #ifndef HB_OPTIMIZE_SIZE for (; i + 3 < stop; i += 4) { @@ -1784,7 +1806,7 @@ struct TupleValues { iter_t (const unsigned char *p_, unsigned len_) : p (p_), endp (p_ + len_) - { if (ensure_run ()) read_value (); } + { if (likely (ensure_run ())) read_value (); } private: const unsigned char *p; @@ -1793,10 +1815,14 @@ struct TupleValues signed run_count = 0; unsigned width = 0; + HB_ALWAYS_INLINE bool ensure_run () { if (likely (run_count > 0)) return true; - + return _ensure_run (); + } + bool _ensure_run () + { if (unlikely (p >= endp)) { run_count = 0; @@ -1886,10 +1912,15 @@ struct TupleValues signed run_count = 0; unsigned width = 0; + HB_ALWAYS_INLINE bool ensure_run () { - if (run_count > 0) return true; + if (likely (run_count > 0)) return true; + return _ensure_run (); + } + bool _ensure_run () + { if (unlikely (p >= end)) { run_count = 0; @@ -2013,7 +2044,10 @@ struct TupleValues } #ifndef HB_OPTIMIZE_SIZE - if (scale == 1.0f) + // The following branch is supposed to speed things up by avoiding + // the multiplication in _add_to<> if scale is 1.0f. + // But in practice it seems to bloat the code and slow things down. + if (false && scale == 1.0f) _add_to (out); else #endif @@ -2038,6 +2072,23 @@ struct TupleList : CFF2Index }; +// Alignment + +template +struct Align +{ + unsigned get_size (const void *base) const + { + unsigned offset = (const char *) this - (const char *) base; + return (alignment - offset) & (alignment - 1); + } + + public: + DEFINE_SIZE_MIN (0); +}; + + + } /* namespace OT */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh index 1e3e0be5106..ec018efe645 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh @@ -79,7 +79,7 @@ struct Dict : UnsizedByteStr { TRACE_SERIALIZE (this); for (unsigned int i = 0; i < dictval.get_count (); i++) - if (unlikely (!opszr.serialize (c, dictval[i], std::forward (ds)...))) + if (unlikely (!opszr.serialize (c, dictval[i], ds...))) return_trace (false); return_trace (true); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-std-str.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-std-str.hh index 65d56ae18b5..bf56abb975c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-std-str.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-std-str.hh @@ -30,396 +30,396 @@ #include "hb.hh" #endif -_S(".notdef") -_S("space") -_S("exclam") -_S("quotedbl") -_S("numbersign") -_S("dollar") -_S("percent") -_S("ampersand") -_S("quoteright") -_S("parenleft") -_S("parenright") -_S("asterisk") -_S("plus") -_S("comma") -_S("hyphen") -_S("period") -_S("slash") -_S("zero") -_S("one") -_S("two") -_S("three") -_S("four") -_S("five") -_S("six") -_S("seven") -_S("eight") -_S("nine") -_S("colon") -_S("semicolon") -_S("less") -_S("equal") -_S("greater") -_S("question") -_S("at") -_S("A") -_S("B") -_S("C") -_S("D") -_S("E") -_S("F") -_S("G") -_S("H") -_S("I") -_S("J") -_S("K") -_S("L") -_S("M") -_S("N") -_S("O") -_S("P") -_S("Q") -_S("R") -_S("S") -_S("T") -_S("U") -_S("V") -_S("W") -_S("X") -_S("Y") -_S("Z") -_S("bracketleft") -_S("backslash") -_S("bracketright") -_S("asciicircum") -_S("underscore") -_S("quoteleft") -_S("a") -_S("b") -_S("c") -_S("d") -_S("e") -_S("f") -_S("g") -_S("h") -_S("i") -_S("j") -_S("k") -_S("l") -_S("m") -_S("n") -_S("o") -_S("p") -_S("q") -_S("r") -_S("s") -_S("t") -_S("u") -_S("v") -_S("w") -_S("x") -_S("y") -_S("z") -_S("braceleft") -_S("bar") -_S("braceright") -_S("asciitilde") -_S("exclamdown") -_S("cent") -_S("sterling") -_S("fraction") -_S("yen") -_S("florin") -_S("section") -_S("currency") -_S("quotesingle") -_S("quotedblleft") -_S("guillemotleft") -_S("guilsinglleft") -_S("guilsinglright") -_S("fi") -_S("fl") -_S("endash") -_S("dagger") -_S("daggerdbl") -_S("periodcentered") -_S("paragraph") -_S("bullet") -_S("quotesinglbase") -_S("quotedblbase") -_S("quotedblright") -_S("guillemotright") -_S("ellipsis") -_S("perthousand") -_S("questiondown") -_S("grave") -_S("acute") -_S("circumflex") -_S("tilde") -_S("macron") -_S("breve") -_S("dotaccent") -_S("dieresis") -_S("ring") -_S("cedilla") -_S("hungarumlaut") -_S("ogonek") -_S("caron") -_S("emdash") -_S("AE") -_S("ordfeminine") -_S("Lslash") -_S("Oslash") -_S("OE") -_S("ordmasculine") -_S("ae") -_S("dotlessi") -_S("lslash") -_S("oslash") -_S("oe") -_S("germandbls") -_S("onesuperior") -_S("logicalnot") -_S("mu") -_S("trademark") -_S("Eth") -_S("onehalf") -_S("plusminus") -_S("Thorn") -_S("onequarter") -_S("divide") -_S("brokenbar") -_S("degree") -_S("thorn") -_S("threequarters") -_S("twosuperior") -_S("registered") -_S("minus") -_S("eth") -_S("multiply") -_S("threesuperior") -_S("copyright") -_S("Aacute") -_S("Acircumflex") -_S("Adieresis") -_S("Agrave") -_S("Aring") -_S("Atilde") -_S("Ccedilla") -_S("Eacute") -_S("Ecircumflex") -_S("Edieresis") -_S("Egrave") -_S("Iacute") -_S("Icircumflex") -_S("Idieresis") -_S("Igrave") -_S("Ntilde") -_S("Oacute") -_S("Ocircumflex") -_S("Odieresis") -_S("Ograve") -_S("Otilde") -_S("Scaron") -_S("Uacute") -_S("Ucircumflex") -_S("Udieresis") -_S("Ugrave") -_S("Yacute") -_S("Ydieresis") -_S("Zcaron") -_S("aacute") -_S("acircumflex") -_S("adieresis") -_S("agrave") -_S("aring") -_S("atilde") -_S("ccedilla") -_S("eacute") -_S("ecircumflex") -_S("edieresis") -_S("egrave") -_S("iacute") -_S("icircumflex") -_S("idieresis") -_S("igrave") -_S("ntilde") -_S("oacute") -_S("ocircumflex") -_S("odieresis") -_S("ograve") -_S("otilde") -_S("scaron") -_S("uacute") -_S("ucircumflex") -_S("udieresis") -_S("ugrave") -_S("yacute") -_S("ydieresis") -_S("zcaron") -_S("exclamsmall") -_S("Hungarumlautsmall") -_S("dollaroldstyle") -_S("dollarsuperior") -_S("ampersandsmall") -_S("Acutesmall") -_S("parenleftsuperior") -_S("parenrightsuperior") -_S("twodotenleader") -_S("onedotenleader") -_S("zerooldstyle") -_S("oneoldstyle") -_S("twooldstyle") -_S("threeoldstyle") -_S("fouroldstyle") -_S("fiveoldstyle") -_S("sixoldstyle") -_S("sevenoldstyle") -_S("eightoldstyle") -_S("nineoldstyle") -_S("commasuperior") -_S("threequartersemdash") -_S("periodsuperior") -_S("questionsmall") -_S("asuperior") -_S("bsuperior") -_S("centsuperior") -_S("dsuperior") -_S("esuperior") -_S("isuperior") -_S("lsuperior") -_S("msuperior") -_S("nsuperior") -_S("osuperior") -_S("rsuperior") -_S("ssuperior") -_S("tsuperior") -_S("ff") -_S("ffi") -_S("ffl") -_S("parenleftinferior") -_S("parenrightinferior") -_S("Circumflexsmall") -_S("hyphensuperior") -_S("Gravesmall") -_S("Asmall") -_S("Bsmall") -_S("Csmall") -_S("Dsmall") -_S("Esmall") -_S("Fsmall") -_S("Gsmall") -_S("Hsmall") -_S("Ismall") -_S("Jsmall") -_S("Ksmall") -_S("Lsmall") -_S("Msmall") -_S("Nsmall") -_S("Osmall") -_S("Psmall") -_S("Qsmall") -_S("Rsmall") -_S("Ssmall") -_S("Tsmall") -_S("Usmall") -_S("Vsmall") -_S("Wsmall") -_S("Xsmall") -_S("Ysmall") -_S("Zsmall") -_S("colonmonetary") -_S("onefitted") -_S("rupiah") -_S("Tildesmall") -_S("exclamdownsmall") -_S("centoldstyle") -_S("Lslashsmall") -_S("Scaronsmall") -_S("Zcaronsmall") -_S("Dieresissmall") -_S("Brevesmall") -_S("Caronsmall") -_S("Dotaccentsmall") -_S("Macronsmall") -_S("figuredash") -_S("hypheninferior") -_S("Ogoneksmall") -_S("Ringsmall") -_S("Cedillasmall") -_S("questiondownsmall") -_S("oneeighth") -_S("threeeighths") -_S("fiveeighths") -_S("seveneighths") -_S("onethird") -_S("twothirds") -_S("zerosuperior") -_S("foursuperior") -_S("fivesuperior") -_S("sixsuperior") -_S("sevensuperior") -_S("eightsuperior") -_S("ninesuperior") -_S("zeroinferior") -_S("oneinferior") -_S("twoinferior") -_S("threeinferior") -_S("fourinferior") -_S("fiveinferior") -_S("sixinferior") -_S("seveninferior") -_S("eightinferior") -_S("nineinferior") -_S("centinferior") -_S("dollarinferior") -_S("periodinferior") -_S("commainferior") -_S("Agravesmall") -_S("Aacutesmall") -_S("Acircumflexsmall") -_S("Atildesmall") -_S("Adieresissmall") -_S("Aringsmall") -_S("AEsmall") -_S("Ccedillasmall") -_S("Egravesmall") -_S("Eacutesmall") -_S("Ecircumflexsmall") -_S("Edieresissmall") -_S("Igravesmall") -_S("Iacutesmall") -_S("Icircumflexsmall") -_S("Idieresissmall") -_S("Ethsmall") -_S("Ntildesmall") -_S("Ogravesmall") -_S("Oacutesmall") -_S("Ocircumflexsmall") -_S("Otildesmall") -_S("Odieresissmall") -_S("OEsmall") -_S("Oslashsmall") -_S("Ugravesmall") -_S("Uacutesmall") -_S("Ucircumflexsmall") -_S("Udieresissmall") -_S("Yacutesmall") -_S("Thornsmall") -_S("Ydieresissmall") -_S("001.000") -_S("001.001") -_S("001.002") -_S("001.003") -_S("Black") -_S("Bold") -_S("Book") -_S("Light") -_S("Medium") -_S("Regular") -_S("Roman") -_S("Semibold") +HB_STR(".notdef") +HB_STR("space") +HB_STR("exclam") +HB_STR("quotedbl") +HB_STR("numbersign") +HB_STR("dollar") +HB_STR("percent") +HB_STR("ampersand") +HB_STR("quoteright") +HB_STR("parenleft") +HB_STR("parenright") +HB_STR("asterisk") +HB_STR("plus") +HB_STR("comma") +HB_STR("hyphen") +HB_STR("period") +HB_STR("slash") +HB_STR("zero") +HB_STR("one") +HB_STR("two") +HB_STR("three") +HB_STR("four") +HB_STR("five") +HB_STR("six") +HB_STR("seven") +HB_STR("eight") +HB_STR("nine") +HB_STR("colon") +HB_STR("semicolon") +HB_STR("less") +HB_STR("equal") +HB_STR("greater") +HB_STR("question") +HB_STR("at") +HB_STR("A") +HB_STR("B") +HB_STR("C") +HB_STR("D") +HB_STR("E") +HB_STR("F") +HB_STR("G") +HB_STR("H") +HB_STR("I") +HB_STR("J") +HB_STR("K") +HB_STR("L") +HB_STR("M") +HB_STR("N") +HB_STR("O") +HB_STR("P") +HB_STR("Q") +HB_STR("R") +HB_STR("S") +HB_STR("T") +HB_STR("U") +HB_STR("V") +HB_STR("W") +HB_STR("X") +HB_STR("Y") +HB_STR("Z") +HB_STR("bracketleft") +HB_STR("backslash") +HB_STR("bracketright") +HB_STR("asciicircum") +HB_STR("underscore") +HB_STR("quoteleft") +HB_STR("a") +HB_STR("b") +HB_STR("c") +HB_STR("d") +HB_STR("e") +HB_STR("f") +HB_STR("g") +HB_STR("h") +HB_STR("i") +HB_STR("j") +HB_STR("k") +HB_STR("l") +HB_STR("m") +HB_STR("n") +HB_STR("o") +HB_STR("p") +HB_STR("q") +HB_STR("r") +HB_STR("s") +HB_STR("t") +HB_STR("u") +HB_STR("v") +HB_STR("w") +HB_STR("x") +HB_STR("y") +HB_STR("z") +HB_STR("braceleft") +HB_STR("bar") +HB_STR("braceright") +HB_STR("asciitilde") +HB_STR("exclamdown") +HB_STR("cent") +HB_STR("sterling") +HB_STR("fraction") +HB_STR("yen") +HB_STR("florin") +HB_STR("section") +HB_STR("currency") +HB_STR("quotesingle") +HB_STR("quotedblleft") +HB_STR("guillemotleft") +HB_STR("guilsinglleft") +HB_STR("guilsinglright") +HB_STR("fi") +HB_STR("fl") +HB_STR("endash") +HB_STR("dagger") +HB_STR("daggerdbl") +HB_STR("periodcentered") +HB_STR("paragraph") +HB_STR("bullet") +HB_STR("quotesinglbase") +HB_STR("quotedblbase") +HB_STR("quotedblright") +HB_STR("guillemotright") +HB_STR("ellipsis") +HB_STR("perthousand") +HB_STR("questiondown") +HB_STR("grave") +HB_STR("acute") +HB_STR("circumflex") +HB_STR("tilde") +HB_STR("macron") +HB_STR("breve") +HB_STR("dotaccent") +HB_STR("dieresis") +HB_STR("ring") +HB_STR("cedilla") +HB_STR("hungarumlaut") +HB_STR("ogonek") +HB_STR("caron") +HB_STR("emdash") +HB_STR("AE") +HB_STR("ordfeminine") +HB_STR("Lslash") +HB_STR("Oslash") +HB_STR("OE") +HB_STR("ordmasculine") +HB_STR("ae") +HB_STR("dotlessi") +HB_STR("lslash") +HB_STR("oslash") +HB_STR("oe") +HB_STR("germandbls") +HB_STR("onesuperior") +HB_STR("logicalnot") +HB_STR("mu") +HB_STR("trademark") +HB_STR("Eth") +HB_STR("onehalf") +HB_STR("plusminus") +HB_STR("Thorn") +HB_STR("onequarter") +HB_STR("divide") +HB_STR("brokenbar") +HB_STR("degree") +HB_STR("thorn") +HB_STR("threequarters") +HB_STR("twosuperior") +HB_STR("registered") +HB_STR("minus") +HB_STR("eth") +HB_STR("multiply") +HB_STR("threesuperior") +HB_STR("copyright") +HB_STR("Aacute") +HB_STR("Acircumflex") +HB_STR("Adieresis") +HB_STR("Agrave") +HB_STR("Aring") +HB_STR("Atilde") +HB_STR("Ccedilla") +HB_STR("Eacute") +HB_STR("Ecircumflex") +HB_STR("Edieresis") +HB_STR("Egrave") +HB_STR("Iacute") +HB_STR("Icircumflex") +HB_STR("Idieresis") +HB_STR("Igrave") +HB_STR("Ntilde") +HB_STR("Oacute") +HB_STR("Ocircumflex") +HB_STR("Odieresis") +HB_STR("Ograve") +HB_STR("Otilde") +HB_STR("Scaron") +HB_STR("Uacute") +HB_STR("Ucircumflex") +HB_STR("Udieresis") +HB_STR("Ugrave") +HB_STR("Yacute") +HB_STR("Ydieresis") +HB_STR("Zcaron") +HB_STR("aacute") +HB_STR("acircumflex") +HB_STR("adieresis") +HB_STR("agrave") +HB_STR("aring") +HB_STR("atilde") +HB_STR("ccedilla") +HB_STR("eacute") +HB_STR("ecircumflex") +HB_STR("edieresis") +HB_STR("egrave") +HB_STR("iacute") +HB_STR("icircumflex") +HB_STR("idieresis") +HB_STR("igrave") +HB_STR("ntilde") +HB_STR("oacute") +HB_STR("ocircumflex") +HB_STR("odieresis") +HB_STR("ograve") +HB_STR("otilde") +HB_STR("scaron") +HB_STR("uacute") +HB_STR("ucircumflex") +HB_STR("udieresis") +HB_STR("ugrave") +HB_STR("yacute") +HB_STR("ydieresis") +HB_STR("zcaron") +HB_STR("exclamsmall") +HB_STR("Hungarumlautsmall") +HB_STR("dollaroldstyle") +HB_STR("dollarsuperior") +HB_STR("ampersandsmall") +HB_STR("Acutesmall") +HB_STR("parenleftsuperior") +HB_STR("parenrightsuperior") +HB_STR("twodotenleader") +HB_STR("onedotenleader") +HB_STR("zerooldstyle") +HB_STR("oneoldstyle") +HB_STR("twooldstyle") +HB_STR("threeoldstyle") +HB_STR("fouroldstyle") +HB_STR("fiveoldstyle") +HB_STR("sixoldstyle") +HB_STR("sevenoldstyle") +HB_STR("eightoldstyle") +HB_STR("nineoldstyle") +HB_STR("commasuperior") +HB_STR("threequartersemdash") +HB_STR("periodsuperior") +HB_STR("questionsmall") +HB_STR("asuperior") +HB_STR("bsuperior") +HB_STR("centsuperior") +HB_STR("dsuperior") +HB_STR("esuperior") +HB_STR("isuperior") +HB_STR("lsuperior") +HB_STR("msuperior") +HB_STR("nsuperior") +HB_STR("osuperior") +HB_STR("rsuperior") +HB_STR("ssuperior") +HB_STR("tsuperior") +HB_STR("ff") +HB_STR("ffi") +HB_STR("ffl") +HB_STR("parenleftinferior") +HB_STR("parenrightinferior") +HB_STR("Circumflexsmall") +HB_STR("hyphensuperior") +HB_STR("Gravesmall") +HB_STR("Asmall") +HB_STR("Bsmall") +HB_STR("Csmall") +HB_STR("Dsmall") +HB_STR("Esmall") +HB_STR("Fsmall") +HB_STR("Gsmall") +HB_STR("Hsmall") +HB_STR("Ismall") +HB_STR("Jsmall") +HB_STR("Ksmall") +HB_STR("Lsmall") +HB_STR("Msmall") +HB_STR("Nsmall") +HB_STR("Osmall") +HB_STR("Psmall") +HB_STR("Qsmall") +HB_STR("Rsmall") +HB_STR("Ssmall") +HB_STR("Tsmall") +HB_STR("Usmall") +HB_STR("Vsmall") +HB_STR("Wsmall") +HB_STR("Xsmall") +HB_STR("Ysmall") +HB_STR("Zsmall") +HB_STR("colonmonetary") +HB_STR("onefitted") +HB_STR("rupiah") +HB_STR("Tildesmall") +HB_STR("exclamdownsmall") +HB_STR("centoldstyle") +HB_STR("Lslashsmall") +HB_STR("Scaronsmall") +HB_STR("Zcaronsmall") +HB_STR("Dieresissmall") +HB_STR("Brevesmall") +HB_STR("Caronsmall") +HB_STR("Dotaccentsmall") +HB_STR("Macronsmall") +HB_STR("figuredash") +HB_STR("hypheninferior") +HB_STR("Ogoneksmall") +HB_STR("Ringsmall") +HB_STR("Cedillasmall") +HB_STR("questiondownsmall") +HB_STR("oneeighth") +HB_STR("threeeighths") +HB_STR("fiveeighths") +HB_STR("seveneighths") +HB_STR("onethird") +HB_STR("twothirds") +HB_STR("zerosuperior") +HB_STR("foursuperior") +HB_STR("fivesuperior") +HB_STR("sixsuperior") +HB_STR("sevensuperior") +HB_STR("eightsuperior") +HB_STR("ninesuperior") +HB_STR("zeroinferior") +HB_STR("oneinferior") +HB_STR("twoinferior") +HB_STR("threeinferior") +HB_STR("fourinferior") +HB_STR("fiveinferior") +HB_STR("sixinferior") +HB_STR("seveninferior") +HB_STR("eightinferior") +HB_STR("nineinferior") +HB_STR("centinferior") +HB_STR("dollarinferior") +HB_STR("periodinferior") +HB_STR("commainferior") +HB_STR("Agravesmall") +HB_STR("Aacutesmall") +HB_STR("Acircumflexsmall") +HB_STR("Atildesmall") +HB_STR("Adieresissmall") +HB_STR("Aringsmall") +HB_STR("AEsmall") +HB_STR("Ccedillasmall") +HB_STR("Egravesmall") +HB_STR("Eacutesmall") +HB_STR("Ecircumflexsmall") +HB_STR("Edieresissmall") +HB_STR("Igravesmall") +HB_STR("Iacutesmall") +HB_STR("Icircumflexsmall") +HB_STR("Idieresissmall") +HB_STR("Ethsmall") +HB_STR("Ntildesmall") +HB_STR("Ogravesmall") +HB_STR("Oacutesmall") +HB_STR("Ocircumflexsmall") +HB_STR("Otildesmall") +HB_STR("Odieresissmall") +HB_STR("OEsmall") +HB_STR("Oslashsmall") +HB_STR("Ugravesmall") +HB_STR("Uacutesmall") +HB_STR("Ucircumflexsmall") +HB_STR("Udieresissmall") +HB_STR("Yacutesmall") +HB_STR("Thornsmall") +HB_STR("Ydieresissmall") +HB_STR("001.000") +HB_STR("001.001") +HB_STR("001.002") +HB_STR("001.003") +HB_STR("Black") +HB_STR("Bold") +HB_STR("Book") +HB_STR("Light") +HB_STR("Medium") +HB_STR("Regular") +HB_STR("Roman") +HB_STR("Semibold") #endif /* HB_OT_CFF1_STD_STR_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh index 27c4d31b9ce..778167eeb23 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh @@ -326,7 +326,7 @@ struct Charset0 void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const { - mapping->resize (num_glyphs, false); + mapping->resize_dirty (num_glyphs); for (hb_codepoint_t gid = 1; gid < num_glyphs; gid++) mapping->arrayZ[gid] = {sids[gid - 1], gid}; } @@ -426,7 +426,7 @@ struct Charset1_2 { void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const { - mapping->resize (num_glyphs, false); + mapping->resize_dirty (num_glyphs); hb_codepoint_t gid = 1; if (gid >= num_glyphs) return; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc index b2702106ecc..499bd942cde 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc @@ -202,7 +202,11 @@ struct cff2_cs_opset_path_t : cff2_cs_opset_tcoords, font->num_coords)); + return get_path_at (font, + glyph, + draw_session, + hb_array (font->coords, + font->has_nonzero_coords ? font->num_coords : 0)); } bool OT::cff2::accelerator_t::get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t coords) const diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh index 6bf37c062fc..93e9c0a2697 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh @@ -501,10 +501,6 @@ struct CmapSubtableFormat4 this->length = c->length () - table_initpos; if ((long long) this->length != (long long) c->length () - table_initpos) { - // Length overflowed. Discard the current object before setting the error condition, otherwise - // discard is a noop which prevents the higher level code from reverting the serializer to the - // pre-error state in cmap4 overflow handling code. - c->pop_discard (); c->err (HB_SERIALIZE_ERROR_INT_OVERFLOW); return; } @@ -701,16 +697,7 @@ struct CmapSubtableFormat4 hb_barrier (); if (unlikely (!c->check_range (this, length))) - { - /* Some broken fonts have too long of a "length" value. - * If that is the case, just change the value to truncate - * the subtable at the end of the blob. */ - uint16_t new_length = (uint16_t) hb_min ((uintptr_t) 65535, - (uintptr_t) (c->end - - (char *) this)); - if (!c->try_set (&length, new_length)) - return_trace (false); - } + return_trace (false); return_trace (16 + 4 * (unsigned int) segCountX2 <= length); } @@ -1500,7 +1487,7 @@ struct CmapSubtable bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { - switch (u.format) { + switch (u.format.v) { case 0: hb_barrier (); return u.format0 .get_glyph (codepoint, glyph); case 4: hb_barrier (); return u.format4 .get_glyph (codepoint, glyph); case 6: hb_barrier (); return u.format6 .get_glyph (codepoint, glyph); @@ -1513,7 +1500,7 @@ struct CmapSubtable } void collect_unicodes (hb_set_t *out, unsigned int num_glyphs = UINT_MAX) const { - switch (u.format) { + switch (u.format.v) { case 0: hb_barrier (); u.format0 .collect_unicodes (out); return; case 4: hb_barrier (); u.format4 .collect_unicodes (out); return; case 6: hb_barrier (); u.format6 .collect_unicodes (out); return; @@ -1529,7 +1516,7 @@ struct CmapSubtable hb_map_t *mapping, /* OUT */ unsigned num_glyphs = UINT_MAX) const { - switch (u.format) { + switch (u.format.v) { case 0: hb_barrier (); u.format0 .collect_mapping (unicodes, mapping); return; case 4: hb_barrier (); u.format4 .collect_mapping (unicodes, mapping); return; case 6: hb_barrier (); u.format6 .collect_mapping (unicodes, mapping); return; @@ -1543,7 +1530,7 @@ struct CmapSubtable unsigned get_language () const { - switch (u.format) { + switch (u.format.v) { case 0: hb_barrier (); return u.format0 .get_language (); case 4: hb_barrier (); return u.format4 .get_language (); case 6: hb_barrier (); return u.format6 .get_language (); @@ -1574,9 +1561,9 @@ struct CmapSubtable bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return_trace (false); + if (!u.format.v.sanitize (c)) return_trace (false); hb_barrier (); - switch (u.format) { + switch (u.format.v) { case 0: hb_barrier (); return_trace (u.format0 .sanitize (c)); case 4: hb_barrier (); return_trace (u.format4 .sanitize (c)); case 6: hb_barrier (); return_trace (u.format6 .sanitize (c)); @@ -1590,7 +1577,7 @@ struct CmapSubtable public: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ CmapSubtableFormat0 format0; CmapSubtableFormat4 format4; CmapSubtableFormat6 format6; @@ -1600,7 +1587,7 @@ struct CmapSubtable CmapSubtableFormat14 format14; } u; public: - DEFINE_SIZE_UNION (2, format); + DEFINE_SIZE_UNION (2, format.v); }; @@ -1646,7 +1633,7 @@ struct EncodingRecord CmapSubtable *cmapsubtable = c->push (); unsigned origin_length = c->length (); cmapsubtable->serialize (c, it, format, plan, &(base+subtable)); - if (c->length () - origin_length > 0) *objidx = c->pop_pack (); + if (c->length () - origin_length > 0 && !c->in_error()) *objidx = c->pop_pack (); else c->pop_discard (); } @@ -1683,6 +1670,10 @@ struct SubtableUnicodesCache { { SubtableUnicodesCache* cache = (SubtableUnicodesCache*) hb_malloc (sizeof(SubtableUnicodesCache)); + + if (unlikely (!cache)) + return nullptr; + new (cache) SubtableUnicodesCache (source_table); return cache; } @@ -1776,6 +1767,10 @@ struct cmap ; SubtableUnicodesCache* cache = SubtableUnicodesCache::create(source_table); + + if (unlikely (!cache)) + return nullptr; + for (const EncodingRecord& _ : it) cache->set_for(&_); // populate the cache for this encoding record. @@ -1810,7 +1805,7 @@ struct cmap if (c->in_error ()) return false; - unsigned format = (base+_.subtable).u.format; + unsigned format = (base+_.subtable).u.format.v; if (format != 4 && format != 12 && format != 14) continue; const hb_set_t* unicodes_set = unicodes_cache->set_for (&_, local_unicodes_cache); @@ -1912,7 +1907,7 @@ struct cmap + hb_iter (encodingRecord) | hb_map (&EncodingRecord::subtable) | hb_map (hb_add (this)) - | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == 14; }) + | hb_filter ([&] (const CmapSubtable& _) { return _.u.format.v == 14; }) | hb_apply ([=] (const CmapSubtable& _) { _.u.format14.closure_glyphs (unicodes, glyphset); }) ; } @@ -1937,7 +1932,7 @@ struct cmap for (const EncodingRecord& _ : encodingrec_iter) { - unsigned format = (this + _.subtable).u.format; + unsigned format = (this + _.subtable).u.format.v; if (format == 12) has_format12 = true; const EncodingRecord *table = std::addressof (_); @@ -2025,7 +2020,7 @@ struct cmap this->subtable_uvs = &Null (CmapSubtableFormat14); { const CmapSubtable *st = table->find_subtable (0, 5); - if (st && st->u.format == 14) + if (st && st->u.format.v == 14) subtable_uvs = &st->u.format14; } @@ -2069,7 +2064,7 @@ struct cmap else #endif { - switch (subtable->u.format) { + switch (subtable->u.format.v) { /* Accelerate format 4 and format 12. */ default: this->get_glyph_funcZ = get_glyph_from; @@ -2276,7 +2271,7 @@ struct cmap (_.platformID == 0 && _.encodingID == 4) || (_.platformID == 3 && _.encodingID == 1) || (_.platformID == 3 && _.encodingID == 10) || - (cmap + _.subtable).u.format == 14; + (cmap + _.subtable).u.format.v == 14; } protected: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc index 0238bb346a9..8add9209f37 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc @@ -37,6 +37,7 @@ #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" +#include "hb-ot-var-gvar-table.hh" #include "hb-ot-cff2-table.hh" #include "hb-ot-cff1-table.hh" #include "hb-ot-hmtx-table.hh" @@ -64,18 +65,22 @@ using hb_ot_font_advance_cache_t = hb_cache_t<24, 16>; static_assert (sizeof (hb_ot_font_advance_cache_t) == 1024, ""); +using hb_ot_font_origin_cache_t = hb_cache_t<20, 20>; +static_assert (sizeof (hb_ot_font_origin_cache_t) == 1024, ""); + struct hb_ot_font_t { const hb_ot_face_t *ot_face; - /* h_advance caching */ + mutable hb_atomic_t cached_serial; mutable hb_atomic_t cached_coords_serial; - struct advance_cache_t + + struct direction_cache_t { mutable hb_atomic_t advance_cache; - mutable hb_atomic_t varStore_cache; + mutable hb_atomic_t varStore_cache; - ~advance_cache_t () + ~direction_cache_t () { clear (); } @@ -116,7 +121,7 @@ struct hb_ot_font_t goto retry; } - OT::ItemVariationStore::cache_t *acquire_varStore_cache (const OT::ItemVariationStore &varStore) const + OT::hb_scalar_cache_t *acquire_varStore_cache (const OT::ItemVariationStore &varStore) const { retry: auto *cache = varStore_cache.get_acquire (); @@ -127,7 +132,7 @@ struct hb_ot_font_t else goto retry; } - void release_varStore_cache (OT::ItemVariationStore::cache_t *cache) const + void release_varStore_cache (OT::hb_scalar_cache_t *cache) const { if (!cache) return; @@ -154,17 +159,157 @@ struct hb_ot_font_t } h, v; + struct origin_cache_t + { + mutable hb_atomic_t origin_cache; + mutable hb_atomic_t varStore_cache; + + ~origin_cache_t () + { + clear (); + } + + hb_ot_font_origin_cache_t *acquire_origin_cache () const + { + retry: + auto *cache = origin_cache.get_acquire (); + if (!cache) + { + cache = (hb_ot_font_origin_cache_t *) hb_malloc (sizeof (hb_ot_font_origin_cache_t)); + if (!cache) + return nullptr; + new (cache) hb_ot_font_origin_cache_t; + return cache; + } + if (origin_cache.cmpexch (cache, nullptr)) + return cache; + else + goto retry; + } + void release_origin_cache (hb_ot_font_origin_cache_t *cache) const + { + if (!cache) + return; + if (!origin_cache.cmpexch (nullptr, cache)) + hb_free (cache); + } + void clear_origin_cache () const + { + retry: + auto *cache = origin_cache.get_acquire (); + if (!cache) + return; + if (origin_cache.cmpexch (cache, nullptr)) + hb_free (cache); + else + goto retry; + } + + OT::hb_scalar_cache_t *acquire_varStore_cache (const OT::ItemVariationStore &varStore) const + { + retry: + auto *cache = varStore_cache.get_acquire (); + if (!cache) + return varStore.create_cache (); + if (varStore_cache.cmpexch (cache, nullptr)) + return cache; + else + goto retry; + } + void release_varStore_cache (OT::hb_scalar_cache_t *cache) const + { + if (!cache) + return; + if (!varStore_cache.cmpexch (nullptr, cache)) + OT::ItemVariationStore::destroy_cache (cache); + } + void clear_varStore_cache () const + { + retry: + auto *cache = varStore_cache.get_acquire (); + if (!cache) + return; + if (varStore_cache.cmpexch (cache, nullptr)) + OT::ItemVariationStore::destroy_cache (cache); + else + goto retry; + } + + void clear () const + { + clear_origin_cache (); + clear_varStore_cache (); + } + } v_origin; + + struct draw_cache_t + { + mutable hb_atomic_t gvar_cache; + + ~draw_cache_t () + { + clear (); + } + + OT::hb_scalar_cache_t *acquire_gvar_cache (const OT::gvar_accelerator_t &gvar) const + { + retry: + auto *cache = gvar_cache.get_acquire (); + if (!cache) + return gvar.create_cache (); + if (gvar_cache.cmpexch (cache, nullptr)) + return cache; + else + goto retry; + } + void release_gvar_cache (OT::hb_scalar_cache_t *cache) const + { + if (!cache) + return; + if (!gvar_cache.cmpexch (nullptr, cache)) + OT::gvar_accelerator_t::destroy_cache (cache); + } + void clear_gvar_cache () const + { + retry: + auto *cache = gvar_cache.get_acquire (); + if (!cache) + return; + if (gvar_cache.cmpexch (cache, nullptr)) + OT::gvar_accelerator_t::destroy_cache (cache); + else + goto retry; + } + + void clear () const + { + clear_gvar_cache (); + } + } draw; + void check_serial (hb_font_t *font) const { int font_serial = font->serial_coords.get_acquire (); + if (cached_serial.get_acquire () != font_serial) + { + /* These caches are dependent on scale and synthetic settings. + * Any change to the font invalidates them. */ + v_origin.clear (); - if (cached_coords_serial.get_acquire () == font_serial) - return; + cached_serial.set_release (font_serial); + } - h.clear (); - v.clear (); + int font_serial_coords = font->serial_coords.get_acquire (); + if (cached_coords_serial.get_acquire () != font_serial_coords) + { + /* These caches are independent of scale or synthetic settings. + * Just variation changes will invalidate them. */ + h.clear (); + v.clear (); + draw.clear (); - cached_coords_serial.set_release (font_serial); + cached_coords_serial.set_release (font_serial_coords); + } } }; @@ -242,37 +387,59 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, unsigned advance_stride, void *user_data HB_UNUSED) { + // Duplicated in v_advances. Ugly. Keep in sync'ish. const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx; - ot_font->check_serial (font); - const OT::HVAR &HVAR = *hmtx.var_table; - const OT::ItemVariationStore &varStore = &HVAR + HVAR.varStore; - OT::ItemVariationStore::cache_t *varStore_cache = ot_font->h.acquire_varStore_cache (varStore); - - hb_ot_font_advance_cache_t *advance_cache = nullptr; - - bool use_cache = font->num_coords; - if (use_cache) - { - advance_cache = ot_font->h.acquire_advance_cache (); - if (!advance_cache) - use_cache = false; - } - - if (!use_cache) + if (unlikely (!hmtx.has_data ())) { + hb_position_t advance = font->face->get_upem () / 2; + advance = font->em_scale_x (advance); for (unsigned int i = 0; i < count; i++) { - *first_advance = font->em_scale_x (hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache)); + *first_advance = advance; + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + return; + } + +#ifndef HB_NO_VAR + if (!font->has_nonzero_coords) + { + fallback: +#else + { +#endif + // Just plain htmx data. No need to cache. + for (unsigned int i = 0; i < count; i++) + { + *first_advance = font->em_scale_x (hmtx.get_advance_without_var_unscaled (*first_glyph)); first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } + return; } - else - { /* Use cache. */ + +#ifndef HB_NO_VAR + /* has_nonzero_coords. */ + + ot_font->check_serial (font); + hb_ot_font_advance_cache_t *advance_cache = ot_font->h.acquire_advance_cache (); + if (!advance_cache) + { + // malloc failure. Just use the fallback non-variable path. + goto fallback; + } + + /* If HVAR is present, use it.*/ + const OT::HVAR &HVAR = *hmtx.var_table; + if (HVAR.has_data ()) + { + const OT::ItemVariationStore &varStore = &HVAR + HVAR.varStore; + OT::hb_scalar_cache_t *varStore_cache = ot_font->h.acquire_varStore_cache (varStore); + for (unsigned int i = 0; i < count; i++) { hb_position_t v; @@ -289,10 +456,49 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } + ot_font->h.release_varStore_cache (varStore_cache); ot_font->h.release_advance_cache (advance_cache); + return; } - ot_font->h.release_varStore_cache (varStore_cache); + const auto &gvar = *ot_face->gvar; + if (gvar.has_data ()) + { + const auto &glyf = *ot_face->glyf; + auto *scratch = glyf.acquire_scratch (); + if (unlikely (!scratch)) + { + ot_font->h.release_advance_cache (advance_cache); + goto fallback; + } + OT::hb_scalar_cache_t *gvar_cache = ot_font->draw.acquire_gvar_cache (gvar); + + for (unsigned int i = 0; i < count; i++) + { + hb_position_t v; + unsigned cv; + if (advance_cache->get (*first_glyph, &cv)) + v = cv; + else + { + v = glyf.get_advance_with_var_unscaled (*first_glyph, font, false, *scratch, gvar_cache); + advance_cache->set (*first_glyph, v); + } + *first_advance = font->em_scale_x (v); + first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + + ot_font->draw.release_gvar_cache (gvar_cache); + glyf.release_scratch (scratch); + ot_font->h.release_advance_cache (advance_cache); + return; + } + + ot_font->h.release_advance_cache (advance_cache); + // No HVAR or GVAR. Just use the fallback non-variable path. + goto fallback; +#endif } #ifndef HB_NO_VERTICAL @@ -305,99 +511,290 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, unsigned advance_stride, void *user_data HB_UNUSED) { + // Duplicated from h_advances. Ugly. Keep in sync'ish. + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; - if (vmtx.has_data ()) + if (unlikely (!vmtx.has_data ())) + { + hb_font_extents_t font_extents; + font->get_h_extents_with_fallback (&font_extents); + hb_position_t advance = font_extents.descender - font_extents.ascender; + for (unsigned int i = 0; i < count; i++) + { + *first_advance = advance; + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + return; + } + +#ifndef HB_NO_VAR + if (!font->has_nonzero_coords) + { + fallback: +#else + { +#endif + // Just plain vtmx data. No need to cache. + for (unsigned int i = 0; i < count; i++) + { + *first_advance = font->em_scale_y (- (int) vmtx.get_advance_without_var_unscaled (*first_glyph)); + first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + return; + } + +#ifndef HB_NO_VAR + /* has_nonzero_coords. */ + + ot_font->check_serial (font); + hb_ot_font_advance_cache_t *advance_cache = ot_font->v.acquire_advance_cache (); + if (!advance_cache) + { + // malloc failure. Just use the fallback non-variable path. + goto fallback; + } + + /* If VVAR is present, use it.*/ + const OT::VVAR &VVAR = *vmtx.var_table; + if (VVAR.has_data ()) { - ot_font->check_serial (font); - const OT::VVAR &VVAR = *vmtx.var_table; const OT::ItemVariationStore &varStore = &VVAR + VVAR.varStore; - OT::ItemVariationStore::cache_t *varStore_cache = ot_font->v.acquire_varStore_cache (varStore); - // TODO Use advance_cache. + OT::hb_scalar_cache_t *varStore_cache = ot_font->v.acquire_varStore_cache (varStore); for (unsigned int i = 0; i < count; i++) { - *first_advance = font->em_scale_y (-(int) vmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache)); + hb_position_t v; + unsigned cv; + if (advance_cache->get (*first_glyph, &cv)) + v = cv; + else + { + v = vmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache); + advance_cache->set (*first_glyph, v); + } + *first_advance = font->em_scale_y (- (int) v); first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } ot_font->v.release_varStore_cache (varStore_cache); + ot_font->v.release_advance_cache (advance_cache); + return; } - else + + const auto &gvar = *ot_face->gvar; + if (gvar.has_data ()) { - hb_font_extents_t font_extents; - font->get_h_extents_with_fallback (&font_extents); - hb_position_t advance = -(font_extents.ascender - font_extents.descender); + const auto &glyf = *ot_face->glyf; + auto *scratch = glyf.acquire_scratch (); + if (unlikely (!scratch)) + { + ot_font->v.release_advance_cache (advance_cache); + goto fallback; + } + OT::hb_scalar_cache_t *gvar_cache = ot_font->draw.acquire_gvar_cache (gvar); for (unsigned int i = 0; i < count; i++) { - *first_advance = advance; + hb_position_t v; + unsigned cv; + if (advance_cache->get (*first_glyph, &cv)) + v = cv; + else + { + v = glyf.get_advance_with_var_unscaled (*first_glyph, font, true, *scratch, gvar_cache); + advance_cache->set (*first_glyph, v); + } + *first_advance = font->em_scale_y (- (int) v); first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } + + ot_font->draw.release_gvar_cache (gvar_cache); + glyf.release_scratch (scratch); + ot_font->v.release_advance_cache (advance_cache); + return; } + + ot_font->v.release_advance_cache (advance_cache); + // No VVAR or GVAR. Just use the fallback non-variable path. + goto fallback; +#endif } #endif #ifndef HB_NO_VERTICAL +HB_HOT static hb_bool_t -hb_ot_get_glyph_v_origin (hb_font_t *font, - void *font_data, - hb_codepoint_t glyph, - hb_position_t *x, - hb_position_t *y, - void *user_data HB_UNUSED) +hb_ot_get_glyph_v_origins (hb_font_t *font, + void *font_data, + unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_x, + unsigned x_stride, + hb_position_t *first_y, + unsigned y_stride, + void *user_data HB_UNUSED) { const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; - *x = font->get_glyph_h_advance (glyph) / 2; - - const OT::VORG &VORG = *ot_face->VORG; - if (VORG.has_data ()) + /* First, set all the x values to half the advance width. */ + font->get_glyph_h_advances (count, + first_glyph, glyph_stride, + first_x, x_stride); + for (unsigned i = 0; i < count; i++) { - float delta = 0; + *first_x /= 2; + first_x = &StructAtOffsetUnaligned (first_x, x_stride); + } + /* The vertical origin business is messy... + * + * We allocate the cache, then have various code paths that use the cache. + * Each one is responsible to free it before returning. + */ + hb_ot_font_origin_cache_t *origin_cache = ot_font->v_origin.acquire_origin_cache (); + + /* If there is VORG, always use it. It uses VVAR for variations if necessary. */ + const OT::VORG &VORG = *ot_face->VORG; + if (origin_cache && VORG.has_data ()) + { #ifndef HB_NO_VAR - const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; - const OT::VVAR &VVAR = *vmtx.var_table; - if (font->num_coords) - VVAR.get_vorg_delta_unscaled (glyph, - font->coords, font->num_coords, - &delta); + if (!font->has_nonzero_coords) #endif + { + for (unsigned i = 0; i < count; i++) + { + hb_position_t origin; + unsigned cv; + if (origin_cache->get (*first_glyph, &cv)) + origin = font->y_scale < 0 ? -static_cast(cv) : static_cast(cv); + else + { + origin = font->em_scalef_y (VORG.get_y_origin (*first_glyph)); + origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin); + } - *y = font->em_scalef_y (VORG.get_y_origin (glyph) + delta); + *first_y = origin; + + first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); + first_y = &StructAtOffsetUnaligned (first_y, y_stride); + } + } +#ifndef HB_NO_VAR + else + { + const OT::VVAR &VVAR = *ot_face->vmtx->var_table; + const auto &varStore = &VVAR + VVAR.varStore; + auto *varStore_cache = ot_font->v_origin.acquire_varStore_cache (varStore); + for (unsigned i = 0; i < count; i++) + { + hb_position_t origin; + unsigned cv; + if (origin_cache->get (*first_glyph, &cv)) + origin = font->y_scale < 0 ? -static_cast(cv) : static_cast(cv); + else + { + origin = font->em_scalef_y (VORG.get_y_origin (*first_glyph) + + VVAR.get_vorg_delta_unscaled (*first_glyph, + font->coords, font->num_coords, + varStore_cache)); + origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin); + } + + *first_y = origin; + + first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); + first_y = &StructAtOffsetUnaligned (first_y, y_stride); + } + ot_font->v_origin.release_varStore_cache (varStore_cache); + } +#endif + ot_font->v_origin.release_origin_cache (origin_cache); return true; } - hb_glyph_extents_t extents = {0}; - - if (hb_font_get_glyph_extents (font, glyph, &extents)) + /* If and only if `vmtx` is present and it's a `glyf` font, + * we use the top phantom point, deduced from vmtx,glyf[,gvar]. */ + const auto &vmtx = *ot_face->vmtx; + const auto &glyf = *ot_face->glyf; + if (origin_cache && vmtx.has_data() && glyf.has_data ()) { - const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; - int tsb = 0; - if (vmtx.get_leading_bearing_with_var_unscaled (font, glyph, &tsb)) + auto *scratch = glyf.acquire_scratch (); + if (unlikely (!scratch)) { - *y = extents.y_bearing + font->em_scale_y (tsb); - return true; + ot_font->v_origin.release_origin_cache (origin_cache); + return false; + } + OT::hb_scalar_cache_t *gvar_cache = font->has_nonzero_coords ? + ot_font->draw.acquire_gvar_cache (*ot_face->gvar) : + nullptr; + + for (unsigned i = 0; i < count; i++) + { + hb_position_t origin; + unsigned cv; + if (origin_cache->get (*first_glyph, &cv)) + origin = font->y_scale < 0 ? -static_cast(cv) : static_cast(cv); + else + { + origin = font->em_scalef_y (glyf.get_v_origin_with_var_unscaled (*first_glyph, font, *scratch, gvar_cache)); + origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin); + } + + *first_y = origin; + + first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); + first_y = &StructAtOffsetUnaligned (first_y, y_stride); } - hb_font_extents_t font_extents; - font->get_h_extents_with_fallback (&font_extents); - hb_position_t advance = font_extents.ascender - font_extents.descender; - hb_position_t diff = advance - -extents.height; - *y = extents.y_bearing + (diff >> 1); + if (gvar_cache) + ot_font->draw.release_gvar_cache (gvar_cache); + glyf.release_scratch (scratch); + ot_font->v_origin.release_origin_cache (origin_cache); return true; } - hb_font_extents_t font_extents; - font->get_h_extents_with_fallback (&font_extents); - *y = font_extents.ascender; + /* Otherwise, use glyph extents to center the glyph vertically. + * If getting glyph extents failed, just use the font ascender. */ + if (origin_cache && font->has_glyph_extents_func ()) + { + hb_font_extents_t font_extents; + font->get_h_extents_with_fallback (&font_extents); + hb_position_t font_advance = font_extents.ascender - font_extents.descender; + for (unsigned i = 0; i < count; i++) + { + hb_position_t origin; + unsigned cv; + + if (origin_cache->get (*first_glyph, &cv)) + origin = font->y_scale < 0 ? -static_cast(cv) : static_cast(cv); + else + { + hb_glyph_extents_t extents = {0}; + if (likely (font->get_glyph_extents (*first_glyph, &extents))) + origin = extents.y_bearing + ((font_advance - -extents.height) >> 1); + else + origin = font_extents.ascender; + + origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin); + } + + *first_y = origin; + + first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); + first_y = &StructAtOffsetUnaligned (first_y, y_stride); + } + } + + ot_font->v_origin.release_origin_cache (origin_cache); return true; } #endif @@ -498,17 +895,33 @@ hb_ot_draw_glyph_or_fail (hb_font_t *font, hb_draw_funcs_t *draw_funcs, void *draw_data, void *user_data) { + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; hb_draw_session_t draw_session {draw_funcs, draw_data}; + bool ret = false; + + OT::hb_scalar_cache_t *gvar_cache = nullptr; + if (font->num_coords) + { + ot_font->check_serial (font); + gvar_cache = ot_font->draw.acquire_gvar_cache (*ot_font->ot_face->gvar); + } + #ifndef HB_NO_VAR_COMPOSITES - if (font->face->table.VARC->get_path (font, glyph, draw_session)) return true; + if (font->face->table.VARC->get_path (font, glyph, draw_session)) { ret = true; goto done; } #endif // Keep the following in synch with VARC::get_path_at() - if (font->face->table.glyf->get_path (font, glyph, draw_session)) return true; + if (font->face->table.glyf->get_path (font, glyph, draw_session, gvar_cache)) { ret = true; goto done; } + #ifndef HB_NO_CFF - if (font->face->table.cff2->get_path (font, glyph, draw_session)) return true; - if (font->face->table.cff1->get_path (font, glyph, draw_session)) return true; + if (font->face->table.cff2->get_path (font, glyph, draw_session)) { ret = true; goto done; } + if (font->face->table.cff1->get_path (font, glyph, draw_session)) { ret = true; goto done; } #endif - return false; + +done: + + ot_font->draw.release_gvar_cache (gvar_cache); + + return ret; } #endif @@ -548,12 +961,11 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_tplan->new_to_old_gid_list) - | hb_map ([c, &_mtx, mtx_map] (hb_codepoint_pair_t _) + | hb_map ([&_mtx, mtx_map] (hb_codepoint_pair_t _) { hb_codepoint_t new_gid = _.first; hb_codepoint_t old_gid = _.second; @@ -246,8 +236,7 @@ struct hmtxvmtx if (!mtx_map->has (new_gid, &v)) { int lsb = 0; - if (!_mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb)) - (void) _glyf_get_leading_bearing_without_var_unscaled (c->plan->source, old_gid, !T::is_horizontal, &lsb); + _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb); return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb); } return *v; @@ -326,49 +315,23 @@ struct hmtxvmtx bool has_data () const { return (bool) num_bearings; } - bool get_leading_bearing_without_var_unscaled (hb_codepoint_t glyph, + void get_leading_bearing_without_var_unscaled (hb_codepoint_t glyph, int *lsb) const { if (glyph < num_long_metrics) { *lsb = table->longMetricZ[glyph].sb; - return true; + return; } if (unlikely (glyph >= num_bearings)) - return false; + { + *lsb = 0; + return; + } const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics]; *lsb = bearings[glyph - num_long_metrics]; - return true; - } - - bool get_leading_bearing_with_var_unscaled (hb_font_t *font, - hb_codepoint_t glyph, - int *lsb) const - { - if (!font->num_coords) - return get_leading_bearing_without_var_unscaled (glyph, lsb); - -#ifndef HB_NO_VAR - float delta; - if (var_table->get_lsb_delta_unscaled (glyph, font->coords, font->num_coords, &delta) && - get_leading_bearing_without_var_unscaled (glyph, lsb)) - { - *lsb += roundf (delta); - return true; - } - - // If there's no vmtx data, the phantom points from glyf table are not accurate, - // so we cannot take the next path. - bool is_vertical = T::tableTag == HB_OT_TAG_vmtx; - if (is_vertical && !has_data ()) - return false; - - return _glyf_get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb); -#else - return false; -#endif } unsigned int get_advance_without_var_unscaled (hb_codepoint_t glyph) const @@ -402,27 +365,17 @@ struct hmtxvmtx return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)]; } - unsigned get_advance_with_var_unscaled (hb_codepoint_t glyph, - hb_font_t *font, - ItemVariationStore::cache_t *store_cache = nullptr) const +#ifndef HB_NO_VAR + unsigned get_advance_with_var_unscaled (hb_codepoint_t glyph, + hb_font_t *font, + hb_scalar_cache_t *store_cache = nullptr) const { unsigned int advance = get_advance_without_var_unscaled (glyph); - -#ifndef HB_NO_VAR - if (unlikely (glyph >= num_bearings) || !font->num_coords) - return advance; - - if (var_table.get_length ()) - return advance + roundf (var_table->get_advance_delta_unscaled (glyph, - font->coords, font->num_coords, - store_cache)); - - unsigned glyf_advance = _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx); - return glyf_advance ? glyf_advance : advance; -#else - return advance; -#endif + return hb_max(0.0f, advance + roundf (var_table->get_advance_delta_unscaled (glyph, + font->coords, font->num_coords, + store_cache))); } +#endif protected: // 0 <= num_long_metrics <= num_bearings <= num_advances <= num_glyphs diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh index 97d012e58b8..42326adcad2 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh @@ -90,11 +90,11 @@ struct KernSubTableFormat3 template void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const { - set_t set; if (likely (glyphCount)) - set.add_range (0, glyphCount - 1); - left_set.union_ (set); - right_set.union_ (set); + { + left_set.add_range (0, num_glyphs - 1); + right_set.add_range (0, num_glyphs - 1); + } } protected: @@ -306,8 +306,8 @@ struct kern { static constexpr hb_tag_t tableTag = HB_OT_TAG_kern; - bool has_data () const { return u.version32; } - unsigned get_type () const { return u.major; } + bool has_data () const { return u.version32.v; } + unsigned get_type () const { return u.major.v; } bool has_state_machine () const { @@ -363,7 +363,7 @@ struct kern bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.version32.sanitize (c)) return_trace (false); + if (!u.version32.v.sanitize (c)) return_trace (false); hb_barrier (); return_trace (dispatch (c)); } @@ -406,15 +406,15 @@ struct kern protected: union { - HBUINT32 version32; - HBUINT16 major; + struct { HBUINT32 v; } version32; + struct { HBUINT16 v; } major; KernOT ot; #ifndef HB_NO_AAT_SHAPE KernAAT aat; #endif } u; public: - DEFINE_SIZE_UNION (4, version32); + DEFINE_SIZE_UNION (4, version32.v); }; struct kern_accelerator_t : kern::accelerator_t { diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh index 04a79a93a89..b9baaca2a23 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh @@ -165,13 +165,13 @@ struct BaseCoordFormat3 struct BaseCoord { - bool has_data () const { return u.format; } + bool has_data () const { return u.format.v; } hb_position_t get_coord (hb_font_t *font, const ItemVariationStore &var_store, hb_direction_t direction) const { - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return u.format1.get_coord (font, direction); case 2: hb_barrier (); return u.format2.get_coord (font, direction); case 3: hb_barrier (); return u.format3.get_coord (font, var_store, direction); @@ -181,7 +181,7 @@ struct BaseCoord void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const { - switch (u.format) { + switch (u.format.v) { case 3: hb_barrier (); u.format3.collect_variation_indices (varidx_set); return; default:return; } @@ -190,9 +190,9 @@ struct BaseCoord template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...)); @@ -203,9 +203,9 @@ struct BaseCoord bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!u.format.sanitize (c))) return_trace (false); + if (unlikely (!u.format.v.sanitize (c))) return_trace (false); hb_barrier (); - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return_trace (u.format1.sanitize (c)); case 2: hb_barrier (); return_trace (u.format2.sanitize (c)); case 3: hb_barrier (); return_trace (u.format3.sanitize (c)); @@ -215,13 +215,13 @@ struct BaseCoord protected: union { - HBUINT16 format; + struct { HBUINT16 v; } format; BaseCoordFormat1 format1; BaseCoordFormat2 format2; BaseCoordFormat3 format3; } u; public: - DEFINE_SIZE_UNION (2, format); + DEFINE_SIZE_UNION (2, format.v); }; struct FeatMinMaxRecord diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh index 7ee34185575..dcacc9cb86c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh @@ -141,6 +141,7 @@ struct hb_subset_layout_context_t : const hb_map_t *lookup_index_map; const hb_hashmap_t> *script_langsys_map; const hb_map_t *feature_index_map; + const hb_map_t *feature_map_w_duplicates; const hb_hashmap_t *feature_substitutes_map; hb_hashmap_t> *feature_record_cond_idx_map; const hb_set_t *catch_all_record_feature_idxes; @@ -165,6 +166,7 @@ struct hb_subset_layout_context_t : lookup_index_map = &c_->plan->gsub_lookups; script_langsys_map = &c_->plan->gsub_langsys; feature_index_map = &c_->plan->gsub_features; + feature_map_w_duplicates = &c_->plan->gsub_features_w_duplicates; feature_substitutes_map = &c_->plan->gsub_feature_substitutes_map; feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gsub_feature_record_cond_idx_map; catch_all_record_feature_idxes = &c_->plan->gsub_old_features; @@ -175,6 +177,7 @@ struct hb_subset_layout_context_t : lookup_index_map = &c_->plan->gpos_lookups; script_langsys_map = &c_->plan->gpos_langsys; feature_index_map = &c_->plan->gpos_features; + feature_map_w_duplicates = &c_->plan->gpos_features_w_duplicates; feature_substitutes_map = &c_->plan->gpos_feature_substitutes_map; feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gpos_feature_record_cond_idx_map; catch_all_record_feature_idxes = &c_->plan->gpos_old_features; @@ -825,46 +828,9 @@ struct Feature const Record_sanitize_closure_t *closure = nullptr) const { TRACE_SANITIZE (this); - if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c)))) - return_trace (false); - hb_barrier (); - - /* Some earlier versions of Adobe tools calculated the offset of the - * FeatureParams subtable from the beginning of the FeatureList table! - * - * If sanitizing "failed" for the FeatureParams subtable, try it with the - * alternative location. We would know sanitize "failed" if old value - * of the offset was non-zero, but it's zeroed now. - * - * Only do this for the 'size' feature, since at the time of the faulty - * Adobe tools, only the 'size' feature had FeatureParams defined. - */ - - if (likely (featureParams.is_null ())) - return_trace (true); - - unsigned int orig_offset = featureParams; - if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))) - return_trace (false); - hb_barrier (); - - if (featureParams == 0 && closure && - closure->tag == HB_TAG ('s','i','z','e') && - closure->list_base && closure->list_base < this) - { - unsigned int new_offset_int = orig_offset - - (((char *) this) - ((char *) closure->list_base)); - - Offset16To new_offset; - /* Check that it would not overflow. */ - new_offset = new_offset_int; - if (new_offset == new_offset_int && - c->try_set (&featureParams, new_offset_int) && - !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)) - return_trace (false); - } - - return_trace (true); + return_trace (c->check_struct (this) && + featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE) && + lookupIndex.sanitize (c)); } Offset16To @@ -1082,15 +1048,15 @@ struct LangSys if (unlikely (!c->serializer->extend_min (out))) return_trace (false); const uint32_t *v; - out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex, &v) ? *v : 0xFFFFu; + out->reqFeatureIndex = l->feature_map_w_duplicates->has (reqFeatureIndex, &v) ? *v : 0xFFFFu; if (!l->visitFeatureIndex (featureIndex.len)) return_trace (false); auto it = + hb_iter (featureIndex) - | hb_filter (l->feature_index_map) - | hb_map (l->feature_index_map) + | hb_filter (l->feature_map_w_duplicates) + | hb_map (l->feature_map_w_duplicates) ; bool ret = bool (it); @@ -1337,7 +1303,7 @@ struct Lookup TRACE_DISPATCH (this, lookup_type); unsigned int count = get_subtable_count (); for (unsigned int i = 0; i < count; i++) { - typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type, std::forward (ds)...); + typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type, ds...); if (c->stop_sublookup_iteration (r)) return_trace (r); } @@ -1387,6 +1353,11 @@ struct Lookup { unsigned new_flag = lookupFlag; new_flag &= ~LookupFlag::UseMarkFilteringSet; + // https://github.com/harfbuzz/harfbuzz/issues/5499 + // If we remove UseMarkFilteringSet flag because the set is now empty, + // we need to add IgnoreMarks flag, otherwise the lookup will not + // ignore any marks, which changes the behavior. + new_flag |= LookupFlag::IgnoreMarks; out->lookupFlag = new_flag; } else @@ -1425,7 +1396,7 @@ struct Lookup if (unlikely (!get_subtables ().sanitize (c, this, get_type ()))) return_trace (false); - if (unlikely (get_type () == TSubTable::Extension && !c->get_edit_count ())) + if (unlikely (get_type () == TSubTable::Extension)) { hb_barrier (); @@ -1433,11 +1404,6 @@ struct Lookup * have the same type, which shall not be the Extension type * itself (but we already checked for that). * This is specially important if one has a reverse type! - * - * We only do this if sanitizer edit_count is zero. Otherwise, - * some of the subtables might have become insane after they - * were sanity-checked by the edits of subsequent subtables. - * https://bugs.chromium.org/p/chromium/issues/detail?id=960331 */ unsigned int type = get_subtable (0).u.extension.get_type (); for (unsigned int i = 1; i < subtables; i++) @@ -2067,7 +2033,7 @@ struct ClassDef unsigned int get (hb_codepoint_t k) const { return get_class (k); } unsigned int get_class (hb_codepoint_t glyph_id) const { - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return u.format1.get_class (glyph_id); case 2: hb_barrier (); return u.format2.get_class (glyph_id); #ifndef HB_NO_BEYOND_64K @@ -2078,7 +2044,7 @@ struct ClassDef } } unsigned int get_class (hb_codepoint_t glyph_id, - hb_ot_lookup_cache_t *cache) const + hb_ot_layout_mapping_cache_t *cache) const { unsigned klass; if (cache && cache->get (glyph_id, &klass)) return klass; @@ -2089,7 +2055,7 @@ struct ClassDef unsigned get_population () const { - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return u.format1.get_population (); case 2: hb_barrier (); return u.format2.get_population (); #ifndef HB_NO_BEYOND_64K @@ -2142,7 +2108,7 @@ struct ClassDef #ifndef HB_NO_BEYOND_64K if (glyph_max > 0xFFFFu) - u.format += 2; + u.format.v += 2; if (unlikely (glyph_max > 0xFFFFFFu)) #else if (unlikely (glyph_max > 0xFFFFu)) @@ -2152,9 +2118,9 @@ struct ClassDef return_trace (false); } - u.format = format; + u.format.v = format; - switch (u.format) + switch (u.format.v) { case 1: hb_barrier (); return_trace (u.format1.serialize (c, it)); case 2: hb_barrier (); return_trace (u.format2.serialize (c, it)); @@ -2173,7 +2139,7 @@ struct ClassDef const Coverage* glyph_filter = nullptr) const { TRACE_SUBSET (this); - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return_trace (u.format1.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter)); case 2: hb_barrier (); return_trace (u.format2.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter)); #ifndef HB_NO_BEYOND_64K @@ -2187,9 +2153,9 @@ struct ClassDef bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return_trace (false); + if (!u.format.v.sanitize (c)) return_trace (false); hb_barrier (); - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return_trace (u.format1.sanitize (c)); case 2: hb_barrier (); return_trace (u.format2.sanitize (c)); #ifndef HB_NO_BEYOND_64K @@ -2202,7 +2168,7 @@ struct ClassDef unsigned cost () const { - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return u.format1.cost (); case 2: hb_barrier (); return u.format2.cost (); #ifndef HB_NO_BEYOND_64K @@ -2218,7 +2184,7 @@ struct ClassDef template bool collect_coverage (set_t *glyphs) const { - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return u.format1.collect_coverage (glyphs); case 2: hb_barrier (); return u.format2.collect_coverage (glyphs); #ifndef HB_NO_BEYOND_64K @@ -2234,7 +2200,7 @@ struct ClassDef template bool collect_class (set_t *glyphs, unsigned int klass) const { - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return u.format1.collect_class (glyphs, klass); case 2: hb_barrier (); return u.format2.collect_class (glyphs, klass); #ifndef HB_NO_BEYOND_64K @@ -2247,7 +2213,7 @@ struct ClassDef bool intersects (const hb_set_t *glyphs) const { - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return u.format1.intersects (glyphs); case 2: hb_barrier (); return u.format2.intersects (glyphs); #ifndef HB_NO_BEYOND_64K @@ -2259,7 +2225,7 @@ struct ClassDef } bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return u.format1.intersects_class (glyphs, klass); case 2: hb_barrier (); return u.format2.intersects_class (glyphs, klass); #ifndef HB_NO_BEYOND_64K @@ -2272,7 +2238,7 @@ struct ClassDef void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const { - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return u.format1.intersected_class_glyphs (glyphs, klass, intersect_glyphs); case 2: hb_barrier (); return u.format2.intersected_class_glyphs (glyphs, klass, intersect_glyphs); #ifndef HB_NO_BEYOND_64K @@ -2285,7 +2251,7 @@ struct ClassDef void intersected_classes (const hb_set_t *glyphs, hb_set_t *intersect_classes) const { - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return u.format1.intersected_classes (glyphs, intersect_classes); case 2: hb_barrier (); return u.format2.intersected_classes (glyphs, intersect_classes); #ifndef HB_NO_BEYOND_64K @@ -2299,7 +2265,7 @@ struct ClassDef protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ ClassDefFormat1_3 format1; ClassDefFormat2_4 format2; #ifndef HB_NO_BEYOND_64K @@ -2308,7 +2274,7 @@ struct ClassDef #endif } u; public: - DEFINE_SIZE_UNION (2, format); + DEFINE_SIZE_UNION (2, format.v); }; template @@ -2326,151 +2292,177 @@ struct delta_row_encoding_t { /* each byte represents a region, value is one of 0/1/2/4, which means bytes * needed for this region */ - hb_vector_t chars; + struct chars_t : hb_vector_t + { + int cmp (const chars_t& other) const + { + return as_array ().cmp (other.as_array ()); + } + + hb_pair_t get_width () + { + unsigned width = 0; + unsigned columns = 0; + for (unsigned i = 0; i < length; i++) + { + unsigned v = arrayZ[i]; + width += v; + columns += (v != 0); + } + return hb_pair (width, columns); + } + + HB_HOT + hb_pair_t combine_width (const chars_t& other) const + { + unsigned combined_width = 0; + unsigned combined_columns = 0; + for (unsigned i = 0; i < length; i++) + { + unsigned v = hb_max (arrayZ[i], other.arrayZ[i]); + combined_width += v; + combined_columns += (v != 0); + } + return hb_pair (combined_width, combined_columns); + } + }; + + hb_pair_t combine_width (const delta_row_encoding_t& other_encoding) const { return chars.combine_width (other_encoding.chars); } + + // Actual data + + chars_t chars; unsigned width = 0; - hb_vector_t columns; unsigned overhead = 0; hb_vector_t*> items; delta_row_encoding_t () = default; - delta_row_encoding_t (hb_vector_t&& chars_, - const hb_vector_t* row = nullptr) : - delta_row_encoding_t () - + delta_row_encoding_t (hb_vector_t*> &&rows, unsigned num_cols) { - chars = std::move (chars_); - width = get_width (); - columns = get_columns (); - overhead = get_chars_overhead (columns); - if (row) items.push (row); + assert (rows); + + items = std::move (rows); + + if (unlikely (!chars.resize (num_cols))) + return; + + calculate_chars (); + } + + void merge (const delta_row_encoding_t& other) + { + items.alloc (items.length + other.items.length); + for (auto &row : other.items) + add_row (row); + + // Merge chars + assert (chars.length == other.chars.length); + for (unsigned i = 0; i < chars.length; i++) + chars.arrayZ[i] = hb_max (chars.arrayZ[i], other.chars.arrayZ[i]); + chars_changed (); + } + + void chars_changed () + { + auto _ = chars.get_width (); + width = _.first; + overhead = get_chars_overhead (_.second); + } + + void calculate_chars () + { + assert (items); + + bool long_words = false; + + for (auto &row : items) + { + assert (row->length == chars.length); + + /* 0/1/2 byte encoding */ + for (unsigned i = 0; i < row->length; i++) + { + int v = row->arrayZ[i]; + if (v == 0) + continue; + else if (v > 32767 || v < -32768) + { + long_words = true; + chars.arrayZ[i] = hb_max (chars.arrayZ[i], 4); + } + else if (v > 127 || v < -128) + chars.arrayZ[i] = hb_max (chars.arrayZ[i], 2); + else + chars.arrayZ[i] = hb_max (chars.arrayZ[i], 1); + } + } + + if (long_words) + { + // Convert 1s to 2s + for (auto &v : chars) + if (v == 1) + v = 2; + } + + chars_changed (); } bool is_empty () const { return !items; } - static hb_vector_t get_row_chars (const hb_vector_t& row) - { - hb_vector_t ret; - if (!ret.alloc (row.length)) return ret; - - bool long_words = false; - - /* 0/1/2 byte encoding */ - for (int i = row.length - 1; i >= 0; i--) - { - int v = row.arrayZ[i]; - if (v == 0) - ret.push (0); - else if (v > 32767 || v < -32768) - { - long_words = true; - break; - } - else if (v > 127 || v < -128) - ret.push (2); - else - ret.push (1); - } - - if (!long_words) - return ret; - - /* redo, 0/2/4 bytes encoding */ - ret.reset (); - for (int i = row.length - 1; i >= 0; i--) - { - int v = row.arrayZ[i]; - if (v == 0) - ret.push (0); - else if (v > 32767 || v < -32768) - ret.push (4); - else - ret.push (2); - } - return ret; - } - - inline unsigned get_width () - { - unsigned ret = + hb_iter (chars) - | hb_reduce (hb_add, 0u) - ; - return ret; - } - - hb_vector_t get_columns () - { - hb_vector_t cols; - cols.alloc (chars.length); - for (auto v : chars) - { - uint8_t flag = v ? 1 : 0; - cols.push (flag); - } - return cols; - } - - static inline unsigned get_chars_overhead (const hb_vector_t& cols) + static inline unsigned get_chars_overhead (unsigned num_columns) { unsigned c = 4 + 6; // 4 bytes for LOffset, 6 bytes for VarData header - unsigned cols_bit_count = 0; - for (auto v : cols) - if (v) cols_bit_count++; - return c + cols_bit_count * 2; + return c + num_columns * 2; } - unsigned get_gain () const + unsigned get_gain (unsigned additional_bytes_per_rows = 1) const { int count = items.length; - return hb_max (0, (int) overhead - count); + return hb_max (0, (int) overhead - count * (int) additional_bytes_per_rows); } int gain_from_merging (const delta_row_encoding_t& other_encoding) const { - int combined_width = 0; - for (unsigned i = 0; i < chars.length; i++) - combined_width += hb_max (chars.arrayZ[i], other_encoding.chars.arrayZ[i]); + // Back of the envelope calculations to reject early. + signed additional_bytes_per_rows = other_encoding.width - width; + if (additional_bytes_per_rows > 0) + { + if (get_gain (additional_bytes_per_rows) == 0) + return 0; + } + else + { + if (other_encoding.get_gain (-additional_bytes_per_rows) == 0) + return 0; + } - hb_vector_t combined_columns; - combined_columns.alloc (columns.length); - for (unsigned i = 0; i < columns.length; i++) - combined_columns.push (columns.arrayZ[i] | other_encoding.columns.arrayZ[i]); + auto pair = combine_width (other_encoding); + unsigned combined_width = pair.first; + unsigned combined_columns = pair.second; - int combined_overhead = get_chars_overhead (combined_columns); - int combined_gain = (int) overhead + (int) other_encoding.overhead - combined_overhead - - (combined_width - (int) width) * items.length - - (combined_width - (int) other_encoding.width) * other_encoding.items.length; + int combined_gain = (int) overhead + (int) other_encoding.overhead; + combined_gain -= (combined_width - (int) width) * items.length; + combined_gain -= (combined_width - (int) other_encoding.width) * other_encoding.items.length; + combined_gain -= get_chars_overhead (combined_columns); return combined_gain; } + bool add_row (const hb_vector_t* row) + { return items.push (row); } + static int cmp (const void *pa, const void *pb) { const delta_row_encoding_t *a = (const delta_row_encoding_t *)pa; const delta_row_encoding_t *b = (const delta_row_encoding_t *)pb; - int gain_a = a->get_gain (); - int gain_b = b->get_gain (); - - if (gain_a != gain_b) - return gain_a - gain_b; - - return (b->chars).as_array ().cmp ((a->chars).as_array ()); - } - - static int cmp_width (const void *pa, const void *pb) - { - const delta_row_encoding_t *a = (const delta_row_encoding_t *)pa; - const delta_row_encoding_t *b = (const delta_row_encoding_t *)pb; - if (a->width != b->width) return (int) a->width - (int) b->width; - return (b->chars).as_array ().cmp ((a->chars).as_array ()); + return b->chars.cmp (a->chars); } - - bool add_row (const hb_vector_t* row) - { return items.push (row); } }; struct VarRegionAxis @@ -2548,32 +2540,112 @@ struct SparseVarRegionAxis DEFINE_SIZE_STATIC (8); }; -#define REGION_CACHE_ITEM_CACHE_INVALID INT_MIN -#define REGION_CACHE_ITEM_MULTIPLIER (float (1 << ((sizeof (int) * 8) - 2))) -#define REGION_CACHE_ITEM_DIVISOR (1.f / float (1 << ((sizeof (int) * 8) - 2))) +struct hb_scalar_cache_t +{ + private: + static constexpr unsigned STATIC_LENGTH = 16; + static constexpr int INVALID = INT_MIN; + static constexpr float MULTIPLIER = 1 << ((sizeof (int) * 8) - 2); + static constexpr float DIVISOR = 1.f / MULTIPLIER; + + public: + hb_scalar_cache_t () : length (STATIC_LENGTH) { clear (); } + + hb_scalar_cache_t (const hb_scalar_cache_t&) = delete; + hb_scalar_cache_t (hb_scalar_cache_t&&) = delete; + hb_scalar_cache_t& operator= (const hb_scalar_cache_t&) = delete; + hb_scalar_cache_t& operator= (hb_scalar_cache_t&&) = delete; + + static hb_scalar_cache_t *create (unsigned int count, + hb_scalar_cache_t *scratch_cache = nullptr) + { + if (!count) return (hb_scalar_cache_t *) &Null(hb_scalar_cache_t); + + if (scratch_cache && count <= scratch_cache->length) + { + scratch_cache->clear (); + return scratch_cache; + } + + auto *cache = (hb_scalar_cache_t *) hb_malloc (sizeof (hb_scalar_cache_t) - sizeof (static_values) + sizeof (static_values[0]) * count); + if (unlikely (!cache)) return (hb_scalar_cache_t *) &Null(hb_scalar_cache_t); + + cache->length = count; + cache->clear (); + + return cache; + } + + static void destroy (hb_scalar_cache_t *cache, + hb_scalar_cache_t *scratch_cache = nullptr) + { + if (cache != &Null(hb_scalar_cache_t) && cache != scratch_cache) + hb_free (cache); + } + + void clear () + { + auto *values = &static_values[0]; + unsigned i = 0; +#ifndef HB_OPTIMIZE_SIZE + for (; i + 3 < length; i += 4) + { + values[i + 0] = INVALID; + values[i + 1] = INVALID; + values[i + 2] = INVALID; + values[i + 3] = INVALID; + } +#endif + for (; i < length; i++) + values[i] = INVALID; + } + + HB_ALWAYS_INLINE + bool get (unsigned i, float *value) const + { + if (unlikely (i >= length)) + { + *value = 0.f; + return true; + } + auto *values = &static_values[0]; + auto *cached_value = &values[i]; + // Super hot. Most common path is that we have a cached value of 0. + int v = *cached_value; + if (likely (!v)) + { + *value = 0.f; + return true; + } + if (v == INVALID) + return false; + *value = v * DIVISOR; + return true; + } + + HB_ALWAYS_INLINE + void set (unsigned i, float value) + { + if (unlikely (i >= length)) return; + auto *values = &static_values[0]; + auto *cached_value = &values[i]; + *cached_value = roundf(value * MULTIPLIER); + } + + private: + unsigned length; + mutable hb_atomic_t static_values[STATIC_LENGTH]; +}; struct VarRegionList { - using cache_t = hb_atomic_t; - - float evaluate (unsigned int region_index, - const int *coords, unsigned int coord_len, - cache_t *cache = nullptr) const + private: + float evaluate_impl (unsigned int region_index, + const int *coords, unsigned int coord_len) const { - if (unlikely (region_index >= regionCount)) - return 0.; - - cache_t *cached_value = nullptr; - if (cache) - { - cached_value = &(cache[region_index]); - if (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID) - return *cached_value * REGION_CACHE_ITEM_DIVISOR; - } - const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount); + float v = 1.f; - float v = 1.; unsigned int count = axisCount; for (unsigned int i = 0; i < count; i++) { @@ -2581,15 +2653,32 @@ struct VarRegionList float factor = axes[i].evaluate (coord); if (factor == 0.f) { - if (cache) - *cached_value = 0.; - return 0.; + v = 0.f; + break; } v *= factor; } + return v; + } + + public: + HB_ALWAYS_INLINE + float evaluate (unsigned int region_index, + const int *coords, unsigned int coord_len, + hb_scalar_cache_t *cache = nullptr) const + { + if (unlikely (region_index >= regionCount)) + return 0.; + + float v; + if (cache && cache->get (region_index, &v)) + return v; + + v = evaluate_impl (region_index, coords, coord_len); + if (cache) - *cached_value = v * REGION_CACHE_ITEM_MULTIPLIER; + cache->set (region_index, v); return v; } @@ -2732,29 +2821,24 @@ struct SparseVariationRegion : Array16Of struct SparseVarRegionList { - using cache_t = hb_atomic_t; - + HB_ALWAYS_INLINE float evaluate (unsigned int region_index, const int *coords, unsigned int coord_len, - cache_t *cache = nullptr) const + hb_scalar_cache_t *cache = nullptr) const { if (unlikely (region_index >= regions.len)) return 0.; - cache_t *cached_value = nullptr; - if (cache) - { - cached_value = &(cache[region_index]); - if (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID) - return *cached_value * REGION_CACHE_ITEM_DIVISOR; - } + float v; + if (cache && cache->get (region_index, &v)) + return v; const SparseVariationRegion ®ion = this+regions[region_index]; - float v = region.evaluate (coords, coord_len); - + v = region.evaluate (coords, coord_len); if (cache) - *cached_value = v * REGION_CACHE_ITEM_MULTIPLIER; + cache->set (region_index, v); + return v; } @@ -2792,46 +2876,62 @@ struct VarData + itemCount * get_row_size (); } - float get_delta (unsigned int inner, - const int *coords, unsigned int coord_count, - const VarRegionList ®ions, - VarRegionList::cache_t *cache = nullptr) const + float _get_delta (unsigned int inner, + const int *coords, unsigned int coord_count, + const VarRegionList ®ions, + hb_scalar_cache_t *cache = nullptr) const { if (unlikely (inner >= itemCount)) return 0.; + bool is_long = longWords (); + unsigned int count = regionIndices.len; + unsigned word_count = wordCount (); + unsigned int scount = is_long ? count : word_count; + unsigned int lcount = is_long ? word_count : 0; - unsigned int count = regionIndices.len; - bool is_long = longWords (); - unsigned word_count = wordCount (); - unsigned int scount = is_long ? count : word_count; - unsigned int lcount = is_long ? word_count : 0; + const HBUINT8 *bytes = get_delta_bytes (); + const HBUINT8 *row = bytes + inner * get_row_size (); - const HBUINT8 *bytes = get_delta_bytes (); - const HBUINT8 *row = bytes + inner * get_row_size (); + float delta = 0.; + unsigned int i = 0; - float delta = 0.; - unsigned int i = 0; + const HBINT32 *lcursor = reinterpret_cast (row); + for (; i < lcount; i++) + { + float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache); + if (scalar) + delta += scalar * *lcursor; + lcursor++; + } + const HBINT16 *scursor = reinterpret_cast (lcursor); + for (; i < scount; i++) + { + float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache); + if (scalar) + delta += scalar * *scursor; + scursor++; + } + const HBINT8 *bcursor = reinterpret_cast (scursor); + for (; i < count; i++) + { + float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache); + if (scalar) + delta += scalar * *bcursor; + bcursor++; + } - const HBINT32 *lcursor = reinterpret_cast (row); - for (; i < lcount; i++) - { - float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache); - delta += scalar * *lcursor++; - } - const HBINT16 *scursor = reinterpret_cast (lcursor); - for (; i < scount; i++) - { - float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache); - delta += scalar * *scursor++; - } - const HBINT8 *bcursor = reinterpret_cast (scursor); - for (; i < count; i++) - { - float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache); - delta += scalar * *bcursor++; - } + return delta; + } - return delta; + HB_ALWAYS_INLINE + float get_delta (unsigned int inner, + const int *coords, unsigned int coord_count, + const VarRegionList ®ions, + hb_scalar_cache_t *cache = nullptr) const + { + unsigned int count = regionIndices.len; + if (!count) return 0.f; // This is quite common, so optimize it. + return _get_delta (inner, coords, coord_count, regions, cache); } void get_region_scalars (const int *coords, unsigned int coord_count, @@ -3150,7 +3250,7 @@ struct MultiVarData const int *coords, unsigned int coord_count, const SparseVarRegionList ®ions, hb_array_t out, - SparseVarRegionList::cache_t *cache = nullptr) const + hb_scalar_cache_t *cache = nullptr) const { auto &deltaSets = StructAfter (regionIndices); @@ -3187,31 +3287,24 @@ struct MultiVarData struct ItemVariationStore { friend struct item_variations_t; - using cache_t = VarRegionList::cache_t; - cache_t *create_cache () const + hb_scalar_cache_t *create_cache () const { #ifdef HB_NO_VAR - return nullptr; + return hb_scalar_cache_t::create (0); #endif - unsigned count = (this+regions).regionCount; - if (!count) return nullptr; - - cache_t *cache = (cache_t *) hb_malloc (sizeof (float) * count); - if (unlikely (!cache)) return nullptr; - - for (unsigned i = 0; i < count; i++) - cache[i] = REGION_CACHE_ITEM_CACHE_INVALID; - - return cache; + return hb_scalar_cache_t::create ((this+regions).regionCount); } - static void destroy_cache (cache_t *cache) { hb_free (cache); } + static void destroy_cache (hb_scalar_cache_t *cache) + { + hb_scalar_cache_t::destroy (cache); + } private: float get_delta (unsigned int outer, unsigned int inner, const int *coords, unsigned int coord_count, - VarRegionList::cache_t *cache = nullptr) const + hb_scalar_cache_t *cache = nullptr) const { #ifdef HB_NO_VAR return 0.f; @@ -3229,7 +3322,7 @@ struct ItemVariationStore public: float get_delta (unsigned int index, const int *coords, unsigned int coord_count, - VarRegionList::cache_t *cache = nullptr) const + hb_scalar_cache_t *cache = nullptr) const { unsigned int outer = index >> 16; unsigned int inner = index & 0xFFFF; @@ -3237,7 +3330,7 @@ struct ItemVariationStore } float get_delta (unsigned int index, hb_array_t coords, - VarRegionList::cache_t *cache = nullptr) const + hb_scalar_cache_t *cache = nullptr) const { return get_delta (index, coords.arrayZ, coords.length, @@ -3356,7 +3449,7 @@ struct ItemVariationStore for (unsigned i = 0; i < count; i++) { hb_inc_bimap_t *map = inner_maps.push (); - if (!c->propagate_error(inner_maps)) + if (unlikely (!c->propagate_error(inner_maps))) return_trace(nullptr); auto &data = this+dataSets[i]; @@ -3445,43 +3538,28 @@ struct ItemVariationStore struct MultiItemVariationStore { - using cache_t = SparseVarRegionList::cache_t; - - cache_t *create_cache (hb_array_t static_cache = hb_array_t ()) const + hb_scalar_cache_t *create_cache (hb_scalar_cache_t *static_cache = nullptr) const { #ifdef HB_NO_VAR - return nullptr; + return hb_scalar_cache_t::create (0); #endif auto &r = this+regions; unsigned count = r.regions.len; - cache_t *cache; - if (count <= static_cache.length) - cache = static_cache.arrayZ; - else - { - cache = (cache_t *) hb_malloc (sizeof (float) * count); - if (unlikely (!cache)) return nullptr; - } - - for (unsigned i = 0; i < count; i++) - cache[i] = REGION_CACHE_ITEM_CACHE_INVALID; - - return cache; + return hb_scalar_cache_t::create (count, static_cache); } - static void destroy_cache (cache_t *cache, - hb_array_t static_cache = hb_array_t ()) + static void destroy_cache (hb_scalar_cache_t *cache, + hb_scalar_cache_t *static_cache = nullptr) { - if (cache != static_cache.arrayZ) - hb_free (cache); + hb_scalar_cache_t::destroy (cache, static_cache); } private: void get_delta (unsigned int outer, unsigned int inner, const int *coords, unsigned int coord_count, hb_array_t out, - VarRegionList::cache_t *cache = nullptr) const + hb_scalar_cache_t *cache = nullptr) const { #ifdef HB_NO_VAR return; @@ -3501,7 +3579,7 @@ struct MultiItemVariationStore void get_delta (unsigned int index, const int *coords, unsigned int coord_count, hb_array_t out, - VarRegionList::cache_t *cache = nullptr) const + hb_scalar_cache_t *cache = nullptr) const { unsigned int outer = index >> 16; unsigned int inner = index & 0xFFFF; @@ -3510,7 +3588,7 @@ struct MultiItemVariationStore void get_delta (unsigned int index, hb_array_t coords, hb_array_t out, - VarRegionList::cache_t *cache = nullptr) const + hb_scalar_cache_t *cache = nullptr) const { return get_delta (index, coords.arrayZ, coords.length, @@ -3540,8 +3618,6 @@ struct MultiItemVariationStore DEFINE_SIZE_ARRAY_SIZED (8, dataSets); }; -#undef REGION_CACHE_ITEM_CACHE_INVALID - template struct DeltaSetIndexMapFormat01 { @@ -3592,13 +3668,19 @@ struct DeltaSetIndexMapFormat01 return_trace (true); } + HB_ALWAYS_INLINE uint32_t map (unsigned int v) const /* Returns 16.16 outer.inner. */ { /* If count is zero, pass value unchanged. This takes * care of direct mapping for advance map. */ if (!mapCount) return v; + return _map (v); + } + HB_HOT + uint32_t _map (unsigned int v) const /* Returns 16.16 outer.inner. */ + { if (v >= mapCount) v = mapCount - 1; @@ -3654,8 +3736,8 @@ struct DeltaSetIndexMap { TRACE_SERIALIZE (this); unsigned length = plan.get_output_map ().length; - u.format = length <= 0xFFFF ? 0 : 1; - switch (u.format) { + u.format.v = length <= 0xFFFF ? 0 : 1; + switch (u.format.v) { case 0: hb_barrier (); return_trace (u.format0.serialize (c, plan)); case 1: hb_barrier (); return_trace (u.format1.serialize (c, plan)); default:return_trace (false); @@ -3664,7 +3746,7 @@ struct DeltaSetIndexMap uint32_t map (unsigned v) const { - switch (u.format) { + switch (u.format.v) { case 0: hb_barrier (); return (u.format0.map (v)); case 1: hb_barrier (); return (u.format1.map (v)); default:return v; @@ -3673,7 +3755,7 @@ struct DeltaSetIndexMap unsigned get_map_count () const { - switch (u.format) { + switch (u.format.v) { case 0: hb_barrier (); return u.format0.get_map_count (); case 1: hb_barrier (); return u.format1.get_map_count (); default:return 0; @@ -3682,7 +3764,7 @@ struct DeltaSetIndexMap unsigned get_width () const { - switch (u.format) { + switch (u.format.v) { case 0: hb_barrier (); return u.format0.get_width (); case 1: hb_barrier (); return u.format1.get_width (); default:return 0; @@ -3691,7 +3773,7 @@ struct DeltaSetIndexMap unsigned get_inner_bit_count () const { - switch (u.format) { + switch (u.format.v) { case 0: hb_barrier (); return u.format0.get_inner_bit_count (); case 1: hb_barrier (); return u.format1.get_inner_bit_count (); default:return 0; @@ -3701,9 +3783,9 @@ struct DeltaSetIndexMap bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return_trace (false); + if (!u.format.v.sanitize (c)) return_trace (false); hb_barrier (); - switch (u.format) { + switch (u.format.v) { case 0: hb_barrier (); return_trace (u.format0.sanitize (c)); case 1: hb_barrier (); return_trace (u.format1.sanitize (c)); default:return_trace (true); @@ -3713,7 +3795,7 @@ struct DeltaSetIndexMap DeltaSetIndexMap* copy (hb_serialize_context_t *c) const { TRACE_SERIALIZE (this); - switch (u.format) { + switch (u.format.v) { case 0: hb_barrier (); return_trace (reinterpret_cast (u.format0.copy (c))); case 1: hb_barrier (); return_trace (reinterpret_cast (u.format1.copy (c))); default:return_trace (nullptr); @@ -3722,12 +3804,12 @@ struct DeltaSetIndexMap protected: union { - HBUINT8 format; /* Format identifier */ + struct { HBUINT8 v; } format; /* Format identifier */ DeltaSetIndexMapFormat01 format0; DeltaSetIndexMapFormat01 format1; } u; public: - DEFINE_SIZE_UNION (1, format); + DEFINE_SIZE_UNION (1, format.v); }; @@ -3736,7 +3818,7 @@ struct ItemVarStoreInstancer ItemVarStoreInstancer (const ItemVariationStore *varStore_, const DeltaSetIndexMap *varIdxMap, hb_array_t coords, - VarRegionList::cache_t *cache = nullptr) : + hb_scalar_cache_t *cache = nullptr) : varStore (varStore_), varIdxMap (varIdxMap), coords (coords), cache (cache) { if (!varStore) @@ -3762,7 +3844,7 @@ struct ItemVarStoreInstancer const ItemVariationStore *varStore; const DeltaSetIndexMap *varIdxMap; hb_array_t coords; - VarRegionList::cache_t *cache; + hb_scalar_cache_t *cache; }; struct MultiItemVarStoreInstancer @@ -3770,7 +3852,7 @@ struct MultiItemVarStoreInstancer MultiItemVarStoreInstancer (const MultiItemVariationStore *varStore, const DeltaSetIndexMap *varIdxMap, hb_array_t coords, - SparseVarRegionList::cache_t *cache = nullptr) : + hb_scalar_cache_t *cache = nullptr) : varStore (varStore), varIdxMap (varIdxMap), coords (coords), cache (cache) { if (!varStore) @@ -3803,7 +3885,7 @@ struct MultiItemVarStoreInstancer const MultiItemVariationStore *varStore; const DeltaSetIndexMap *varIdxMap; hb_array_t coords; - SparseVarRegionList::cache_t *cache; + hb_scalar_cache_t *cache; }; @@ -4130,7 +4212,7 @@ struct Condition bool evaluate (const int *coords, unsigned int coord_len, Instancer *instancer) const { - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return u.format1.evaluate (coords, coord_len, instancer); case 2: hb_barrier (); return u.format2.evaluate (coords, coord_len, instancer); case 3: hb_barrier (); return u.format3.evaluate (coords, coord_len, instancer); @@ -4143,7 +4225,7 @@ struct Condition Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c, hb_map_t *condition_map /* OUT */) const { - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return u.format1.keep_with_variations (c, condition_map); // TODO(subset) default: c->apply = false; return KEEP_COND_WITH_VAR; @@ -4153,9 +4235,9 @@ struct Condition template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...)); @@ -4168,9 +4250,9 @@ struct Condition bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return_trace (false); + if (!u.format.v.sanitize (c)) return_trace (false); hb_barrier (); - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return_trace (u.format1.sanitize (c)); case 2: hb_barrier (); return_trace (u.format2.sanitize (c)); case 3: hb_barrier (); return_trace (u.format3.sanitize (c)); @@ -4182,7 +4264,7 @@ struct Condition protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ ConditionAxisRange format1; ConditionValue format2; ConditionAnd format3; @@ -4190,7 +4272,7 @@ struct Condition ConditionNegate format5; } u; public: - DEFINE_SIZE_UNION (2, format); + DEFINE_SIZE_UNION (2, format.v); }; template @@ -4353,7 +4435,7 @@ struct FeatureTableSubstitutionRecord if (unlikely (!s->extend_min (this))) return_trace (false); uint32_t *new_feature_idx; - if (!c->feature_index_map->has (feature_index, &new_feature_idx)) + if (!c->feature_map_w_duplicates->has (feature_index, &new_feature_idx)) return_trace (false); if (!s->check_assign (featureIndex, *new_feature_idx, HB_SERIALIZE_ERROR_INT_OVERFLOW)) @@ -4371,7 +4453,7 @@ struct FeatureTableSubstitutionRecord { TRACE_SUBSET (this); uint32_t *new_feature_index; - if (!c->feature_index_map->has (featureIndex, &new_feature_index)) + if (!c->feature_map_w_duplicates->has (featureIndex, &new_feature_index)) return_trace (false); auto *out = c->subset_context->serializer->embed (this); @@ -4645,7 +4727,7 @@ struct FeatureVariations int keep_up_to = -1; for (int i = varRecords.len - 1; i >= 0; i--) { - if (varRecords[i].intersects_features (this, l->feature_index_map)) { + if (varRecords[i].intersects_features (this, l->feature_map_w_duplicates)) { keep_up_to = i; break; } @@ -4783,13 +4865,13 @@ struct VariationDevice hb_position_t get_x_delta (hb_font_t *font, const ItemVariationStore &store, - ItemVariationStore::cache_t *store_cache = nullptr) const - { return !font->num_coords ? 0 : font->em_scalef_x (get_delta (font, store, store_cache)); } + hb_scalar_cache_t *store_cache = nullptr) const + { return !font->has_nonzero_coords ? 0 : font->em_scalef_x (get_delta (font, store, store_cache)); } hb_position_t get_y_delta (hb_font_t *font, const ItemVariationStore &store, - ItemVariationStore::cache_t *store_cache = nullptr) const - { return !font->num_coords ? 0 : font->em_scalef_y (get_delta (font, store, store_cache)); } + hb_scalar_cache_t *store_cache = nullptr) const + { return !font->has_nonzero_coords ? 0 : font->em_scalef_y (get_delta (font, store, store_cache)); } VariationDevice* copy (hb_serialize_context_t *c, const hb_hashmap_t> *layout_variation_idx_delta_map) const @@ -4823,9 +4905,9 @@ struct VariationDevice float get_delta (hb_font_t *font, const ItemVariationStore &store, - ItemVariationStore::cache_t *store_cache = nullptr) const + hb_scalar_cache_t *store_cache = nullptr) const { - return store.get_delta (varIdx, font->coords, font->num_coords, (ItemVariationStore::cache_t *) store_cache); + return store.get_delta (varIdx, font->coords, font->num_coords, store_cache); } protected: @@ -4850,7 +4932,7 @@ struct Device { hb_position_t get_x_delta (hb_font_t *font, const ItemVariationStore &store=Null (ItemVariationStore), - ItemVariationStore::cache_t *store_cache = nullptr) const + hb_scalar_cache_t *store_cache = nullptr) const { switch (u.b.format) { @@ -4868,7 +4950,7 @@ struct Device } hb_position_t get_y_delta (hb_font_t *font, const ItemVariationStore &store=Null (ItemVariationStore), - ItemVariationStore::cache_t *store_cache = nullptr) const + hb_scalar_cache_t *store_cache = nullptr) const { switch (u.b.format) { @@ -4954,6 +5036,18 @@ struct Device } } + bool is_variation_device () const + { + switch (u.b.format) { +#ifndef HB_NO_VAR + case 0x8000: + return true; +#endif + default: + return false; + } + } + protected: union { DeviceHeader b; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gpos-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gpos-table.hh index 0cfa139a260..f6aabc84ac9 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gpos-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gpos-table.hh @@ -63,12 +63,20 @@ inline bool PosLookup::dispatch_recurse_func (hb_ot_apply c->set_lookup_index (lookup_index); c->set_lookup_props (l.get_props ()); + uint32_t stack_match_positions[8]; + hb_vector_t saved_match_positions; + saved_match_positions.set_storage (stack_match_positions); + hb_swap (c->match_positions, saved_match_positions); + bool ret = false; auto *accel = gpos->get_accel (lookup_index); - ret = accel && accel->apply (c, l.get_subtable_count (), false); + ret = accel && accel->apply (c, false); c->set_lookup_index (saved_lookup_index); c->set_lookup_props (saved_lookup_props); + + hb_swap (c->match_positions, saved_match_positions); + return ret; } #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsub-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsub-table.hh index fd8a68be02d..8d5e1f18638 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsub-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsub-table.hh @@ -76,12 +76,20 @@ inline bool SubstLookup::dispatch_recurse_func (hb_ot_app c->set_lookup_index (lookup_index); c->set_lookup_props (l.get_props ()); + uint32_t stack_match_positions[8]; + hb_vector_t saved_match_positions; + saved_match_positions.set_storage (stack_match_positions); + hb_swap (c->match_positions, saved_match_positions); + bool ret = false; auto *accel = gsub->get_accel (lookup_index); - ret = accel && accel->apply (c, l.get_subtable_count (), false); + ret = accel && accel->apply (c, false); c->set_lookup_index (saved_lookup_index); c->set_lookup_props (saved_lookup_props); + + hb_swap (c->match_positions, saved_match_positions); + return ret; } #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh index 072e5cdba26..05bbf3395bf 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh @@ -397,303 +397,311 @@ struct hb_collect_coverage_context_t : set_t *set; }; -struct hb_ot_apply_context_t : - hb_dispatch_context_t +struct matcher_t { - struct matcher_t + typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data); + + template + void init (const context_t *c, bool context_match = false) { - typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data); + set_match_func (nullptr, nullptr); + lookup_props = c->lookup_props; + /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */ + ignore_zwnj = c->table_index == 1 || (context_match && c->auto_zwnj); + /* Ignore ZWJ if we are matching context, or asked to. */ + ignore_zwj = context_match || c->auto_zwj; + /* Ignore hidden glyphs (like CGJ) during GPOS. */ + ignore_hidden = c->table_index == 1; + mask = context_match ? -1 : c->lookup_mask; + /* Per syllable matching is only for GSUB. */ + per_syllable = c->table_index == 0 && c->per_syllable; + syllable = 0; + } - void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; } - void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; } - void set_ignore_hidden (bool ignore_hidden_) { ignore_hidden = ignore_hidden_; } - void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } - void set_mask (hb_mask_t mask_) { mask = mask_; } - void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; } - void set_syllable (uint8_t syllable_) { syllable = per_syllable ? syllable_ : 0; } - void set_match_func (match_func_t match_func_, - const void *match_data_) - { match_func = match_func_; match_data = match_data_; } + void set_match_func (match_func_t match_func_, + const void *match_data_) + { match_func = match_func_; match_data = match_data_; } - enum may_match_t { - MATCH_NO, - MATCH_YES, - MATCH_MAYBE - }; - -#ifndef HB_OPTIMIZE_SIZE - HB_ALWAYS_INLINE -#endif - may_match_t may_match (hb_glyph_info_t &info, - hb_codepoint_t glyph_data) const - { - if (!(info.mask & mask) || - (syllable && syllable != info.syllable ())) - return MATCH_NO; - - if (match_func) - return match_func (info, glyph_data, match_data) ? MATCH_YES : MATCH_NO; - - return MATCH_MAYBE; - } - - enum may_skip_t { - SKIP_NO, - SKIP_YES, - SKIP_MAYBE - }; - -#ifndef HB_OPTIMIZE_SIZE - HB_ALWAYS_INLINE -#endif - may_skip_t may_skip (const hb_ot_apply_context_t *c, - const hb_glyph_info_t &info) const - { - if (!c->check_glyph_property (&info, lookup_props)) - return SKIP_YES; - - if (unlikely (_hb_glyph_info_is_default_ignorable (&info) && - (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) && - (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) && - (ignore_hidden || !_hb_glyph_info_is_hidden (&info)))) - return SKIP_MAYBE; - - return SKIP_NO; - } - - protected: - unsigned int lookup_props = 0; - hb_mask_t mask = -1; - bool ignore_zwnj = false; - bool ignore_zwj = false; - bool ignore_hidden = false; - bool per_syllable = false; - uint8_t syllable = 0; - match_func_t match_func = nullptr; - const void *match_data = nullptr; + enum may_match_t { + MATCH_NO, + MATCH_YES, + MATCH_MAYBE }; - struct skipping_iterator_t +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif + may_match_t may_match (hb_glyph_info_t &info, + hb_codepoint_t glyph_data) const { - void init (hb_ot_apply_context_t *c_, bool context_match = false) - { - c = c_; - end = c->buffer->len; - match_glyph_data16 = nullptr; + if (!(info.mask & mask) || + (per_syllable && syllable && syllable != info.syllable ())) + return MATCH_NO; + + if (match_func) + return match_func (info, glyph_data, match_data) ? MATCH_YES : MATCH_NO; + + return MATCH_MAYBE; + } + + enum may_skip_t { + SKIP_NO, + SKIP_YES, + SKIP_MAYBE + }; + + template +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif + may_skip_t may_skip (const context_t *c, + const hb_glyph_info_t &info) const + { + if (!c->check_glyph_property (&info, lookup_props)) + return SKIP_YES; + + if (unlikely (_hb_glyph_info_is_default_ignorable (&info) && + (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) && + (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) && + (ignore_hidden || !_hb_glyph_info_is_hidden (&info)))) + return SKIP_MAYBE; + + return SKIP_NO; + } + + public: + unsigned int lookup_props = 0; + hb_mask_t mask = -1; + bool ignore_zwnj = false; + bool ignore_zwj = false; + bool ignore_hidden = false; + bool per_syllable = false; + uint8_t syllable = 0; + match_func_t match_func = nullptr; + const void *match_data = nullptr; +}; + +template +struct skipping_iterator_t +{ + void init (context_t *c_, bool context_match = false) + { + c = c_; + end = c->buffer->len; + match_glyph_data16 = nullptr; #ifndef HB_NO_BEYOND_64K - match_glyph_data24 = nullptr; + match_glyph_data24 = nullptr; #endif - matcher.set_match_func (nullptr, nullptr); - matcher.set_lookup_props (c->lookup_props); - /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */ - matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj)); - /* Ignore ZWJ if we are matching context, or asked to. */ - matcher.set_ignore_zwj (context_match || c->auto_zwj); - /* Ignore hidden glyphs (like CGJ) during GPOS. */ - matcher.set_ignore_hidden (c->table_index == 1); - matcher.set_mask (context_match ? -1 : c->lookup_mask); - /* Per syllable matching is only for GSUB. */ - matcher.set_per_syllable (c->table_index == 0 && c->per_syllable); - matcher.set_syllable (0); - } - void set_lookup_props (unsigned int lookup_props) - { - matcher.set_lookup_props (lookup_props); - } - void set_match_func (matcher_t::match_func_t match_func_, - const void *match_data_) - { - matcher.set_match_func (match_func_, match_data_); - } - void set_glyph_data (const HBUINT16 glyph_data[]) - { - match_glyph_data16 = glyph_data; + matcher.init (c, context_match); + } + void set_lookup_props (unsigned int lookup_props) + { + matcher.lookup_props = lookup_props; + } + void set_match_func (matcher_t::match_func_t match_func_, + const void *match_data_) + { + matcher.set_match_func (match_func_, match_data_); + } + void set_glyph_data (const HBUINT16 glyph_data[]) + { + match_glyph_data16 = glyph_data; #ifndef HB_NO_BEYOND_64K - match_glyph_data24 = nullptr; + match_glyph_data24 = nullptr; #endif - } + } #ifndef HB_NO_BEYOND_64K - void set_glyph_data (const HBUINT24 glyph_data[]) - { - match_glyph_data16 = nullptr; - match_glyph_data24 = glyph_data; - } + void set_glyph_data (const HBUINT24 glyph_data[]) + { + match_glyph_data16 = nullptr; + match_glyph_data24 = glyph_data; + } #endif #ifndef HB_OPTIMIZE_SIZE - HB_ALWAYS_INLINE + HB_ALWAYS_INLINE #endif - void reset (unsigned int start_index_) - { - idx = start_index_; - end = c->buffer->len; - matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); - } - -#ifndef HB_OPTIMIZE_SIZE - HB_ALWAYS_INLINE -#endif - void reset_fast (unsigned int start_index_) - { - // Doesn't set end or syllable. Used by GPOS which doesn't care / change. - idx = start_index_; - } - - void reject () - { - backup_glyph_data (); - } - - matcher_t::may_skip_t -#ifndef HB_OPTIMIZE_SIZE - HB_ALWAYS_INLINE -#endif - may_skip (const hb_glyph_info_t &info) const - { return matcher.may_skip (c, info); } - - enum match_t { - MATCH, - NOT_MATCH, - SKIP - }; - -#ifndef HB_OPTIMIZE_SIZE - HB_ALWAYS_INLINE -#endif - match_t match (hb_glyph_info_t &info) - { - matcher_t::may_skip_t skip = matcher.may_skip (c, info); - if (unlikely (skip == matcher_t::SKIP_YES)) - return SKIP; - - matcher_t::may_match_t match = matcher.may_match (info, get_glyph_data ()); - if (match == matcher_t::MATCH_YES || - (match == matcher_t::MATCH_MAYBE && - skip == matcher_t::SKIP_NO)) - return MATCH; - - if (skip == matcher_t::SKIP_NO) - return NOT_MATCH; - - return SKIP; + void reset (unsigned int start_index_) + { + // For GSUB forward iterator + idx = start_index_; + end = c->buffer->len; + matcher.syllable = c->buffer->cur().syllable(); + } + void reset_back (unsigned int start_index_, bool from_out_buffer = false) + { + // For GSUB backward iterator + idx = start_index_; + matcher.syllable = c->buffer->cur().syllable(); } #ifndef HB_OPTIMIZE_SIZE - HB_ALWAYS_INLINE + HB_ALWAYS_INLINE #endif - bool next (unsigned *unsafe_to = nullptr) - { - const signed stop = (signed) end - 1; - while ((signed) idx < stop) - { - idx++; - switch (match (c->buffer->info[idx])) - { - case MATCH: - { - advance_glyph_data (); - return true; - } - case NOT_MATCH: - { - if (unsafe_to) - *unsafe_to = idx + 1; - return false; - } - case SKIP: - continue; - } - } - if (unsafe_to) - *unsafe_to = end; - return false; - } + void reset_fast (unsigned int start_index_) + { + // Doesn't set end or syllable. Used by GPOS which doesn't care / change. + idx = start_index_; + } + #ifndef HB_OPTIMIZE_SIZE - HB_ALWAYS_INLINE + HB_ALWAYS_INLINE #endif - bool prev (unsigned *unsafe_from = nullptr) - { - const unsigned stop = 0; - while (idx > stop) - { - idx--; - switch (match (c->buffer->out_info[idx])) - { - case MATCH: - { - advance_glyph_data (); - return true; - } - case NOT_MATCH: - { - if (unsafe_from) - *unsafe_from = hb_max (1u, idx) - 1u; - return false; - } - case SKIP: - continue; - } - } - if (unsafe_from) - *unsafe_from = 0; - return false; - } + matcher_t::may_skip_t may_skip (const hb_glyph_info_t &info) const + { return matcher.may_skip (c, info); } - HB_ALWAYS_INLINE - hb_codepoint_t - get_glyph_data () - { - if (match_glyph_data16) return *match_glyph_data16; -#ifndef HB_NO_BEYOND_64K - else - if (match_glyph_data24) return *match_glyph_data24; -#endif - return 0; - } - HB_ALWAYS_INLINE - void - advance_glyph_data () - { - if (match_glyph_data16) match_glyph_data16++; -#ifndef HB_NO_BEYOND_64K - else - if (match_glyph_data24) match_glyph_data24++; -#endif - } - void - backup_glyph_data () - { - if (match_glyph_data16) match_glyph_data16--; -#ifndef HB_NO_BEYOND_64K - else - if (match_glyph_data24) match_glyph_data24--; -#endif - } - - unsigned int idx; - protected: - hb_ot_apply_context_t *c; - matcher_t matcher; - const HBUINT16 *match_glyph_data16; -#ifndef HB_NO_BEYOND_64K - const HBUINT24 *match_glyph_data24; -#endif - - unsigned int end; + enum match_t { + MATCH, + NOT_MATCH, + SKIP }; +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif + match_t match (hb_glyph_info_t &info) + { + matcher_t::may_skip_t skip = matcher.may_skip (c, info); + if (unlikely (skip == matcher_t::SKIP_YES)) + return SKIP; + matcher_t::may_match_t match = matcher.may_match (info, get_glyph_data ()); + if (match == matcher_t::MATCH_YES || + (match == matcher_t::MATCH_MAYBE && + skip == matcher_t::SKIP_NO)) + return MATCH; + + if (skip == matcher_t::SKIP_NO) + return NOT_MATCH; + + return SKIP; + } + +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif + bool next (unsigned *unsafe_to = nullptr) + { + auto *info = c->buffer->info; + const signed stop = (signed) end - 1; + while ((signed) idx < stop) + { + idx++; + switch (match (info[idx])) + { + case MATCH: + { + advance_glyph_data (); + return true; + } + case NOT_MATCH: + { + if (unsafe_to) + *unsafe_to = idx + 1; + return false; + } + case SKIP: + continue; + } + } + if (unsafe_to) + *unsafe_to = end; + return false; + } +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif + bool prev (unsigned *unsafe_from = nullptr) + { + auto *out_info = c->buffer->out_info; + const unsigned stop = 0; + while (idx > stop) + { + idx--; + switch (match (out_info[idx])) + { + case MATCH: + { + advance_glyph_data (); + return true; + } + case NOT_MATCH: + { + if (unsafe_from) + *unsafe_from = hb_max (1u, idx) - 1u; + return false; + } + case SKIP: + continue; + } + } + if (unsafe_from) + *unsafe_from = 0; + return false; + } + + HB_ALWAYS_INLINE + hb_codepoint_t + get_glyph_data () + { + if (match_glyph_data16) return *match_glyph_data16; +#ifndef HB_NO_BEYOND_64K + else + if (match_glyph_data24) return *match_glyph_data24; +#endif + return 0; + } + HB_ALWAYS_INLINE + void + advance_glyph_data () + { + if (match_glyph_data16) match_glyph_data16++; +#ifndef HB_NO_BEYOND_64K + else + if (match_glyph_data24) match_glyph_data24++; +#endif + } + + unsigned int idx; + protected: + context_t *c; + matcher_t matcher; + const HBUINT16 *match_glyph_data16; +#ifndef HB_NO_BEYOND_64K + const HBUINT24 *match_glyph_data24; +#endif + + unsigned int end; +}; + +struct hb_ot_apply_context_t : + hb_dispatch_context_t +{ const char *get_name () { return "APPLY"; } typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index); + template - return_t dispatch (const T &obj) { return obj.apply (this); } + static inline auto apply_ (const T &obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (return_t, obj.apply (c, nullptr) ) + template + static inline auto apply_ (const T &obj, hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (return_t, obj.apply (c) ) + template + return_t dispatch (const T &obj) { return apply_(obj, this, hb_prioritize); } + static return_t default_return_value () { return false; } bool stop_sublookup_iteration (return_t r) const { return r; } return_t recurse (unsigned int sub_lookup_index) { - if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0)) + assert (recurse_func); + if (unlikely (nesting_level_left == 0)) { - buffer->shaping_failed = true; + buffer->successful = false; + return default_return_value (); + } + + buffer->max_ops--; + if (unlikely (buffer->max_ops < 0)) + { + buffer->successful = false; return default_return_value (); } @@ -703,7 +711,7 @@ struct hb_ot_apply_context_t : return ret; } - skipping_iterator_t iter_input, iter_context; + skipping_iterator_t iter_input, iter_context; unsigned int table_index; /* GSUB/GPOS */ hb_font_t *font; @@ -715,8 +723,7 @@ struct hb_ot_apply_context_t : const GDEF::accelerator_t &gdef_accel; const hb_ot_layout_lookup_accelerator_t *lookup_accel = nullptr; const ItemVariationStore &var_store; - ItemVariationStore::cache_t *var_store_cache; - hb_set_digest_t digest; + hb_scalar_cache_t *var_store_cache; hb_direction_t direction; hb_mask_t lookup_mask = 1; @@ -734,11 +741,14 @@ struct hb_ot_apply_context_t : signed last_base = -1; // GPOS uses unsigned last_base_until = 0; // GPOS uses + hb_vector_t match_positions; + uint32_t stack_match_positions[8]; + hb_ot_apply_context_t (unsigned int table_index_, hb_font_t *font_, hb_buffer_t *buffer_, hb_blob_t *table_blob_, - ItemVariationStore::cache_t *var_store_cache_ = nullptr) : + hb_scalar_cache_t *var_store_cache_ = nullptr) : table_index (table_index_), font (font_), face (font->face), buffer (buffer_), sanitizer (table_blob_), @@ -762,7 +772,7 @@ struct hb_ot_apply_context_t : has_glyph_classes (gdef.has_glyph_classes ()) { init_iters (); - buffer->collect_codepoints (digest); + match_positions.set_storage (stack_match_positions); } void init_iters () @@ -778,7 +788,11 @@ struct hb_ot_apply_context_t : void set_random (bool random_) { random = random_; } void set_recurse_func (recurse_func_t func) { recurse_func = func; } void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; } - void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); } + void set_lookup_props (unsigned int lookup_props_) + { + lookup_props = gdef_accel.sanitize_lookup_props (lookup_props_); + init_iters (); + } uint32_t random_number () { @@ -787,7 +801,9 @@ struct hb_ot_apply_context_t : return buffer->random_state; } - bool match_properties_mark (hb_codepoint_t glyph, + HB_ALWAYS_INLINE + HB_HOT + bool match_properties_mark (const hb_glyph_info_t *info, unsigned int glyph_props, unsigned int match_props) const { @@ -795,7 +811,7 @@ struct hb_ot_apply_context_t : * match_props has the set index. */ if (match_props & LookupFlag::UseMarkFilteringSet) - return gdef_accel.mark_set_covers (match_props >> 16, glyph); + return gdef_accel.mark_set_covers (match_props >> 16, info->codepoint); /* The second byte of match_props has the meaning * "ignore marks of attachment type different than @@ -811,7 +827,7 @@ struct hb_ot_apply_context_t : HB_ALWAYS_INLINE #endif bool check_glyph_property (const hb_glyph_info_t *info, - unsigned int match_props) const + unsigned match_props) const { unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info); @@ -821,8 +837,8 @@ struct hb_ot_apply_context_t : if (glyph_props & match_props & LookupFlag::IgnoreFlags) return false; - if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) - return match_properties_mark (info->codepoint, glyph_props, match_props); + if (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK) + return match_properties_mark (info, glyph_props, match_props); return true; } @@ -832,7 +848,7 @@ struct hb_ot_apply_context_t : bool ligature = false, bool component = false) { - digest.add (glyph_index); + buffer->digest.add (glyph_index); if (new_syllables != (unsigned) -1) buffer->cur().syllable() = new_syllables; @@ -890,54 +906,58 @@ struct hb_ot_apply_context_t : } }; -enum class hb_ot_lookup_cache_op_t +enum class hb_ot_subtable_cache_op_t { - CREATE, ENTER, LEAVE, - DESTROY, }; struct hb_accelerate_subtables_context_t : hb_dispatch_context_t { - template - static inline bool apply_to (const void *obj, hb_ot_apply_context_t *c) + template + static inline auto apply_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<1>) HB_RETURN (bool, obj->apply (c, external_cache) ) + template + static inline auto apply_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<0>) HB_RETURN (bool, obj->apply (c) ) + template + static inline bool apply_to (const void *obj, hb_ot_apply_context_t *c, void *external_cache) { - const Type *typed_obj = (const Type *) obj; - return typed_obj->apply (c); + const T *typed_obj = (const T *) obj; + return apply_ (typed_obj, c, external_cache, hb_prioritize); } #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE template - static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply_cached (c) ) + static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<2>) HB_RETURN (bool, obj->apply_cached (c, external_cache) ) template - static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (bool, obj->apply (c) ) - template - static inline bool apply_cached_to (const void *obj, hb_ot_apply_context_t *c) + static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<1>) HB_RETURN (bool, obj->apply (c, external_cache) ) + template + static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<0>) HB_RETURN (bool, obj->apply (c) ) + template + static inline bool apply_cached_to (const void *obj, hb_ot_apply_context_t *c, void *external_cache) { - const Type *typed_obj = (const Type *) obj; - return apply_cached_ (typed_obj, c, hb_prioritize); + const T *typed_obj = (const T *) obj; + return apply_cached_ (typed_obj, c, external_cache, hb_prioritize); } template - static inline auto cache_func_ (void *p, - hb_ot_lookup_cache_op_t op, - hb_priority<1>) HB_RETURN (void *, T::cache_func (p, op) ) + static inline auto cache_func_ (hb_ot_apply_context_t *c, + hb_ot_subtable_cache_op_t op, + hb_priority<1>) HB_RETURN (bool, T::cache_func (c, op) ) template - static inline void * cache_func_ (void *p, - hb_ot_lookup_cache_op_t op HB_UNUSED, - hb_priority<0>) { return (void *) false; } + static inline bool cache_func_ (hb_ot_apply_context_t *c, + hb_ot_subtable_cache_op_t op HB_UNUSED, + hb_priority<0>) { return false; } template - static inline void * cache_func_to (void *p, - hb_ot_lookup_cache_op_t op) + static inline bool cache_func_to (hb_ot_apply_context_t *c, + hb_ot_subtable_cache_op_t op) { - return cache_func_ (p, op, hb_prioritize); + return cache_func_ (c, op, hb_prioritize); } #endif - typedef bool (*hb_apply_func_t) (const void *obj, hb_ot_apply_context_t *c); - typedef void * (*hb_cache_func_t) (void *p, hb_ot_lookup_cache_op_t op); + typedef bool (*hb_apply_func_t) (const void *obj, hb_ot_apply_context_t *c, void *external_cache); + typedef bool (*hb_cache_func_t) (hb_ot_apply_context_t *c, hb_ot_subtable_cache_op_t op); struct hb_applicable_t { @@ -950,6 +970,7 @@ struct hb_accelerate_subtables_context_t : #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE , hb_apply_func_t apply_cached_func_ , hb_cache_func_t cache_func_ + , void *external_cache_ #endif ) { @@ -958,27 +979,34 @@ struct hb_accelerate_subtables_context_t : #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE apply_cached_func = apply_cached_func_; cache_func = cache_func_; + external_cache = external_cache_; #endif digest.init (); obj_.get_coverage ().collect_coverage (&digest); } +#ifdef HB_NO_OT_LAYOUT_LOOKUP_CACHE bool apply (hb_ot_apply_context_t *c) const { - return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c); + return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c, nullptr); + } +#else + bool apply (hb_ot_apply_context_t *c) const + { + return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c, external_cache); } -#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE bool apply_cached (hb_ot_apply_context_t *c) const { - return digest.may_have (c->buffer->cur().codepoint) && apply_cached_func (obj, c); + return digest.may_have (c->buffer->cur().codepoint) && apply_cached_func (obj, c, external_cache); } + bool cache_enter (hb_ot_apply_context_t *c) const { - return (bool) cache_func (c, hb_ot_lookup_cache_op_t::ENTER); + return cache_func (c, hb_ot_subtable_cache_op_t::ENTER); } void cache_leave (hb_ot_apply_context_t *c) const { - cache_func (c, hb_ot_lookup_cache_op_t::LEAVE); + cache_func (c, hb_ot_subtable_cache_op_t::LEAVE); } #endif @@ -988,6 +1016,7 @@ struct hb_accelerate_subtables_context_t : #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE hb_apply_func_t apply_cached_func; hb_cache_func_t cache_func; + void *external_cache; #endif hb_set_digest_t digest; }; @@ -997,12 +1026,23 @@ struct hb_accelerate_subtables_context_t : auto cache_cost (const T &obj, hb_priority<1>) HB_AUTO_RETURN ( obj.cache_cost () ) template auto cache_cost (const T &obj, hb_priority<0>) HB_AUTO_RETURN ( 0u ) + + template + auto external_cache_create (const T &obj, hb_priority<1>) HB_AUTO_RETURN ( obj.external_cache_create () ) + template + auto external_cache_create (const T &obj, hb_priority<0>) HB_AUTO_RETURN ( nullptr ) #endif /* Dispatch interface. */ template return_t dispatch (const T &obj) { +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + void *external_cache = nullptr; + if (i < 8) + external_cache = external_cache_create (obj, hb_prioritize); +#endif + hb_applicable_t *entry = &array[i++]; entry->init (obj, @@ -1010,6 +1050,7 @@ struct hb_accelerate_subtables_context_t : #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE , apply_cached_to , cache_func_to + , external_cache #endif ); @@ -1023,10 +1064,10 @@ struct hb_accelerate_subtables_context_t : * and we allocate the cache opportunity to the costliest subtable. */ unsigned cost = cache_cost (obj, hb_prioritize); - if (cost > cache_user_cost) + if (cost > subtable_cache_user_cost) { - cache_user_idx = i - 1; - cache_user_cost = cost; + subtable_cache_user_idx = i - 1; + subtable_cache_user_cost = cost; } #endif @@ -1041,8 +1082,8 @@ struct hb_accelerate_subtables_context_t : unsigned i = 0; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - unsigned cache_user_idx = (unsigned) -1; - unsigned cache_user_cost = 0; + unsigned subtable_cache_user_idx = (unsigned) -1; + unsigned subtable_cache_user_cost = 0; #endif }; @@ -1191,38 +1232,50 @@ static inline bool match_class (hb_glyph_info_t &info, unsigned value, const voi const ClassDef &class_def = *reinterpret_cast(data); return class_def.get_class (info.codepoint) == value; } -static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, const void *data) +static inline unsigned get_class_cached (const ClassDef &class_def, hb_glyph_info_t &info) { unsigned klass = info.syllable(); if (klass < 255) - return klass == value; - const ClassDef &class_def = *reinterpret_cast(data); + return klass; klass = class_def.get_class (info.codepoint); if (likely (klass < 255)) info.syllable() = klass; - return klass == value; + return klass; } -static inline bool match_class_cached1 (hb_glyph_info_t &info, unsigned value, const void *data) +static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, const void *data) +{ + const ClassDef &class_def = *reinterpret_cast(data); + return get_class_cached (class_def, info) == value; +} +static inline unsigned get_class_cached1 (const ClassDef &class_def, hb_glyph_info_t &info) { unsigned klass = info.syllable() & 0x0F; if (klass < 15) - return klass == value; - const ClassDef &class_def = *reinterpret_cast(data); + return klass; klass = class_def.get_class (info.codepoint); if (likely (klass < 15)) info.syllable() = (info.syllable() & 0xF0) | klass; - return klass == value; + return klass; } -static inline bool match_class_cached2 (hb_glyph_info_t &info, unsigned value, const void *data) +static inline bool match_class_cached1 (hb_glyph_info_t &info, unsigned value, const void *data) +{ + const ClassDef &class_def = *reinterpret_cast(data); + return get_class_cached1 (class_def, info) == value; +} +static inline unsigned get_class_cached2 (const ClassDef &class_def, hb_glyph_info_t &info) { unsigned klass = (info.syllable() & 0xF0) >> 4; if (klass < 15) - return klass == value; - const ClassDef &class_def = *reinterpret_cast(data); + return klass; klass = class_def.get_class (info.codepoint); if (likely (klass < 15)) info.syllable() = (info.syllable() & 0x0F) | (klass << 4); - return klass == value; + return klass; +} +static inline bool match_class_cached2 (hb_glyph_info_t &info, unsigned value, const void *data) +{ + const ClassDef &class_def = *reinterpret_cast(data); + return get_class_cached2 (class_def, info) == value; } static inline bool match_coverage (hb_glyph_info_t &info, unsigned value, const void *data) { @@ -1261,16 +1314,24 @@ static bool match_input (hb_ot_apply_context_t *c, match_func_t match_func, const void *match_data, unsigned int *end_position, - unsigned int *match_positions, unsigned int *p_total_component_count = nullptr) { TRACE_APPLY (nullptr); - if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false); - hb_buffer_t *buffer = c->buffer; - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + if (count == 1) + { + *end_position = buffer->idx + 1; + c->match_positions[0] = buffer->idx; + if (p_total_component_count) + *p_total_component_count = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); + return_trace (true); + } + + if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false); + + auto &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx); skippy_iter.set_match_func (match_func, match_data); skippy_iter.set_glyph_data (input); @@ -1319,7 +1380,10 @@ static bool match_input (hb_ot_apply_context_t *c, return_trace (false); } - match_positions[i] = skippy_iter.idx; + if (unlikely (i + 1 > c->match_positions.length && + !c->match_positions.resize_dirty (i + 1))) + return_trace (false); + c->match_positions.arrayZ[i] = skippy_iter.idx; unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]); unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]); @@ -1349,7 +1413,7 @@ static bool match_input (hb_ot_apply_context_t *c, j--; } - if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES) + if (found && skippy_iter.may_skip (out[j]) == matcher_t::SKIP_YES) ligbase = LIGBASE_MAY_SKIP; else ligbase = LIGBASE_MAY_NOT_SKIP; @@ -1379,13 +1443,12 @@ static bool match_input (hb_ot_apply_context_t *c, *p_total_component_count = total_component_count; } - match_positions[0] = buffer->idx; + c->match_positions.arrayZ[0] = buffer->idx; return_trace (true); } static inline bool ligate_input (hb_ot_apply_context_t *c, unsigned int count, /* Including the first glyph */ - const unsigned int *match_positions, /* Including the first glyph */ unsigned int match_end, hb_codepoint_t lig_glyph, unsigned int total_component_count) @@ -1428,10 +1491,10 @@ static inline bool ligate_input (hb_ot_apply_context_t *c, * https://bugzilla.gnome.org/show_bug.cgi?id=437633 */ - bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]); - bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]); + bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[c->match_positions.arrayZ[0]]); + bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[c->match_positions.arrayZ[0]]); for (unsigned int i = 1; i < count; i++) - if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]])) + if (!_hb_glyph_info_is_mark (&buffer->info[c->match_positions.arrayZ[i]])) { is_base_ligature = false; is_mark_ligature = false; @@ -1457,7 +1520,7 @@ static inline bool ligate_input (hb_ot_apply_context_t *c, for (unsigned int i = 1; i < count; i++) { - while (buffer->idx < match_positions[i] && buffer->successful) + while (buffer->idx < c->match_positions.arrayZ[i] && buffer->successful) { if (is_ligature) { @@ -1512,8 +1575,14 @@ static bool match_backtrack (hb_ot_apply_context_t *c, { TRACE_APPLY (nullptr); - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context; - skippy_iter.reset (c->buffer->backtrack_len ()); + if (!count) + { + *match_start = c->buffer->backtrack_len (); + return_trace (true); + } + + auto &skippy_iter = c->iter_context; + skippy_iter.reset_back (c->buffer->backtrack_len ()); skippy_iter.set_match_func (match_func, match_data); skippy_iter.set_glyph_data (backtrack); @@ -1545,7 +1614,13 @@ static bool match_lookahead (hb_ot_apply_context_t *c, { TRACE_APPLY (nullptr); - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context; + if (!count) + { + *end_index = start_index; + return_trace (true); + } + + auto &skippy_iter = c->iter_context; assert (start_index >= 1); skippy_iter.reset (start_index - 1); skippy_iter.set_match_func (match_func, match_data); @@ -1696,7 +1771,6 @@ static inline void recurse_lookups (context_t *c, static inline void apply_lookup (hb_ot_apply_context_t *c, unsigned int count, /* Including the first glyph */ - unsigned int *match_positions, /* Including the first glyph */ unsigned int lookupCount, const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ unsigned int match_end) @@ -1704,9 +1778,6 @@ static inline void apply_lookup (hb_ot_apply_context_t *c, hb_buffer_t *buffer = c->buffer; int end; - unsigned int *match_positions_input = match_positions; - unsigned int match_positions_count = count; - /* All positions are distance from beginning of *output* buffer. * Adjust. */ { @@ -1716,7 +1787,7 @@ static inline void apply_lookup (hb_ot_apply_context_t *c, int delta = bl - buffer->idx; /* Convert positions to new indexing. */ for (unsigned int j = 0; j < count; j++) - match_positions[j] += delta; + c->match_positions.arrayZ[j] += delta; } for (unsigned int i = 0; i < lookupCount && buffer->successful; i++) @@ -1728,10 +1799,10 @@ static inline void apply_lookup (hb_ot_apply_context_t *c, unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len (); /* This can happen if earlier recursed lookups deleted many entries. */ - if (unlikely (match_positions[idx] >= orig_len)) + if (unlikely (c->match_positions.arrayZ[idx] >= orig_len)) continue; - if (unlikely (!buffer->move_to (match_positions[idx]))) + if (unlikely (!buffer->move_to (c->match_positions.arrayZ[idx]))) break; if (unlikely (buffer->max_ops <= 0)) @@ -1790,9 +1861,9 @@ static inline void apply_lookup (hb_ot_apply_context_t *c, */ end += delta; - if (end < int (match_positions[idx])) + if (end < int (c->match_positions.arrayZ[idx])) { - /* End might end up being smaller than match_positions[idx] if the recursed + /* End might end up being smaller than match_positions.arrayZ[idx] if the recursed * lookup ended up removing many items. * Just never rewind end beyond start of current position, since that is * not possible in the recursed lookup. Also adjust delta as such. @@ -1800,8 +1871,8 @@ static inline void apply_lookup (hb_ot_apply_context_t *c, * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 * https://github.com/harfbuzz/harfbuzz/issues/1611 */ - delta += match_positions[idx] - end; - end = match_positions[idx]; + delta += c->match_positions.arrayZ[idx] - end; + end = c->match_positions.arrayZ[idx]; } unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */ @@ -1810,27 +1881,9 @@ static inline void apply_lookup (hb_ot_apply_context_t *c, { if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH)) break; - if (unlikely (delta + count > match_positions_count)) - { - unsigned new_match_positions_count = hb_max (delta + count, hb_max(match_positions_count, 4u) * 1.5); - if (match_positions == match_positions_input) - { - match_positions = (unsigned int *) hb_malloc (new_match_positions_count * sizeof (match_positions[0])); - if (unlikely (!match_positions)) - break; - memcpy (match_positions, match_positions_input, count * sizeof (match_positions[0])); - match_positions_count = new_match_positions_count; - } - else - { - unsigned int *new_match_positions = (unsigned int *) hb_realloc (match_positions, new_match_positions_count * sizeof (match_positions[0])); - if (unlikely (!new_match_positions)) - break; - match_positions = new_match_positions; - match_positions_count = new_match_positions_count; - } - } - + if (unlikely (count + delta > c->match_positions.length && + !c->match_positions.resize_dirty (count + delta))) + return; } else { @@ -1840,23 +1893,20 @@ static inline void apply_lookup (hb_ot_apply_context_t *c, } /* Shift! */ - memmove (match_positions + next + delta, match_positions + next, - (count - next) * sizeof (match_positions[0])); + memmove (c->match_positions + next + delta, c->match_positions + next, + (count - next) * sizeof (c->match_positions.arrayZ[0])); next += delta; count += delta; /* Fill in new entries. */ for (unsigned int j = idx + 1; j < next; j++) - match_positions[j] = match_positions[j - 1] + 1; + c->match_positions.arrayZ[j] = c->match_positions.arrayZ[j - 1] + 1; /* And fixup the rest. */ for (; next < count; next++) - match_positions[next] += delta; + c->match_positions.arrayZ[next] += delta; } - if (match_positions != match_positions_input) - hb_free (match_positions); - assert (end >= 0); (void) buffer->move_to (end); } @@ -1950,34 +2000,25 @@ static inline bool context_would_apply_lookup (hb_would_apply_context_t *c, } template -HB_ALWAYS_INLINE -static bool context_apply_lookup (hb_ot_apply_context_t *c, - unsigned int inputCount, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ - unsigned int lookupCount, - const LookupRecord lookupRecord[], - const ContextApplyLookupContext &lookup_context) +static inline bool context_apply_lookup (hb_ot_apply_context_t *c, + unsigned int inputCount, /* Including the first glyph (not matched) */ + const HBUINT input[], /* Array of input values--start with second glyph */ + unsigned int lookupCount, + const LookupRecord lookupRecord[], + const ContextApplyLookupContext &lookup_context) { if (unlikely (inputCount > HB_MAX_CONTEXT_LENGTH)) return false; - unsigned match_positions_stack[4]; - unsigned *match_positions = match_positions_stack; - if (unlikely (inputCount > ARRAY_LENGTH (match_positions_stack))) - { - match_positions = (unsigned *) hb_malloc (hb_max (inputCount, 1u) * sizeof (match_positions[0])); - if (unlikely (!match_positions)) - return false; - } unsigned match_end = 0; bool ret = false; if (match_input (c, inputCount, input, lookup_context.funcs.match, lookup_context.match_data, - &match_end, match_positions)) + &match_end)) { c->buffer->unsafe_to_break (c->buffer->idx, match_end); apply_lookup (c, - inputCount, match_positions, + inputCount, lookupCount, lookupRecord, match_end); ret = true; @@ -1988,12 +2029,34 @@ static bool context_apply_lookup (hb_ot_apply_context_t *c, ret = false; } - if (unlikely (match_positions != match_positions_stack)) - hb_free (match_positions); - return ret; } +static inline bool context_cache_func (hb_ot_apply_context_t *c, hb_ot_subtable_cache_op_t op) +{ + switch (op) + { + case hb_ot_subtable_cache_op_t::ENTER: + { + if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable)) + return false; + auto &info = c->buffer->info; + unsigned count = c->buffer->len; + for (unsigned i = 0; i < count; i++) + info[i].syllable() = 255; + c->new_syllables = 255; + return true; + } + case hb_ot_subtable_cache_op_t::LEAVE: + { + c->new_syllables = (unsigned) -1; + HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable); + break; + } + } + return false; +} + template struct Rule { @@ -2209,24 +2272,29 @@ struct RuleSet * * Replicated from LigatureSet::apply(). */ - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + /* We use the iter_context instead of iter_input, to avoid skipping + * default-ignorables and such. + * + * Related: https://github.com/harfbuzz/harfbuzz/issues/4813 + */ + auto &skippy_iter = c->iter_context; skippy_iter.reset (c->buffer->idx); skippy_iter.set_match_func (match_always, nullptr); skippy_iter.set_glyph_data ((HBUINT16 *) nullptr); - unsigned unsafe_to = (unsigned) -1, unsafe_to1 = 0, unsafe_to2 = 0; + unsigned unsafe_to = (unsigned) -1, unsafe_to1, unsafe_to2 = 0; hb_glyph_info_t *first = nullptr, *second = nullptr; bool matched = skippy_iter.next (); if (likely (matched)) { - first = &c->buffer->info[skippy_iter.idx]; - unsafe_to = skippy_iter.idx + 1; - if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])) { /* Can't use the fast path if eg. the next char is a default-ignorable * or other skippable. */ goto slow; } + + first = &c->buffer->info[skippy_iter.idx]; + unsafe_to1 = skippy_iter.idx + 1; } else { @@ -2242,8 +2310,15 @@ struct RuleSet ; } matched = skippy_iter.next (); - if (likely (matched && !skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))) + if (likely (matched)) { + if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])) + { + /* Can't use the fast path if eg. the next char is a default-ignorable + * or other skippable. */ + goto slow; + } + second = &c->buffer->info[skippy_iter.idx]; unsafe_to2 = skippy_iter.idx + 1; } @@ -2280,6 +2355,15 @@ struct RuleSet { if (unsafe_to == (unsigned) -1) unsafe_to = unsafe_to1; + + // Skip ahead to next possible first glyph match. + for (; i + 1 < num_rules; i++) + { + const auto &r2 = this+rule.arrayZ[i + 1]; + const auto &input2 = r2.inputZ; + if (r2.inputCount <= 1 || input2.arrayZ[0] != input.arrayZ[0]) + break; + } } } if (likely (unsafe_to != (unsigned) -1)) @@ -2622,46 +2706,37 @@ struct ContextFormat2_5 unsigned cache_cost () const { - unsigned c = (this+classDef).cost () * ruleSet.len; - return c >= 4 ? c : 0; + return (this+classDef).cost (); } - static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) + static bool cache_func (hb_ot_apply_context_t *c, hb_ot_subtable_cache_op_t op) { - switch (op) - { - case hb_ot_lookup_cache_op_t::CREATE: - return (void *) true; - case hb_ot_lookup_cache_op_t::ENTER: - { - hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p; - if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable)) - return (void *) false; - auto &info = c->buffer->info; - unsigned count = c->buffer->len; - for (unsigned i = 0; i < count; i++) - info[i].syllable() = 255; - c->new_syllables = 255; - return (void *) true; - } - case hb_ot_lookup_cache_op_t::LEAVE: - { - hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p; - c->new_syllables = (unsigned) -1; - HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable); - return nullptr; - } - case hb_ot_lookup_cache_op_t::DESTROY: - return nullptr; - } - return nullptr; + return context_cache_func (c, op); } - bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } - bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); } - bool _apply (hb_ot_apply_context_t *c, bool cached) const + struct external_cache_t + { + hb_ot_layout_binary_cache_t coverage; + }; + void *external_cache_create () const + { + external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t)); + if (likely (cache)) + { + cache->coverage.clear (); + } + return cache; + } + bool apply_cached (hb_ot_apply_context_t *c, void *external_cache) const { return _apply (c, true, external_cache); } + bool apply (hb_ot_apply_context_t *c, void *external_cache) const { return _apply (c, false, external_cache); } + bool _apply (hb_ot_apply_context_t *c, bool cached, void *external_cache) const { TRACE_APPLY (this); +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + external_cache_t *cache = (external_cache_t *) external_cache; + unsigned int index = (this+coverage).get_coverage_binary (c->buffer->cur().codepoint, cache ? &cache->coverage : nullptr); +#else unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); +#endif if (index == NOT_COVERED) return_trace (false); const ClassDef &class_def = this+classDef; @@ -2671,10 +2746,7 @@ struct ContextFormat2_5 &class_def }; - if (cached && c->buffer->cur().syllable() < 255) - index = c->buffer->cur().syllable (); - else - index = class_def.get_class (c->buffer->cur().codepoint); + index = cached ? get_class_cached (class_def, c->buffer->cur()) : class_def.get_class (c->buffer->cur().codepoint); const RuleSet &rule_set = this+ruleSet[index]; return_trace (rule_set.apply (c, lookup_context)); } @@ -2919,9 +2991,9 @@ struct Context template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...)); @@ -2935,7 +3007,7 @@ struct Context protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ ContextFormat1_4 format1; ContextFormat2_5 format2; ContextFormat3 format3; @@ -3069,27 +3141,18 @@ static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c } template -HB_ALWAYS_INLINE -static bool chain_context_apply_lookup (hb_ot_apply_context_t *c, - unsigned int backtrackCount, - const HBUINT backtrack[], - unsigned int inputCount, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ - unsigned int lookaheadCount, - const HBUINT lookahead[], - unsigned int lookupCount, - const LookupRecord lookupRecord[], - const ChainContextApplyLookupContext &lookup_context) +static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c, + unsigned int backtrackCount, + const HBUINT backtrack[], + unsigned int inputCount, /* Including the first glyph (not matched) */ + const HBUINT input[], /* Array of input values--start with second glyph */ + unsigned int lookaheadCount, + const HBUINT lookahead[], + unsigned int lookupCount, + const LookupRecord lookupRecord[], + const ChainContextApplyLookupContext &lookup_context) { if (unlikely (inputCount > HB_MAX_CONTEXT_LENGTH)) return false; - unsigned match_positions_stack[4]; - unsigned *match_positions = match_positions_stack; - if (unlikely (inputCount > ARRAY_LENGTH (match_positions_stack))) - { - match_positions = (unsigned *) hb_malloc (hb_max (inputCount, 1u) * sizeof (match_positions[0])); - if (unlikely (!match_positions)) - return false; - } unsigned start_index = c->buffer->out_len; unsigned end_index = c->buffer->idx; @@ -3098,15 +3161,14 @@ static bool chain_context_apply_lookup (hb_ot_apply_context_t *c, if (!(match_input (c, inputCount, input, lookup_context.funcs.match[1], lookup_context.match_data[1], - &match_end, match_positions) && (end_index = match_end) + &match_end) && (end_index = match_end) && match_lookahead (c, lookaheadCount, lookahead, lookup_context.funcs.match[2], lookup_context.match_data[2], match_end, &end_index))) { c->buffer->unsafe_to_concat (c->buffer->idx, end_index); - ret = false; - goto done; + return false; } if (!match_backtrack (c, @@ -3115,19 +3177,14 @@ static bool chain_context_apply_lookup (hb_ot_apply_context_t *c, &start_index)) { c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index); - ret = false; - goto done; + return false; } c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index); apply_lookup (c, - inputCount, match_positions, + inputCount, lookupCount, lookupRecord, match_end); - done: - - if (unlikely (match_positions != match_positions_stack)) - hb_free (match_positions); return ret; } @@ -3411,33 +3468,29 @@ struct ChainRuleSet * * Replicated from LigatureSet::apply(). */ - /* If the input skippy has non-auto joiners behavior (as in Indic shapers), - * skip this fast path, as we don't distinguish between input & lookahead - * matching in the fast path. + /* We use the iter_context instead of iter_input, to avoid skipping + * default-ignorables and such. * - * https://github.com/harfbuzz/harfbuzz/issues/4813 + * Related: https://github.com/harfbuzz/harfbuzz/issues/4813 */ - if (!c->auto_zwnj || !c->auto_zwj) - goto slow; - - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + auto &skippy_iter = c->iter_context; skippy_iter.reset (c->buffer->idx); skippy_iter.set_match_func (match_always, nullptr); skippy_iter.set_glyph_data ((HBUINT16 *) nullptr); - unsigned unsafe_to = (unsigned) -1, unsafe_to1 = 0, unsafe_to2 = 0; + unsigned unsafe_to = (unsigned) -1, unsafe_to1, unsafe_to2 = 0; hb_glyph_info_t *first = nullptr, *second = nullptr; bool matched = skippy_iter.next (); if (likely (matched)) { - first = &c->buffer->info[skippy_iter.idx]; - unsafe_to1 = skippy_iter.idx + 1; - if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])) { /* Can't use the fast path if eg. the next char is a default-ignorable * or other skippable. */ goto slow; } + + first = &c->buffer->info[skippy_iter.idx]; + unsafe_to1 = skippy_iter.idx + 1; } else { @@ -3458,8 +3511,15 @@ struct ChainRuleSet ; } matched = skippy_iter.next (); - if (likely (matched && !skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))) + if (likely (matched)) { + if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])) + { + /* Can't use the fast path if eg. the next char is a default-ignorable + * or other skippable. */ + goto slow; + } + second = &c->buffer->info[skippy_iter.idx]; unsafe_to2 = skippy_iter.idx + 1; } @@ -3475,7 +3535,7 @@ struct ChainRuleSet const auto &input = StructAfter (r.backtrack); const auto &lookahead = StructAfter (input); - unsigned lenP1 = hb_max ((unsigned) input.lenP1, 1u); + unsigned lenP1 = input.lenP1; if (lenP1 > 1 ? (!match_input || match_input (*first, input.arrayZ[0], input_data)) @@ -3483,6 +3543,7 @@ struct ChainRuleSet (!lookahead.len || !match_lookahead || match_lookahead (*first, lookahead.arrayZ[0], lookahead_data))) { + lenP1 = hb_max (lenP1, 1u); if (!second || (lenP1 > 2 ? (!match_input || @@ -3505,6 +3566,18 @@ struct ChainRuleSet { if (unsafe_to == (unsigned) -1) unsafe_to = unsafe_to1; + + if (lenP1 > 1) + { + // Skip ahead to next possible first glyph match. + for (; i + 1 < num_rules; i++) + { + const auto &r2 = this+rule.arrayZ[i + 1]; + const auto &input2 = StructAfter (r2.backtrack); + if (input2.lenP1 <= 1 || input2.arrayZ[0] != input.arrayZ[0]) + break; + } + } } } if (likely (unsafe_to != (unsigned) -1)) @@ -3873,45 +3946,37 @@ struct ChainContextFormat2_5 unsigned cache_cost () const { - return (this+lookaheadClassDef).cost () * ruleSet.len; + return (this+inputClassDef).cost () + (this+lookaheadClassDef).cost (); } - static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) + static bool cache_func (hb_ot_apply_context_t *c, hb_ot_subtable_cache_op_t op) { - switch (op) - { - case hb_ot_lookup_cache_op_t::CREATE: - return (void *) true; - case hb_ot_lookup_cache_op_t::ENTER: - { - hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p; - if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable)) - return (void *) false; - auto &info = c->buffer->info; - unsigned count = c->buffer->len; - for (unsigned i = 0; i < count; i++) - info[i].syllable() = 255; - c->new_syllables = 255; - return (void *) true; - } - case hb_ot_lookup_cache_op_t::LEAVE: - { - hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p; - c->new_syllables = (unsigned) -1; - HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable); - return nullptr; - } - case hb_ot_lookup_cache_op_t::DESTROY: - return nullptr; - } - return nullptr; + return context_cache_func (c, op); } - bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } - bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); } - bool _apply (hb_ot_apply_context_t *c, bool cached) const + struct external_cache_t + { + hb_ot_layout_binary_cache_t coverage; + }; + void *external_cache_create () const + { + external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t)); + if (likely (cache)) + { + cache->coverage.clear (); + } + return cache; + } + bool apply_cached (hb_ot_apply_context_t *c, void *external_cache) const { return _apply (c, true, external_cache); } + bool apply (hb_ot_apply_context_t *c, void *external_cache) const { return _apply (c, false, external_cache); } + bool _apply (hb_ot_apply_context_t *c, bool cached, void *external_cache) const { TRACE_APPLY (this); +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + external_cache_t *cache = (external_cache_t *) external_cache; + unsigned int index = (this+coverage).get_coverage_binary (c->buffer->cur().codepoint, cache ? &cache->coverage : nullptr); +#else unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); +#endif if (index == NOT_COVERED) return_trace (false); const ClassDef &backtrack_class_def = this+backtrackClassDef; @@ -3929,11 +3994,9 @@ struct ChainContextFormat2_5 &lookahead_class_def} }; - // Note: Corresponds to match_class_cached2 - if (cached && ((c->buffer->cur().syllable() & 0xF0) >> 4) < 15) - index = (c->buffer->cur().syllable () & 0xF0) >> 4; - else - index = input_class_def.get_class (c->buffer->cur().codepoint); + index = cached + ? get_class_cached2 (input_class_def, c->buffer->cur()) + : input_class_def.get_class (c->buffer->cur().codepoint); const ChainRuleSet &rule_set = this+ruleSet[index]; return_trace (rule_set.apply (c, lookup_context)); } @@ -4261,9 +4324,9 @@ struct ChainContext template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...)); @@ -4277,7 +4340,7 @@ struct ChainContext protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ ChainContextFormat1_4 format1; ChainContextFormat2_5 format2; ChainContextFormat3 format3; @@ -4352,7 +4415,7 @@ struct Extension { unsigned int get_type () const { - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return u.format1.get_type (); default:return 0; } @@ -4360,7 +4423,7 @@ struct Extension template const X& get_subtable () const { - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return u.format1.template get_subtable (); default:return Null (typename T::SubTable); } @@ -4372,7 +4435,7 @@ struct Extension template typename hb_subset_context_t::return_t dispatch (hb_subset_context_t *c, Ts&&... ds) const { - switch (u.format) { + switch (u.format.v) { case 1: hb_barrier (); return u.format1.subset (c); default: return c->default_return_value (); } @@ -4381,9 +4444,9 @@ struct Extension template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: hb_barrier (); return_trace (u.format1.dispatch (c, std::forward (ds)...)); default:return_trace (c->default_return_value ()); } @@ -4391,7 +4454,7 @@ struct Extension protected: union { - HBUINT16 format; /* Format identifier */ + struct { HBUINT16 v; } format; /* Format identifier */ ExtensionFormat1 format1; } u; }; @@ -4428,22 +4491,14 @@ struct hb_ot_layout_lookup_accelerator_t for (auto& subtable : hb_iter (thiz->subtables, count)) thiz->digest.union_ (subtable.digest); + thiz->count = count; + #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - if (c_accelerate_subtables.cache_user_cost < 4) - c_accelerate_subtables.cache_user_idx = (unsigned) -1; - - thiz->cache_user_idx = c_accelerate_subtables.cache_user_idx; - - if (thiz->cache_user_idx != (unsigned) -1) - { - thiz->cache = thiz->subtables[thiz->cache_user_idx].cache_func (nullptr, hb_ot_lookup_cache_op_t::CREATE); - if (!thiz->cache) - thiz->cache_user_idx = (unsigned) -1; - } + thiz->subtable_cache_user_idx = c_accelerate_subtables.subtable_cache_user_idx; for (unsigned i = 0; i < count; i++) - if (i != thiz->cache_user_idx) - thiz->subtables[i].apply_cached_func = thiz->subtables[i].apply_func; + if (i != thiz->subtable_cache_user_idx) + thiz->subtables[i].apply_cached_func = thiz->subtables[i].apply_func; #endif return thiz; @@ -4452,11 +4507,8 @@ struct hb_ot_layout_lookup_accelerator_t void fini () { #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - if (cache) - { - assert (cache_user_idx != (unsigned) -1); - subtables[cache_user_idx].cache_func (cache, hb_ot_lookup_cache_op_t::DESTROY); - } + for (unsigned i = 0; i < count; i++) + hb_free (subtables[i].external_cache); #endif } @@ -4466,14 +4518,14 @@ struct hb_ot_layout_lookup_accelerator_t #ifndef HB_OPTIMIZE_SIZE HB_ALWAYS_INLINE #endif - bool apply (hb_ot_apply_context_t *c, unsigned subtables_count, bool use_cache) const + bool apply (hb_ot_apply_context_t *c, bool use_cache) const { c->lookup_accel = this; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE if (use_cache) { return - + hb_iter (hb_iter (subtables, subtables_count)) + + hb_iter (hb_iter (subtables, count)) | hb_map ([&c] (const hb_accelerate_subtables_context_t::hb_applicable_t &_) { return _.apply_cached (c); }) | hb_any ; @@ -4482,7 +4534,7 @@ struct hb_ot_layout_lookup_accelerator_t #endif { return - + hb_iter (hb_iter (subtables, subtables_count)) + + hb_iter (hb_iter (subtables, count)) | hb_map ([&c] (const hb_accelerate_subtables_context_t::hb_applicable_t &_) { return _.apply (c); }) | hb_any ; @@ -4493,8 +4545,8 @@ struct hb_ot_layout_lookup_accelerator_t bool cache_enter (hb_ot_apply_context_t *c) const { #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - return cache_user_idx != (unsigned) -1 && - subtables[cache_user_idx].cache_enter (c); + return subtable_cache_user_idx != (unsigned) -1 && + subtables[subtable_cache_user_idx].cache_enter (c); #else return false; #endif @@ -4502,19 +4554,17 @@ struct hb_ot_layout_lookup_accelerator_t void cache_leave (hb_ot_apply_context_t *c) const { #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - subtables[cache_user_idx].cache_leave (c); + subtables[subtable_cache_user_idx].cache_leave (c); #endif } hb_set_digest_t digest; + private: + unsigned count = 0; /* Number of subtables in the array. */ #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - public: - void *cache = nullptr; - private: - unsigned cache_user_idx = (unsigned) -1; + unsigned subtable_cache_user_idx = (unsigned) -1; #endif - private: hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY]; }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc index afe52963201..c73e4dc4b6d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc @@ -343,7 +343,7 @@ hb_ot_layout_get_glyphs_in_class (hb_face_t *face, * @face: The #hb_face_t to work on * @glyph: The #hb_codepoint_t code point to query * @start_offset: offset of the first attachment point to retrieve - * @point_count: (inout) (optional): Input = the maximum number of attachment points to return; + * @point_count: (inout) (nullable): Input = the maximum number of attachment points to return; * Output = the actual number of attachment points returned (may be zero) * @point_array: (out) (array length=point_count): The array of attachment points found for the query * @@ -373,7 +373,7 @@ hb_ot_layout_get_attach_points (hb_face_t *face, * @direction: The #hb_direction_t text direction to use * @glyph: The #hb_codepoint_t code point to query * @start_offset: offset of the first caret position to retrieve - * @caret_count: (inout) (optional): Input = the maximum number of caret positions to return; + * @caret_count: (inout) (nullable): Input = the maximum number of caret positions to return; * Output = the actual number of caret positions returned (may be zero) * @caret_array: (out) (array length=caret_count): The array of caret positions found for the query * @@ -444,7 +444,7 @@ get_gsubgpos_table (hb_face_t *face, * @face: #hb_face_t to work upon * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS * @start_offset: offset of the first script tag to retrieve - * @script_count: (inout) (optional): Input = the maximum number of script tags to return; + * @script_count: (inout) (nullable): Input = the maximum number of script tags to return; * Output = the actual number of script tags returned (may be zero) * @script_tags: (out) (array length=script_count): The array of #hb_tag_t script tags found for the query * @@ -541,8 +541,8 @@ hb_ot_layout_table_choose_script (hb_face_t *face, * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS * @script_count: Number of script tags in the array * @script_tags: Array of #hb_tag_t script tags - * @script_index: (out) (optional): The index of the requested script - * @chosen_script: (out) (optional): #hb_tag_t of the requested script + * @script_index: (out) (nullable): The index of the requested script + * @chosen_script: (out) (nullable): #hb_tag_t of the requested script * * Selects an OpenType script for @table_tag from the @script_tags array. * @@ -613,7 +613,7 @@ hb_ot_layout_table_select_script (hb_face_t *face, * @face: #hb_face_t to work upon * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS * @start_offset: offset of the first feature tag to retrieve - * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return; + * @feature_count: (inout) (nullable): Input = the maximum number of feature tags to return; * Output = the actual number of feature tags returned (may be zero) * @feature_tags: (out) (array length=feature_count): Array of feature tags found in the table * @@ -683,7 +683,7 @@ hb_ot_layout_table_find_feature (hb_face_t *face, * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS * @script_index: The index of the requested script tag * @start_offset: offset of the first language tag to retrieve - * @language_count: (inout) (optional): Input = the maximum number of language tags to return; + * @language_count: (inout) (nullable): Input = the maximum number of language tags to return; * Output = the actual number of language tags returned (may be zero) * @language_tags: (out) (array length=language_count): Array of language tags found in the table * @@ -911,7 +911,7 @@ hb_ot_layout_language_get_required_feature (hb_face_t *face, * @script_index: The index of the requested script tag * @language_index: The index of the requested language tag * @start_offset: offset of the first feature tag to retrieve - * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return; + * @feature_count: (inout) (nullable): Input = the maximum number of feature tags to return; * Output: the actual number of feature tags returned (may be zero) * @feature_indexes: (out) (array length=feature_count): The array of feature indexes found for the query * @@ -947,7 +947,7 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face, * @script_index: The index of the requested script tag * @language_index: The index of the requested language tag * @start_offset: offset of the first feature tag to retrieve - * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return; + * @feature_count: (inout) (nullable): Input = the maximum number of feature tags to return; * Output = the actual number of feature tags returned (may be zero) * @feature_tags: (out) (array length=feature_count): The array of #hb_tag_t feature tags found for the query * @@ -1035,7 +1035,7 @@ hb_ot_layout_language_find_feature (hb_face_t *face, * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS * @feature_index: The index of the requested feature * @start_offset: offset of the first lookup to retrieve - * @lookup_count: (inout) (optional): Input = the maximum number of lookups to return; + * @lookup_count: (inout) (nullable): Input = the maximum number of lookups to return; * Output = the actual number of lookups returned (may be zero) * @lookup_indexes: (out) (array length=lookup_count): The array of lookup indexes found for the query * @@ -1386,10 +1386,10 @@ hb_ot_layout_collect_lookups (hb_face_t *face, * @face: #hb_face_t to work upon * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS * @lookup_index: The index of the feature lookup to query - * @glyphs_before: (out): Array of glyphs preceding the substitution range - * @glyphs_input: (out): Array of input glyphs that would be substituted by the lookup - * @glyphs_after: (out): Array of glyphs following the substitution range - * @glyphs_output: (out): Array of glyphs that would be the substituted output of the lookup + * @glyphs_before: (out) (nullable): Array of glyphs preceding the substitution range + * @glyphs_input: (out) (nullable): Array of input glyphs that would be substituted by the lookup + * @glyphs_after: (out) (nullable): Array of glyphs following the substitution range + * @glyphs_output: (out) (nullable): Array of glyphs that would be the substituted output of the lookup * * Fetches a list of all glyphs affected by the specified lookup in the * specified face's GSUB table or GPOS table. @@ -1473,7 +1473,7 @@ hb_ot_layout_table_find_feature_variations (hb_face_t *face, * @feature_index: The index of the feature to query * @variations_index: The index of the feature variation to query * @start_offset: offset of the first lookup to retrieve - * @lookup_count: (inout) (optional): Input = the maximum number of lookups to return; + * @lookup_count: (inout) (nullable): Input = the maximum number of lookups to return; * Output = the actual number of lookups returned (may be zero) * @lookup_indexes: (out) (array length=lookup_count): The array of lookups found for the query * @@ -1777,15 +1777,15 @@ hb_ot_layout_get_size_params (hb_face_t *face, * @face: #hb_face_t to work upon * @table_tag: table tag to query, "GSUB" or "GPOS". * @feature_index: index of feature to query. - * @label_id: (out) (optional): The ‘name’ table name ID that specifies a string - * for a user-interface label for this feature. (May be NULL.) - * @tooltip_id: (out) (optional): The ‘name’ table name ID that specifies a string + * @label_id: (out) (nullable): The ‘name’ table name ID that specifies a string + * for a user-interface label for this feature. + * @tooltip_id: (out) (nullable): The ‘name’ table name ID that specifies a string * that an application can use for tooltip text for this - * feature. (May be NULL.) - * @sample_id: (out) (optional): The ‘name’ table name ID that specifies sample text - * that illustrates the effect of this feature. (May be NULL.) - * @num_named_parameters: (out) (optional): Number of named parameters. (May be zero.) - * @first_param_id: (out) (optional): The first ‘name’ table name ID used to specify + * feature. + * @sample_id: (out) (nullable): The ‘name’ table name ID that specifies sample text + * that illustrates the effect of this feature. + * @num_named_parameters: (out) (nullable): Number of named parameters. + * @first_param_id: (out) (nullable): The first ‘name’ table name ID used to specify * strings for user-interface labels for the feature * parameters. (Must be zero if numParameters is zero.) * @@ -1852,7 +1852,7 @@ hb_ot_layout_feature_get_name_ids (hb_face_t *face, * @table_tag: table tag to query, "GSUB" or "GPOS". * @feature_index: index of feature to query. * @start_offset: offset of the first character to retrieve - * @char_count: (inout) (optional): Input = the maximum number of characters to return; + * @char_count: (inout) (nullable): Input = the maximum number of characters to return; * Output = the actual number of characters returned (may be zero) * @characters: (out caller-allocates) (array length=char_count): A buffer pointer. * The Unicode codepoints of the characters for which this feature provides @@ -1915,31 +1915,33 @@ struct GPOSProxy static inline bool apply_forward (OT::hb_ot_apply_context_t *c, - const OT::hb_ot_layout_lookup_accelerator_t &accel, - unsigned subtable_count) + const OT::hb_ot_layout_lookup_accelerator_t &accel) { - bool use_cache = accel.cache_enter (c); + bool use_hot_subtable_cache = accel.cache_enter (c); bool ret = false; hb_buffer_t *buffer = c->buffer; - while (buffer->idx < buffer->len && buffer->successful) + while (buffer->successful) { - bool applied = false; - auto &cur = buffer->cur(); - if (accel.digest.may_have (cur.codepoint) && - (cur.mask & c->lookup_mask) && - c->check_glyph_property (&cur, c->lookup_props)) - { - applied = accel.apply (c, subtable_count, use_cache); - } + hb_glyph_info_t *info = buffer->info; + unsigned j = buffer->idx; + while (j < buffer->len && + !(accel.digest.may_have (info[j].codepoint) && + (info[j].mask & c->lookup_mask) && + c->check_glyph_property (&info[j], c->lookup_props))) + j++; + if (unlikely (j > buffer->idx && !buffer->next_glyphs (j - buffer->idx))) + break; + if (buffer->idx >= buffer->len) + break; - if (applied) + if (accel.apply (c, use_hot_subtable_cache)) ret = true; else (void) buffer->next_glyph (); } - if (use_cache) + if (use_hot_subtable_cache) accel.cache_leave (c); return ret; @@ -1947,8 +1949,7 @@ apply_forward (OT::hb_ot_apply_context_t *c, static inline bool apply_backward (OT::hb_ot_apply_context_t *c, - const OT::hb_ot_layout_lookup_accelerator_t &accel, - unsigned subtable_count) + const OT::hb_ot_layout_lookup_accelerator_t &accel) { bool ret = false; hb_buffer_t *buffer = c->buffer; @@ -1958,11 +1959,10 @@ apply_backward (OT::hb_ot_apply_context_t *c, if (accel.digest.may_have (cur.codepoint) && (cur.mask & c->lookup_mask) && c->check_glyph_property (&cur, c->lookup_props)) - ret |= accel.apply (c, subtable_count, false); + ret |= accel.apply (c, false); /* The reverse lookup doesn't "advance" cursor (for good reason). */ buffer->idx--; - } while ((int) buffer->idx >= 0); return ret; @@ -1975,7 +1975,6 @@ apply_string (OT::hb_ot_apply_context_t *c, const OT::hb_ot_layout_lookup_accelerator_t &accel) { hb_buffer_t *buffer = c->buffer; - unsigned subtable_count = lookup.get_subtable_count (); if (unlikely (!buffer->len || !c->lookup_mask)) return false; @@ -1991,7 +1990,7 @@ apply_string (OT::hb_ot_apply_context_t *c, buffer->clear_output (); buffer->idx = 0; - ret = apply_forward (c, accel, subtable_count); + ret = apply_forward (c, accel); if (!Proxy::always_inplace) buffer->sync (); @@ -2001,7 +2000,7 @@ apply_string (OT::hb_ot_apply_context_t *c, /* in-place backward substitution/positioning */ assert (!buffer->have_output); buffer->idx = buffer->len - 1; - ret = apply_backward (c, accel, subtable_count); + ret = apply_backward (c, accel); } return ret; @@ -2017,7 +2016,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, unsigned int i = 0; auto *font_data = font->data.ot.get (); - auto *var_store_cache = font_data == HB_SHAPER_DATA_SUCCEEDED ? nullptr : (OT::ItemVariationStore::cache_t *) font_data; + auto *var_store_cache = (OT::hb_scalar_cache_t *) font_data; OT::hb_ot_apply_context_t c (table_index, font, buffer, proxy.accel.get_blob (), var_store_cache); c.set_recurse_func (Proxy::Lookup::template dispatch_recurse_func); @@ -2037,11 +2036,8 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, if (buffer->messaging () && !buffer->message (font, "start lookup %u feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag))) continue; - /* c.digest is a digest of all the current glyphs in the buffer - * (plus some past glyphs). - * - * Only try applying the lookup if there is any overlap. */ - if (accel->digest.may_intersect (c.digest)) + /* Only try applying the lookup if there is any overlap. */ + if (accel->digest.may_intersect (buffer->digest)) { c.set_lookup_index (lookup_index); c.set_lookup_mask (lookup.mask, false); @@ -2067,7 +2063,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, if (stage->pause_func (plan, font, buffer)) { /* Refresh working buffer digest since buffer changed. */ - buffer->collect_codepoints (c.digest); + buffer->update_digest (); } } } @@ -2601,6 +2597,7 @@ hb_ot_layout_get_baseline_with_fallback2 (hb_font_t *font, #endif +#ifndef HB_NO_LAYOUT_RARELY_USED struct hb_get_glyph_alternates_dispatch_t : hb_dispatch_context_t { @@ -2620,14 +2617,13 @@ struct hb_get_glyph_alternates_dispatch_t : ( _dispatch (obj, hb_prioritize, std::forward (ds)...) ) }; -#ifndef HB_NO_LAYOUT_RARELY_USED /** * hb_ot_layout_lookup_get_glyph_alternates: * @face: a face. * @lookup_index: index of the feature lookup to query. * @glyph: a glyph id. * @start_offset: starting offset. - * @alternate_count: (inout) (optional): Input = the maximum number of alternate glyphs to return; + * @alternate_count: (inout) (nullable): Input = the maximum number of alternate glyphs to return; * Output = the actual number of alternate glyphs returned (may be zero). * @alternate_glyphs: (out caller-allocates) (array length=alternate_count): A glyphs buffer. * Alternate glyphs associated with the glyph id. @@ -2654,6 +2650,64 @@ hb_ot_layout_lookup_get_glyph_alternates (hb_face_t *face, return ret; } +struct hb_collect_glyph_alternates_dispatch_t : + hb_dispatch_context_t +{ + static return_t default_return_value () { return false; } + bool stop_sublookup_iteration (return_t r) const { return false; } + + private: + template auto + _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN + ( (obj.collect_glyph_alternates (std::forward (ds)...), true) ) + template auto + _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN + ( default_return_value () ) + public: + template auto + dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN + ( _dispatch (obj, hb_prioritize, std::forward (ds)...) ) +}; + +/** + * hb_ot_layout_lookup_collect_glyph_alternates: + * @face: a face. + * @lookup_index: index of the feature lookup to query. + * @alternate_count: (inout): mapping from glyph index to number of alternates for that glyph. + * @alternate_glyphs: (inout): mapping from encoded glyph index and alternate index, to alternate glyph ids. + * + * Collects alternates of glyphs from a given GSUB lookup index. + * + * For one-to-one GSUB glyph substitutions, this function collects the + * substituted glyph. + * + * For lookups that assign multiple alternates to a glyph, all alternate glyphs are collected. + * + * For other lookup types, nothing is performed and `false` is returned. + * + * The `alternate_count` mapping will contain the number of alternates for each glyph id. + * Upon entry, this mapping should contain the glyph ids as keys, and the number of alternates + * currently known for each glyph id as values. + * + * The `alternate_glyphs` mapping will contain the alternate glyph ids for each glyph id. + * The mapping is encoded in the following way, upon entry and after processing: + * If G is the glyph id, and A0, A1, ..., A(n-1) are the alternate glyph ids, + * the mapping will contain the following entries: (G + (i << 24)) -> A(i) + * for i = 0, 1, ..., n-1 where n is the number of alternates for G as per `alternate_count`. + * + * Return value: `true` if alternates were collected, `false` otherwise. + * Since: 12.1.0 + */ +HB_EXTERN hb_bool_t +hb_ot_layout_lookup_collect_glyph_alternates (hb_face_t *face, + unsigned lookup_index, + hb_map_t *alternate_count /* IN/OUT */, + hb_map_t *alternate_glyphs /* IN/OUT */) +{ + hb_collect_glyph_alternates_dispatch_t c; + const OT::SubstLookup &lookup = face->table.GSUB->table->get_lookup (lookup_index); + return lookup.dispatch (&c, alternate_count, alternate_glyphs); +} struct hb_position_single_dispatch_t : hb_dispatch_context_t diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.h index 1d9db1105bd..b814c2acda3 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.h @@ -383,6 +383,12 @@ hb_ot_layout_lookup_get_glyph_alternates (hb_face_t *face, unsigned *alternate_count /* IN/OUT */, hb_codepoint_t *alternate_glyphs /* OUT */); +HB_EXTERN hb_bool_t +hb_ot_layout_lookup_collect_glyph_alternates (hb_face_t *face, + unsigned lookup_index, + hb_map_t *alternate_count /* IN/OUT */, + hb_map_t *alternate_glyphs /* IN/OUT */); + HB_EXTERN hb_bool_t hb_ot_layout_lookup_would_substitute (hb_face_t *face, unsigned int lookup_index, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh index a68c8421e4c..f669ac7c46d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh @@ -217,8 +217,6 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer) if (u >= 0x80u) { - buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII; - if (unlikely (unicode->is_default_ignorable (u))) { buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES; @@ -247,6 +245,7 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer) if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (gen_cat))) { + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_CONTINUATIONS; props |= UPROPS_MASK_CONTINUATION; props |= unicode->modified_combining_class (u)<<8; } @@ -361,8 +360,9 @@ _hb_glyph_info_unhide (hb_glyph_info_t *info) } static inline void -_hb_glyph_info_set_continuation (hb_glyph_info_t *info) +_hb_glyph_info_set_continuation (hb_glyph_info_t *info, hb_buffer_t *buffer) { + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_CONTINUATIONS; info->unicode_props() |= UPROPS_MASK_CONTINUATION; } static inline void @@ -410,18 +410,6 @@ _hb_glyph_info_is_zwj (const hb_glyph_info_t *info) return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWJ); } static inline bool -_hb_glyph_info_is_joiner (const hb_glyph_info_t *info) -{ - return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & (UPROPS_MASK_Cf_ZWNJ|UPROPS_MASK_Cf_ZWJ)); -} -static inline void -_hb_glyph_info_flip_joiners (hb_glyph_info_t *info) -{ - if (!_hb_glyph_info_is_unicode_format (info)) - return; - info->unicode_props() ^= UPROPS_MASK_Cf_ZWNJ | UPROPS_MASK_Cf_ZWJ; -} -static inline bool _hb_glyph_info_is_aat_deleted (const hb_glyph_info_t *info) { return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_AAT_DELETED); @@ -657,4 +645,18 @@ _hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer) #undef lig_props #undef glyph_props +static inline void +_hb_collect_glyph_alternates_add (hb_codepoint_t from, + hb_codepoint_t to, + hb_map_t *alternate_count, + hb_map_t *alternate_glyphs) +{ + hb_codepoint_t zero = 0; + hb_codepoint_t *i = &zero; + alternate_count->has (from, &i); + alternate_glyphs->set (from | (*i << 24), to); + alternate_count->set (from, *i + 1); +} + + #endif /* HB_OT_LAYOUT_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh index b33e01fd6c9..ad9d7cb03e8 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh @@ -69,6 +69,8 @@ struct MathValueRecord struct MathConstants { + friend struct MATH; + MathConstants* copy (hb_serialize_context_t *c) const { TRACE_SERIALIZE (this); @@ -1109,8 +1111,8 @@ struct MATH { #ifndef HB_NO_MATH switch HB_CODEPOINT_ENCODE3 (font->face->table.MATH.get_blob ()->length, - get_constant (HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT, font), - get_constant (HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT, font)) + (this+mathConstants).minHeight[1], // displayOperatorMinHeight + (this+mathConstants).minHeight[0]) // delimitedSubFormulaMinHeight { /* sha1sum:ab4a4fe054d23061f3c039493d6f665cfda2ecf5 cambria.ttc * sha1sum:086855301bff644f9d8827b88491fcf73a6d4cb9 cambria.ttc diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-post-macroman.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-post-macroman.hh index b4df8aaeeab..269b4d3fe45 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-post-macroman.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-post-macroman.hh @@ -31,264 +31,264 @@ #endif -_S(".notdef") -_S(".null") -_S("nonmarkingreturn") -_S("space") -_S("exclam") -_S("quotedbl") -_S("numbersign") -_S("dollar") -_S("percent") -_S("ampersand") -_S("quotesingle") -_S("parenleft") -_S("parenright") -_S("asterisk") -_S("plus") -_S("comma") -_S("hyphen") -_S("period") -_S("slash") -_S("zero") -_S("one") -_S("two") -_S("three") -_S("four") -_S("five") -_S("six") -_S("seven") -_S("eight") -_S("nine") -_S("colon") -_S("semicolon") -_S("less") -_S("equal") -_S("greater") -_S("question") -_S("at") -_S("A") -_S("B") -_S("C") -_S("D") -_S("E") -_S("F") -_S("G") -_S("H") -_S("I") -_S("J") -_S("K") -_S("L") -_S("M") -_S("N") -_S("O") -_S("P") -_S("Q") -_S("R") -_S("S") -_S("T") -_S("U") -_S("V") -_S("W") -_S("X") -_S("Y") -_S("Z") -_S("bracketleft") -_S("backslash") -_S("bracketright") -_S("asciicircum") -_S("underscore") -_S("grave") -_S("a") -_S("b") -_S("c") -_S("d") -_S("e") -_S("f") -_S("g") -_S("h") -_S("i") -_S("j") -_S("k") -_S("l") -_S("m") -_S("n") -_S("o") -_S("p") -_S("q") -_S("r") -_S("s") -_S("t") -_S("u") -_S("v") -_S("w") -_S("x") -_S("y") -_S("z") -_S("braceleft") -_S("bar") -_S("braceright") -_S("asciitilde") -_S("Adieresis") -_S("Aring") -_S("Ccedilla") -_S("Eacute") -_S("Ntilde") -_S("Odieresis") -_S("Udieresis") -_S("aacute") -_S("agrave") -_S("acircumflex") -_S("adieresis") -_S("atilde") -_S("aring") -_S("ccedilla") -_S("eacute") -_S("egrave") -_S("ecircumflex") -_S("edieresis") -_S("iacute") -_S("igrave") -_S("icircumflex") -_S("idieresis") -_S("ntilde") -_S("oacute") -_S("ograve") -_S("ocircumflex") -_S("odieresis") -_S("otilde") -_S("uacute") -_S("ugrave") -_S("ucircumflex") -_S("udieresis") -_S("dagger") -_S("degree") -_S("cent") -_S("sterling") -_S("section") -_S("bullet") -_S("paragraph") -_S("germandbls") -_S("registered") -_S("copyright") -_S("trademark") -_S("acute") -_S("dieresis") -_S("notequal") -_S("AE") -_S("Oslash") -_S("infinity") -_S("plusminus") -_S("lessequal") -_S("greaterequal") -_S("yen") -_S("mu") -_S("partialdiff") -_S("summation") -_S("product") -_S("pi") -_S("integral") -_S("ordfeminine") -_S("ordmasculine") -_S("Omega") -_S("ae") -_S("oslash") -_S("questiondown") -_S("exclamdown") -_S("logicalnot") -_S("radical") -_S("florin") -_S("approxequal") -_S("Delta") -_S("guillemotleft") -_S("guillemotright") -_S("ellipsis") -_S("nonbreakingspace") -_S("Agrave") -_S("Atilde") -_S("Otilde") -_S("OE") -_S("oe") -_S("endash") -_S("emdash") -_S("quotedblleft") -_S("quotedblright") -_S("quoteleft") -_S("quoteright") -_S("divide") -_S("lozenge") -_S("ydieresis") -_S("Ydieresis") -_S("fraction") -_S("currency") -_S("guilsinglleft") -_S("guilsinglright") -_S("fi") -_S("fl") -_S("daggerdbl") -_S("periodcentered") -_S("quotesinglbase") -_S("quotedblbase") -_S("perthousand") -_S("Acircumflex") -_S("Ecircumflex") -_S("Aacute") -_S("Edieresis") -_S("Egrave") -_S("Iacute") -_S("Icircumflex") -_S("Idieresis") -_S("Igrave") -_S("Oacute") -_S("Ocircumflex") -_S("apple") -_S("Ograve") -_S("Uacute") -_S("Ucircumflex") -_S("Ugrave") -_S("dotlessi") -_S("circumflex") -_S("tilde") -_S("macron") -_S("breve") -_S("dotaccent") -_S("ring") -_S("cedilla") -_S("hungarumlaut") -_S("ogonek") -_S("caron") -_S("Lslash") -_S("lslash") -_S("Scaron") -_S("scaron") -_S("Zcaron") -_S("zcaron") -_S("brokenbar") -_S("Eth") -_S("eth") -_S("Yacute") -_S("yacute") -_S("Thorn") -_S("thorn") -_S("minus") -_S("multiply") -_S("onesuperior") -_S("twosuperior") -_S("threesuperior") -_S("onehalf") -_S("onequarter") -_S("threequarters") -_S("franc") -_S("Gbreve") -_S("gbreve") -_S("Idotaccent") -_S("Scedilla") -_S("scedilla") -_S("Cacute") -_S("cacute") -_S("Ccaron") -_S("ccaron") -_S("dcroat") +HB_STR(".notdef") +HB_STR(".null") +HB_STR("nonmarkingreturn") +HB_STR("space") +HB_STR("exclam") +HB_STR("quotedbl") +HB_STR("numbersign") +HB_STR("dollar") +HB_STR("percent") +HB_STR("ampersand") +HB_STR("quotesingle") +HB_STR("parenleft") +HB_STR("parenright") +HB_STR("asterisk") +HB_STR("plus") +HB_STR("comma") +HB_STR("hyphen") +HB_STR("period") +HB_STR("slash") +HB_STR("zero") +HB_STR("one") +HB_STR("two") +HB_STR("three") +HB_STR("four") +HB_STR("five") +HB_STR("six") +HB_STR("seven") +HB_STR("eight") +HB_STR("nine") +HB_STR("colon") +HB_STR("semicolon") +HB_STR("less") +HB_STR("equal") +HB_STR("greater") +HB_STR("question") +HB_STR("at") +HB_STR("A") +HB_STR("B") +HB_STR("C") +HB_STR("D") +HB_STR("E") +HB_STR("F") +HB_STR("G") +HB_STR("H") +HB_STR("I") +HB_STR("J") +HB_STR("K") +HB_STR("L") +HB_STR("M") +HB_STR("N") +HB_STR("O") +HB_STR("P") +HB_STR("Q") +HB_STR("R") +HB_STR("S") +HB_STR("T") +HB_STR("U") +HB_STR("V") +HB_STR("W") +HB_STR("X") +HB_STR("Y") +HB_STR("Z") +HB_STR("bracketleft") +HB_STR("backslash") +HB_STR("bracketright") +HB_STR("asciicircum") +HB_STR("underscore") +HB_STR("grave") +HB_STR("a") +HB_STR("b") +HB_STR("c") +HB_STR("d") +HB_STR("e") +HB_STR("f") +HB_STR("g") +HB_STR("h") +HB_STR("i") +HB_STR("j") +HB_STR("k") +HB_STR("l") +HB_STR("m") +HB_STR("n") +HB_STR("o") +HB_STR("p") +HB_STR("q") +HB_STR("r") +HB_STR("s") +HB_STR("t") +HB_STR("u") +HB_STR("v") +HB_STR("w") +HB_STR("x") +HB_STR("y") +HB_STR("z") +HB_STR("braceleft") +HB_STR("bar") +HB_STR("braceright") +HB_STR("asciitilde") +HB_STR("Adieresis") +HB_STR("Aring") +HB_STR("Ccedilla") +HB_STR("Eacute") +HB_STR("Ntilde") +HB_STR("Odieresis") +HB_STR("Udieresis") +HB_STR("aacute") +HB_STR("agrave") +HB_STR("acircumflex") +HB_STR("adieresis") +HB_STR("atilde") +HB_STR("aring") +HB_STR("ccedilla") +HB_STR("eacute") +HB_STR("egrave") +HB_STR("ecircumflex") +HB_STR("edieresis") +HB_STR("iacute") +HB_STR("igrave") +HB_STR("icircumflex") +HB_STR("idieresis") +HB_STR("ntilde") +HB_STR("oacute") +HB_STR("ograve") +HB_STR("ocircumflex") +HB_STR("odieresis") +HB_STR("otilde") +HB_STR("uacute") +HB_STR("ugrave") +HB_STR("ucircumflex") +HB_STR("udieresis") +HB_STR("dagger") +HB_STR("degree") +HB_STR("cent") +HB_STR("sterling") +HB_STR("section") +HB_STR("bullet") +HB_STR("paragraph") +HB_STR("germandbls") +HB_STR("registered") +HB_STR("copyright") +HB_STR("trademark") +HB_STR("acute") +HB_STR("dieresis") +HB_STR("notequal") +HB_STR("AE") +HB_STR("Oslash") +HB_STR("infinity") +HB_STR("plusminus") +HB_STR("lessequal") +HB_STR("greaterequal") +HB_STR("yen") +HB_STR("mu") +HB_STR("partialdiff") +HB_STR("summation") +HB_STR("product") +HB_STR("pi") +HB_STR("integral") +HB_STR("ordfeminine") +HB_STR("ordmasculine") +HB_STR("Omega") +HB_STR("ae") +HB_STR("oslash") +HB_STR("questiondown") +HB_STR("exclamdown") +HB_STR("logicalnot") +HB_STR("radical") +HB_STR("florin") +HB_STR("approxequal") +HB_STR("Delta") +HB_STR("guillemotleft") +HB_STR("guillemotright") +HB_STR("ellipsis") +HB_STR("nonbreakingspace") +HB_STR("Agrave") +HB_STR("Atilde") +HB_STR("Otilde") +HB_STR("OE") +HB_STR("oe") +HB_STR("endash") +HB_STR("emdash") +HB_STR("quotedblleft") +HB_STR("quotedblright") +HB_STR("quoteleft") +HB_STR("quoteright") +HB_STR("divide") +HB_STR("lozenge") +HB_STR("ydieresis") +HB_STR("Ydieresis") +HB_STR("fraction") +HB_STR("currency") +HB_STR("guilsinglleft") +HB_STR("guilsinglright") +HB_STR("fi") +HB_STR("fl") +HB_STR("daggerdbl") +HB_STR("periodcentered") +HB_STR("quotesinglbase") +HB_STR("quotedblbase") +HB_STR("perthousand") +HB_STR("Acircumflex") +HB_STR("Ecircumflex") +HB_STR("Aacute") +HB_STR("Edieresis") +HB_STR("Egrave") +HB_STR("Iacute") +HB_STR("Icircumflex") +HB_STR("Idieresis") +HB_STR("Igrave") +HB_STR("Oacute") +HB_STR("Ocircumflex") +HB_STR("apple") +HB_STR("Ograve") +HB_STR("Uacute") +HB_STR("Ucircumflex") +HB_STR("Ugrave") +HB_STR("dotlessi") +HB_STR("circumflex") +HB_STR("tilde") +HB_STR("macron") +HB_STR("breve") +HB_STR("dotaccent") +HB_STR("ring") +HB_STR("cedilla") +HB_STR("hungarumlaut") +HB_STR("ogonek") +HB_STR("caron") +HB_STR("Lslash") +HB_STR("lslash") +HB_STR("Scaron") +HB_STR("scaron") +HB_STR("Zcaron") +HB_STR("zcaron") +HB_STR("brokenbar") +HB_STR("Eth") +HB_STR("eth") +HB_STR("Yacute") +HB_STR("yacute") +HB_STR("Thorn") +HB_STR("thorn") +HB_STR("minus") +HB_STR("multiply") +HB_STR("onesuperior") +HB_STR("twosuperior") +HB_STR("threesuperior") +HB_STR("onehalf") +HB_STR("onequarter") +HB_STR("threequarters") +HB_STR("franc") +HB_STR("Gbreve") +HB_STR("gbreve") +HB_STR("Idotaccent") +HB_STR("Scedilla") +HB_STR("scedilla") +HB_STR("Cacute") +HB_STR("cacute") +HB_STR("Ccaron") +HB_STR("ccaron") +HB_STR("dcroat") #endif /* HB_OT_POST_MACROMAN_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc index 2401e18f0e6..c17e7628975 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc @@ -409,16 +409,13 @@ position_around_base (const hb_ot_shape_plan_t *plan, } static inline void -position_cluster (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer, - unsigned int start, - unsigned int end, - bool adjust_offsets_when_zeroing) +position_cluster_impl (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + bool adjust_offsets_when_zeroing) { - if (end - start < 2) - return; - /* Find the base glyph */ hb_glyph_info_t *info = buffer->info; for (unsigned int i = start; i < end; i++) @@ -441,6 +438,20 @@ position_cluster (const hb_ot_shape_plan_t *plan, } } +static HB_ALWAYS_INLINE void +position_cluster (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + bool adjust_offsets_when_zeroing) +{ + if (end - start < 2) + return; + + position_cluster_impl (plan, font, buffer, start, end, adjust_offsets_when_zeroing); +} + void _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan, hb_font_t *font, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.cc index cb941bc7fbd..508ed6a5076 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.cc @@ -78,14 +78,14 @@ static inline void set_glyph (hb_glyph_info_t &info, hb_font_t *font) { - (void) font->get_nominal_glyph (info.codepoint, &info.glyph_index()); + (void) font->get_nominal_glyph (info.codepoint, &info.normalizer_glyph_index()); } static inline void output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph) { /* This is very confusing indeed. */ - buffer->cur().glyph_index() = glyph; + buffer->cur().normalizer_glyph_index() = glyph; (void) buffer->output_glyph (unichar); _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer); } @@ -93,7 +93,7 @@ output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph) static inline void next_char (hb_buffer_t *buffer, hb_codepoint_t glyph) { - buffer->cur().glyph_index() = glyph; + buffer->cur().normalizer_glyph_index() = glyph; (void) buffer->next_glyph (); } @@ -210,7 +210,7 @@ handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, hb_font_t * const font = c->font; for (; buffer->idx < end - 1 && buffer->successful;) { if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) { - if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index())) + if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().normalizer_glyph_index())) { hb_codepoint_t unicode = buffer->cur().codepoint; (void) buffer->replace_glyphs (2, 1, &unicode); @@ -342,7 +342,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, unsigned int done = font->get_nominal_glyphs (end - buffer->idx, &buffer->cur().codepoint, sizeof (buffer->info[0]), - &buffer->cur().glyph_index(), + &buffer->cur().normalizer_glyph_index(), sizeof (buffer->info[0])); if (unlikely (!buffer->next_glyphs (done))) break; } @@ -456,7 +456,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, buffer->out_len--; /* Remove the second composable. */ /* Modify starter and carry on. */ buffer->out_info[starter].codepoint = composed; - buffer->out_info[starter].glyph_index() = glyph; + buffer->out_info[starter].normalizer_glyph_index() = glyph; _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer); continue; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.hh index 9f17bdbb243..138e895e8e1 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.hh @@ -32,7 +32,7 @@ /* buffer var allocations, used during the normalization process */ -#define glyph_index() var1.u32 +#define normalizer_glyph_index() var1.u32 struct hb_ot_shape_plan_t; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc index 477a7c7fc72..69b188f7aa3 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc @@ -44,6 +44,7 @@ #include "hb-ot-face.hh" #include "hb-set.hh" +#include "hb-unicode.hh" #include "hb-aat-layout.hh" #include "hb-ot-layout-gdef-table.hh" @@ -92,7 +93,7 @@ hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t *fac shaper = hb_ot_shaper_categorize (props.script, props.direction, map.chosen_script[0]); script_zero_marks = shaper->zero_width_marks != HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE; - script_fallback_mark_positioning = shaper->fallback_position; + script_fallback_position = shaper->fallback_position; #ifndef HB_NO_AAT_SHAPE /* https://github.com/harfbuzz/harfbuzz/issues/1528 */ @@ -178,12 +179,12 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan, #endif #ifndef HB_NO_OT_KERN else if (hb_ot_layout_has_kerning (face)) - plan.apply_kern = true; + plan.apply_kern = script_fallback_position; // Not all shapers apply legacy `kern` #endif else {} } - plan.apply_fallback_kern = !(plan.apply_gpos || plan.apply_kerx || plan.apply_kern); + plan.apply_fallback_kern = script_fallback_position && !(plan.apply_gpos || plan.apply_kerx || plan.apply_kern); plan.zero_marks = script_zero_marks && !plan.apply_kerx && @@ -203,7 +204,7 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan, ); plan.fallback_mark_positioning = plan.adjust_mark_positioning_when_zeroing && - script_fallback_mark_positioning; + script_fallback_position; #ifndef HB_NO_AAT_SHAPE /* If we're using morx shaping, we cancel mark position adjustment because @@ -425,25 +426,20 @@ _hb_ot_shaper_face_data_destroy (hb_ot_face_data_t *data) */ struct hb_ot_font_data_t { - OT::ItemVariationStore::cache_t unused; // Just for alignment + OT::hb_scalar_cache_t unused; // Just for alignment }; hb_ot_font_data_t * _hb_ot_shaper_font_data_create (hb_font_t *font) { - if (!font->num_coords) - return (hb_ot_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; - const OT::ItemVariationStore &var_store = font->face->table.GDEF->table->get_var_store (); - auto *cache = (hb_ot_font_data_t *) var_store.create_cache (); - return cache ? cache : (hb_ot_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; + return (hb_ot_font_data_t *) var_store.create_cache (); } void _hb_ot_shaper_font_data_destroy (hb_ot_font_data_t *data) { - if (data == HB_SHAPER_DATA_SUCCEEDED) return; - OT::ItemVariationStore::destroy_cache ((OT::ItemVariationStore::cache_t *) data); + OT::ItemVariationStore::destroy_cache ((OT::hb_scalar_cache_t *) data); } @@ -488,6 +484,9 @@ hb_set_unicode_props (hb_buffer_t *buffer) { _hb_glyph_info_set_unicode_props (&info[i], buffer); + if (info[i].codepoint < 0x80) + continue; + unsigned gen_cat = _hb_glyph_info_get_general_category (&info[i]); if (FLAG_UNSAFE (gen_cat) & (FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) | @@ -502,7 +501,7 @@ hb_set_unicode_props (hb_buffer_t *buffer) if (unlikely (gen_cat == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL && hb_in_range (info[i].codepoint, 0x1F3FBu, 0x1F3FFu))) { - _hb_glyph_info_set_continuation (&info[i]); + _hb_glyph_info_set_continuation (&info[i], buffer); } /* Regional_Indicators are hairy as hell... * https://github.com/harfbuzz/harfbuzz/issues/2265 */ @@ -510,18 +509,18 @@ hb_set_unicode_props (hb_buffer_t *buffer) { if (_hb_codepoint_is_regional_indicator (info[i - 1].codepoint) && !_hb_glyph_info_is_continuation (&info[i - 1])) - _hb_glyph_info_set_continuation (&info[i]); + _hb_glyph_info_set_continuation (&info[i], buffer); } #ifndef HB_NO_EMOJI_SEQUENCES else if (unlikely (_hb_glyph_info_is_zwj (&info[i]))) { - _hb_glyph_info_set_continuation (&info[i]); + _hb_glyph_info_set_continuation (&info[i], buffer); if (i + 1 < count && _hb_unicode_is_emoji_Extended_Pictographic (info[i + 1].codepoint)) { i++; _hb_glyph_info_set_unicode_props (&info[i], buffer); - _hb_glyph_info_set_continuation (&info[i]); + _hb_glyph_info_set_continuation (&info[i], buffer); } } #endif @@ -540,7 +539,9 @@ hb_set_unicode_props (hb_buffer_t *buffer) * https://github.com/harfbuzz/harfbuzz/issues/3844 */ else if (unlikely (hb_in_ranges (info[i].codepoint, 0xFF9Eu, 0xFF9Fu, 0xE0020u, 0xE007Fu))) - _hb_glyph_info_set_continuation (&info[i]); + _hb_glyph_info_set_continuation (&info[i], buffer); + else if (unlikely (info[i].codepoint == 0x2044u /* FRACTION SLASH */)) + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_FRACTION_SLASH; } } @@ -576,7 +577,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) static void hb_form_clusters (hb_buffer_t *buffer) { - if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII)) + if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_CONTINUATIONS)) return; if (HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES (buffer->cluster_level)) @@ -618,14 +619,14 @@ hb_ensure_native_direction (hb_buffer_t *buffer) for (unsigned i = 0; i < count; i++) { auto gc = _hb_glyph_info_get_general_category (&info[i]); - if (gc == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) - found_number = true; - else if (HB_UNICODE_GENERAL_CATEGORY_IS_LETTER (gc)) + if (HB_UNICODE_GENERAL_CATEGORY_IS_LETTER (gc)) { found_letter = true; break; } - else if (_hb_codepoint_is_regional_indicator (info[i].codepoint)) + else if (gc == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) + found_number = true; + else if (unlikely (_hb_codepoint_is_regional_indicator (info[i].codepoint))) found_ri = true; } if ((found_number || found_ri) && !found_letter) @@ -651,59 +652,6 @@ hb_ensure_native_direction (hb_buffer_t *buffer) * Substitute */ -#ifndef HB_NO_VERTICAL -static hb_codepoint_t -hb_vert_char_for (hb_codepoint_t u) -{ - switch (u >> 8) - { - case 0x20: switch (u) { - case 0x2013u: return 0xfe32u; // EN DASH - case 0x2014u: return 0xfe31u; // EM DASH - case 0x2025u: return 0xfe30u; // TWO DOT LEADER - case 0x2026u: return 0xfe19u; // HORIZONTAL ELLIPSIS - } break; - case 0x30: switch (u) { - case 0x3001u: return 0xfe11u; // IDEOGRAPHIC COMMA - case 0x3002u: return 0xfe12u; // IDEOGRAPHIC FULL STOP - case 0x3008u: return 0xfe3fu; // LEFT ANGLE BRACKET - case 0x3009u: return 0xfe40u; // RIGHT ANGLE BRACKET - case 0x300au: return 0xfe3du; // LEFT DOUBLE ANGLE BRACKET - case 0x300bu: return 0xfe3eu; // RIGHT DOUBLE ANGLE BRACKET - case 0x300cu: return 0xfe41u; // LEFT CORNER BRACKET - case 0x300du: return 0xfe42u; // RIGHT CORNER BRACKET - case 0x300eu: return 0xfe43u; // LEFT WHITE CORNER BRACKET - case 0x300fu: return 0xfe44u; // RIGHT WHITE CORNER BRACKET - case 0x3010u: return 0xfe3bu; // LEFT BLACK LENTICULAR BRACKET - case 0x3011u: return 0xfe3cu; // RIGHT BLACK LENTICULAR BRACKET - case 0x3014u: return 0xfe39u; // LEFT TORTOISE SHELL BRACKET - case 0x3015u: return 0xfe3au; // RIGHT TORTOISE SHELL BRACKET - case 0x3016u: return 0xfe17u; // LEFT WHITE LENTICULAR BRACKET - case 0x3017u: return 0xfe18u; // RIGHT WHITE LENTICULAR BRACKET - } break; - case 0xfe: switch (u) { - case 0xfe4fu: return 0xfe34u; // WAVY LOW LINE - } break; - case 0xff: switch (u) { - case 0xff01u: return 0xfe15u; // FULLWIDTH EXCLAMATION MARK - case 0xff08u: return 0xfe35u; // FULLWIDTH LEFT PARENTHESIS - case 0xff09u: return 0xfe36u; // FULLWIDTH RIGHT PARENTHESIS - case 0xff0cu: return 0xfe10u; // FULLWIDTH COMMA - case 0xff1au: return 0xfe13u; // FULLWIDTH COLON - case 0xff1bu: return 0xfe14u; // FULLWIDTH SEMICOLON - case 0xff1fu: return 0xfe16u; // FULLWIDTH QUESTION MARK - case 0xff3bu: return 0xfe47u; // FULLWIDTH LEFT SQUARE BRACKET - case 0xff3du: return 0xfe48u; // FULLWIDTH RIGHT SQUARE BRACKET - case 0xff3fu: return 0xfe33u; // FULLWIDTH LOW LINE - case 0xff5bu: return 0xfe37u; // FULLWIDTH LEFT CURLY BRACKET - case 0xff5du: return 0xfe38u; // FULLWIDTH RIGHT CURLY BRACKET - } break; - } - - return u; -} -#endif - static inline void hb_ot_rotate_chars (const hb_ot_shape_context_t *c) { @@ -729,7 +677,7 @@ hb_ot_rotate_chars (const hb_ot_shape_context_t *c) if (HB_DIRECTION_IS_VERTICAL (c->target_direction) && !c->plan->has_vert) { for (unsigned int i = 0; i < count; i++) { - hb_codepoint_t codepoint = hb_vert_char_for (info[i].codepoint); + hb_codepoint_t codepoint = hb_unicode_funcs_t::vertical_char_for (info[i].codepoint); if (unlikely (codepoint != info[i].codepoint && c->font->has_glyph (codepoint))) info[i].codepoint = codepoint; } @@ -744,7 +692,7 @@ hb_ot_shape_setup_masks_fraction (const hb_ot_shape_context_t *c) return; #endif - if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) || + if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_FRACTION_SLASH) || !c->plan->has_frac) return; @@ -845,7 +793,13 @@ hb_ot_zero_width_default_ignorables (const hb_buffer_t *buffer) unsigned int i = 0; for (i = 0; i < count; i++) if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i]))) - pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0; + { + pos[i].x_advance = pos[i].y_advance = 0; + if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) + pos[i].x_offset = 0; + else + pos[i].y_offset = 0; + } } static void @@ -900,11 +854,11 @@ hb_ot_hide_default_ignorables (hb_buffer_t *buffer, static inline void hb_ot_map_glyphs_fast (hb_buffer_t *buffer) { - /* Normalization process sets up glyph_index(), we just copy it. */ + /* Normalization process sets up normalizer_glyph_index(), we just copy it. */ unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) - info[i].codepoint = info[i].glyph_index(); + info[i].codepoint = info[i].normalizer_glyph_index(); buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS; } @@ -942,7 +896,7 @@ hb_ot_substitute_default (const hb_ot_shape_context_t *c) hb_ot_rotate_chars (c); - HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index); + HB_BUFFER_ALLOCATE_VAR (buffer, normalizer_glyph_index); _hb_ot_shape_normalize (c->plan, buffer, c->font); @@ -954,7 +908,7 @@ hb_ot_substitute_default (const hb_ot_shape_context_t *c) hb_ot_map_glyphs_fast (buffer); - HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index); + HB_BUFFER_DEALLOCATE_VAR (buffer, normalizer_glyph_index); } static inline void @@ -969,11 +923,17 @@ hb_ot_substitute_plan (const hb_ot_shape_context_t *c) #ifndef HB_NO_AAT_SHAPE if (unlikely (c->plan->apply_morx)) + { hb_aat_layout_substitute (c->plan, c->font, c->buffer, c->user_features, c->num_user_features); + c->buffer->update_digest (); + } else #endif + { + c->buffer->update_digest (); c->plan->substitute (c->font, buffer); + } } static inline void @@ -1054,23 +1014,16 @@ hb_ot_position_default (const hb_ot_shape_context_t *c) { c->font->get_glyph_h_advances (count, &info[0].codepoint, sizeof(info[0]), &pos[0].x_advance, sizeof(pos[0])); - /* The nil glyph_h_origin() func returns 0, so no need to apply it. */ - if (c->font->has_glyph_h_origin_func ()) - for (unsigned int i = 0; i < count; i++) - c->font->subtract_glyph_h_origin (info[i].codepoint, - &pos[i].x_offset, - &pos[i].y_offset); + // h_origin defaults to zero; only apply it if the font has it. + if (c->font->has_glyph_h_origin_func () || c->font->has_glyph_h_origins_func ()) + c->font->subtract_glyph_h_origins (c->buffer); } else { c->font->get_glyph_v_advances (count, &info[0].codepoint, sizeof(info[0]), &pos[0].y_advance, sizeof(pos[0])); - for (unsigned int i = 0; i < count; i++) - { - c->font->subtract_glyph_v_origin (info[i].codepoint, - &pos[i].x_offset, - &pos[i].y_offset); - } + // v_origin defaults to non-zero; apply even if only fallback is there. + c->font->subtract_glyph_v_origins (c->buffer); } if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK) _hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer); @@ -1079,10 +1032,6 @@ hb_ot_position_default (const hb_ot_shape_context_t *c) static inline void hb_ot_position_plan (const hb_ot_shape_context_t *c) { - unsigned int count = c->buffer->len; - hb_glyph_info_t *info = c->buffer->info; - hb_glyph_position_t *pos = c->buffer->pos; - /* If the font has no GPOS and direction is forward, then when * zeroing mark widths, we shift the mark with it, such that the * mark is positioned hanging over the previous glyph. When @@ -1097,12 +1046,9 @@ hb_ot_position_plan (const hb_ot_shape_context_t *c) /* We change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */ - /* The nil glyph_h_origin() func returns 0, so no need to apply it. */ - if (c->font->has_glyph_h_origin_func ()) - for (unsigned int i = 0; i < count; i++) - c->font->add_glyph_h_origin (info[i].codepoint, - &pos[i].x_offset, - &pos[i].y_offset); + // h_origin defaults to zero; only apply it if the font has it. + if (c->font->has_glyph_h_origin_func () || c->font->has_glyph_h_origins_func ()) + c->font->add_glyph_h_origins (c->buffer); hb_ot_layout_position_start (c->font, c->buffer); @@ -1139,12 +1085,9 @@ hb_ot_position_plan (const hb_ot_shape_context_t *c) hb_ot_zero_width_default_ignorables (c->buffer); hb_ot_layout_position_finish_offsets (c->font, c->buffer); - /* The nil glyph_h_origin() func returns 0, so no need to apply it. */ - if (c->font->has_glyph_h_origin_func ()) - for (unsigned int i = 0; i < count; i++) - c->font->subtract_glyph_h_origin (info[i].codepoint, - &pos[i].x_offset, - &pos[i].y_offset); + // h_origin defaults to zero; only apply it if the font has it. + if (c->font->has_glyph_h_origin_func () || c->font->has_glyph_h_origins_func ()) + c->font->subtract_glyph_h_origins (c->buffer); if (c->plan->fallback_mark_positioning) _hb_ot_shape_fallback_mark_position (c->plan, c->font, c->buffer, @@ -1172,8 +1115,33 @@ hb_propagate_flags (hb_buffer_t *buffer) /* Propagate cluster-level glyph flags to be the same on all cluster glyphs. * Simplifies using them. */ - if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS)) + hb_mask_t and_mask = HB_GLYPH_FLAG_DEFINED; + if ((buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0) + and_mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_CONCAT; + + hb_glyph_info_t *info = buffer->info; + + if ((buffer->flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL) == 0) + { + foreach_cluster (buffer, start, end) + { + if (end - start == 1) + { + info[start].mask &= and_mask; + continue; + } + + unsigned int mask = 0; + for (unsigned int i = start; i < end; i++) + mask |= info[i].mask; + + mask &= and_mask; + + for (unsigned int i = start; i < end; i++) + info[i].mask = mask; + } return; + } /* If we are producing SAFE_TO_INSERT_TATWEEL, then do two things: * @@ -1181,30 +1149,20 @@ hb_propagate_flags (hb_buffer_t *buffer) * are UNSAFE_TO_BREAK, then clear the SAFE_TO_INSERT_TATWEEL, * - Any place that is SAFE_TO_INSERT_TATWEEL, is also now UNSAFE_TO_BREAK. * - * We couldn't make this interaction earlier. It has to be done here. + * We couldn't make this interaction earlier. It has to be done this way. */ - bool flip_tatweel = buffer->flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL; - - bool clear_concat = (buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0; - - hb_glyph_info_t *info = buffer->info; - foreach_cluster (buffer, start, end) { unsigned int mask = 0; for (unsigned int i = start; i < end; i++) - mask |= info[i].mask & HB_GLYPH_FLAG_DEFINED; + mask |= info[i].mask; - if (flip_tatweel) - { - if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK) - mask &= ~HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL; - if (mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL) - mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT; - } + if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK) + mask &= ~HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL; + if (mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL) + mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT; - if (clear_concat) - mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_CONCAT; + mask &= and_mask; for (unsigned int i = start; i < end; i++) info[i].mask = mask; @@ -1245,8 +1203,6 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c) _hb_buffer_deallocate_unicode_vars (c->buffer); c->buffer->props.direction = c->target_direction; - - c->buffer->leave (); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh index 068d7192d0d..649acddb414 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh @@ -150,7 +150,7 @@ struct hb_ot_shape_planner_t static constexpr bool apply_morx = false; #endif bool script_zero_marks : 1; - bool script_fallback_mark_positioning : 1; + bool script_fallback_position : 1; const struct hb_ot_shaper_t *shaper; HB_INTERNAL hb_ot_shape_planner_t (hb_face_t *face, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-joining-list.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-joining-list.hh index e38686e3ebb..79d3014d3e1 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-joining-list.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-joining-list.hh @@ -6,10 +6,10 @@ * * on files with these headers: * - * # ArabicShaping-16.0.0.txt - * # Date: 2024-07-30 - * # Scripts-16.0.0.txt - * # Date: 2024-04-30, 21:48:40 GMT + * # ArabicShaping-17.0.0.txt + * # Date: 2025-08-14 + * # Scripts-17.0.0.txt + * # Date: 2025-07-24, 13:28:55 GMT */ #ifndef HB_OT_SHAPER_ARABIC_JOINING_LIST_HH diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-table.hh index 19bd72d4218..5f87995ea9c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-table.hh @@ -6,10 +6,10 @@ * * on files with these headers: * - * # ArabicShaping-16.0.0.txt - * # Date: 2024-07-30 - * # Blocks-16.0.0.txt - * # Date: 2024-02-02 + * # ArabicShaping-17.0.0.txt + * # Date: 2025-08-14 + * # Blocks-17.0.0.txt + * # Date: 2025-08-01 * UnicodeData.txt does not have a header. */ @@ -80,7 +80,7 @@ static const uint8_t joining_table[] = /* Arabic Extended-B */ /* 0860 */ R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R, - /* 0880 */ R,R,R,C,C,C,D,U,U,D,D,D,D,D,R,X,U,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X, + /* 0880 */ R,R,R,C,C,C,D,U,U,D,D,D,D,D,R,D,U,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X, /* Arabic Extended-A */ @@ -140,9 +140,9 @@ static const uint8_t joining_table[] = /* Arabic Extended-C */ - /* 10EC0 */ R,D,D, + /* 10EC0 */ R,D,D,X,D,D, -#define joining_offset_0x10f30u 1185 +#define joining_offset_0x10f30u 1188 /* Sogdian */ @@ -161,14 +161,14 @@ static const uint8_t joining_table[] = /* 10FA0 */ D,U,D,D,R,R,R,U,D,R,R,D,D,R,D,D, /* 10FC0 */ U,D,R,R,D,U,U,U,U,R,D,L, -#define joining_offset_0x110bdu 1341 +#define joining_offset_0x110bdu 1344 /* Kaithi */ /* 110A0 */ U,X,X, /* 110C0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,U, -#define joining_offset_0x1e900u 1358 +#define joining_offset_0x1e900u 1361 /* Adlam */ @@ -176,7 +176,7 @@ static const uint8_t joining_table[] = /* 1E920 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D, /* 1E940 */ D,D,D,D,X,X,X,X,X,X,X,T, -}; /* Table items: 1434; occupancy: 57% */ +}; /* Table items: 1437; occupancy: 58% */ static unsigned int @@ -204,7 +204,7 @@ joining_type (hb_codepoint_t u) if (hb_in_range (u, 0x10AC0u, 0x10AEFu)) return joining_table[u - 0x10AC0u + joining_offset_0x10ac0u]; if (hb_in_range (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u]; if (hb_in_range (u, 0x10D00u, 0x10D23u)) return joining_table[u - 0x10D00u + joining_offset_0x10d00u]; - if (hb_in_range (u, 0x10EC2u, 0x10EC4u)) return joining_table[u - 0x10EC2u + joining_offset_0x10ec2u]; + if (hb_in_range (u, 0x10EC2u, 0x10EC7u)) return joining_table[u - 0x10EC2u + joining_offset_0x10ec2u]; if (hb_in_range (u, 0x10F30u, 0x10FCBu)) return joining_table[u - 0x10F30u + joining_offset_0x10f30u]; break; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc index 7379bb7f15b..981c0f9224b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc @@ -654,7 +654,7 @@ postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan, /* https://www.unicode.org/reports/tr53/ */ -static hb_codepoint_t +static const hb_codepoint_t modifier_combining_marks[] = { 0x0654u, /* ARABIC HAMZA ABOVE */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc index 5c46ebbc281..5f15aff8b7c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc @@ -427,7 +427,7 @@ const hb_ot_shaper_t _hb_ot_shaper_hangul = HB_TAG_NONE, /* gpos_tag */ HB_OT_SHAPE_NORMALIZATION_MODE_NONE, HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, - false, /* fallback_position */ + true, /* fallback_position */ }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-machine.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-machine.hh index 25e6d85ef80..76c5e83e30f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-machine.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-machine.hh @@ -53,7 +53,7 @@ enum indic_syllable_type_t { }; -#line 57 "hb-ot-shaper-indic-machine.hh" +#line 54 "hb-ot-shaper-indic-machine.hh" #define indic_syllable_machine_ex_A 9u #define indic_syllable_machine_ex_C 1u #define indic_syllable_machine_ex_CM 16u @@ -77,7 +77,7 @@ enum indic_syllable_type_t { #define indic_syllable_machine_ex_ZWNJ 5u -#line 81 "hb-ot-shaper-indic-machine.hh" +#line 76 "hb-ot-shaper-indic-machine.hh" static const unsigned char _indic_syllable_machine_trans_keys[] = { 8u, 57u, 4u, 57u, 5u, 57u, 5u, 57u, 13u, 13u, 4u, 57u, 4u, 57u, 4u, 57u, 8u, 57u, 5u, 57u, 5u, 57u, 13u, 13u, 4u, 57u, 4u, 57u, 4u, 57u, 4u, 57u, @@ -1126,7 +1126,7 @@ find_syllables_indic (hb_buffer_t *buffer) int cs; hb_glyph_info_t *info = buffer->info; -#line 1130 "hb-ot-shaper-indic-machine.hh" +#line 1119 "hb-ot-shaper-indic-machine.hh" { cs = indic_syllable_machine_start; ts = 0; @@ -1142,7 +1142,7 @@ find_syllables_indic (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 1146 "hb-ot-shaper-indic-machine.hh" +#line 1131 "hb-ot-shaper-indic-machine.hh" { int _slen; int _trans; @@ -1156,7 +1156,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 1160 "hb-ot-shaper-indic-machine.hh" +#line 1143 "hb-ot-shaper-indic-machine.hh" } _keys = _indic_syllable_machine_trans_keys + (cs<<1); @@ -1268,7 +1268,7 @@ _eof_trans: #line 117 "hb-ot-shaper-indic-machine.rl" {act = 7;} break; -#line 1272 "hb-ot-shaper-indic-machine.hh" +#line 1232 "hb-ot-shaper-indic-machine.hh" } _again: @@ -1277,7 +1277,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 1281 "hb-ot-shaper-indic-machine.hh" +#line 1239 "hb-ot-shaper-indic-machine.hh" } if ( ++p != pe ) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-table.cc index b87c530853b..bf27efee21b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-table.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-table.cc @@ -6,12 +6,12 @@ * * on files with these headers: * - * # IndicSyllabicCategory-16.0.0.txt - * # Date: 2024-04-30, 21:48:21 GMT - * # IndicPositionalCategory-16.0.0.txt - * # Date: 2024-04-30, 21:48:21 GMT - * # Blocks-16.0.0.txt - * # Date: 2024-02-02 + * # IndicSyllabicCategory-17.0.0.txt + * # Date: 2025-08-01, 04:02:23 GMT + * # IndicPositionalCategory-17.0.0.txt + * # Date: 2025-07-29, 13:35:52 GMT + * # Blocks-17.0.0.txt + * # Date: 2025-08-01 */ #include "hb.hh" diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic.cc index d78b5670f61..bec802429ab 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic.cc @@ -296,11 +296,6 @@ struct indic_shape_plan_t const indic_config_t *config; bool is_old_spec; -#ifndef HB_NO_UNISCRIBE_BUG_COMPATIBLE - bool uniscribe_bug_compatible; -#else - static constexpr bool uniscribe_bug_compatible = false; -#endif mutable hb_atomic_t virama_glyph; hb_indic_would_substitute_feature_t rphf; @@ -327,9 +322,6 @@ data_create_indic (const hb_ot_shape_plan_t *plan) } indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FFu) != '2'); -#ifndef HB_NO_UNISCRIBE_BUG_COMPATIBLE - indic_plan->uniscribe_bug_compatible = hb_options ().uniscribe_bug_compatible; -#endif indic_plan->virama_glyph = -1; /* Use zero-context would_substitute() matching for new-spec of the main @@ -943,17 +935,7 @@ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, unsigned int start, unsigned int end) { /* We treat placeholder/dotted-circle as if they are consonants, so we - * should just chain. Only if not in compatibility mode that is... */ - - const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; - if (indic_plan->uniscribe_bug_compatible) - { - /* For dotted-circle, this is what Uniscribe does: - * If dotted-circle is the last glyph, it just does nothing. - * Ie. It doesn't form Reph. */ - if (buffer->info[end - 1].indic_category() == I_Cat(DOTTEDCIRCLE)) - return; - } + * should just chain... */ initial_reordering_consonant_syllable (plan, face, buffer, start, end); } @@ -1347,8 +1329,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, * Uniscribe doesn't do this. * TEST: U+0930,U+094D,U+0915,U+094B,U+094D */ - if (!indic_plan->uniscribe_bug_compatible && - unlikely (is_halant (info[new_reph_pos]))) + if (unlikely (is_halant (info[new_reph_pos]))) { for (unsigned int i = base + 1; i < new_reph_pos; i++) if (FLAG_UNSAFE (info[i].indic_category()) & (FLAG (I_Cat(M)) | FLAG (I_Cat(MPst)))) @@ -1451,27 +1432,6 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, else buffer->unsafe_to_break (start - 1, start + 1); } - - - /* - * Finish off the clusters and go home! - */ - if (indic_plan->uniscribe_bug_compatible) - { - switch ((hb_tag_t) plan->props.script) - { - case HB_SCRIPT_TAMIL: - break; - - default: - /* Uniscribe merges the entire syllable into a single cluster... Except for Tamil. - * This means, half forms are submerged into the main consonant's cluster. - * This is unnecessary, and makes cursor positioning harder, but that's what - * Uniscribe does. */ - buffer->merge_clusters (start, end); - break; - } - } } @@ -1501,9 +1461,7 @@ preprocess_text_indic (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, hb_font_t *font) { - const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; - if (!indic_plan->uniscribe_bug_compatible) - _hb_preprocess_text_vowel_constraints (plan, buffer, font); + _hb_preprocess_text_vowel_constraints (plan, buffer, font); } static bool diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-khmer-machine.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-khmer-machine.hh index e1f657c758a..2442f0341ef 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-khmer-machine.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-khmer-machine.hh @@ -48,7 +48,7 @@ enum khmer_syllable_type_t { }; -#line 52 "hb-ot-shaper-khmer-machine.hh" +#line 49 "hb-ot-shaper-khmer-machine.hh" #define khmer_syllable_machine_ex_C 1u #define khmer_syllable_machine_ex_DOTTEDCIRCLE 11u #define khmer_syllable_machine_ex_H 4u @@ -66,7 +66,7 @@ enum khmer_syllable_type_t { #define khmer_syllable_machine_ex_ZWNJ 5u -#line 70 "hb-ot-shaper-khmer-machine.hh" +#line 65 "hb-ot-shaper-khmer-machine.hh" static const unsigned char _khmer_syllable_machine_trans_keys[] = { 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, @@ -294,7 +294,7 @@ find_syllables_khmer (hb_buffer_t *buffer) int cs; hb_glyph_info_t *info = buffer->info; -#line 298 "hb-ot-shaper-khmer-machine.hh" +#line 287 "hb-ot-shaper-khmer-machine.hh" { cs = khmer_syllable_machine_start; ts = 0; @@ -310,7 +310,7 @@ find_syllables_khmer (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 314 "hb-ot-shaper-khmer-machine.hh" +#line 299 "hb-ot-shaper-khmer-machine.hh" { int _slen; int _trans; @@ -324,7 +324,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 328 "hb-ot-shaper-khmer-machine.hh" +#line 311 "hb-ot-shaper-khmer-machine.hh" } _keys = _khmer_syllable_machine_trans_keys + (cs<<1); @@ -394,7 +394,7 @@ _eof_trans: #line 98 "hb-ot-shaper-khmer-machine.rl" {act = 3;} break; -#line 398 "hb-ot-shaper-khmer-machine.hh" +#line 368 "hb-ot-shaper-khmer-machine.hh" } _again: @@ -403,7 +403,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 407 "hb-ot-shaper-khmer-machine.hh" +#line 375 "hb-ot-shaper-khmer-machine.hh" } if ( ++p != pe ) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-khmer.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-khmer.cc index 2a4aed2ab1b..1f5028aa3ee 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-khmer.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-khmer.cc @@ -141,12 +141,6 @@ override_features_khmer (hb_ot_shape_planner_t *plan) * typographical correctness.", hence in overrides... */ map->enable_feature (HB_TAG('c','l','i','g')); - /* Uniscribe does not apply 'kern' in Khmer. */ - if (hb_options ().uniscribe_bug_compatible) - { - map->disable_feature (HB_TAG('k','e','r','n')); - } - map->disable_feature (HB_TAG('l','i','g','a')); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-myanmar-machine.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-myanmar-machine.hh index 64eb761b4ea..6e5fce609bc 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-myanmar-machine.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-myanmar-machine.hh @@ -50,7 +50,7 @@ enum myanmar_syllable_type_t { }; -#line 54 "hb-ot-shaper-myanmar-machine.hh" +#line 51 "hb-ot-shaper-myanmar-machine.hh" #define myanmar_syllable_machine_ex_A 9u #define myanmar_syllable_machine_ex_As 32u #define myanmar_syllable_machine_ex_C 1u @@ -78,7 +78,7 @@ enum myanmar_syllable_type_t { #define myanmar_syllable_machine_ex_ZWNJ 5u -#line 82 "hb-ot-shaper-myanmar-machine.hh" +#line 77 "hb-ot-shaper-myanmar-machine.hh" static const unsigned char _myanmar_syllable_machine_trans_keys[] = { 1u, 57u, 3u, 57u, 5u, 57u, 5u, 57u, 3u, 57u, 5u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 5u, 57u, 1u, 15u, 3u, 57u, 3u, 57u, 3u, 57u, @@ -549,7 +549,7 @@ find_syllables_myanmar (hb_buffer_t *buffer) int cs; hb_glyph_info_t *info = buffer->info; -#line 553 "hb-ot-shaper-myanmar-machine.hh" +#line 542 "hb-ot-shaper-myanmar-machine.hh" { cs = myanmar_syllable_machine_start; ts = 0; @@ -565,7 +565,7 @@ find_syllables_myanmar (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 569 "hb-ot-shaper-myanmar-machine.hh" +#line 554 "hb-ot-shaper-myanmar-machine.hh" { int _slen; int _trans; @@ -579,7 +579,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 583 "hb-ot-shaper-myanmar-machine.hh" +#line 566 "hb-ot-shaper-myanmar-machine.hh" } _keys = _myanmar_syllable_machine_trans_keys + (cs<<1); @@ -649,7 +649,7 @@ _eof_trans: #line 113 "hb-ot-shaper-myanmar-machine.rl" {act = 3;} break; -#line 653 "hb-ot-shaper-myanmar-machine.hh" +#line 623 "hb-ot-shaper-myanmar-machine.hh" } _again: @@ -658,7 +658,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 662 "hb-ot-shaper-myanmar-machine.hh" +#line 630 "hb-ot-shaper-myanmar-machine.hh" } if ( ++p != pe ) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc index a0ea464e775..42fc4bbcc44 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc @@ -163,7 +163,7 @@ thai_pua_shape (hb_codepoint_t u, thai_action_t action, hb_font_t *font) } -static enum thai_above_state_t +static const enum thai_above_state_t { /* Cluster above looks like: */ T0, /* ⣤ */ T1, /* ⣼ */ @@ -191,7 +191,7 @@ static const struct thai_above_state_machine_edge_t { }; -static enum thai_below_state_t +static const enum thai_below_state_t { B0, /* No descender */ B1, /* Removable descender */ @@ -334,7 +334,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan, /* Is SARA AM. Decompose and reorder. */ (void) buffer->output_glyph (NIKHAHIT_FROM_SARA_AM (u)); - _hb_glyph_info_set_continuation (&buffer->prev()); + _hb_glyph_info_set_continuation (&buffer->prev(), buffer); if (unlikely (!buffer->replace_glyph (SARA_AA_FROM_SARA_AM (u)))) break; /* Make Nikhahit be recognized as a ccc=0 mark when zeroing widths. */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-machine.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-machine.hh index 46f66f7d285..22a5356a877 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-machine.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-machine.hh @@ -53,7 +53,7 @@ enum use_syllable_type_t { }; -#line 57 "hb-ot-shaper-use-machine.hh" +#line 54 "hb-ot-shaper-use-machine.hh" #define use_syllable_machine_ex_B 1u #define use_syllable_machine_ex_CGJ 6u #define use_syllable_machine_ex_CMAbv 31u @@ -100,7 +100,7 @@ enum use_syllable_type_t { #define use_syllable_machine_ex_ZWNJ 14u -#line 104 "hb-ot-shaper-use-machine.hh" +#line 99 "hb-ot-shaper-use-machine.hh" static const unsigned char _use_syllable_machine_trans_keys[] = { 49u, 51u, 0u, 56u, 11u, 56u, 11u, 56u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, @@ -929,7 +929,7 @@ find_syllables_use (hb_buffer_t *buffer) unsigned int act HB_UNUSED; int cs; -#line 933 "hb-ot-shaper-use-machine.hh" +#line 922 "hb-ot-shaper-use-machine.hh" { cs = use_syllable_machine_start; ts = 0; @@ -942,7 +942,7 @@ find_syllables_use (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 946 "hb-ot-shaper-use-machine.hh" +#line 931 "hb-ot-shaper-use-machine.hh" { int _slen; int _trans; @@ -956,7 +956,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 960 "hb-ot-shaper-use-machine.hh" +#line 943 "hb-ot-shaper-use-machine.hh" } _keys = _use_syllable_machine_trans_keys + (cs<<1); @@ -1078,7 +1078,7 @@ _eof_trans: #line 181 "hb-ot-shaper-use-machine.rl" {act = 9;} break; -#line 1082 "hb-ot-shaper-use-machine.hh" +#line 1039 "hb-ot-shaper-use-machine.hh" } _again: @@ -1087,7 +1087,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 1091 "hb-ot-shaper-use-machine.hh" +#line 1046 "hb-ot-shaper-use-machine.hh" } if ( ++p != pe ) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-table.hh index d3c49949aa8..a69abefdd01 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-table.hh @@ -6,18 +6,18 @@ * * on files with these headers: * - * # IndicSyllabicCategory-16.0.0.txt - * # Date: 2024-04-30, 21:48:21 GMT - * # IndicPositionalCategory-16.0.0.txt - * # Date: 2024-04-30, 21:48:21 GMT - * # ArabicShaping-16.0.0.txt - * # Date: 2024-07-30 - * # DerivedCoreProperties-16.0.0.txt - * # Date: 2024-05-31, 18:09:32 GMT - * # Blocks-16.0.0.txt - * # Date: 2024-02-02 - * # Scripts-16.0.0.txt - * # Date: 2024-04-30, 21:48:40 GMT + * # IndicSyllabicCategory-17.0.0.txt + * # Date: 2025-08-01, 04:02:23 GMT + * # IndicPositionalCategory-17.0.0.txt + * # Date: 2025-07-29, 13:35:52 GMT + * # ArabicShaping-17.0.0.txt + * # Date: 2025-08-14 + * # DerivedCoreProperties-17.0.0.txt + * # Date: 2025-07-30, 23:55:08 GMT + * # Blocks-17.0.0.txt + * # Date: 2025-08-01 + * # Scripts-17.0.0.txt + * # Date: 2025-07-24, 13:28:55 GMT * # Override values For Indic_Syllabic_Category * # Not derivable * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17 @@ -101,8 +101,9 @@ #ifndef HB_OPTIMIZE_SIZE -static const uint8_t -hb_use_u8[3345] = +#include + +static const uint8_t hb_use_u8[3343]= { 16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 57, 58, 59, 195, 211, 62, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, @@ -126,24 +127,24 @@ hb_use_u8[3345] = 49, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 50, 51, 2, 2, 2, 2, 2, 2, 2, 2, 52, 53, 2, 54, 2, 2, 55, 56, 2, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 2, 70, 71, 72, 73, - 2, 74, 2, 75, 76, 77, 78, 2, 2, 79, 80, 81, 82, 2, 83, 84, - 2, 85, 85, 85, 85, 85, 85, 85, 85, 86, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 87, 2, 2, 2, 2, 2, 2, 2, + 2, 74, 2, 75, 76, 77, 78, 79, 2, 80, 81, 82, 83, 2, 84, 85, + 2, 86, 86, 86, 86, 86, 86, 86, 86, 87, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 88, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 88, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 89, 90, 2, 2, 2, 91, 2, 2, 2, 92, - 93, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 94, 94, 94, 95, 2, 2, 2, 2, 2, + 2, 2, 2, 89, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 90, 91, 2, 2, 2, 92, 2, 2, 2, 93, + 94, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 95, 95, 95, 96, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 96, 97, 2, 2, 2, 2, 2, - 2, 2, 2, 98, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, 98, 2, 2, 2, 2, 2, + 2, 2, 2, 99, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 99, 2, 2, 100, 2, 2, 2, 101, 2, 102, 2, 2, 2, - 2, 2, 2, 103, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 104, 104, 105, 106, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, - 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, - 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 2, 2, 2, 100, 2, 2, 101, 2, 2, 2, 102, 2, 103, 2, 2, 2, + 2, 2, 2, 104, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 105, 105, 106, 107, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, + 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, + 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 0, 5, 0, 0, 0, 0, 0, 6, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -192,99 +193,99 @@ hb_use_u8[3345] = 48, 48, 48, 48, 15, 82, 83, 84, 85, 86, 87, 0, 0, 0, 0, 88, 0, 9, 0, 0, 30, 0, 89, 81, 90, 2, 2, 2, 2, 9, 0, 0, 0, 42, 42, 91, 92, 2, 2, 2, 2, 2, 2, 2, 2, 13, 9, 0, - 0, 93, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 9, 22, 80, 45, 22, 94, 61, 0, 0, 95, 96, 95, 95, 97, 98, 0, - 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 9, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 29, 0, 0, - 0, 2, 2, 2, 2, 2, 9, 0, 0, 2, 2, 2, 52, 99, 45, 0, - 0, 2, 2, 100, 101, 102, 103, 61, 63, 104, 16, 45, 22, 59, 21, 80, - 48, 48, 76, 11, 11, 11, 105, 46, 40, 11, 106, 74, 2, 2, 2, 2, - 2, 2, 2, 107, 22, 20, 20, 22, 48, 48, 22, 108, 2, 2, 2, 9, - 0, 0, 0, 0, 0, 0, 109, 110, 110, 110, 110, 0, 0, 0, 0, 0, - 0, 106, 74, 2, 2, 2, 2, 2, 2, 60, 61, 59, 25, 22, 111, 61, - 2, 2, 2, 2, 107, 22, 23, 45, 45, 102, 112, 0, 0, 0, 0, 0, - 0, 2, 2, 61, 18, 48, 23, 113, 102, 102, 102, 114, 115, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 0, 30, 2, 11, 46, 116, 116, 116, 11, 116, - 116, 15, 116, 116, 116, 26, 0, 40, 0, 0, 0, 117, 51, 11, 5, 0, - 0, 0, 0, 0, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 6, 119, - 120, 42, 42, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, 120, - 121, 120, 120, 120, 120, 120, 120, 120, 120, 0, 0, 122, 0, 0, 0, 0, - 0, 0, 7, 122, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 123, 123, 0, 0, - 0, 2, 2, 2, 2, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, - 124, 0, 123, 123, 0, 0, 0, 0, 0, 2, 53, 2, 108, 2, 10, 2, - 2, 2, 65, 19, 16, 0, 0, 31, 0, 2, 2, 0, 0, 0, 0, 0, - 0, 29, 2, 2, 2, 2, 2, 2, 2, 2, 2, 125, 23, 23, 23, 23, - 23, 23, 23, 126, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 2, 0, 0, 0, 0, 0, 52, 2, 2, 2, 22, 22, 127, 116, - 0, 2, 2, 2, 128, 20, 59, 20, 113, 102, 129, 0, 0, 0, 0, 0, - 0, 11, 130, 2, 2, 2, 2, 2, 2, 2, 131, 23, 22, 20, 48, 132, - 133, 134, 0, 0, 0, 0, 0, 0, 0, 2, 2, 52, 30, 2, 2, 2, - 2, 2, 2, 2, 2, 10, 22, 59, 99, 76, 135, 136, 137, 0, 0, 0, - 0, 2, 138, 2, 2, 2, 2, 139, 0, 30, 2, 42, 5, 0, 79, 15, - 2, 53, 22, 140, 52, 53, 2, 2, 105, 10, 9, 0, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 141, 21, 25, 0, 0, 142, 143, 0, 0, 0, - 0, 2, 65, 45, 23, 80, 47, 144, 0, 81, 81, 81, 81, 81, 81, 81, - 81, 0, 0, 0, 0, 0, 0, 0, 6, 120, 120, 120, 120, 121, 0, 0, - 0, 2, 2, 2, 2, 2, 9, 2, 2, 2, 9, 2, 30, 2, 2, 2, - 2, 2, 30, 2, 2, 2, 30, 9, 0, 128, 20, 27, 31, 0, 0, 145, - 146, 2, 2, 30, 2, 30, 2, 2, 2, 2, 2, 2, 0, 14, 37, 0, - 147, 2, 2, 13, 37, 0, 30, 2, 2, 2, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 30, 2, 2, 9, 2, 2, 11, 41, 0, 0, 0, - 0, 2, 2, 2, 0, 27, 22, 22, 30, 2, 2, 2, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 27, 38, 0, 2, 2, 2, 116, 116, 116, 116, - 116, 148, 2, 9, 0, 0, 0, 0, 0, 2, 14, 14, 0, 0, 0, 0, - 0, 9, 2, 2, 9, 2, 2, 2, 2, 30, 2, 9, 0, 30, 2, 0, - 0, 149, 150, 151, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 22, 20, - 20, 20, 22, 22, 134, 0, 0, 0, 0, 0, 152, 152, 152, 152, 152, 152, - 152, 152, 152, 152, 2, 2, 2, 2, 2, 53, 52, 53, 0, 0, 0, 0, - 153, 11, 74, 2, 2, 2, 2, 2, 2, 18, 19, 21, 16, 24, 37, 0, - 0, 0, 31, 0, 0, 0, 0, 0, 0, 11, 49, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 128, 20, 22, 154, 22, 21, 155, 156, 2, 2, 2, 2, - 2, 0, 0, 65, 157, 0, 0, 0, 0, 2, 13, 0, 0, 0, 0, 0, - 0, 2, 65, 25, 20, 20, 20, 22, 22, 108, 158, 0, 0, 56, 159, 31, - 160, 30, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23, - 19, 22, 22, 161, 44, 0, 0, 0, 49, 128, 0, 0, 0, 0, 0, 0, - 0, 2, 2, 2, 9, 9, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2, - 30, 2, 2, 2, 2, 2, 2, 2, 10, 18, 19, 21, 22, 162, 31, 0, - 0, 11, 11, 30, 2, 2, 2, 9, 30, 9, 2, 30, 2, 2, 58, 17, - 23, 16, 23, 47, 32, 33, 32, 34, 0, 0, 0, 0, 35, 0, 0, 0, - 2, 2, 23, 0, 11, 11, 11, 46, 0, 11, 11, 46, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 30, 0, 9, 2, 2, 2, 30, 45, 59, 20, - 20, 31, 33, 32, 32, 25, 163, 29, 164, 165, 37, 0, 0, 0, 0, 0, - 0, 12, 26, 0, 0, 0, 0, 0, 0, 2, 2, 65, 25, 20, 20, 20, - 22, 23, 126, 15, 17, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, - 166, 167, 0, 0, 0, 0, 0, 0, 0, 18, 19, 20, 20, 66, 99, 25, - 160, 11, 168, 9, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, - 65, 25, 20, 20, 0, 48, 48, 11, 169, 37, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2, 2, 20, 0, 23, 19, 20, 20, 21, 16, 82, - 169, 38, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 10, 170, - 25, 20, 22, 22, 168, 9, 0, 0, 0, 2, 2, 2, 2, 2, 9, 43, - 136, 23, 22, 20, 76, 21, 22, 0, 0, 2, 2, 2, 9, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 2, 18, 19, 20, 21, 22, 105, 169, 37, 0, - 0, 2, 2, 2, 9, 30, 0, 2, 2, 2, 2, 30, 9, 2, 2, 2, - 2, 23, 23, 18, 32, 33, 12, 171, 165, 172, 173, 0, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 0, 2, 2, 2, 65, 25, 20, 20, 0, 22, 23, - 29, 108, 0, 33, 0, 0, 0, 0, 0, 52, 20, 22, 22, 22, 140, 2, - 2, 2, 174, 175, 11, 15, 176, 61, 177, 0, 0, 1, 147, 0, 0, 0, - 0, 52, 20, 22, 16, 19, 20, 2, 2, 2, 2, 158, 158, 158, 178, 178, - 178, 178, 178, 178, 15, 179, 0, 30, 0, 22, 20, 20, 31, 22, 22, 11, + 0, 2, 2, 2, 2, 2, 2, 2, 9, 22, 80, 45, 22, 93, 61, 0, + 0, 94, 95, 94, 94, 96, 97, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 0, 2, 2, 9, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, + 0, 2, 2, 2, 2, 29, 0, 0, 0, 2, 2, 2, 2, 2, 9, 0, + 0, 2, 2, 2, 52, 98, 45, 0, 0, 2, 2, 99, 100, 101, 102, 61, + 63, 103, 16, 45, 22, 59, 21, 80, 48, 48, 76, 11, 11, 11, 104, 46, + 40, 11, 105, 74, 2, 2, 2, 2, 2, 2, 2, 106, 22, 20, 20, 22, + 48, 48, 22, 107, 2, 2, 2, 9, 0, 0, 0, 0, 0, 0, 108, 109, + 109, 109, 109, 0, 0, 0, 0, 0, 0, 105, 74, 2, 2, 2, 2, 2, + 2, 60, 61, 59, 25, 22, 110, 61, 2, 2, 2, 2, 106, 22, 23, 45, + 45, 101, 111, 0, 0, 0, 0, 0, 0, 2, 2, 61, 18, 48, 23, 112, + 101, 101, 101, 113, 114, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 30, + 2, 11, 46, 115, 115, 115, 11, 115, 115, 15, 115, 115, 115, 26, 0, 40, + 0, 0, 0, 116, 51, 11, 5, 0, 0, 0, 0, 0, 0, 0, 117, 0, + 0, 0, 0, 0, 0, 0, 6, 118, 119, 42, 42, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 119, 119, 120, 119, 119, 119, 119, 119, 119, 119, + 119, 0, 0, 121, 0, 0, 0, 0, 0, 0, 7, 121, 0, 0, 0, 0, + 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 0, 0, 0, 0, 122, 122, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, + 30, 0, 0, 0, 0, 0, 0, 0, 123, 0, 122, 122, 0, 0, 0, 0, + 0, 2, 53, 2, 107, 2, 10, 2, 2, 2, 65, 19, 16, 0, 0, 31, + 0, 2, 2, 0, 0, 0, 0, 0, 0, 29, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 124, 23, 23, 23, 23, 23, 23, 23, 125, 0, 0, 0, 0, + 0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 0, 0, 0, 0, 0, + 52, 2, 2, 2, 22, 22, 126, 115, 0, 2, 2, 2, 127, 20, 59, 20, + 112, 101, 128, 0, 0, 0, 0, 0, 0, 11, 129, 2, 2, 2, 2, 2, + 2, 2, 130, 23, 22, 20, 48, 131, 132, 133, 0, 0, 0, 0, 0, 0, + 0, 2, 2, 52, 30, 2, 2, 2, 2, 2, 2, 2, 2, 10, 22, 59, + 98, 76, 134, 135, 136, 0, 0, 0, 0, 2, 137, 2, 2, 2, 2, 138, + 0, 30, 2, 42, 5, 0, 79, 15, 2, 139, 20, 53, 127, 139, 2, 2, + 140, 10, 9, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 141, 21, + 25, 0, 0, 142, 143, 0, 0, 0, 0, 2, 65, 45, 23, 80, 47, 144, + 0, 81, 81, 81, 81, 81, 81, 81, 81, 0, 0, 0, 0, 0, 0, 0, + 6, 119, 119, 119, 119, 120, 0, 0, 0, 2, 2, 2, 2, 2, 9, 2, + 2, 2, 9, 2, 30, 2, 2, 2, 2, 2, 30, 2, 2, 2, 30, 9, + 0, 127, 20, 27, 31, 0, 0, 145, 146, 2, 2, 30, 2, 30, 2, 2, + 2, 2, 2, 2, 0, 14, 37, 0, 147, 2, 2, 13, 37, 0, 30, 2, + 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 2, 2, + 9, 2, 2, 11, 41, 0, 0, 0, 0, 2, 2, 2, 0, 27, 22, 22, + 30, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 27, 38, + 0, 2, 2, 2, 115, 115, 115, 115, 115, 148, 2, 9, 0, 0, 0, 0, + 0, 2, 14, 14, 0, 0, 0, 0, 0, 9, 2, 2, 9, 2, 2, 2, + 2, 30, 2, 9, 0, 30, 2, 0, 0, 149, 150, 151, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 22, 22, 20, 20, 20, 22, 22, 133, 0, 0, 0, + 0, 0, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 2, 2, 2, 2, + 2, 53, 52, 53, 0, 0, 0, 0, 153, 11, 74, 2, 2, 2, 2, 2, + 2, 18, 19, 21, 16, 24, 37, 0, 0, 0, 31, 0, 0, 0, 0, 0, + 0, 11, 49, 2, 2, 2, 2, 2, 2, 2, 2, 2, 127, 20, 22, 154, + 22, 21, 155, 156, 2, 2, 2, 2, 2, 0, 0, 65, 157, 0, 0, 0, + 0, 2, 13, 0, 0, 0, 0, 0, 0, 2, 65, 25, 20, 20, 20, 22, + 22, 107, 158, 0, 0, 56, 159, 31, 160, 30, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 23, 19, 22, 22, 161, 44, 0, 0, 0, + 49, 127, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 9, 2, 2, + 30, 2, 2, 2, 2, 2, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2, + 10, 18, 19, 21, 22, 162, 31, 0, 0, 11, 11, 30, 2, 2, 2, 9, + 30, 9, 2, 30, 2, 2, 58, 17, 23, 16, 23, 47, 32, 33, 32, 34, + 0, 0, 0, 0, 35, 0, 0, 0, 2, 2, 23, 0, 11, 11, 11, 46, + 0, 11, 11, 46, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 30, 0, + 9, 2, 2, 2, 30, 45, 59, 20, 20, 31, 33, 32, 32, 25, 163, 29, + 164, 165, 37, 0, 0, 0, 0, 0, 0, 12, 26, 0, 0, 0, 0, 0, + 0, 2, 2, 65, 25, 20, 20, 20, 22, 23, 125, 15, 17, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 0, 0, 166, 167, 0, 0, 0, 0, 0, 0, + 0, 18, 19, 20, 20, 66, 98, 25, 160, 11, 168, 9, 0, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 2, 2, 65, 25, 20, 20, 0, 48, 48, 11, + 169, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 20, + 0, 23, 19, 20, 20, 21, 16, 82, 169, 38, 0, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 10, 170, 25, 20, 22, 22, 168, 9, 0, 0, + 0, 2, 2, 2, 2, 2, 9, 43, 135, 23, 22, 20, 76, 21, 22, 0, + 0, 2, 2, 2, 9, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 18, + 19, 20, 21, 22, 104, 169, 37, 0, 0, 2, 2, 2, 9, 30, 0, 2, + 2, 2, 2, 30, 9, 2, 2, 2, 2, 23, 23, 18, 32, 33, 12, 171, + 165, 172, 173, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2, + 2, 65, 25, 20, 20, 0, 22, 23, 29, 107, 0, 33, 0, 0, 0, 0, + 0, 52, 20, 22, 22, 22, 139, 2, 2, 2, 174, 140, 11, 15, 175, 61, + 176, 0, 0, 1, 147, 0, 0, 0, 0, 52, 20, 22, 16, 19, 20, 2, + 2, 2, 2, 158, 158, 158, 177, 177, 177, 177, 177, 177, 15, 178, 0, 30, + 0, 16, 20, 16, 16, 0, 0, 0, 0, 22, 20, 20, 31, 22, 22, 11, 169, 0, 61, 61, 61, 61, 61, 61, 61, 66, 21, 82, 46, 0, 0, 0, 0, 2, 2, 2, 9, 2, 30, 2, 2, 52, 22, 22, 31, 0, 38, 22, - 27, 11, 159, 180, 181, 0, 0, 0, 0, 2, 2, 2, 30, 9, 2, 2, + 27, 11, 159, 179, 180, 0, 0, 0, 0, 2, 2, 2, 30, 9, 2, 2, 2, 2, 2, 2, 2, 2, 23, 23, 47, 22, 35, 82, 68, 0, 0, 0, - 0, 2, 182, 66, 47, 0, 0, 0, 0, 11, 183, 2, 2, 2, 2, 2, + 0, 2, 181, 66, 47, 0, 0, 0, 0, 11, 182, 2, 2, 2, 2, 2, 2, 2, 2, 23, 22, 20, 31, 0, 48, 16, 143, 0, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 156, 0, 0, 184, 184, 184, 184, 184, 184, 184, - 184, 185, 185, 185, 186, 187, 185, 184, 184, 188, 184, 184, 189, 190, 190, 190, - 190, 190, 190, 190, 0, 0, 0, 0, 0, 184, 184, 184, 184, 184, 191, 0, - 0, 2, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, 22, 22, 192, 193, - 194, 11, 11, 11, 46, 0, 0, 0, 0, 29, 74, 2, 2, 2, 2, 2, + 0, 2, 2, 2, 2, 2, 156, 0, 0, 183, 183, 183, 183, 183, 183, 183, + 183, 184, 184, 184, 185, 186, 184, 183, 183, 187, 183, 183, 188, 189, 189, 189, + 189, 189, 189, 189, 0, 0, 0, 0, 0, 183, 183, 183, 183, 183, 190, 0, + 0, 2, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, 22, 22, 191, 192, + 193, 11, 11, 11, 46, 0, 0, 0, 0, 29, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 65, 47, 0, 2, 2, 2, 2, 2, 9, 0, - 58, 195, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 0, 0, 0, 40, 116, 26, 0, 0, 0, 0, 0, + 58, 194, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 0, 0, 0, 40, 115, 26, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 30, 2, 2, 2, 2, 2, 0, 58, 37, 0, 6, 120, 120, 120, 121, 0, + 30, 2, 2, 2, 2, 2, 0, 58, 37, 0, 6, 119, 119, 119, 120, 0, 0, 11, 11, 11, 49, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 46, 2, 2, 2, 2, 2, 2, 11, 11, 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2, 2, 2, 2, @@ -300,23 +301,21 @@ hb_use_u8[3345] = VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv, FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB, - CMAbv,CMAbv, B, GB, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, - VPre, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, - VPst, H, B, O,SMAbv,SMAbv,SMAbv, VPst, IS, RK, RK, VBlw, FAbv,VMPre,VMPre,FMAbv, - CMBlw,VMBlw,VMBlw,VMAbv, CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, SB, - SE, O, H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B, - CMAbv, VAbv, MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, - FPst, VBlw, B, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O, + CMAbv,CMAbv, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B, + MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H, + B, O,SMAbv,SMAbv,SMAbv, VPst, IS, RK, RK, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw, + VMBlw,VMAbv, CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, SB, SE, O, + H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv, + MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw, + B, VBlw,VMAbv, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O, HN, VPre, VBlw, VAbv, IS,CMAbv, O, VPst, B, R, R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,VMPst, O,VMAbv,CMBlw, IS, R,FMAbv, B, CS, CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv, - VPst, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, CS, SUB, SUB, GB, FBlw, FBlw,CMAbv, - IS, VBlw, IS, R, MBlw, GB, VAbv, R,VMPst, G, G, J, J, J, SB, SE, - J, HR, G, G, HM, HM, HM, G, O, MPre, MPre, MPst,VMAbv, MBlw, VBlw, O, - VBlw, + VPst, MPst, R, MPst,CMBlw, B,FMBlw, CS, SUB, SUB, GB, FBlw, FBlw,CMAbv, IS, VBlw, + IS, R, MBlw, GB, VAbv, R,VMPst, G, G, J, J, J, SB, SE, J, HR, + G, G, HM, HM, HM, G, O, MPre, MPre, MPst,VMAbv, MBlw, VBlw, O, VBlw, }; -static const uint16_t -hb_use_u16[856] = +static const uint16_t hb_use_u16[864]= { 0, 0, 1, 2, 0, 3, 0, 3, 0, 0, 4, 5, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, @@ -330,66 +329,65 @@ hb_use_u16[856] = 73, 74, 75, 76, 77, 0, 0, 0, 10, 10, 78, 79, 80, 81, 82, 83, 84, 85, 0, 0, 0, 0, 0, 0, 10, 86, 10, 87, 10, 88, 89, 90, 10, 10, 10, 91, 92, 93, 2, 0, 94, 0, 10, 10, 10, 10, 10, 95, - 96, 10, 97, 0, 0, 0, 0, 0, 98, 99,100,101, 31, 10,102,103, - 10, 10,104, 10,105,106, 0, 0, 10,107, 10, 10, 10,108,109,110, - 2, 2, 0, 0, 0, 0, 0, 0,111, 10, 10,112,113, 2,114,115, - 116, 10,117, 10, 10, 10,118,119, 10, 10,120,121,122, 0, 0, 0, - 0, 0, 0, 0, 0,123,124,125, 0, 0, 0, 0, 0, 0, 0,126, - 127,128,129, 0, 0, 0,130,131,132, 0, 0, 0, 0, 0, 0,133, - 0, 0, 0, 0,134, 0, 0, 0, 0, 0, 0, 0, 0, 0,135, 0, - 0, 0, 0, 10, 10, 10,136,137, 0, 0,138, 0, 0, 0, 0, 0, - 139, 10,140, 0, 10, 10, 10,141,142, 10, 10,143,144, 2,145,146, - 10, 10,147, 10,148,149, 0, 0,150, 10, 10,151,152, 2,153, 99, - 10, 10,154,155,156, 2, 10,157, 10, 10, 10,158,159, 0,160,161, - 0, 0, 0, 0, 10, 10,162, 2,163, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,164, 0, 0, 0, 0, 0, 0, 0,165, - 0, 0, 0, 0, 0, 0, 0,166,166,167, 34,168, 0, 0, 0, 0, - 169,170, 10,171, 95, 0, 0, 0, 0, 0, 0, 0, 70, 10,172, 0, - 10,173,174, 0, 0, 0, 0, 0, 10, 10,175, 2, 9, 10,176, 10, - 177, 0, 0, 0, 0, 0, 0, 0, 10, 10,178,173, 0, 0, 0, 0, - 0, 0, 0, 10,179,180, 0, 10,181, 0, 0,182,183, 0, 0, 0, - 184, 10, 10,185,186,187,188,189,190, 10, 10,191,192, 0, 0, 0, - 193, 10,194,195,196, 10, 10,197,190, 10, 10,198,199,106,200,103, - 10, 34,201,202,203, 0, 0, 0,204,205, 95, 10, 10,206,207, 2, - 208, 21, 22,209,210,211,212,213,214, 10, 10,215,216,217,218, 0, - 10, 10, 10,219,220,221,222, 0,200, 10, 10,223,224, 2, 0, 0, - 10, 10,225,226,227,228, 0, 0, 10, 10, 10,229,230, 2, 0, 0, - 10, 10,231,232, 2, 10,141, 0, 10,233,234,104,235, 0, 0, 0, - 10, 10,236,237, 0, 0, 0, 0,238,239, 10,240,241, 2, 0, 0, - 0, 0,242, 10, 10,243,244, 0,245, 10, 10,246,247,248, 10, 10, - 249,250, 0, 0, 0, 0, 0, 0, 22, 10,225,251, 8, 10, 71, 19, - 10,252, 74,253, 0, 0, 0, 0,254, 10, 10,255,256, 2,257, 10, - 258,259, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10,260, - 261, 49, 10,262,263,264, 0, 0,265,265,265,265,265,265,265,265, - 265,265,265,266,267,268,265,265,265,265,265,265,265,265,265,269, - 10,270,271, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, - 10, 10, 10,272, 0, 0, 0, 0, 0, 0, 0, 0,273, 10,274, 2, - 10, 10, 10, 10,275,276,277,277,278,279, 0, 0, 0, 0,280, 0, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,177, 0,281, - 10, 10, 10, 10, 10, 10,106, 71, 95,282, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,283, 10, 10, 71,284,285, 0, 0, 0, - 0, 10,286, 0, 10, 10,287, 2, 0, 0, 0, 0, 0, 10,288, 2, - 0, 0, 0, 0, 0, 10,289,106, 10, 10, 10, 10,290, 2, 0, 0, - 130,130,130,130,130,130,130,130,163,163,163,163,163,163,163,163, - 163,163,163,163,163,163,163,130, + 96, 10, 97, 0, 0, 0, 0, 0, 10, 98, 99,100, 31, 10,101,102, + 10, 10,103, 10,104,105, 0, 0, 10,106, 10, 10, 10,107,108,109, + 2, 2, 0, 0, 0, 0, 0, 0,110, 10, 10,111,112, 2,113,114, + 115, 10,116, 10, 10, 10,117,118, 10, 10,119,120,121, 0, 0, 0, + 0, 0, 0, 0, 0,122,123,124, 0, 0, 0, 0, 0, 0, 0,125, + 126,127,128, 0, 0, 0,129,130,131, 0, 0, 0, 0, 0, 0,132, + 0, 0, 0, 0,133, 0, 0, 0, 0, 0, 0, 0, 0, 0,134, 0, + 0, 0, 0, 10, 10, 10,135,136, 0, 0,137, 0, 0, 0, 0, 0, + 138, 10,139, 0, 10, 10, 10,140,141, 10, 10,142,143, 2,144,145, + 10, 10,146, 10,147,148, 0, 0,149, 10, 10,150,151, 2,152, 98, + 10, 10,153,154,155, 2, 10,156, 10, 10, 10,157,158, 0,159,160, + 0, 0, 0, 0, 10, 10,161, 2,162, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,163, 0, 0, 0, 0, 0, 0, 0,164, + 0, 0, 0, 0, 0, 0, 0,165,165,166, 34,167, 0, 0, 0, 0, + 168,169, 10,170, 95, 0, 0, 0, 0, 0, 0, 0, 70, 10,171, 0, + 10,172,173, 0, 0, 0, 0, 0, 10, 10,174, 2, 9, 10,175, 10, + 176, 0, 0, 0, 0, 0, 0, 0, 10, 10,177,172, 0, 0, 0, 0, + 0, 0, 0, 10,178,179, 0, 10,180, 0, 0,181,182, 0, 0, 0, + 183, 10, 10,184,185,186,187,188,189, 10, 10,190,191, 0, 0, 0, + 192, 10,193,194,195, 10, 10,196,189, 10, 10,197,198,105,199,102, + 10, 34,200,201,202, 0, 0, 0,203,204, 95, 10, 10,205,206, 2, + 207, 21, 22,208,209,210,211,212,213, 10, 10,214,215,216,217, 0, + 10, 10, 10,218,219,220,221, 0,199, 10, 10,222,223, 2, 0, 0, + 10, 10,224,225,226,227, 0, 0, 10, 10, 10,228,229, 2, 0, 0, + 10, 10,230,231, 2, 10,140, 0, 10,232,233,103,234, 0, 0, 0, + 10, 10,235,236, 0, 0, 0, 0,237,238, 10,239,240, 2, 0, 0, + 0, 0,241, 10, 10,242,243, 0,244, 10, 10,245,246,247, 10, 10, + 248,249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,250, 0, + 22, 10,224,251, 8, 10, 71, 19, 10,252, 74,253, 0, 0, 0, 0, + 254, 10, 10,255,256, 2,257, 10,258,259, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 10,260,261, 49, 10,262,263,264, 0, 0, + 265,265,265,265,265,265,265,265,265,265,265,266,267,268,265,265, + 265,265,265,265,265,265,265,269, 10,270,271, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 0, 0, 0, 10, 10, 10,272, 0, 0, 0, 0, + 0, 0, 0, 0,273, 10,274, 2, 10, 10, 10, 10,275,276,277,277, + 278,279, 0, 0, 0, 0,280, 0, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10,176, 0,281, 10, 10, 10, 10, 10, 10,105, 71, + 95,282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,283, + 10, 10, 71,284,285, 0, 0, 0, 0, 10,286, 0, 10, 10,287, 2, + 0, 0, 0, 0, 0, 10,288, 2, 0, 0, 0, 0, 0, 10,289,105, + 10, 10, 10, 10,290, 2, 0, 0,129,129,129,129,129,129,129,129, + 162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,129, }; -static inline unsigned -hb_use_b4 (const uint8_t* a, unsigned i) +static inline uint8_t hb_use_b4 (const uint8_t* a, unsigned i) { - return (a[i>>1]>>((i&1u)<<2))&15u; + return (a[i>>1]>>((i&1)<<2))&15; } -static inline uint_fast8_t -hb_use_get_category (unsigned u) +static inline uint8_t hb_use_get_category (unsigned u) { - return u<921600u?hb_use_u8[2953+(((hb_use_u8[625+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O; + return u<921600 ? hb_use_u8[2953u+((hb_use_u8[625u+((hb_use_u16[((hb_use_u8[113u+((hb_use_b4(hb_use_u8,((((((((u)>>1))>>3))>>3))>>5)))<<5)+((((((((u)>>1))>>3))>>3))&31)])<<3)+((((((u)>>1))>>3))&7)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : O; } #else -static const uint8_t -hb_use_u8[3657] = +#include + +static const uint8_t hb_use_u8[3663]= { 16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 57, 58, 59, 195, 211, 62, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, @@ -405,16 +403,16 @@ hb_use_u8[3657] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 25, 26, 27, 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 29, 30, 1, 1, 1, 1, 1, 31, 1, 1, 1, 1, 32, 33, 1, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 1, 48, 49, 50, - 51, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 54, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 55, 1, 1, 1, 1, 1, 1, 1, 1, 56, 57, 1, 58, 1, - 59, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 60, 61, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 1, - 1, 1, 63, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 64, 65, 1, 66, 67, 1, 1, 1, 68, 1, 1, 1, 1, 1, - 1, 69, 70, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 0, 1, 2, 2, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 53, 53, 53, 54, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 55, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 56, 1, 1, 1, 1, 1, 1, 1, 1, 57, 58, 1, 59, 1, + 60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 61, 62, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 63, 1, 1, + 1, 1, 64, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 65, 66, 1, 67, 68, 1, 1, 1, 69, 1, 1, 1, 1, 1, + 1, 70, 71, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 0, 1, 2, 2, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, 9, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, @@ -438,120 +436,120 @@ hb_use_u8[3657] = 0, 0, 0, 0, 0, 56, 179, 180, 0, 56, 181, 182, 0, 56, 183, 184, 185, 186, 187, 188, 0, 0, 0, 0, 0, 56, 189, 0, 0, 0, 0, 0, 0, 190, 191, 192, 0, 0, 193, 194, 195, 196, 197, 198, 56, 199, 0, 0, - 0, 200, 201, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 67, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 211, 212, 213, 214, 0, 0, 0, 0, - 0, 215, 215, 215, 215, 215, 215, 215, 215, 215, 216, 217, 215, 215, 215, 215, - 215, 215, 215, 215, 215, 215, 215, 215, 218, 219, 220, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 67, 0, 56, 221, 0, 0, 0, 0, 0, - 0, 0, 0, 222, 223, 0, 0, 0, 0, 56, 56, 224, 225, 226, 0, 0, - 227, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 228, - 229, 56, 56, 56, 230, 231, 0, 0, 0, 0, 0, 0, 232, 0, 0, 0, - 0, 56, 233, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 235, 56, - 236, 0, 0, 0, 0, 0, 0, 101, 237, 0, 0, 0, 0, 0, 0, 101, - 238, 56, 56, 239, 0, 0, 0, 0, 0, 240, 240, 240, 240, 240, 240, 240, - 240, 241, 241, 241, 241, 241, 241, 241, 242, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 2, 2, 2, 2, 0, 0, - 0, 0, 0, 0, 0, 0, 3, 4, 0, 5, 0, 0, 0, 0, 0, 6, - 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 10, 11, 11, 11, 11, 0, 0, 0, 9, 12, - 0, 2, 2, 2, 2, 13, 14, 0, 0, 11, 15, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 16, 17, 18, 19, 20, 21, 22, 16, 23, 24, - 25, 12, 26, 27, 20, 2, 2, 2, 2, 2, 20, 0, 2, 2, 2, 2, - 2, 0, 2, 2, 2, 2, 2, 2, 2, 28, 29, 30, 2, 2, 2, 9, - 30, 9, 30, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 9, 2, 2, - 2, 9, 9, 0, 2, 2, 0, 17, 18, 19, 20, 31, 32, 33, 32, 34, - 0, 0, 0, 0, 35, 0, 0, 2, 30, 2, 0, 0, 0, 0, 0, 9, - 36, 12, 15, 30, 2, 2, 9, 0, 30, 9, 2, 30, 9, 2, 0, 37, - 18, 19, 31, 0, 27, 38, 27, 39, 0, 40, 0, 0, 0, 30, 2, 9, - 9, 0, 0, 0, 2, 2, 2, 2, 2, 41, 42, 43, 0, 0, 0, 0, - 0, 12, 15, 30, 2, 2, 2, 2, 30, 2, 30, 2, 2, 2, 2, 2, - 2, 9, 2, 30, 2, 2, 0, 17, 18, 19, 20, 21, 27, 22, 35, 24, - 0, 0, 0, 0, 0, 30, 41, 41, 44, 12, 29, 30, 2, 2, 2, 9, - 30, 9, 2, 30, 2, 2, 0, 17, 45, 0, 0, 27, 22, 0, 0, 2, - 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 46, 30, 2, 2, 9, 0, - 2, 9, 2, 2, 0, 30, 9, 9, 2, 0, 30, 9, 0, 2, 9, 0, - 2, 2, 2, 2, 2, 2, 0, 0, 23, 16, 47, 0, 48, 33, 48, 34, - 0, 0, 0, 0, 35, 0, 0, 0, 0, 15, 29, 49, 2, 2, 2, 9, - 2, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 17, - 22, 16, 23, 47, 22, 38, 22, 39, 0, 0, 0, 27, 31, 2, 9, 0, - 0, 10, 29, 30, 2, 2, 2, 9, 2, 2, 2, 30, 2, 2, 0, 17, - 45, 0, 0, 35, 47, 0, 0, 0, 9, 50, 51, 0, 0, 0, 0, 0, - 0, 11, 29, 2, 2, 2, 2, 9, 2, 2, 2, 2, 2, 2, 52, 53, - 23, 19, 20, 31, 48, 33, 48, 34, 54, 0, 0, 0, 35, 0, 0, 0, - 30, 12, 29, 30, 2, 2, 2, 2, 2, 2, 2, 2, 9, 0, 2, 2, - 2, 2, 30, 2, 2, 2, 2, 30, 0, 2, 2, 2, 9, 0, 55, 0, - 35, 23, 22, 31, 31, 18, 48, 48, 25, 0, 23, 0, 0, 0, 0, 0, - 0, 2, 0, 2, 9, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, - 0, 2, 2, 56, 56, 57, 0, 0, 18, 2, 2, 2, 2, 30, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 9, 0, 58, 21, 59, 22, 22, 20, 20, - 46, 21, 11, 31, 11, 2, 2, 60, 61, 61, 61, 61, 61, 62, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 63, - 0, 0, 0, 0, 64, 0, 0, 0, 0, 2, 2, 2, 2, 2, 65, 45, - 59, 66, 22, 22, 67, 68, 69, 70, 71, 2, 2, 2, 2, 2, 1, 0, - 5, 2, 2, 2, 23, 20, 2, 2, 72, 71, 73, 74, 65, 73, 29, 29, - 2, 52, 22, 53, 2, 2, 2, 2, 2, 2, 75, 76, 77, 29, 29, 78, - 79, 2, 2, 2, 2, 2, 29, 45, 0, 2, 59, 80, 0, 0, 0, 0, - 30, 2, 59, 47, 0, 0, 0, 0, 0, 2, 59, 0, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 2, 9, 2, 9, 59, 0, 0, 0, 0, 0, - 0, 2, 2, 81, 45, 22, 59, 20, 48, 48, 48, 48, 15, 82, 83, 84, - 85, 86, 87, 0, 0, 0, 0, 88, 0, 9, 0, 0, 30, 0, 89, 81, - 90, 2, 2, 2, 2, 9, 0, 0, 0, 42, 42, 91, 92, 2, 2, 2, - 2, 2, 2, 2, 2, 13, 9, 0, 0, 93, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 9, 22, 80, 45, 22, 94, 61, 0, - 0, 95, 96, 95, 95, 97, 98, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 200, 0, 0, 0, 0, 201, 202, 203, 204, 205, 206, 0, + 0, 207, 208, 209, 210, 211, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 212, 213, 214, 215, 0, 0, 0, 0, 0, 216, 216, 216, 216, 216, 216, 216, + 216, 216, 217, 218, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, + 219, 220, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, + 0, 56, 222, 0, 0, 0, 0, 0, 0, 0, 0, 223, 224, 0, 0, 0, + 0, 56, 56, 225, 226, 227, 0, 0, 228, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 229, 230, 56, 56, 56, 231, 232, 0, 0, + 0, 0, 0, 0, 233, 0, 0, 0, 0, 56, 234, 235, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 101, 236, 56, 237, 0, 0, 0, 0, 0, 0, 101, + 238, 0, 0, 0, 0, 0, 0, 101, 239, 56, 56, 240, 0, 0, 0, 0, + 0, 241, 241, 241, 241, 241, 241, 241, 241, 242, 242, 242, 242, 242, 242, 242, + 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, + 0, 5, 0, 0, 0, 0, 0, 6, 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 11, + 11, 11, 11, 0, 0, 0, 9, 12, 0, 2, 2, 2, 2, 13, 14, 0, + 0, 11, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 17, + 18, 19, 20, 21, 22, 16, 23, 24, 25, 12, 26, 27, 20, 2, 2, 2, + 2, 2, 20, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, + 2, 28, 29, 30, 2, 2, 2, 9, 30, 9, 30, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 9, 2, 2, 2, 9, 9, 0, 2, 2, 0, 17, + 18, 19, 20, 31, 32, 33, 32, 34, 0, 0, 0, 0, 35, 0, 0, 2, + 30, 2, 0, 0, 0, 0, 0, 9, 36, 12, 15, 30, 2, 2, 9, 0, + 30, 9, 2, 30, 9, 2, 0, 37, 18, 19, 31, 0, 27, 38, 27, 39, + 0, 40, 0, 0, 0, 30, 2, 9, 9, 0, 0, 0, 2, 2, 2, 2, + 2, 41, 42, 43, 0, 0, 0, 0, 0, 12, 15, 30, 2, 2, 2, 2, + 30, 2, 30, 2, 2, 2, 2, 2, 2, 9, 2, 30, 2, 2, 0, 17, + 18, 19, 20, 21, 27, 22, 35, 24, 0, 0, 0, 0, 0, 30, 41, 41, + 44, 12, 29, 30, 2, 2, 2, 9, 30, 9, 2, 30, 2, 2, 0, 17, + 45, 0, 0, 27, 22, 0, 0, 2, 30, 30, 0, 0, 0, 0, 0, 0, + 0, 0, 46, 30, 2, 2, 9, 0, 2, 9, 2, 2, 0, 30, 9, 9, + 2, 0, 30, 9, 0, 2, 9, 0, 2, 2, 2, 2, 2, 2, 0, 0, + 23, 16, 47, 0, 48, 33, 48, 34, 0, 0, 0, 0, 35, 0, 0, 0, + 0, 15, 29, 49, 2, 2, 2, 9, 2, 9, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 17, 22, 16, 23, 47, 22, 38, 22, 39, + 0, 0, 0, 27, 31, 2, 9, 0, 0, 10, 29, 30, 2, 2, 2, 9, + 2, 2, 2, 30, 2, 2, 0, 17, 45, 0, 0, 35, 47, 0, 0, 0, + 9, 50, 51, 0, 0, 0, 0, 0, 0, 11, 29, 2, 2, 2, 2, 9, + 2, 2, 2, 2, 2, 2, 52, 53, 23, 19, 20, 31, 48, 33, 48, 34, + 54, 0, 0, 0, 35, 0, 0, 0, 30, 12, 29, 30, 2, 2, 2, 2, + 2, 2, 2, 2, 9, 0, 2, 2, 2, 2, 30, 2, 2, 2, 2, 30, + 0, 2, 2, 2, 9, 0, 55, 0, 35, 23, 22, 31, 31, 18, 48, 48, + 25, 0, 23, 0, 0, 0, 0, 0, 0, 2, 0, 2, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 2, 56, 56, 57, 0, 0, + 18, 2, 2, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2, 2, 2, 9, + 0, 58, 21, 59, 22, 22, 20, 20, 46, 21, 11, 31, 11, 2, 2, 60, + 61, 61, 61, 61, 61, 62, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 63, 0, 0, 0, 0, 64, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 65, 45, 59, 66, 22, 22, 67, 68, 69, 70, + 71, 2, 2, 2, 2, 2, 1, 0, 5, 2, 2, 2, 23, 20, 2, 2, + 72, 71, 73, 74, 65, 73, 29, 29, 2, 52, 22, 53, 2, 2, 2, 2, + 2, 2, 75, 76, 77, 29, 29, 78, 79, 2, 2, 2, 2, 2, 29, 45, + 0, 2, 59, 80, 0, 0, 0, 0, 30, 2, 59, 47, 0, 0, 0, 0, + 0, 2, 59, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 9, + 2, 9, 59, 0, 0, 0, 0, 0, 0, 2, 2, 81, 45, 22, 59, 20, + 48, 48, 48, 48, 15, 82, 83, 84, 85, 86, 87, 0, 0, 0, 0, 88, + 0, 9, 0, 0, 30, 0, 89, 81, 90, 2, 2, 2, 2, 9, 0, 0, + 0, 42, 42, 91, 92, 2, 2, 2, 2, 2, 2, 2, 2, 13, 9, 0, + 0, 2, 2, 2, 2, 2, 2, 2, 9, 22, 80, 45, 22, 93, 61, 0, + 0, 94, 95, 94, 94, 96, 97, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 9, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 29, 0, 0, 0, 2, 2, 2, 2, 2, 9, 0, - 0, 2, 2, 2, 52, 99, 45, 0, 0, 2, 2, 100, 101, 102, 103, 61, - 63, 104, 16, 45, 22, 59, 21, 80, 48, 48, 76, 11, 11, 11, 105, 46, - 40, 11, 106, 74, 2, 2, 2, 2, 2, 2, 2, 107, 22, 20, 20, 22, - 48, 48, 22, 108, 2, 2, 2, 9, 0, 0, 0, 0, 0, 0, 109, 110, - 110, 110, 110, 0, 0, 0, 0, 0, 0, 106, 74, 2, 2, 2, 2, 2, - 2, 60, 61, 59, 25, 22, 111, 61, 2, 2, 2, 2, 107, 22, 23, 45, - 45, 102, 112, 0, 0, 0, 0, 0, 0, 2, 2, 61, 18, 48, 23, 113, - 102, 102, 102, 114, 115, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 30, - 2, 11, 46, 116, 116, 116, 11, 116, 116, 15, 116, 116, 116, 26, 0, 40, - 0, 0, 0, 117, 51, 11, 5, 0, 0, 0, 0, 0, 0, 0, 118, 0, - 0, 0, 0, 0, 0, 0, 6, 119, 120, 42, 42, 5, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 120, 120, 121, 120, 120, 120, 120, 120, 120, 120, - 120, 0, 0, 122, 0, 0, 0, 0, 0, 0, 7, 122, 0, 0, 0, 0, + 0, 2, 2, 2, 52, 98, 45, 0, 0, 2, 2, 99, 100, 101, 102, 61, + 63, 103, 16, 45, 22, 59, 21, 80, 48, 48, 76, 11, 11, 11, 104, 46, + 40, 11, 105, 74, 2, 2, 2, 2, 2, 2, 2, 106, 22, 20, 20, 22, + 48, 48, 22, 107, 2, 2, 2, 9, 0, 0, 0, 0, 0, 0, 108, 109, + 109, 109, 109, 0, 0, 0, 0, 0, 0, 105, 74, 2, 2, 2, 2, 2, + 2, 60, 61, 59, 25, 22, 110, 61, 2, 2, 2, 2, 106, 22, 23, 45, + 45, 101, 111, 0, 0, 0, 0, 0, 0, 2, 2, 61, 18, 48, 23, 112, + 101, 101, 101, 113, 114, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 30, + 2, 11, 46, 115, 115, 115, 11, 115, 115, 15, 115, 115, 115, 26, 0, 40, + 0, 0, 0, 116, 51, 11, 5, 0, 0, 0, 0, 0, 0, 0, 117, 0, + 0, 0, 0, 0, 0, 0, 6, 118, 119, 42, 42, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 119, 119, 120, 119, 119, 119, 119, 119, 119, 119, + 119, 0, 0, 121, 0, 0, 0, 0, 0, 0, 7, 121, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, - 0, 0, 0, 0, 123, 123, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, - 30, 0, 0, 0, 0, 0, 0, 0, 124, 0, 123, 123, 0, 0, 0, 0, - 0, 2, 53, 2, 108, 2, 10, 2, 2, 2, 65, 19, 16, 0, 0, 31, + 0, 0, 0, 0, 122, 122, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, + 30, 0, 0, 0, 0, 0, 0, 0, 123, 0, 122, 122, 0, 0, 0, 0, + 0, 2, 53, 2, 107, 2, 10, 2, 2, 2, 65, 19, 16, 0, 0, 31, 0, 2, 2, 0, 0, 0, 0, 0, 0, 29, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 125, 23, 23, 23, 23, 23, 23, 23, 126, 0, 0, 0, 0, + 2, 2, 2, 124, 23, 23, 23, 23, 23, 23, 23, 125, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 0, 0, 0, 0, 0, - 52, 2, 2, 2, 22, 22, 127, 116, 0, 2, 2, 2, 128, 20, 59, 20, - 113, 102, 129, 0, 0, 0, 0, 0, 0, 11, 130, 2, 2, 2, 2, 2, - 2, 2, 131, 23, 22, 20, 48, 132, 133, 134, 0, 0, 0, 0, 0, 0, + 52, 2, 2, 2, 22, 22, 126, 115, 0, 2, 2, 2, 127, 20, 59, 20, + 112, 101, 128, 0, 0, 0, 0, 0, 0, 11, 129, 2, 2, 2, 2, 2, + 2, 2, 130, 23, 22, 20, 48, 131, 132, 133, 0, 0, 0, 0, 0, 0, 0, 2, 2, 52, 30, 2, 2, 2, 2, 2, 2, 2, 2, 10, 22, 59, - 99, 76, 135, 136, 137, 0, 0, 0, 0, 2, 138, 2, 2, 2, 2, 139, - 0, 30, 2, 42, 5, 0, 79, 15, 2, 53, 22, 140, 52, 53, 2, 2, - 105, 10, 9, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 141, 21, + 98, 76, 134, 135, 136, 0, 0, 0, 0, 2, 137, 2, 2, 2, 2, 138, + 0, 30, 2, 42, 5, 0, 79, 15, 2, 139, 20, 53, 127, 139, 2, 2, + 140, 10, 9, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 141, 21, 25, 0, 0, 142, 143, 0, 0, 0, 0, 2, 65, 45, 23, 80, 47, 144, 0, 81, 81, 81, 81, 81, 81, 81, 81, 0, 0, 0, 0, 0, 0, 0, - 6, 120, 120, 120, 120, 121, 0, 0, 0, 2, 2, 2, 2, 2, 9, 2, + 6, 119, 119, 119, 119, 120, 0, 0, 0, 2, 2, 2, 2, 2, 9, 2, 2, 2, 9, 2, 30, 2, 2, 2, 2, 2, 30, 2, 2, 2, 30, 9, - 0, 128, 20, 27, 31, 0, 0, 145, 146, 2, 2, 30, 2, 30, 2, 2, + 0, 127, 20, 27, 31, 0, 0, 145, 146, 2, 2, 30, 2, 30, 2, 2, 2, 2, 2, 2, 0, 14, 37, 0, 147, 2, 2, 13, 37, 0, 30, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 2, 2, 9, 2, 2, 11, 41, 0, 0, 0, 0, 2, 2, 2, 0, 27, 22, 22, 30, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 27, 38, - 0, 2, 2, 2, 116, 116, 116, 116, 116, 148, 2, 9, 0, 0, 0, 0, + 0, 2, 2, 2, 115, 115, 115, 115, 115, 148, 2, 9, 0, 0, 0, 0, 0, 2, 14, 14, 0, 0, 0, 0, 0, 9, 2, 2, 9, 2, 2, 2, 2, 30, 2, 9, 0, 30, 2, 0, 0, 149, 150, 151, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 22, 22, 20, 20, 20, 22, 22, 134, 0, 0, 0, + 2, 2, 2, 2, 2, 22, 22, 20, 20, 20, 22, 22, 133, 0, 0, 0, 0, 0, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 2, 2, 2, 2, 2, 53, 52, 53, 0, 0, 0, 0, 153, 11, 74, 2, 2, 2, 2, 2, 2, 18, 19, 21, 16, 24, 37, 0, 0, 0, 31, 0, 0, 0, 0, 0, - 0, 11, 49, 2, 2, 2, 2, 2, 2, 2, 2, 2, 128, 20, 22, 154, + 0, 11, 49, 2, 2, 2, 2, 2, 2, 2, 2, 2, 127, 20, 22, 154, 22, 21, 155, 156, 2, 2, 2, 2, 2, 0, 0, 65, 157, 0, 0, 0, 0, 2, 13, 0, 0, 0, 0, 0, 0, 2, 65, 25, 20, 20, 20, 22, - 22, 108, 158, 0, 0, 56, 159, 31, 160, 30, 2, 2, 2, 2, 2, 2, + 22, 107, 158, 0, 0, 56, 159, 31, 160, 30, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23, 19, 22, 22, 161, 44, 0, 0, 0, - 49, 128, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 9, 2, 2, + 49, 127, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 9, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2, 10, 18, 19, 21, 22, 162, 31, 0, 0, 11, 11, 30, 2, 2, 2, 9, 30, 9, 2, 30, 2, 2, 58, 17, 23, 16, 23, 47, 32, 33, 32, 34, @@ -559,70 +557,69 @@ hb_use_u8[3657] = 0, 11, 11, 46, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 30, 0, 9, 2, 2, 2, 30, 45, 59, 20, 20, 31, 33, 32, 32, 25, 163, 29, 164, 165, 37, 0, 0, 0, 0, 0, 0, 12, 26, 0, 0, 0, 0, 0, - 0, 2, 2, 65, 25, 20, 20, 20, 22, 23, 126, 15, 17, 0, 0, 0, + 0, 2, 2, 65, 25, 20, 20, 20, 22, 23, 125, 15, 17, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 166, 167, 0, 0, 0, 0, 0, 0, - 0, 18, 19, 20, 20, 66, 99, 25, 160, 11, 168, 9, 0, 0, 0, 0, + 0, 18, 19, 20, 20, 66, 98, 25, 160, 11, 168, 9, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 65, 25, 20, 20, 0, 48, 48, 11, 169, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 20, 0, 23, 19, 20, 20, 21, 16, 82, 169, 38, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 10, 170, 25, 20, 22, 22, 168, 9, 0, 0, - 0, 2, 2, 2, 2, 2, 9, 43, 136, 23, 22, 20, 76, 21, 22, 0, + 0, 2, 2, 2, 2, 2, 9, 43, 135, 23, 22, 20, 76, 21, 22, 0, 0, 2, 2, 2, 9, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 18, - 19, 20, 21, 22, 105, 169, 37, 0, 0, 2, 2, 2, 9, 30, 0, 2, + 19, 20, 21, 22, 104, 169, 37, 0, 0, 2, 2, 2, 9, 30, 0, 2, 2, 2, 2, 30, 9, 2, 2, 2, 2, 23, 23, 18, 32, 33, 12, 171, 165, 172, 173, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2, - 2, 65, 25, 20, 20, 0, 22, 23, 29, 108, 0, 33, 0, 0, 0, 0, - 0, 52, 20, 22, 22, 22, 140, 2, 2, 2, 174, 175, 11, 15, 176, 61, - 177, 0, 0, 1, 147, 0, 0, 0, 0, 52, 20, 22, 16, 19, 20, 2, - 2, 2, 2, 158, 158, 158, 178, 178, 178, 178, 178, 178, 15, 179, 0, 30, - 0, 22, 20, 20, 31, 22, 22, 11, 169, 0, 61, 61, 61, 61, 61, 61, - 61, 66, 21, 82, 46, 0, 0, 0, 0, 2, 2, 2, 9, 2, 30, 2, - 2, 52, 22, 22, 31, 0, 38, 22, 27, 11, 159, 180, 181, 0, 0, 0, - 0, 2, 2, 2, 30, 9, 2, 2, 2, 2, 2, 2, 2, 2, 23, 23, - 47, 22, 35, 82, 68, 0, 0, 0, 0, 2, 182, 66, 47, 0, 0, 0, - 0, 11, 183, 2, 2, 2, 2, 2, 2, 2, 2, 23, 22, 20, 31, 0, - 48, 16, 143, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 156, 0, - 0, 184, 184, 184, 184, 184, 184, 184, 184, 185, 185, 185, 186, 187, 185, 184, - 184, 188, 184, 184, 189, 190, 190, 190, 190, 190, 190, 190, 0, 0, 0, 0, - 0, 184, 184, 184, 184, 184, 191, 0, 0, 2, 2, 2, 2, 2, 2, 2, - 22, 22, 22, 22, 22, 22, 192, 193, 194, 11, 11, 11, 46, 0, 0, 0, - 0, 29, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 65, 47, - 0, 2, 2, 2, 2, 2, 9, 0, 58, 195, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, - 40, 116, 26, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 30, 2, 2, 2, 2, 2, 0, 58, - 37, 0, 6, 120, 120, 120, 121, 0, 0, 11, 11, 11, 49, 2, 2, 2, - 0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, - 46, 2, 2, 2, 2, 2, 2, 11, 11, 2, 2, 2, 2, 2, 2, 22, - 22, 2, 2, 2, 2, 2, 2, 2, 20, 2, 2, 44, 44, 44, 92, 0, - 0, O, O, O, GB, B, B, O, SB, O, SE, GB, O, O, WJ,FMPst, - FMPst, O, CGJ, B, O, B,VMAbv,VMAbv,VMAbv, O,VMAbv, B,CMBlw,CMBlw,CMBlw,VMAbv, - VMPst, VAbv, VPst,CMBlw, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, - VPst, VPst, H, VPre, VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,VMPst, O, B, VBlw, - O, O, VPre, VPre, O, VPre, H, O, VPst,FMAbv, O,CMBlw, O, VAbv, O, VAbv, - H, O,VMBlw,VMAbv,CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv, O, VPst, - O, VPre, VPre,VMAbv, B, O, CS, CS,VMPst, B, VAbv, VAbv, B, R, O, HVM, - O, O,FMBlw, O,CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB, SUB, O, SUB, SUB, - O,FMBlw, O, B, VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw, - B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw, B, - VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS, - FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB, B, VAbv, SUB, FPst, - FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, - SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,SMAbv,SMAbv,SMAbv, VPst, - IS, RK, RK, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv, CS, O,FMAbv, ZWNJ, - CGJ, WJ, WJ, WJ, O,FMPst, O, SB, SE, O, H, MPst, VPst, H,VMAbv, VAbv, - VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H, O, VBlw, - MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw, B, B, VPre, O,VMPst, IS, - O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, - B, N, N, O, HN, VPre, VBlw, VAbv, IS,CMAbv, O, VPst, B, R, R,CMBlw, - VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,VMPst, O,VMAbv,CMBlw, IS, R,FMAbv, B, CS, - CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv, VPst, MPst, R, MPst,CMBlw, B,FMBlw, VBlw, - VMAbv, CS, SUB, SUB, GB, FBlw, FBlw,CMAbv, IS, VBlw, IS, R, MBlw, GB, VAbv, R, - VMPst, G, G, J, J, J, SB, SE, J, HR, G, G, HM, HM, HM, G, - O, MPre, MPre, MPst,VMAbv, MBlw, VBlw, O, VBlw, + 2, 65, 25, 20, 20, 0, 22, 23, 29, 107, 0, 33, 0, 0, 0, 0, + 0, 52, 20, 22, 22, 22, 139, 2, 2, 2, 174, 140, 11, 15, 175, 61, + 176, 0, 0, 1, 147, 0, 0, 0, 0, 52, 20, 22, 16, 19, 20, 2, + 2, 2, 2, 158, 158, 158, 177, 177, 177, 177, 177, 177, 15, 178, 0, 30, + 0, 16, 20, 16, 16, 0, 0, 0, 0, 22, 20, 20, 31, 22, 22, 11, + 169, 0, 61, 61, 61, 61, 61, 61, 61, 66, 21, 82, 46, 0, 0, 0, + 0, 2, 2, 2, 9, 2, 30, 2, 2, 52, 22, 22, 31, 0, 38, 22, + 27, 11, 159, 179, 180, 0, 0, 0, 0, 2, 2, 2, 30, 9, 2, 2, + 2, 2, 2, 2, 2, 2, 23, 23, 47, 22, 35, 82, 68, 0, 0, 0, + 0, 2, 181, 66, 47, 0, 0, 0, 0, 11, 182, 2, 2, 2, 2, 2, + 2, 2, 2, 23, 22, 20, 31, 0, 48, 16, 143, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 156, 0, 0, 183, 183, 183, 183, 183, 183, 183, + 183, 184, 184, 184, 185, 186, 184, 183, 183, 187, 183, 183, 188, 189, 189, 189, + 189, 189, 189, 189, 0, 0, 0, 0, 0, 183, 183, 183, 183, 183, 190, 0, + 0, 2, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, 22, 22, 191, 192, + 193, 11, 11, 11, 46, 0, 0, 0, 0, 29, 74, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 65, 47, 0, 2, 2, 2, 2, 2, 9, 0, + 58, 194, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 0, 0, 0, 40, 115, 26, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 30, 2, 2, 2, 2, 2, 0, 58, 37, 0, 6, 119, 119, 119, 120, 0, + 0, 11, 11, 11, 49, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 46, 2, 2, 2, 2, 2, 2, 11, + 11, 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2, 2, 2, 2, + 20, 2, 2, 44, 44, 44, 92, 0, 0, O, O, O, GB, B, B, O, + SB, O, SE, GB, O, O, WJ,FMPst,FMPst, O, CGJ, B, O, B,VMAbv,VMAbv, + VMAbv, O,VMAbv, B,CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw, B, VPst, VPre, VPst, + VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre, VPst,VMBlw, O, O, + VAbv, GB,VMAbv,VMPst,VMPst, O, B, VBlw, O, O, VPre, VPre, O, VPre, H, O, + VPst,FMAbv, O,CMBlw, O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,CMAbv, GB, GB, O, + MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv, B, O, CS, CS, + VMPst, B, VAbv, VAbv, B, R, O, HVM, O, O,FMBlw, O,CMAbv, O,CMBlw, VAbv, + VBlw, B, SUB, SUB, SUB, O, SUB, SUB, O,FMBlw, O, B, VPst, VBlw, VPre,VMAbv, + VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw, + VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv, + FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB, + CMAbv,CMAbv, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B, + MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H, + B, O,SMAbv,SMAbv,SMAbv, VPst, IS, RK, RK, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw, + VMBlw,VMAbv, CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, SB, SE, O, + H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv, + MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw, + B, VBlw,VMAbv, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O, + IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O, HN, VPre, VBlw, VAbv, + IS,CMAbv, O, VPst, B, R, R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,VMPst, + O,VMAbv,CMBlw, IS, R,FMAbv, B, CS, CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv, + VPst, MPst, R, MPst,CMBlw, B,FMBlw, CS, SUB, SUB, GB, FBlw, FBlw,CMAbv, IS, VBlw, + IS, R, MBlw, GB, VAbv, R,VMPst, G, G, J, J, J, SB, SE, J, HR, + G, G, HM, HM, HM, G, O, MPre, MPre, MPst,VMAbv, MBlw, VBlw, O, VBlw, }; -static const uint16_t -hb_use_u16[486] = +static const uint16_t hb_use_u16[488]= { 0, 0, 1, 2, 0, 3, 4, 5, 0, 6, 7, 0, 8, 0, 9, 10, 11, 12, 10, 13, 14, 10, 10, 15, 16, 17, 18, 19, 20, 21, 22, 23, @@ -633,43 +630,43 @@ hb_use_u16[486] = 31, 66, 67, 68, 10, 69, 70, 10, 71, 72, 73, 74, 75, 76, 77, 0, 10, 10, 78, 79, 80, 81, 82, 83, 84, 85, 10, 86, 10, 87, 10, 88, 89, 90, 10, 91, 92, 93, 2, 0, 94, 0, 10, 95, 96, 10, 97, 0, - 98, 99,100,101, 31, 10,102,103,104, 10,105,106, 10,107, 10,108, - 109,110, 2, 2,111, 10, 10,112,113, 2,114,115,116, 10,117, 10, - 118,119,120,121,122, 0, 0,123,124,125, 0,126,127,128,129, 0, - 130,131,132, 0, 0,133,134, 0,135, 0, 0, 10,136,137,138, 0, - 139, 10,140, 0, 10,141,142, 10, 10,143,144, 2,145,146,147, 10, - 148,149,150, 10, 10,151,152, 2,153, 99,154,155,156, 2, 10,157, - 10,158,159, 0,160,161,162, 2,163, 0, 0,164, 0,165, 0,166, - 166,167, 34,168,169,170, 10,171, 95, 0,172, 0, 10,173,174, 0, - 175, 2,176, 10,177, 0,178,173,179,180,181, 0, 0,182,183, 0, - 184, 10, 10,185,186,187,188,189,190, 10, 10,191,192, 0,193, 10, - 194,195,196, 10, 10,197, 10,198,199,106,200,103, 10, 34,201,202, - 203, 0,204,205, 95, 10, 10,206,207, 2,208, 21, 22,209,210,211, - 212,213,214, 10, 10,215,216,217,218, 0, 10,219,220,221,222, 0, - 200, 10, 10,223,224, 2,225,226,227,228, 10,229,230, 2,231,232, - 2, 10,141, 0, 10,233,234,104,235, 0,236,237,238,239, 10,240, - 241, 2,242, 10, 10,243,244, 0,245, 10, 10,246,247,248,249,250, - 22, 10,225,251, 8, 10, 71, 19, 10,252, 74,253,254, 10, 10,255, - 256, 2,257, 10,258,259, 10,260,261, 49, 10,262,263,264,265,265, - 265,266,267,268,265,269, 10,270,271, 2, 10,272,273, 10,274, 2, - 275,276,277,277,278,279,280, 0, 10,177, 0,281,106, 71, 95,282, - 0,283, 71,284,285, 0,286, 0,287, 2,288, 2,289,106,290, 2, - 130,130,163,163,163,130, + 10, 98, 99,100, 31, 10,101,102,103, 10,104,105, 10,106, 10,107, + 108,109, 2, 2,110, 10, 10,111,112, 2,113,114,115, 10,116, 10, + 117,118,119,120,121, 0, 0,122,123,124, 0,125,126,127,128, 0, + 129,130,131, 0, 0,132,133, 0,134, 0, 0, 10,135,136,137, 0, + 138, 10,139, 0, 10,140,141, 10, 10,142,143, 2,144,145,146, 10, + 147,148,149, 10, 10,150,151, 2,152, 98,153,154,155, 2, 10,156, + 10,157,158, 0,159,160,161, 2,162, 0, 0,163, 0,164, 0,165, + 165,166, 34,167,168,169, 10,170, 95, 0,171, 0, 10,172,173, 0, + 174, 2,175, 10,176, 0,177,172,178,179,180, 0, 0,181,182, 0, + 183, 10, 10,184,185,186,187,188,189, 10, 10,190,191, 0,192, 10, + 193,194,195, 10, 10,196, 10,197,198,105,199,102, 10, 34,200,201, + 202, 0,203,204, 95, 10, 10,205,206, 2,207, 21, 22,208,209,210, + 211,212,213, 10, 10,214,215,216,217, 0, 10,218,219,220,221, 0, + 199, 10, 10,222,223, 2,224,225,226,227, 10,228,229, 2,230,231, + 2, 10,140, 0, 10,232,233,103,234, 0,235,236,237,238, 10,239, + 240, 2,241, 10, 10,242,243, 0,244, 10, 10,245,246,247,248,249, + 250, 0, 22, 10,224,251, 8, 10, 71, 19, 10,252, 74,253,254, 10, + 10,255,256, 2,257, 10,258,259, 10,260,261, 49, 10,262,263,264, + 265,265,265,266,267,268,265,269, 10,270,271, 2, 10,272,273, 10, + 274, 2,275,276,277,277,278,279,280, 0, 10,176, 0,281,105, 71, + 95,282, 0,283, 71,284,285, 0,286, 0,287, 2,288, 2,289,105, + 290, 2,129,129,162,162,162,129, }; -static inline unsigned -hb_use_b4 (const uint8_t* a, unsigned i) +static inline uint8_t hb_use_b4 (const uint8_t* a, unsigned i) { - return (a[i>>1]>>((i&1u)<<2))&15u; + return (a[i>>1]>>((i&1)<<2))&15; } -static inline uint_fast8_t -hb_use_get_category (unsigned u) +static inline uint8_t hb_use_get_category (unsigned u) { - return u<921600u?hb_use_u8[3265+(((hb_use_u8[937+(((hb_use_u16[((hb_use_u8[369+(((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>1>>3>>4))<<4)+((u>>1>>3>>1>>3)&15u))])<<3)+((u>>1>>3>>1)&7u))])<<1)+((u>>1>>3)&1u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O; + return u<921600 ? hb_use_u8[3273u+((hb_use_u8[945u+((hb_use_u16[((hb_use_u8[369u+((hb_use_u8[113u+((hb_use_b4(hb_use_u8,((((((((((u)>>1))>>3))>>1))>>3))>>4)))<<4)+((((((((((u)>>1))>>3))>>1))>>3))&15)])<<3)+((((((((u)>>1))>>3))>>1))&7)])<<1)+((((((u)>>1))>>3))&1)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : O; } + #endif + #undef B #undef CGJ #undef CS diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-vowel-constraints.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-vowel-constraints.cc index 4a112e1c289..bb586a68ce5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-vowel-constraints.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-vowel-constraints.cc @@ -10,8 +10,8 @@ * # Date: 2015-03-12, 21:17:00 GMT [AG] * # Date: 2019-11-08, 23:22:00 GMT [AG] * - * # Scripts-16.0.0.txt - * # Date: 2024-04-30, 21:48:40 GMT + * # Scripts-17.0.0.txt + * # Date: 2025-07-24, 13:28:55 GMT */ #include "hb.hh" diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper.hh index 48cd5296ffd..9993507e360 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper.hh @@ -396,6 +396,12 @@ hb_ot_shaper_categorize (hb_script_t script, case HB_SCRIPT_TODHRI: case HB_SCRIPT_TULU_TIGALARI: + /* Unicode-17.0 additions */ + case HB_SCRIPT_BERIA_ERFE: + case HB_SCRIPT_SIDETIC: + case HB_SCRIPT_TAI_YO: + case HB_SCRIPT_TOLONG_SIKI: + /* If the designer designed the font for the 'DFLT' script, * (or we ended up arbitrarily pick 'latn'), use the default shaper. * Otherwise, use the specific shaper. diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh index 10165f57b75..28bc23d8f01 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh @@ -352,7 +352,7 @@ struct AxisValue { float get_value (unsigned int axis_index) const { - switch (u.format) + switch (u.format.v) { case 1: hb_barrier (); return u.format1.get_value (); case 2: hb_barrier (); return u.format2.get_value (); @@ -364,7 +364,7 @@ struct AxisValue unsigned int get_axis_index () const { - switch (u.format) + switch (u.format.v) { case 1: hb_barrier (); return u.format1.get_axis_index (); case 2: hb_barrier (); return u.format2.get_axis_index (); @@ -376,7 +376,7 @@ struct AxisValue hb_ot_name_id_t get_value_name_id () const { - switch (u.format) + switch (u.format.v) { case 1: hb_barrier (); return u.format1.get_value_name_id (); case 2: hb_barrier (); return u.format2.get_value_name_id (); @@ -389,9 +389,9 @@ struct AxisValue template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { - if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); - TRACE_DISPATCH (this, u.format); - switch (u.format) { + if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format.v); + switch (u.format.v) { case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...)); @@ -403,7 +403,7 @@ struct AxisValue bool keep_axis_value (const hb_array_t axis_records, hb_hashmap_t *user_axes_location) const { - switch (u.format) + switch (u.format.v) { case 1: hb_barrier (); return u.format1.keep_axis_value (axis_records, user_axes_location); case 2: hb_barrier (); return u.format2.keep_axis_value (axis_records, user_axes_location); @@ -420,7 +420,7 @@ struct AxisValue return_trace (false); hb_barrier (); - switch (u.format) + switch (u.format.v) { case 1: hb_barrier (); return_trace (u.format1.sanitize (c)); case 2: hb_barrier (); return_trace (u.format2.sanitize (c)); @@ -433,14 +433,14 @@ struct AxisValue protected: union { - HBUINT16 format; + struct { HBUINT16 v; } format; AxisValueFormat1 format1; AxisValueFormat2 format2; AxisValueFormat3 format3; AxisValueFormat4 format4; } u; public: - DEFINE_SIZE_UNION (2, format); + DEFINE_SIZE_UNION (2, format.v); }; struct AxisValueOffsetArray: UnsizedArrayOf> diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-tag-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-tag-table.hh index 50ddf5f6967..4933e661371 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-tag-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-tag-table.hh @@ -6,8 +6,8 @@ * * on files with these headers: * - * - * File-Date: 2025-01-21 + * + * File-Date: 2025-08-25 */ #ifndef HB_OT_TAG_TABLE_HH @@ -704,7 +704,7 @@ static const LangTag ot_languages3[] = { /*{HB_TAG('g','u','z',' '), HB_TAG('G','U','Z',' ')},*/ /* Gusii */ {HB_TAG('g','w','i',' '), HB_TAG('A','T','H',' ')}, /* Gwichʼin -> Athapaskan */ {HB_TAG('g','y','n',' '), HB_TAG('C','P','P',' ')}, /* Guyanese Creole English -> Creoles */ - {HB_TAG('h','a','a',' '), HB_TAG('A','T','H',' ')}, /* Han -> Athapaskan */ + {HB_TAG('h','a','a',' '), HB_TAG('A','T','H',' ')}, /* Hän -> Athapaskan */ {HB_TAG('h','a','e',' '), HB_TAG('O','R','O',' ')}, /* Eastern Oromo -> Oromo */ {HB_TAG('h','a','i',' '), HB_TAG('H','A','I','0')}, /* Haida [macrolanguage] */ {HB_TAG('h','a','k',' '), HB_TAG('Z','H','S',' ')}, /* Hakka Chinese -> Chinese, Simplified */ @@ -921,7 +921,7 @@ static const LangTag ot_languages3[] = { {HB_TAG('k','v','t',' '), HB_TAG('K','R','N',' ')}, /* Lahta Karen -> Karen */ {HB_TAG('k','v','u',' '), HB_TAG('K','R','N',' ')}, /* Yinbaw Karen -> Karen */ {HB_TAG('k','v','y',' '), HB_TAG('K','R','N',' ')}, /* Yintale Karen -> Karen */ -/*{HB_TAG('k','w','k',' '), HB_TAG('K','W','K',' ')},*/ /* Kwakiutl -> Kwakʼwala */ +/*{HB_TAG('k','w','k',' '), HB_TAG('K','W','K',' ')},*/ /* Kwakʼwala */ {HB_TAG('k','w','w',' '), HB_TAG('C','P','P',' ')}, /* Kwinti -> Creoles */ {HB_TAG('k','w','y',' '), HB_TAG('K','O','N','0')}, /* San Salvador Kongo -> Kongo */ {HB_TAG('k','x','c',' '), HB_TAG('K','M','S',' ')}, /* Konso -> Komso */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-avar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-avar-table.hh index e26687c34ed..8a9307d6933 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-avar-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-avar-table.hh @@ -143,10 +143,13 @@ struct AxisValueMap struct SegmentMaps : Array16Of { - int map (int value, unsigned int from_offset = 0, unsigned int to_offset = 1) const + float map_float (float value, unsigned int from_offset = 0, unsigned int to_offset = 1) const { -#define fromCoord coords[from_offset].to_int () -#define toCoord coords[to_offset].to_int () +#define fromCoord coords[from_offset].to_float () +#define toCoord coords[to_offset].to_float () + + const auto *map = arrayZ; + /* The following special-cases are not part of OpenType, which requires * that at least -1, 0, and +1 must be mapped. But we include these as * part of a better error recovery scheme. */ @@ -155,47 +158,98 @@ struct SegmentMaps : Array16Of if (!len) return value; else /* len == 1*/ - return value - arrayZ[0].fromCoord + arrayZ[0].toCoord; + return value - map[0].fromCoord + map[0].toCoord; } - if (value <= arrayZ[0].fromCoord) - return value - arrayZ[0].fromCoord + arrayZ[0].toCoord; + // At least two mappings now. - unsigned int i; - unsigned int count = len - 1; - for (i = 1; i < count && value > arrayZ[i].fromCoord; i++) - ; + /* CoreText is wild... + * PingFangUI avar needs all this special-casing... + * So we implement an extended version of the spec here, + * which is more robust and more likely to be compatible with + * the wild. */ - if (value >= arrayZ[i].fromCoord) - return value - arrayZ[i].fromCoord + arrayZ[i].toCoord; + unsigned start = 0; + unsigned end = len; + if (map[start].fromCoord == -1 && map[start].toCoord == -1 && map[start+1].fromCoord == -1) + start++; + if (map[end-1].fromCoord == +1 && map[end-1].toCoord == +1 && map[end-2].fromCoord == +1) + end--; - if (unlikely (arrayZ[i-1].fromCoord == arrayZ[i].fromCoord)) - return arrayZ[i-1].toCoord; + /* Look for exact match first, and do lots of special-casing. */ + unsigned i; + for (i = start; i < end; i++) + if (value == map[i].fromCoord) + break; + if (i < end) + { + // There's at least one exact match. See if there are more. + unsigned j = i; + for (; j + 1 < end; j++) + if (value != map[j + 1].fromCoord) + break; + + // [i,j] inclusive are all exact matches: + + // If there's only one, return it. This is the only spec-compliant case. + if (i == j) + return map[i].toCoord; + // If there's exactly three, return the middle one. + if (i + 2 == j) + return map[i + 1].toCoord; + + // Ignore the middle ones. Return the one mapping closer to 0. + if (value < 0) return map[j].toCoord; + if (value > 0) return map[i].toCoord; + + // Mapping 0? CoreText seems confused. It seems to prefer 0 here... + // So we'll just return the smallest one. lol + return fabsf (map[i].toCoord) < fabsf (map[j].toCoord) ? map[i].toCoord : map[j].toCoord; + + // Mapping 0? Return one not mapping to 0. + if (map[i].toCoord == 0) + return map[j].toCoord; + else + return map[i].toCoord; + } + + /* There's at least two and we're not an exact match. Prepare to lerp. */ + + // Find the segment we're in. + for (i = start; i < end; i++) + if (value < map[i].fromCoord) + break; + + if (i == 0) + { + // Value before all segments; Shift. + return value - map[0].fromCoord + map[0].toCoord; + } + if (i == end) + { + // Value after all segments; Shift. + return value - map[end - 1].fromCoord + map[end - 1].toCoord; + } + + // Actually interpolate. + auto &before = map[i-1]; + auto &after = map[i]; + float denom = after.fromCoord - before.fromCoord; // Can't be zero by now. + return before.toCoord + ((after.toCoord - before.toCoord) * (value - before.fromCoord)) / denom; - int denom = arrayZ[i].fromCoord - arrayZ[i-1].fromCoord; - return roundf (arrayZ[i-1].toCoord + ((float) (arrayZ[i].toCoord - arrayZ[i-1].toCoord) * - (value - arrayZ[i-1].fromCoord)) / denom); #undef toCoord #undef fromCoord } - int unmap (int value) const { return map (value, 1, 0); } + float unmap_float (float value) const { return map_float (value, 1, 0); } + + // TODO Kill this. Triple unmap_axis_range (const Triple& axis_range) const { - F2DOT14 val, unmapped_val; - - val.set_float (axis_range.minimum); - unmapped_val.set_int (unmap (val.to_int ())); - float unmapped_min = unmapped_val.to_float (); - - val.set_float (axis_range.middle); - unmapped_val.set_int (unmap (val.to_int ())); - float unmapped_middle = unmapped_val.to_float (); - - val.set_float (axis_range.maximum); - unmapped_val.set_int (unmap (val.to_int ())); - float unmapped_max = unmapped_val.to_float (); + float unmapped_min = unmap_float (axis_range.minimum); + float unmapped_middle = unmap_float (axis_range.middle); + float unmapped_max = unmap_float (axis_range.maximum); return Triple{(double) unmapped_min, (double) unmapped_middle, (double) unmapped_max}; } @@ -203,6 +257,11 @@ struct SegmentMaps : Array16Of bool subset (hb_subset_context_t *c, hb_tag_t axis_tag) const { TRACE_SUBSET (this); + + /* This function cannot work on avar2 table (and currently doesn't). + * We should instead keep the design coords in the shape plan and use + * those. unmap_axis_range needs to be killed. */ + /* avar mapped normalized axis range*/ Triple *axis_range; if (!c->plan->axes_location.has (axis_tag, &axis_range)) @@ -304,14 +363,14 @@ struct avar return_trace (true); } - void map_coords (int *coords, unsigned int coords_length) const + void map_coords_16_16 (int *coords, unsigned int coords_length) const { unsigned int count = hb_min (coords_length, axisCount); const SegmentMaps *map = &firstAxisSegmentMaps; for (unsigned int i = 0; i < count; i++) { - coords[i] = map->map (coords[i]); + coords[i] = roundf (map->map_float (coords[i] / 65536.f) * 65536.f); map = &StructAfter (*map); } @@ -329,15 +388,20 @@ struct avar const auto &var_store = this+v2.varStore; auto *var_store_cache = var_store.create_cache (); + hb_vector_t coords_2_14; + coords_2_14.resize (coords_length); + for (unsigned i = 0; i < coords_length; i++) + coords_2_14[i] = roundf (coords[i] / 4.f); // 16.16 -> 2.14 + hb_vector_t out; out.alloc (coords_length); for (unsigned i = 0; i < coords_length; i++) { int v = coords[i]; uint32_t varidx = varidx_map.map (i); - float delta = var_store.get_delta (varidx, coords, coords_length, var_store_cache); - v += roundf (delta); - v = hb_clamp (v, -(1<<14), +(1<<14)); + float delta = var_store.get_delta (varidx, coords_2_14.arrayZ, coords_2_14.length, var_store_cache); + v += roundf (delta * 4); // 2.14 -> 16.16 + v = hb_clamp (v, -(1<<16), +(1<<16)); out.push (v); } for (unsigned i = 0; i < coords_length; i++) @@ -347,16 +411,54 @@ struct avar #endif } - void unmap_coords (int *coords, unsigned int coords_length) const + bool has_v2_data () const { return version.major > 1; } + + // axis normalization is done in 2.14 here + // TODO: deprecate this API once fonttools is updated to use 16.16 normalization + bool map_coords_2_14 (float *coords, unsigned int coords_length) const { + hb_vector_t coords_2_14; + if (!coords_2_14.resize (coords_length)) return false; unsigned int count = hb_min (coords_length, axisCount); const SegmentMaps *map = &firstAxisSegmentMaps; for (unsigned int i = 0; i < count; i++) { - coords[i] = map->unmap (coords[i]); + int v = roundf (map->map_float (coords[i]) * 16384.f); + coords_2_14[i] = v; + coords[i] = v / 16384.f; map = &StructAfter (*map); } + +#ifndef HB_NO_AVAR2 + if (version.major < 2) + return true; + hb_barrier (); + + for (; count < axisCount; count++) + map = &StructAfter (*map); + + const auto &v2 = * (const avarV2Tail *) map; + + const auto &varidx_map = this+v2.varIdxMap; + const auto &var_store = this+v2.varStore; + auto *var_store_cache = var_store.create_cache (); + + for (unsigned i = 0; i < coords_length; i++) + { + int v = coords_2_14[i]; + uint32_t varidx = varidx_map.map (i); + float delta = var_store.get_delta (varidx, coords_2_14.arrayZ, coords_2_14.length, var_store_cache); + v += roundf (delta); + v = hb_clamp (v, -(1<<16), +(1<<16)); + coords[i] = v / 16384.f; + } + + OT::ItemVariationStore::destroy_cache (var_store_cache); + return true; +#else + return version.major < 2; +#endif } bool subset (hb_subset_context_t *c) const diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-common.hh index 72deddef213..d0a4224c9b0 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-common.hh @@ -27,24 +27,35 @@ #define HB_OT_VAR_COMMON_HH #include "hb-ot-layout-common.hh" +#include "hb-alloc-pool.hh" #include "hb-priority-queue.hh" #include "hb-subset-instancer-iup.hh" namespace OT { +using rebase_tent_result_scratch_t = hb_pair_t; /* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */ struct TupleVariationHeader { friend struct tuple_delta_t; - unsigned get_size (unsigned axis_count) const - { return min_size + get_all_tuples (axis_count).get_size (); } + unsigned get_size (unsigned axis_count_times_2) const + { + // This function is super hot in mega-var-fonts with hundreds of masters. + unsigned ti = tupleIndex; + if (unlikely ((ti & (TupleIndex::EmbeddedPeakTuple | TupleIndex::IntermediateRegion)))) + { + unsigned count = ((ti & TupleIndex::EmbeddedPeakTuple) != 0) + ((ti & TupleIndex::IntermediateRegion) != 0) * 2; + return min_size + count * axis_count_times_2; + } + return min_size; + } unsigned get_data_size () const { return varDataSize; } - const TupleVariationHeader &get_next (unsigned axis_count) const - { return StructAtOffset (this, get_size (axis_count)); } + const TupleVariationHeader &get_next (unsigned axis_count_times_2) const + { return StructAtOffset (this, get_size (axis_count_times_2)); } bool unpack_axis_tuples (unsigned axis_count, const hb_array_t shared_tuples, @@ -53,7 +64,7 @@ struct TupleVariationHeader { const F2DOT14 *peak_tuple = nullptr; if (has_peak ()) - peak_tuple = get_peak_tuple (axis_count).arrayZ; + peak_tuple = get_peak_tuple (axis_count); else { unsigned int index = get_index (); @@ -68,8 +79,8 @@ struct TupleVariationHeader if (has_interm) { - start_tuple = get_start_tuple (axis_count).arrayZ; - end_tuple = get_end_tuple (axis_count).arrayZ; + start_tuple = get_start_tuple (axis_count); + end_tuple = get_end_tuple (axis_count); } for (unsigned i = 0; i < axis_count; i++) @@ -98,88 +109,109 @@ struct TupleVariationHeader return true; } + HB_ALWAYS_INLINE double calculate_scalar (hb_array_t coords, unsigned int coord_count, const hb_array_t shared_tuples, - const hb_vector_t> *shared_tuple_active_idx = nullptr) const + hb_scalar_cache_t *shared_tuple_scalar_cache = nullptr) const { + unsigned tuple_index = tupleIndex; + const F2DOT14 *peak_tuple; - unsigned start_idx = 0; - unsigned end_idx = coord_count; - unsigned step = 1; + bool has_interm = tuple_index & TupleIndex::IntermediateRegion; // Inlined for performance - if (has_peak ()) - peak_tuple = get_peak_tuple (coord_count).arrayZ; + if (unlikely (tuple_index & TupleIndex::EmbeddedPeakTuple)) // Inlined for performance + { + peak_tuple = get_peak_tuple (coord_count); + shared_tuple_scalar_cache = nullptr; + } else { - unsigned int index = get_index (); + unsigned int index = tuple_index & TupleIndex::TupleIndexMask; // Inlined for performance + + float scalar; + if (shared_tuple_scalar_cache && + shared_tuple_scalar_cache->get (index, &scalar)) + { + if (has_interm && (scalar != 0 && scalar != 1.f)) + shared_tuple_scalar_cache = nullptr; + else + return (double) scalar; + } + if (unlikely ((index + 1) * coord_count > shared_tuples.length)) return 0.0; - peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count).arrayZ; + peak_tuple = shared_tuples.arrayZ + (coord_count * index); - if (shared_tuple_active_idx) - { - if (unlikely (index >= shared_tuple_active_idx->length)) - return 0.0; - auto _ = (*shared_tuple_active_idx).arrayZ[index]; - if (_.second != -1) - { - start_idx = _.first; - end_idx = _.second + 1; - step = _.second - _.first; - } - else if (_.first != -1) - { - start_idx = _.first; - end_idx = start_idx + 1; - } - } } const F2DOT14 *start_tuple = nullptr; const F2DOT14 *end_tuple = nullptr; - bool has_interm = has_intermediate (); + if (has_interm) { - start_tuple = get_start_tuple (coord_count).arrayZ; - end_tuple = get_end_tuple (coord_count).arrayZ; + start_tuple = get_start_tuple (coord_count); + end_tuple = get_end_tuple (coord_count); } double scalar = 1.0; - for (unsigned int i = start_idx; i < end_idx; i += step) +#ifndef HB_OPTIMIZE_SIZE +#if HB_FAST_NUM_ACCESS + bool skip = coord_count >= 16; +#endif +#endif + for (unsigned int i = 0; i < coord_count; i++) { +#ifndef HB_OPTIMIZE_SIZE +#if HB_FAST_NUM_ACCESS + if (skip) + { + while (i + 4 <= coord_count && * (HBUINT64LE *) &peak_tuple[i] == 0) + i += 4; + while (i < coord_count && peak_tuple[i].to_int () == 0) + i += 1; + if (i >= coord_count) + break; + } +#endif +#endif + int peak = peak_tuple[i].to_int (); if (!peak) continue; int v = coords[i]; + if (!v) { scalar = 0.0; break; } if (v == peak) continue; if (has_interm) { + shared_tuple_scalar_cache = nullptr; int start = start_tuple[i].to_int (); int end = end_tuple[i].to_int (); if (unlikely (start > peak || peak > end || (start < 0 && end > 0 && peak))) continue; - if (v < start || v > end) return 0.0; + if (v < start || v > end) { scalar = 0.0; break; } if (v < peak) { if (peak != start) scalar *= (double) (v - start) / (peak - start); } else { if (peak != end) scalar *= (double) (end - v) / (end - peak); } } - else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.0; + else if (v < hb_min (0, peak) || v > hb_max (0, peak)) { scalar = 0.0; break; } else scalar *= (double) v / peak; } + if (shared_tuple_scalar_cache) + shared_tuple_scalar_cache->set (get_index (), scalar); return scalar; } - bool has_peak () const { return tupleIndex & TuppleIndex::EmbeddedPeakTuple; } - bool has_intermediate () const { return tupleIndex & TuppleIndex::IntermediateRegion; } - bool has_private_points () const { return tupleIndex & TuppleIndex::PrivatePointNumbers; } - unsigned get_index () const { return tupleIndex & TuppleIndex::TupleIndexMask; } + bool has_peak () const { return tupleIndex & TupleIndex::EmbeddedPeakTuple; } + bool has_intermediate () const { return tupleIndex & TupleIndex::IntermediateRegion; } + bool has_private_points () const { return tupleIndex & TupleIndex::PrivatePointNumbers; } + unsigned get_index () const { return tupleIndex & TupleIndex::TupleIndexMask; } protected: - struct TuppleIndex : HBUINT16 + struct TupleIndex : HBUINT16 { enum Flags { EmbeddedPeakTuple = 0x8000u, @@ -188,22 +220,24 @@ struct TupleVariationHeader TupleIndexMask = 0x0FFFu }; - TuppleIndex& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } + TupleIndex& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } DEFINE_SIZE_STATIC (2); }; hb_array_t get_all_tuples (unsigned axis_count) const { return StructAfter> (tupleIndex).as_array ((has_peak () + has_intermediate () * 2) * axis_count); } - hb_array_t get_peak_tuple (unsigned axis_count) const - { return get_all_tuples (axis_count).sub_array (0, axis_count); } - hb_array_t get_start_tuple (unsigned axis_count) const - { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count, axis_count); } - hb_array_t get_end_tuple (unsigned axis_count) const - { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count + axis_count, axis_count); } + const F2DOT14* get_all_tuples_base (unsigned axis_count) const + { return StructAfter> (tupleIndex).arrayZ; } + const F2DOT14* get_peak_tuple (unsigned axis_count) const + { return get_all_tuples_base (axis_count); } + const F2DOT14* get_start_tuple (unsigned axis_count) const + { return get_all_tuples_base (axis_count) + has_peak () * axis_count; } + const F2DOT14* get_end_tuple (unsigned axis_count) const + { return get_all_tuples_base (axis_count) + has_peak () * axis_count + axis_count; } HBUINT16 varDataSize; /* The size in bytes of the serialized * data for this tuple variation table. */ - TuppleIndex tupleIndex; /* A packed field. The high 4 bits are flags (see below). + TupleIndex tupleIndex; /* A packed field. The high 4 bits are flags (see below). The low 12 bits are an index into a shared tuple records array. */ /* UnsizedArrayOf peakTuple - optional */ @@ -221,6 +255,21 @@ struct TupleVariationHeader DEFINE_SIZE_MIN (4); }; +struct optimize_scratch_t +{ + iup_scratch_t iup; + hb_vector_t opt_indices; + hb_vector_t rounded_x_deltas; + hb_vector_t rounded_y_deltas; + hb_vector_t opt_deltas_x; + hb_vector_t opt_deltas_y; + hb_vector_t opt_point_data; + hb_vector_t opt_deltas_data; + hb_vector_t point_data; + hb_vector_t deltas_data; + hb_vector_t rounded_deltas; +}; + struct tuple_delta_t { static constexpr bool realloc_move = true; // Watch out when adding new members! @@ -241,11 +290,12 @@ struct tuple_delta_t hb_vector_t compiled_tuple_header; hb_vector_t compiled_deltas; - /* compiled peak coords, empty for non-gvar tuples */ - hb_vector_t compiled_peak_coords; + hb_vector_t compiled_peak_coords; + hb_vector_t compiled_interm_coords; - tuple_delta_t () = default; + tuple_delta_t (hb_alloc_pool_t *pool = nullptr) {} tuple_delta_t (const tuple_delta_t& o) = default; + tuple_delta_t& operator = (const tuple_delta_t& o) = default; friend void swap (tuple_delta_t& a, tuple_delta_t& b) noexcept { @@ -267,6 +317,18 @@ struct tuple_delta_t return *this; } + void copy_from (const tuple_delta_t& o, hb_alloc_pool_t *pool = nullptr) + { + axis_tuples = o.axis_tuples; + indices.duplicate_vector_from_pool (pool, o.indices); + deltas_x.duplicate_vector_from_pool (pool, o.deltas_x); + deltas_y.duplicate_vector_from_pool (pool, o.deltas_y); + compiled_tuple_header.duplicate_vector_from_pool (pool, o.compiled_tuple_header); + compiled_deltas.duplicate_vector_from_pool (pool, o.compiled_deltas); + compiled_peak_coords.duplicate_vector_from_pool (pool, o.compiled_peak_coords); + compiled_interm_coords.duplicate_vector_from_pool (pool, o.compiled_interm_coords); + } + void remove_axis (hb_tag_t axis_tag) { axis_tuples.del (axis_tag); } @@ -321,31 +383,44 @@ struct tuple_delta_t return *this; } - hb_vector_t change_tuple_var_axis_limit (hb_tag_t axis_tag, Triple axis_limit, - TripleDistances axis_triple_distances) const + void change_tuple_var_axis_limit (hb_tag_t axis_tag, Triple axis_limit, + TripleDistances axis_triple_distances, + hb_vector_t& out, + rebase_tent_result_scratch_t &scratch, + hb_alloc_pool_t *pool = nullptr) { - hb_vector_t out; + // May move *this out. + + out.reset (); Triple *tent; if (!axis_tuples.has (axis_tag, &tent)) { - out.push (*this); - return out; + out.push (std::move (*this)); + return; } if ((tent->minimum < 0.0 && tent->maximum > 0.0) || !(tent->minimum <= tent->middle && tent->middle <= tent->maximum)) - return out; + return; if (tent->middle == 0.0) { - out.push (*this); - return out; + out.push (std::move (*this)); + return; } - rebase_tent_result_t solutions = rebase_tent (*tent, axis_limit, axis_triple_distances); - for (auto &t : solutions) + rebase_tent_result_t &solutions = scratch.first; + rebase_tent (*tent, axis_limit, axis_triple_distances, solutions, scratch.second); + for (unsigned i = 0; i < solutions.length; i++) { - tuple_delta_t new_var = *this; + auto &t = solutions.arrayZ[i]; + + tuple_delta_t new_var; + if (i < solutions.length - 1) + new_var.copy_from (*this, pool); + else + new_var = std::move (*this); + if (t.second == Triple ()) new_var.remove_axis (axis_tag); else @@ -354,38 +429,76 @@ struct tuple_delta_t new_var *= t.first; out.push (std::move (new_var)); } - - return out; } - bool compile_peak_coords (const hb_map_t& axes_index_map, - const hb_map_t& axes_old_index_tag_map) + bool compile_coords (const hb_map_t& axes_index_map, + const hb_map_t& axes_old_index_tag_map, + hb_alloc_pool_t *pool= nullptr) { - unsigned axis_count = axes_index_map.get_population (); - if (unlikely (!compiled_peak_coords.alloc (axis_count * F2DOT14::static_size))) + unsigned cur_axis_count = axes_index_map.get_population (); + if (pool) + { + if (unlikely (!compiled_peak_coords.allocate_from_pool (pool, cur_axis_count))) + return false; + } + else if (unlikely (!compiled_peak_coords.resize (cur_axis_count))) return false; + hb_array_t start_coords, end_coords; + unsigned orig_axis_count = axes_old_index_tag_map.get_population (); + unsigned j = 0; for (unsigned i = 0; i < orig_axis_count; i++) { if (!axes_index_map.has (i)) continue; hb_tag_t axis_tag = axes_old_index_tag_map.get (i); - Triple *coords; - F2DOT14 peak_coord; + Triple *coords = nullptr; if (axis_tuples.has (axis_tag, &coords)) - peak_coord.set_float (coords->middle); - else - peak_coord.set_int (0); + { + float min_val = coords->minimum; + float val = coords->middle; + float max_val = coords->maximum; - /* push F2DOT14 value into char vector */ - int16_t val = peak_coord.to_int (); - compiled_peak_coords.push (static_cast (val >> 8)); - compiled_peak_coords.push (static_cast (val & 0xFF)); + compiled_peak_coords.arrayZ[j].set_float (val); + + if (min_val != hb_min (val, 0.f) || max_val != hb_max (val, 0.f)) + { + if (!compiled_interm_coords) + { + if (pool) + { + if (unlikely (!compiled_interm_coords.allocate_from_pool (pool, 2 * cur_axis_count))) + return false; + } + else if (unlikely (!compiled_interm_coords.resize (2 * cur_axis_count))) + return false; + start_coords = compiled_interm_coords.as_array ().sub_array (0, cur_axis_count); + end_coords = compiled_interm_coords.as_array ().sub_array (cur_axis_count); + + for (unsigned k = 0; k < j; k++) + { + signed peak = compiled_peak_coords.arrayZ[k].to_int (); + if (!peak) continue; + start_coords.arrayZ[k].set_int (hb_min (peak, 0)); + end_coords.arrayZ[k].set_int (hb_max (peak, 0)); + } + } + + } + + if (compiled_interm_coords) + { + start_coords.arrayZ[j].set_float (min_val); + end_coords.arrayZ[j].set_float (max_val); + } + } + + j++; } - return !compiled_peak_coords.in_error (); + return !compiled_peak_coords.in_error () && !compiled_interm_coords.in_error (); } /* deltas should be compiled already before we compile tuple @@ -394,7 +507,8 @@ struct tuple_delta_t bool compile_tuple_var_header (const hb_map_t& axes_index_map, unsigned points_data_length, const hb_map_t& axes_old_index_tag_map, - const hb_hashmap_t*, unsigned>* shared_tuples_idx_map) + const hb_hashmap_t*, unsigned>* shared_tuples_idx_map, + hb_alloc_pool_t *pool = nullptr) { /* compiled_deltas could be empty after iup delta optimization, we can skip * compiling this tuple and return true */ @@ -403,7 +517,7 @@ struct tuple_delta_t unsigned cur_axis_count = axes_index_map.get_population (); /* allocate enough memory: 1 peak + 2 intermediate coords + fixed header size */ unsigned alloc_len = 3 * cur_axis_count * (F2DOT14::static_size) + 4; - if (unlikely (!compiled_tuple_header.resize (alloc_len))) return false; + if (unlikely (!compiled_tuple_header.allocate_from_pool (pool, alloc_len, false))) return false; unsigned flag = 0; /* skip the first 4 header bytes: variationDataSize+tupleIndex */ @@ -411,6 +525,9 @@ struct tuple_delta_t F2DOT14* end = reinterpret_cast (compiled_tuple_header.end ()); hb_array_t coords (p, end - p); + if (!shared_tuples_idx_map) + compile_coords (axes_index_map, axes_old_index_tag_map); // non-gvar tuples do not have compiled coords yet + /* encode peak coords */ unsigned peak_count = 0; unsigned *shared_tuple_idx; @@ -421,16 +538,16 @@ struct tuple_delta_t } else { - peak_count = encode_peak_coords(coords, flag, axes_index_map, axes_old_index_tag_map); + peak_count = encode_peak_coords(coords, flag); if (!peak_count) return false; } /* encode interim coords, it's optional so returned num could be 0 */ - unsigned interim_count = encode_interm_coords (coords.sub_array (peak_count), flag, axes_index_map, axes_old_index_tag_map); + unsigned interim_count = encode_interm_coords (coords.sub_array (peak_count), flag); /* pointdata length = 0 implies "use shared points" */ if (points_data_length) - flag |= TupleVariationHeader::TuppleIndex::PrivatePointNumbers; + flag |= TupleVariationHeader::TupleIndex::PrivatePointNumbers; unsigned serialized_data_size = points_data_length + compiled_deltas.length; TupleVariationHeader *o = reinterpret_cast (compiled_tuple_header.begin ()); @@ -438,105 +555,63 @@ struct tuple_delta_t o->tupleIndex = flag; unsigned total_header_len = 4 + (peak_count + interim_count) * (F2DOT14::static_size); - return compiled_tuple_header.resize (total_header_len); + compiled_tuple_header.shrink_back_to_pool (pool, total_header_len); + return true; } unsigned encode_peak_coords (hb_array_t peak_coords, - unsigned& flag, - const hb_map_t& axes_index_map, - const hb_map_t& axes_old_index_tag_map) const + unsigned& flag) const { - unsigned orig_axis_count = axes_old_index_tag_map.get_population (); - auto it = peak_coords.iter (); - unsigned count = 0; - for (unsigned i = 0; i < orig_axis_count; i++) - { - if (!axes_index_map.has (i)) /* axis pinned */ - continue; - hb_tag_t axis_tag = axes_old_index_tag_map.get (i); - Triple *coords; - if (!axis_tuples.has (axis_tag, &coords)) - (*it).set_int (0); - else - (*it).set_float (coords->middle); - it++; - count++; - } - flag |= TupleVariationHeader::TuppleIndex::EmbeddedPeakTuple; - return count; + hb_memcpy (&peak_coords[0], &compiled_peak_coords[0], compiled_peak_coords.length * sizeof (compiled_peak_coords[0])); + flag |= TupleVariationHeader::TupleIndex::EmbeddedPeakTuple; + return compiled_peak_coords.length; } /* if no need to encode intermediate coords, then just return p */ unsigned encode_interm_coords (hb_array_t coords, - unsigned& flag, - const hb_map_t& axes_index_map, - const hb_map_t& axes_old_index_tag_map) const + unsigned& flag) const { - unsigned orig_axis_count = axes_old_index_tag_map.get_population (); - unsigned cur_axis_count = axes_index_map.get_population (); - - auto start_coords_iter = coords.sub_array (0, cur_axis_count).iter (); - auto end_coords_iter = coords.sub_array (cur_axis_count).iter (); - bool encode_needed = false; - unsigned count = 0; - for (unsigned i = 0; i < orig_axis_count; i++) + if (compiled_interm_coords) { - if (!axes_index_map.has (i)) /* axis pinned */ - continue; - hb_tag_t axis_tag = axes_old_index_tag_map.get (i); - Triple *coords; - float min_val = 0.f, val = 0.f, max_val = 0.f; - if (axis_tuples.has (axis_tag, &coords)) - { - min_val = coords->minimum; - val = coords->middle; - max_val = coords->maximum; - } - - (*start_coords_iter).set_float (min_val); - (*end_coords_iter).set_float (max_val); - - start_coords_iter++; - end_coords_iter++; - count += 2; - if (min_val != hb_min (val, 0.f) || max_val != hb_max (val, 0.f)) - encode_needed = true; + hb_memcpy (&coords[0], &compiled_interm_coords[0], compiled_interm_coords.length * sizeof (compiled_interm_coords[0])); + flag |= TupleVariationHeader::TupleIndex::IntermediateRegion; } - - if (encode_needed) - { - flag |= TupleVariationHeader::TuppleIndex::IntermediateRegion; - return count; - } - return 0; + return compiled_interm_coords.length; } - bool compile_deltas () - { return compile_deltas (indices, deltas_x, deltas_y, compiled_deltas); } + bool compile_deltas (hb_vector_t &rounded_deltas_scratch, + hb_alloc_pool_t *pool = nullptr) + { return compile_deltas (indices, deltas_x, deltas_y, compiled_deltas, rounded_deltas_scratch, pool); } static bool compile_deltas (hb_array_t point_indices, hb_array_t x_deltas, hb_array_t y_deltas, - hb_vector_t &compiled_deltas /* OUT */) + hb_vector_t &compiled_deltas, /* OUT */ + hb_vector_t &rounded_deltas, /* scratch */ + hb_alloc_pool_t *pool = nullptr) { - hb_vector_t rounded_deltas; - if (unlikely (!rounded_deltas.alloc (point_indices.length))) + if (unlikely (!rounded_deltas.resize_dirty (point_indices.length))) return false; + unsigned j = 0; for (unsigned i = 0; i < point_indices.length; i++) { if (!point_indices[i]) continue; - int rounded_delta = (int) roundf (x_deltas.arrayZ[i]); - rounded_deltas.push (rounded_delta); + rounded_deltas.arrayZ[j++] = (int) roundf (x_deltas.arrayZ[i]); } + rounded_deltas.resize (j); if (!rounded_deltas) return true; - /* allocate enough memories 5 * num_deltas */ - unsigned alloc_len = 5 * rounded_deltas.length; + /* Allocate enough memory: this is the correct bound: + * Worst case scenario is that each delta has to be encoded in 4 bytes, and there + * are runs of 64 items each. Any delta encoded in less than 4 bytes (2, 1, or 0) + * is still smaller than the 4-byte encoding even with their control byte. + * The initial 2 is to handle length==0, for both x and y deltas. */ + unsigned alloc_len = 2 + 4 * rounded_deltas.length + (rounded_deltas.length + 63) / 64; if (y_deltas) alloc_len *= 2; - if (unlikely (!compiled_deltas.resize (alloc_len))) return false; + if (unlikely (!compiled_deltas.allocate_from_pool (pool, alloc_len, false))) return false; unsigned encoded_len = compile_deltas (compiled_deltas, rounded_deltas); @@ -557,28 +632,30 @@ struct tuple_delta_t if (j != rounded_deltas.length) return false; encoded_len += compile_deltas (compiled_deltas.as_array ().sub_array (encoded_len), rounded_deltas); } - return compiled_deltas.resize (encoded_len); + compiled_deltas.shrink_back_to_pool (pool, encoded_len); + return true; } static unsigned compile_deltas (hb_array_t encoded_bytes, hb_array_t deltas) { - return TupleValues::compile (deltas, encoded_bytes); + return TupleValues::compile_unsafe (deltas, encoded_bytes); } - bool calc_inferred_deltas (const contour_point_vector_t& orig_points) + bool calc_inferred_deltas (const contour_point_vector_t& orig_points, + hb_vector_t &scratch) { unsigned point_count = orig_points.length; if (point_count != indices.length) return false; unsigned ref_count = 0; - hb_vector_t end_points; + + hb_vector_t &end_points = scratch.reset (); for (unsigned i = 0; i < point_count; i++) { - if (indices.arrayZ[i]) - ref_count++; + ref_count += indices.arrayZ[i]; if (orig_points.arrayZ[i].is_end_point) end_points.push (i); } @@ -587,7 +664,7 @@ struct tuple_delta_t return true; if (unlikely (end_points.in_error ())) return false; - hb_set_t inferred_idxes; + hb_bit_set_t inferred_idxes; unsigned start_point = 0; for (unsigned end_point : end_points) { @@ -661,6 +738,7 @@ struct tuple_delta_t bool optimize (const contour_point_vector_t& contour_points, bool is_composite, + optimize_scratch_t &scratch, double tolerance = 0.5 + 1e-10) { unsigned count = contour_points.length; @@ -668,22 +746,21 @@ struct tuple_delta_t deltas_y.length != count) return false; - hb_vector_t opt_indices; - hb_vector_t rounded_x_deltas, rounded_y_deltas; + hb_vector_t &opt_indices = scratch.opt_indices.reset (); + hb_vector_t &rounded_x_deltas = scratch.rounded_x_deltas; + hb_vector_t &rounded_y_deltas = scratch.rounded_y_deltas; - if (unlikely (!rounded_x_deltas.alloc (count) || - !rounded_y_deltas.alloc (count))) + if (unlikely (!rounded_x_deltas.resize_dirty (count) || + !rounded_y_deltas.resize_dirty (count))) return false; for (unsigned i = 0; i < count; i++) { - int rounded_x_delta = (int) roundf (deltas_x.arrayZ[i]); - int rounded_y_delta = (int) roundf (deltas_y.arrayZ[i]); - rounded_x_deltas.push (rounded_x_delta); - rounded_y_deltas.push (rounded_y_delta); + rounded_x_deltas.arrayZ[i] = (int) roundf (deltas_x.arrayZ[i]); + rounded_y_deltas.arrayZ[i] = (int) roundf (deltas_y.arrayZ[i]); } - if (!iup_delta_optimize (contour_points, rounded_x_deltas, rounded_y_deltas, opt_indices, tolerance)) + if (!iup_delta_optimize (contour_points, rounded_x_deltas, rounded_y_deltas, opt_indices, scratch.iup, tolerance)) return false; unsigned ref_count = 0; @@ -692,7 +769,8 @@ struct tuple_delta_t if (ref_count == count) return true; - hb_vector_t opt_deltas_x, opt_deltas_y; + hb_vector_t &opt_deltas_x = scratch.opt_deltas_x.reset (); + hb_vector_t &opt_deltas_y = scratch.opt_deltas_y.reset (); bool is_comp_glyph_wo_deltas = (is_composite && ref_count == 0); if (is_comp_glyph_wo_deltas) { @@ -705,34 +783,31 @@ struct tuple_delta_t opt_indices.arrayZ[i] = false; } - hb_vector_t opt_point_data; + hb_vector_t &opt_point_data = scratch.opt_point_data.reset (); if (!compile_point_set (opt_indices, opt_point_data)) return false; - hb_vector_t opt_deltas_data; + hb_vector_t &opt_deltas_data = scratch.opt_deltas_data.reset (); if (!compile_deltas (opt_indices, is_comp_glyph_wo_deltas ? opt_deltas_x : deltas_x, is_comp_glyph_wo_deltas ? opt_deltas_y : deltas_y, - opt_deltas_data)) + opt_deltas_data, + scratch.rounded_deltas)) return false; - hb_vector_t point_data; + hb_vector_t &point_data = scratch.point_data.reset (); if (!compile_point_set (indices, point_data)) return false; - hb_vector_t deltas_data; - if (!compile_deltas (indices, deltas_x, deltas_y, deltas_data)) + hb_vector_t &deltas_data = scratch.deltas_data.reset (); + if (!compile_deltas (indices, deltas_x, deltas_y, deltas_data, scratch.rounded_deltas)) return false; if (opt_point_data.length + opt_deltas_data.length < point_data.length + deltas_data.length) { - indices.fini (); indices = std::move (opt_indices); if (is_comp_glyph_wo_deltas) { - deltas_x.fini (); deltas_x = std::move (opt_deltas_x); - - deltas_y.fini (); deltas_y = std::move (opt_deltas_y); } } @@ -757,7 +832,7 @@ struct tuple_delta_t /* allocate enough memories: 2 bytes for count + 3 bytes for each point */ unsigned num_bytes = 2 + 3 *num_points; - if (unlikely (!compiled_points.resize (num_bytes, false))) + if (unlikely (!compiled_points.resize_dirty (num_bytes))) return false; unsigned pos = 0; @@ -821,7 +896,7 @@ struct tuple_delta_t else compiled_points.arrayZ[header_pos] = (run_length - 1) | 0x80; } - return compiled_points.resize (pos, false); + return compiled_points.resize_dirty (pos); } static double infer_delta (double target_val, double prev_val, double next_val, double prev_delta, double next_delta) @@ -852,15 +927,15 @@ struct TupleVariationData return_trace (c->check_struct (this)); } - unsigned get_size (unsigned axis_count) const + unsigned get_size (unsigned axis_count_times_2) const { unsigned total_size = min_size; unsigned count = tupleVarCount.get_count (); const TupleVariationHeader *tuple_var_header = &(get_tuple_var_header()); for (unsigned i = 0; i < count; i++) { - total_size += tuple_var_header->get_size (axis_count) + tuple_var_header->get_data_size (); - tuple_var_header = &tuple_var_header->get_next (axis_count); + total_size += tuple_var_header->get_size (axis_count_times_2) + tuple_var_header->get_data_size (); + tuple_var_header = &tuple_var_header->get_next (axis_count_times_2); } return total_size; @@ -925,8 +1000,12 @@ struct TupleVariationData const hb_map_t *axes_old_index_tag_map, const hb_vector_t &shared_indices, const hb_array_t shared_tuples, - bool is_composite_glyph) + hb_alloc_pool_t *pool = nullptr, + bool is_composite_glyph = false) { + hb_vector_t private_indices; + hb_vector_t deltas_x; + hb_vector_t deltas_y; do { const HBUINT8 *p = iterator.get_serialized_data (); @@ -939,7 +1018,7 @@ struct TupleVariationData || axis_tuples.is_empty ()) return false; - hb_vector_t private_indices; + private_indices.reset (); bool has_private_points = iterator.current_tuple->has_private_points (); const HBUINT8 *end = p + length; if (has_private_points && @@ -950,27 +1029,24 @@ struct TupleVariationData bool apply_to_all = (indices.length == 0); unsigned num_deltas = apply_to_all ? point_count : indices.length; - hb_vector_t deltas_x; - - if (unlikely (!deltas_x.resize (num_deltas, false) || + if (unlikely (!deltas_x.resize_dirty (num_deltas) || !TupleVariationData::decompile_deltas (p, deltas_x, end))) return false; - hb_vector_t deltas_y; if (is_gvar) { - if (unlikely (!deltas_y.resize (num_deltas, false) || + if (unlikely (!deltas_y.resize_dirty (num_deltas) || !TupleVariationData::decompile_deltas (p, deltas_y, end))) return false; } tuple_delta_t var; var.axis_tuples = std::move (axis_tuples); - if (unlikely (!var.indices.resize (point_count) || - !var.deltas_x.resize (point_count, false))) + if (unlikely (!var.indices.allocate_from_pool (pool, point_count) || + !var.deltas_x.allocate_from_pool (pool, point_count, false))) return false; - if (is_gvar && unlikely (!var.deltas_y.resize (point_count, false))) + if (is_gvar && unlikely (!var.deltas_y.allocate_from_pool (pool, point_count, false))) return false; for (unsigned i = 0; i < num_deltas; i++) @@ -1012,8 +1088,8 @@ struct TupleVariationData /* In VarData, deltas are organized in rows, convert them into * column(region) based tuples, resize deltas_x first */ tuple_delta_t tuple; - if (!tuple.deltas_x.resize (item_count, false) || - !tuple.indices.resize (item_count, false)) + if (!tuple.deltas_x.resize_dirty (item_count) || + !tuple.indices.resize_dirty (item_count)) return false; for (unsigned i = 0; i < item_count; i++) @@ -1041,7 +1117,8 @@ struct TupleVariationData } bool change_tuple_variations_axis_limits (const hb_hashmap_t& normalized_axes_location, - const hb_hashmap_t& axes_triple_distances) + const hb_hashmap_t& axes_triple_distances, + hb_alloc_pool_t *pool = nullptr) { /* sort axis_tag/axis_limits, make result deterministic */ hb_vector_t axis_tags; @@ -1050,6 +1127,10 @@ struct TupleVariationData for (auto t : normalized_axes_location.keys ()) axis_tags.push (t); + // Reused vectors for reduced malloc pressure. + rebase_tent_result_scratch_t scratch; + hb_vector_t out; + axis_tags.qsort (_cmp_axis_tag); for (auto axis_tag : axis_tags) { @@ -1061,9 +1142,10 @@ struct TupleVariationData axis_triple_distances = axes_triple_distances.get (axis_tag); hb_vector_t new_vars; - for (const tuple_delta_t& var : tuple_vars) + for (tuple_delta_t& var : tuple_vars) { - hb_vector_t out = var.change_tuple_var_axis_limit (axis_tag, *axis_limit, axis_triple_distances); + // This may move var out. + var.change_tuple_var_axis_limit (axis_tag, *axis_limit, axis_triple_distances, out, scratch, pool); if (!out) continue; unsigned new_len = new_vars.length + out.length; @@ -1074,7 +1156,6 @@ struct TupleVariationData for (unsigned i = 0; i < out.length; i++) new_vars.push (std::move (out[i])); } - tuple_vars.fini (); tuple_vars = std::move (new_vars); } return true; @@ -1085,9 +1166,12 @@ struct TupleVariationData bool merge_tuple_variations (contour_point_vector_t* contour_points = nullptr) { hb_vector_t new_vars; + // The pre-allocation is essential for address stability of pointers + // we store in the hashmap. + if (unlikely (!new_vars.alloc (tuple_vars.length))) + return false; hb_hashmap_t*, unsigned> m; - unsigned i = 0; - for (const tuple_delta_t& var : tuple_vars) + for (tuple_delta_t& var : tuple_vars) { /* if all axes are pinned, drop the tuple variation */ if (var.axis_tuples.is_empty ()) @@ -1107,13 +1191,17 @@ struct TupleVariationData } else { - new_vars.push (var); - if (!m.set (&(var.axis_tuples), i)) + auto *new_var = new_vars.push (); + if (unlikely (new_vars.in_error ())) + return false; + hb_swap (*new_var, var); + if (unlikely (!m.set (&(new_var->axis_tuples), new_vars.length - 1))) return false; - i++; } } - tuple_vars.fini (); + m.fini (); // Just in case, since it points into new_vars data. + // Shouldn't be necessary though, since we only move new_vars, not its + // contents. tuple_vars = std::move (new_vars); return true; } @@ -1173,20 +1261,22 @@ struct TupleVariationData } } - bool calc_inferred_deltas (const contour_point_vector_t& contour_points) + bool calc_inferred_deltas (const contour_point_vector_t& contour_points, + hb_vector_t &scratch) { for (tuple_delta_t& var : tuple_vars) - if (!var.calc_inferred_deltas (contour_points)) + if (!var.calc_inferred_deltas (contour_points, scratch)) return false; return true; } - bool iup_optimize (const contour_point_vector_t& contour_points) + bool iup_optimize (const contour_point_vector_t& contour_points, + optimize_scratch_t &scratch) { for (tuple_delta_t& var : tuple_vars) { - if (!var.optimize (contour_points, is_composite)) + if (!var.optimize (contour_points, is_composite, scratch)) return false; } return true; @@ -1195,16 +1285,21 @@ struct TupleVariationData public: bool instantiate (const hb_hashmap_t& normalized_axes_location, const hb_hashmap_t& axes_triple_distances, + optimize_scratch_t &scratch, + hb_alloc_pool_t *pool = nullptr, contour_point_vector_t* contour_points = nullptr, bool optimize = false) { if (!tuple_vars) return true; - if (!change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances)) + if (!change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances, pool)) return false; /* compute inferred deltas only for gvar */ if (contour_points) - if (!calc_inferred_deltas (*contour_points)) + { + hb_vector_t scratch; + if (!calc_inferred_deltas (*contour_points, scratch)) return false; + } /* if iup delta opt is on, contour_points can't be null */ if (optimize && !contour_points) @@ -1213,7 +1308,7 @@ struct TupleVariationData if (!merge_tuple_variations (optimize ? contour_points : nullptr)) return false; - if (optimize && !iup_optimize (*contour_points)) return false; + if (optimize && !iup_optimize (*contour_points, scratch)) return false; return !tuple_vars.in_error (); } @@ -1221,7 +1316,8 @@ struct TupleVariationData const hb_map_t& axes_old_index_tag_map, bool use_shared_points, bool is_gvar = false, - const hb_hashmap_t*, unsigned>* shared_tuples_idx_map = nullptr) + const hb_hashmap_t*, unsigned>* shared_tuples_idx_map = nullptr, + hb_alloc_pool_t *pool = nullptr) { // return true for empty glyph if (!tuple_vars) @@ -1241,6 +1337,7 @@ struct TupleVariationData if (shared_points_bytes) compiled_byte_size += shared_points_bytes->length; } + hb_vector_t rounded_deltas_scratch; // compile delta and tuple var header for each tuple variation for (auto& tuple: tuple_vars) { @@ -1254,12 +1351,13 @@ struct TupleVariationData * this tuple */ if (!points_data->length) continue; - if (!tuple.compile_deltas ()) + if (!tuple.compile_deltas (rounded_deltas_scratch, pool)) return false; unsigned points_data_length = (points_data != shared_points_bytes) ? points_data->length : 0; if (!tuple.compile_tuple_var_header (axes_index_map, points_data_length, axes_old_index_tag_map, - shared_tuples_idx_map)) + shared_tuples_idx_map, + pool)) return false; compiled_byte_size += tuple.compiled_tuple_header.length + points_data_length + tuple.compiled_deltas.length; } @@ -1330,8 +1428,9 @@ struct TupleVariationData { var_data_bytes = var_data_bytes_; var_data = var_data_bytes_.as (); - index = 0; + tuples_left = var_data->tupleVarCount.get_count (); axis_count = axis_count_; + axis_count_times_2 = axis_count_ * 2; current_tuple = &var_data->get_tuple_var_header (); data_offset = 0; table_base = table_base_; @@ -1349,30 +1448,42 @@ struct TupleVariationData return true; } - bool is_valid () const + bool is_valid () { - return (index < var_data->tupleVarCount.get_count ()) && - var_data_bytes.check_range (current_tuple, TupleVariationHeader::min_size) && - var_data_bytes.check_range (current_tuple, hb_max (current_tuple->get_data_size (), - current_tuple->get_size (axis_count))); + if (unlikely (tuples_left <= 0)) + return false; + + current_tuple_size = TupleVariationHeader::min_size; + if (unlikely (!var_data_bytes.check_end ((const char *) current_tuple + current_tuple_size))) + return false; + + current_tuple_size = current_tuple->get_size (axis_count_times_2); + if (unlikely (!var_data_bytes.check_end ((const char *) current_tuple + current_tuple_size))) + return false; + + return true; } + HB_ALWAYS_INLINE bool move_to_next () { data_offset += current_tuple->get_data_size (); - current_tuple = ¤t_tuple->get_next (axis_count); - index++; + current_tuple = &StructAtOffset (current_tuple, current_tuple_size); + tuples_left--; return is_valid (); } + // TODO: Make it return (sanitized) hb_bytes_t const HBUINT8 *get_serialized_data () const { return &(table_base+var_data->data) + data_offset; } private: + signed tuples_left; const TupleVariationData *var_data; - unsigned int index; unsigned int axis_count; + unsigned int axis_count_times_2; unsigned int data_offset; + unsigned int current_tuple_size; const void *table_base; public: @@ -1411,7 +1522,7 @@ struct TupleVariationData if (unlikely (p + 1 > end)) return false; count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++; } - if (unlikely (!points.resize (count, false))) return false; + if (unlikely (!points.resize_dirty (count))) return false; unsigned n = 0; unsigned i = 0; @@ -1446,12 +1557,14 @@ struct TupleVariationData } template + HB_ALWAYS_INLINE static bool decompile_deltas (const HBUINT8 *&p /* IN/OUT */, hb_vector_t &deltas /* IN/OUT */, const HBUINT8 *end, - bool consume_all = false) + bool consume_all = false, + unsigned start = 0) { - return TupleValues::decompile (p, deltas, end, consume_all); + return TupleValues::decompile (p, deltas, end, consume_all, start); } bool has_data () const { return tupleVarCount; } @@ -1463,6 +1576,7 @@ struct TupleVariationData const hb_vector_t &shared_indices, const hb_array_t shared_tuples, tuple_variations_t& tuple_variations, /* OUT */ + hb_alloc_pool_t *pool = nullptr, bool is_composite_glyph = false) const { return tuple_variations.create_from_tuple_var_data (iterator, tupleVarCount, @@ -1470,6 +1584,7 @@ struct TupleVariationData axes_old_index_tag_map, shared_indices, shared_tuples, + pool, is_composite_glyph); } @@ -1634,8 +1749,9 @@ struct item_variations_t bool instantiate_tuple_vars (const hb_hashmap_t& normalized_axes_location, const hb_hashmap_t& axes_triple_distances) { + optimize_scratch_t scratch; for (tuple_variations_t& tuple_vars : vars) - if (!tuple_vars.instantiate (normalized_axes_location, axes_triple_distances)) + if (!tuple_vars.instantiate (normalized_axes_location, axes_triple_distances, scratch)) return false; if (!build_region_list ()) return false; @@ -1720,30 +1836,28 @@ struct item_variations_t struct combined_gain_idx_tuple_t { - int gain; - unsigned idx_1; - unsigned idx_2; + uint64_t encoded; combined_gain_idx_tuple_t () = default; - combined_gain_idx_tuple_t (int gain_, unsigned i, unsigned j) - :gain (gain_), idx_1 (i), idx_2 (j) {} + combined_gain_idx_tuple_t (unsigned gain, unsigned i, unsigned j) + : encoded ((uint64_t (0xFFFFFF - gain) << 40) | (uint64_t (i) << 20) | uint64_t (j)) + { + assert (gain < 0xFFFFFF); + assert (i < 0xFFFFFFF && j < 0xFFFFFFF); + } bool operator < (const combined_gain_idx_tuple_t& o) { - if (gain != o.gain) - return gain < o.gain; - - if (idx_1 != o.idx_1) - return idx_1 < o.idx_1; - - return idx_2 < o.idx_2; + return encoded < o.encoded; } bool operator <= (const combined_gain_idx_tuple_t& o) { - if (*this < o) return true; - return gain == o.gain && idx_1 == o.idx_1 && idx_2 == o.idx_2; + return encoded <= o.encoded; } + + unsigned idx_1 () const { return (encoded >> 20) & 0xFFFFF; }; + unsigned idx_2 () const { return encoded & 0xFFFFF; }; }; bool as_item_varstore (bool optimize=true, bool use_no_variation_idx=true) @@ -1765,9 +1879,9 @@ struct item_variations_t hb_hashmap_t*> front_mapping; unsigned start_row = 0; hb_vector_t encoding_objs; - hb_hashmap_t, unsigned> chars_idx_map; /* delta_rows map, used for filtering out duplicate rows */ + hb_vector_t *> major_rows; hb_hashmap_t*, unsigned> delta_rows_map; for (unsigned major = 0; major < vars.length; major++) { @@ -1775,6 +1889,9 @@ struct item_variations_t * (row based) delta */ const tuple_variations_t& tuples = vars[major]; unsigned num_rows = var_data_num_rows[major]; + + if (!num_rows) continue; + for (const tuple_delta_t& tuple: tuples.tuple_vars) { if (tuple.deltas_x.length != num_rows) @@ -1789,24 +1906,11 @@ struct item_variations_t { int rounded_delta = roundf (tuple.deltas_x[i]); delta_rows[start_row + i][*col_idx] += rounded_delta; - if ((!has_long) && (rounded_delta < -65536 || rounded_delta > 65535)) - has_long = true; + has_long |= rounded_delta < -65536 || rounded_delta > 65535; } } - if (!optimize) - { - /* assemble a delta_row_encoding_t for this subtable, skip optimization so - * chars is not initialized, we only need delta rows for serialization */ - delta_row_encoding_t obj; - for (unsigned r = start_row; r < start_row + num_rows; r++) - obj.add_row (&(delta_rows.arrayZ[r])); - - encodings.push (std::move (obj)); - start_row += num_rows; - continue; - } - + major_rows.reset (); for (unsigned minor = 0; minor < num_rows; minor++) { const hb_vector_t& row = delta_rows[start_row + minor]; @@ -1828,42 +1932,40 @@ struct item_variations_t if (!front_mapping.set ((major<<16) + minor, &row)) return false; - hb_vector_t chars = delta_row_encoding_t::get_row_chars (row); - if (!chars) return false; - if (delta_rows_map.has (&row)) continue; delta_rows_map.set (&row, 1); - unsigned *obj_idx; - if (chars_idx_map.has (chars, &obj_idx)) - { - delta_row_encoding_t& obj = encoding_objs[*obj_idx]; - if (!obj.add_row (&row)) - return false; - } - else - { - if (!chars_idx_map.set (chars, encoding_objs.length)) - return false; - delta_row_encoding_t obj (std::move (chars), &row); - encoding_objs.push (std::move (obj)); - } + + major_rows.push (&row); } + if (major_rows) + encoding_objs.push (delta_row_encoding_t (std::move (major_rows), num_cols)); + start_row += num_rows; } /* return directly if no optimization, maintain original VariationIndex so * varidx_map would be empty */ - if (!optimize) return !encodings.in_error (); + if (!optimize) + { + encodings = std::move (encoding_objs); + return !encodings.in_error (); + } - /* sort encoding_objs */ + /* NOTE: Fonttools instancer always optimizes VarStore from scratch. This + * is too costly for large fonts. So, instead, we retain the encodings of + * the original VarStore, and just try to combine them if possible. This + * is a compromise between optimization and performance and practically + * works very well. */ + + // This produces slightly smaller results in some cases. encoding_objs.qsort (); - /* main algorithm: repeatedly pick 2 best encodings to combine, and combine - * them */ - hb_priority_queue_t queue; + /* main algorithm: repeatedly pick 2 best encodings to combine, and combine them */ + using item_t = hb_priority_queue_t::item_t; + hb_vector_t queue_items; unsigned num_todos = encoding_objs.length; for (unsigned i = 0; i < num_todos; i++) { @@ -1871,16 +1973,18 @@ struct item_variations_t { int combining_gain = encoding_objs.arrayZ[i].gain_from_merging (encoding_objs.arrayZ[j]); if (combining_gain > 0) - queue.insert (combined_gain_idx_tuple_t (-combining_gain, i, j), 0); + queue_items.push (item_t (combined_gain_idx_tuple_t (combining_gain, i, j), 0)); } } - hb_set_t removed_todo_idxes; + hb_priority_queue_t queue (std::move (queue_items)); + + hb_bit_set_t removed_todo_idxes; while (queue) { auto t = queue.pop_minimum ().first; - unsigned i = t.idx_1; - unsigned j = t.idx_2; + unsigned i = t.idx_1 (); + unsigned j = t.idx_2 (); if (removed_todo_idxes.has (i) || removed_todo_idxes.has (j)) continue; @@ -1891,40 +1995,36 @@ struct item_variations_t removed_todo_idxes.add (i); removed_todo_idxes.add (j); - hb_vector_t combined_chars; - if (!combined_chars.alloc (encoding.chars.length)) - return false; - - for (unsigned idx = 0; idx < encoding.chars.length; idx++) - { - uint8_t v = hb_max (encoding.chars.arrayZ[idx], other_encoding.chars.arrayZ[idx]); - combined_chars.push (v); - } - - delta_row_encoding_t combined_encoding_obj (std::move (combined_chars)); - for (const auto& row : hb_concat (encoding.items, other_encoding.items)) - combined_encoding_obj.add_row (row); + encoding.merge (other_encoding); for (unsigned idx = 0; idx < encoding_objs.length; idx++) { if (removed_todo_idxes.has (idx)) continue; const delta_row_encoding_t& obj = encoding_objs.arrayZ[idx]; - if (obj.chars == combined_chars) + // In the unlikely event that the same encoding exists already, combine it. + if (obj.width == encoding.width && obj.chars == encoding.chars) { + // This is straight port from fonttools algorithm. I added this branch there + // because I thought it can happen. But looks like we never get in here in + // practice. I'm not confident enough to remove it though; in theory it can + // happen. I think it's just that our tests are not extensive enough to hit + // this path. + for (const auto& row : obj.items) - combined_encoding_obj.add_row (row); + encoding.add_row (row); removed_todo_idxes.add (idx); continue; } - int combined_gain = combined_encoding_obj.gain_from_merging (obj); + int combined_gain = encoding.gain_from_merging (obj); if (combined_gain > 0) - queue.insert (combined_gain_idx_tuple_t (-combined_gain, idx, encoding_objs.length), 0); + queue.insert (combined_gain_idx_tuple_t (combined_gain, idx, encoding_objs.length), 0); } - encoding_objs.push (std::move (combined_encoding_obj)); + auto moved_encoding = std::move (encoding); + encoding_objs.push (moved_encoding); } int num_final_encodings = (int) encoding_objs.length - (int) removed_todo_idxes.get_population (); @@ -1937,9 +2037,6 @@ struct item_variations_t encodings.push (std::move (encoding_objs.arrayZ[i])); } - /* sort again based on width, make result deterministic */ - encodings.qsort (delta_row_encoding_t::cmp_width); - return compile_varidx_map (front_mapping); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-cvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-cvar-table.hh index 3dc4ebaebd8..d8f497d5346 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-cvar-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-cvar-table.hh @@ -84,7 +84,7 @@ struct cvar if (!coords) return true; hb_vector_t shared_indices; TupleVariationData<>::tuple_iterator_t iterator; - unsigned var_data_length = tuple_var_data->get_size (axis_count); + unsigned var_data_length = tuple_var_data->get_size (axis_count * 2); hb_bytes_t var_data_bytes = hb_bytes_t (reinterpret_cast (tuple_var_data), var_data_length); if (!TupleVariationData<>::get_tuple_iterator (var_data_bytes, axis_count, base, shared_indices, &iterator)) @@ -113,7 +113,7 @@ struct cvar bool apply_to_all = (indices.length == 0); unsigned num_deltas = apply_to_all ? num_cvt_item : indices.length; - if (unlikely (!unpacked_deltas.resize (num_deltas, false))) return false; + if (unlikely (!unpacked_deltas.resize_dirty (num_deltas))) return false; if (unlikely (!TupleVariationData<>::decompile_deltas (p, unpacked_deltas, end))) return false; for (unsigned int i = 0; i < num_deltas; i++) @@ -158,7 +158,8 @@ struct cvar tuple_variations)) return_trace (false); - if (!tuple_variations.instantiate (c->plan->axes_location, c->plan->axes_triple_distances)) + optimize_scratch_t scratch; + if (!tuple_variations.instantiate (c->plan->axes_location, c->plan->axes_triple_distances, scratch)) return_trace (false); if (!tuple_variations.compile_bytes (c->plan->axes_index_map, c->plan->axes_old_index_tag_map, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-fvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-fvar-table.hh index f2725eaa282..74d392de9b7 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-fvar-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-fvar-table.hh @@ -179,7 +179,7 @@ struct AxisRecord hb_tag_t get_axis_tag () const { return axisTag; } - int normalize_axis_value (float v) const + float normalize_axis_value (float v) const { float min_value, default_value, max_value; get_coordinates (min_value, default_value, max_value); @@ -189,23 +189,9 @@ struct AxisRecord if (v == default_value) return 0; else if (v < default_value) - v = (v - default_value) / (default_value - min_value); + return (v - default_value) / (default_value - min_value); else - v = (v - default_value) / (max_value - default_value); - return roundf (v * 16384.f); - } - - float unnormalize_axis_value (int v) const - { - float min_value, default_value, max_value; - get_coordinates (min_value, default_value, max_value); - - if (v == 0) - return default_value; - else if (v < 0) - return v * (default_value - min_value) / 16384.f + default_value; - else - return v * (max_value - default_value) / 16384.f + default_value; + return (v - default_value) / (max_value - default_value); } hb_ot_name_id_t get_name_id () const { return axisNameID; } @@ -341,12 +327,9 @@ struct fvar return axes.lfind (tag, &i) && ((void) axes[i].get_axis_info (i, info), true); } - int normalize_axis_value (unsigned int axis_index, float v) const + float normalize_axis_value (unsigned int axis_index, float v) const { return get_axes ()[axis_index].normalize_axis_value (v); } - float unnormalize_axis_value (unsigned int axis_index, int v) const - { return get_axes ()[axis_index].unnormalize_axis_value (v); } - unsigned int get_instance_count () const { return instanceCount; } hb_ot_name_id_t get_instance_subfamily_name_id (unsigned int instance_index) const diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh index 9f9b5be3cbe..7c42f548456 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh @@ -66,12 +66,14 @@ struct glyph_variations_t hb_vector_t glyph_variations; - hb_vector_t compiled_shared_tuples; + hb_vector_t compiled_shared_tuples; private: unsigned shared_tuples_count = 0; /* shared coords-> index map after instantiation */ - hb_hashmap_t*, unsigned> shared_tuples_idx_map; + hb_hashmap_t*, unsigned> shared_tuples_idx_map; + + hb_alloc_pool_t pool; public: unsigned compiled_shared_tuples_count () const @@ -128,6 +130,7 @@ struct glyph_variations_t iterator, &(plan->axes_old_index_tag_map), shared_indices, shared_tuples, tuple_vars, /* OUT */ + &pool, is_composite_glyph)) return false; glyph_variations.push (std::move (tuple_vars)); @@ -139,6 +142,7 @@ struct glyph_variations_t { unsigned count = plan->new_to_old_gid_list.length; bool iup_optimize = false; + optimize_scratch_t scratch; iup_optimize = plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS; for (unsigned i = 0; i < count; i++) { @@ -146,7 +150,7 @@ struct glyph_variations_t contour_point_vector_t *all_points; if (!plan->new_gid_contour_points_map.has (new_gid, &all_points)) return false; - if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, all_points, iup_optimize)) + if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, scratch, &pool, all_points, iup_optimize)) return false; } return true; @@ -161,7 +165,8 @@ struct glyph_variations_t if (!vars.compile_bytes (axes_index_map, axes_old_index_tag_map, true, /* use shared points*/ true, - &shared_tuples_idx_map)) + &shared_tuples_idx_map, + &pool)) return false; return true; @@ -172,20 +177,21 @@ struct glyph_variations_t { /* key is pointer to compiled_peak_coords inside each tuple, hashing * function will always deref pointers first */ - hb_hashmap_t*, unsigned> coords_count_map; + hb_hashmap_t*, unsigned> coords_count_map; /* count the num of shared coords */ for (tuple_variations_t& vars: glyph_variations) { for (tuple_delta_t& var : vars.tuple_vars) { - if (!var.compile_peak_coords (axes_index_map, axes_old_index_tag_map)) + if (!var.compile_coords (axes_index_map, axes_old_index_tag_map, &pool)) return false; - unsigned* count; - if (coords_count_map.has (&(var.compiled_peak_coords), &count)) - coords_count_map.set (&(var.compiled_peak_coords), *count + 1); + unsigned *count; + unsigned hash = hb_hash (&var.compiled_peak_coords); + if (coords_count_map.has_with_hash (&(var.compiled_peak_coords), hash, &count)) + (*count)++; else - coords_count_map.set (&(var.compiled_peak_coords), 1); + coords_count_map.set_with_hash (&(var.compiled_peak_coords), hash, 1); } } @@ -193,66 +199,45 @@ struct glyph_variations_t return false; /* add only those coords that are used more than once into the vector and sort */ - hb_vector_t*> shared_coords; - if (unlikely (!shared_coords.alloc (coords_count_map.get_population ()))) - return false; - - for (const auto _ : coords_count_map.iter ()) - { - if (_.second == 1) continue; - shared_coords.push (_.first); - } + hb_vector_t*, unsigned>> shared_coords { + + hb_iter (coords_count_map) + | hb_filter ([] (const hb_pair_t*, unsigned>& p) { return p.second > 1; }) + }; + if (unlikely (shared_coords.in_error ())) return false; /* no shared tuples: no coords are used more than once */ if (!shared_coords) return true; /* sorting based on the coords frequency first (high to low), then compare * the coords bytes */ - hb_qsort (shared_coords.arrayZ, shared_coords.length, sizeof (hb_vector_t*), _cmp_coords, (void *) (&coords_count_map)); + shared_coords.qsort (_cmp_coords); /* build shared_coords->idx map and shared tuples byte array */ shared_tuples_count = hb_min (0xFFFu + 1, shared_coords.length); - unsigned len = shared_tuples_count * (shared_coords[0]->length); + unsigned len = shared_tuples_count * (shared_coords[0].first->length); if (unlikely (!compiled_shared_tuples.alloc (len))) return false; for (unsigned i = 0; i < shared_tuples_count; i++) { - shared_tuples_idx_map.set (shared_coords[i], i); + shared_tuples_idx_map.set (shared_coords[i].first, i); /* add a concat() in hb_vector_t? */ - for (char c : shared_coords[i]->iter ()) + for (auto c : shared_coords[i].first->iter ()) compiled_shared_tuples.push (c); } return true; } - static int _cmp_coords (const void *pa, const void *pb, void *arg) + static int _cmp_coords (const void *pa, const void *pb) { - const hb_hashmap_t*, unsigned>* coords_count_map = - reinterpret_cast*, unsigned>*> (arg); + const hb_pair_t *, unsigned> *a = (const hb_pair_t *, unsigned> *) pa; + const hb_pair_t *, unsigned> *b = (const hb_pair_t *, unsigned> *) pb; - /* shared_coords is hb_vector_t*> so casting pa/pb - * to be a pointer to a pointer */ - const hb_vector_t** a = reinterpret_cast**> (const_cast(pa)); - const hb_vector_t** b = reinterpret_cast**> (const_cast(pb)); + if (a->second != b->second) + return b->second - a->second; // high to low - bool has_a = coords_count_map->has (*a); - bool has_b = coords_count_map->has (*b); - - if (has_a && has_b) - { - unsigned a_num = coords_count_map->get (*a); - unsigned b_num = coords_count_map->get (*b); - - if (a_num != b_num) - return b_num - a_num; - - return (*b)->as_array().cmp ((*a)->as_array ()); - } - else if (has_a) return -1; - else if (has_b) return 1; - else return 0; + return b->first->as_array().cmp (a->first->as_array ()); } templatesharedTuples = 0; else { - hb_array_t shared_tuples = glyph_vars.compiled_shared_tuples.as_array ().copy (c); + hb_array_t shared_tuples = glyph_vars.compiled_shared_tuples.as_array ().copy (c); if (!shared_tuples.arrayZ) return_trace (false); - out->sharedTuples = shared_tuples.arrayZ - (char *) out; + out->sharedTuples = (const char *) shared_tuples.arrayZ - (char *) out; } char *glyph_var_data = c->start_embed (); @@ -463,10 +448,18 @@ struct gvar_GVAR if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) it++; unsigned int subset_data_size = 0; + unsigned padding_size = 0; for (auto &_ : it) { hb_codepoint_t old_gid = _.second; - subset_data_size += get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length; + unsigned glyph_data_size = get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length; + if (glyph_data_size % 2) + { + glyph_data_size++; + padding_size++; + } + + subset_data_size += glyph_data_size; } /* According to the spec: If the short format (Offset16) is used for offsets, @@ -495,6 +488,8 @@ struct gvar_GVAR /* This ordering relative to the shared tuples array, which puts the glyphVariationData last in the table, is required when HB_SUBSET_FLAGS_IFTB_REQUIREMENTS is set */ + if (long_offset) + subset_data_size -= padding_size; char *subset_data = c->serializer->allocate_size (subset_data_size, false); if (!subset_data) return_trace (false); out->dataZ = subset_data - (char *) out; @@ -533,8 +528,16 @@ struct gvar_GVAR old_gid); hb_memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length); - subset_data += var_data_bytes.length; - glyph_offset += var_data_bytes.length; + unsigned glyph_data_size = var_data_bytes.length; + subset_data += glyph_data_size; + glyph_offset += glyph_data_size; + + if (!long_offset && (glyph_data_size % 2)) + { + *subset_data = 0; + subset_data++; + glyph_offset++; + } if (long_offset) ((HBUINT32 *) subset_offsets)[gid] = glyph_offset; @@ -582,6 +585,17 @@ struct gvar_GVAR public: struct accelerator_t { + + hb_scalar_cache_t *create_cache () const + { + return hb_scalar_cache_t::create (table->sharedTupleCount); + } + + static void destroy_cache (hb_scalar_cache_t *cache) + { + hb_scalar_cache_t::destroy (cache); + } + bool has_data () const { return table->has_data (); } accelerator_t (hb_face_t *face) @@ -589,36 +603,6 @@ struct gvar_GVAR table = hb_sanitize_context_t ().reference_table (face); /* If sanitize failed, set glyphCount to 0. */ glyphCount = table->version.to_int () ? face->get_num_glyphs () : 0; - - /* For shared tuples that only have one or two axes active, shared the index - * of that axis as a cache. This will speed up caclulate_scalar() a lot - * for fonts with lots of axes and many "monovar" or "duovar" tuples. */ - hb_array_t shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount); - unsigned count = table->sharedTupleCount; - if (unlikely (!shared_tuple_active_idx.resize (count, false))) return; - unsigned axis_count = table->axisCount; - for (unsigned i = 0; i < count; i++) - { - hb_array_t tuple = shared_tuples.sub_array (axis_count * i, axis_count); - int idx1 = -1, idx2 = -1; - for (unsigned j = 0; j < axis_count; j++) - { - const F2DOT14 &peak = tuple.arrayZ[j]; - if (peak.to_int () != 0) - { - if (idx1 == -1) - idx1 = j; - else if (idx2 == -1) - idx2 = j; - else - { - idx1 = idx2 = -1; - break; - } - } - } - shared_tuple_active_idx.arrayZ[i] = {idx1, idx2}; - } } ~accelerator_t () { table.destroy (); } @@ -655,6 +639,7 @@ struct gvar_GVAR hb_array_t coords, const hb_array_t points, hb_glyf_scratch_t &scratch, + hb_scalar_cache_t *gvar_cache = nullptr, bool phantom_only = false) const { if (unlikely (glyph >= glyphCount)) return true; @@ -690,10 +675,12 @@ struct gvar_GVAR unsigned count = points.length; bool flush = false; + do { float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples, - &shared_tuple_active_idx); + gvar_cache); + if (scalar == 0.f) continue; const HBUINT8 *p = iterator.get_serialized_data (); unsigned int length = iterator.current_tuple->get_data_size (); @@ -702,7 +689,7 @@ struct gvar_GVAR if (!deltas) { - if (unlikely (!deltas_vec.resize (count, false))) return false; + if (unlikely (!deltas_vec.resize_dirty (count))) return false; deltas = deltas_vec.as_array (); hb_memset (deltas.arrayZ + (phantom_only ? count - 4 : 0), 0, (phantom_only ? 4 : count) * sizeof (deltas[0])); @@ -717,11 +704,12 @@ struct gvar_GVAR const hb_array_t &indices = has_private_points ? private_indices : shared_indices; bool apply_to_all = (indices.length == 0); - unsigned int num_deltas = apply_to_all ? points.length : indices.length; - if (unlikely (!x_deltas.resize (num_deltas, false))) return false; - if (unlikely (!GlyphVariationData::decompile_deltas (p, x_deltas, end))) return false; - if (unlikely (!y_deltas.resize (num_deltas, false))) return false; - if (unlikely (!GlyphVariationData::decompile_deltas (p, y_deltas, end))) return false; + unsigned num_deltas = apply_to_all ? points.length : indices.length; + unsigned start_deltas = (apply_to_all && phantom_only && num_deltas >= 4 ? num_deltas - 4 : 0); + if (unlikely (!x_deltas.resize_dirty (num_deltas))) return false; + if (unlikely (!GlyphVariationData::decompile_deltas (p, x_deltas, end, false, start_deltas))) return false; + if (unlikely (!y_deltas.resize_dirty (num_deltas))) return false; + if (unlikely (!GlyphVariationData::decompile_deltas (p, y_deltas, end, false, start_deltas))) return false; if (!apply_to_all) { @@ -884,7 +872,6 @@ struct gvar_GVAR private: hb_blob_ptr_t table; unsigned glyphCount; - hb_vector_t> shared_tuple_active_idx; }; protected: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-hvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-hvar-table.hh index 40a85a62b78..652d738e7b5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-hvar-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-hvar-table.hh @@ -42,57 +42,62 @@ struct index_map_subset_plan_t VORG_INDEX }; - void init (const DeltaSetIndexMap &index_map, + void init (const DeltaSetIndexMap *index_map, hb_inc_bimap_t &outer_map, hb_vector_t &inner_sets, const hb_subset_plan_t *plan, bool bypass_empty = true) { map_count = 0; - outer_bit_count = 0; - inner_bit_count = 1; max_inners.init (); output_map.init (); - if (bypass_empty && !index_map.get_map_count ()) return; + if (bypass_empty && (!index_map || !index_map->get_map_count ())) return; unsigned int last_val = (unsigned int)-1; hb_codepoint_t last_gid = HB_CODEPOINT_INVALID; - outer_bit_count = (index_map.get_width () * 8) - index_map.get_inner_bit_count (); max_inners.resize (inner_sets.length); for (unsigned i = 0; i < inner_sets.length; i++) max_inners[i] = 0; /* Search backwards for a map value different from the last map value */ auto &new_to_old_gid_list = plan->new_to_old_gid_list; unsigned count = new_to_old_gid_list.length; - for (unsigned j = count; j; j--) + if (!index_map) { - hb_codepoint_t gid = new_to_old_gid_list.arrayZ[j - 1].first; - hb_codepoint_t old_gid = new_to_old_gid_list.arrayZ[j - 1].second; - - unsigned int v = index_map.map (old_gid); - if (last_gid == HB_CODEPOINT_INVALID) + map_count = new_to_old_gid_list.tail ().first + 1; + } + else + { + for (unsigned j = count; j; j--) { + hb_codepoint_t gid = new_to_old_gid_list.arrayZ[j - 1].first; + hb_codepoint_t old_gid = new_to_old_gid_list.arrayZ[j - 1].second; + + unsigned int v = index_map->map (old_gid); + if (last_gid == HB_CODEPOINT_INVALID) + { last_val = v; last_gid = gid; continue; - } - if (v != last_val) + } + if (v != last_val) break; - last_gid = gid; + last_gid = gid; + } + + if (unlikely (last_gid == (hb_codepoint_t)-1)) return; + map_count = last_gid + 1; } - if (unlikely (last_gid == (hb_codepoint_t)-1)) return; - map_count = last_gid + 1; for (auto _ : plan->new_to_old_gid_list) { hb_codepoint_t gid = _.first; if (gid >= map_count) break; hb_codepoint_t old_gid = _.second; - unsigned int v = index_map.map (old_gid); + unsigned int v = index_map ? index_map->map (old_gid): old_gid; unsigned int outer = v >> 16; unsigned int inner = v & 0xFFFF; outer_map.add (outer); @@ -113,6 +118,9 @@ struct index_map_subset_plan_t const hb_vector_t &inner_maps, const hb_subset_plan_t *plan) { + outer_bit_count = 1; + inner_bit_count = 1; + for (unsigned int i = 0; i < max_inners.length; i++) { if (inner_maps[i].get_population () == 0) continue; @@ -128,9 +136,13 @@ struct index_map_subset_plan_t if (unlikely (new_gid >= map_count)) break; - uint32_t v = input_map->map (old_gid); - unsigned int outer = v >> 16; - output_map.arrayZ[new_gid] = (outer_map[outer] << 16) | (inner_maps[outer][v & 0xFFFF]); + uint32_t v = input_map? input_map->map (old_gid) : old_gid; + unsigned outer = v >> 16; + unsigned new_outer = outer_map[outer]; + unsigned bit_count = (new_outer == 0) ? 1 : hb_bit_storage (new_outer); + outer_bit_count = hb_max (bit_count, outer_bit_count); + + output_map.arrayZ[new_gid] = (new_outer << 16) | (inner_maps[outer][v & 0xFFFF]); } } @@ -204,8 +216,8 @@ struct hvarvvar_subset_plan_t if (unlikely (!index_map_plans.length || !inner_sets.length || !inner_maps.length)) return; bool retain_adv_map = false; - index_map_plans[0].init (*index_maps[0], outer_map, inner_sets, plan, false); - if (index_maps[0] == &Null (DeltaSetIndexMap)) + index_map_plans[0].init (index_maps[0], outer_map, inner_sets, plan, false); + if (!index_maps[0]) { retain_adv_map = plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS; outer_map.add (0); @@ -215,7 +227,7 @@ struct hvarvvar_subset_plan_t } for (unsigned int i = 1; i < index_maps.length; i++) - index_map_plans[i].init (*index_maps[i], outer_map, inner_sets, plan); + index_map_plans[i].init (index_maps[i], outer_map, inner_sets, plan); outer_map.sort (); @@ -284,6 +296,8 @@ struct HVARVVAR static constexpr hb_tag_t HVARTag = HB_OT_TAG_HVAR; static constexpr hb_tag_t VVARTag = HB_OT_TAG_VVAR; + bool has_data () const { return version.major != 0; } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -301,9 +315,14 @@ struct HVARVVAR void listup_index_maps (hb_vector_t &index_maps) const { - index_maps.push (&(this+advMap)); - index_maps.push (&(this+lsbMap)); - index_maps.push (&(this+rsbMap)); + if (advMap) index_maps.push (&(this+advMap)); + else index_maps.push (nullptr); + + if (lsbMap) index_maps.push (&(this+lsbMap)); + else index_maps.push (nullptr); + + if (rsbMap) index_maps.push (&(this+rsbMap)); + else index_maps.push (nullptr); } bool serialize_index_maps (hb_serialize_context_t *c, @@ -382,9 +401,10 @@ struct HVARVVAR hvar_plan.index_map_plans.as_array ())); } + HB_ALWAYS_INLINE float get_advance_delta_unscaled (hb_codepoint_t glyph, const int *coords, unsigned int coord_count, - ItemVariationStore::cache_t *store_cache = nullptr) const + hb_scalar_cache_t *store_cache = nullptr) const { uint32_t varidx = (this+advMap).map (glyph); return (this+varStore).get_delta (varidx, @@ -392,16 +412,6 @@ struct HVARVVAR store_cache); } - bool get_lsb_delta_unscaled (hb_codepoint_t glyph, - const int *coords, unsigned int coord_count, - float *lsb) const - { - if (!lsbMap) return false; - uint32_t varidx = (this+lsbMap).map (glyph); - *lsb = (this+varStore).get_delta (varidx, coords, coord_count); - return true; - } - public: FixedVersion<>version; /* Version of the metrics variation table * initially set to 0x00010000u */ @@ -435,7 +445,8 @@ struct VVAR : HVARVVAR { void listup_index_maps (hb_vector_t &index_maps) const { HVARVVAR::listup_index_maps (index_maps); - index_maps.push (&(this+vorgMap)); + if (vorgMap) index_maps.push (&(this+vorgMap)); + else index_maps.push (nullptr); } bool serialize_index_maps (hb_serialize_context_t *c, @@ -454,14 +465,16 @@ struct VVAR : HVARVVAR { bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset (c); } - bool get_vorg_delta_unscaled (hb_codepoint_t glyph, - const int *coords, unsigned int coord_count, - float *delta) const + HB_ALWAYS_INLINE + float get_vorg_delta_unscaled (hb_codepoint_t glyph, + const int *coords, unsigned int coord_count, + hb_scalar_cache_t *store_cache = nullptr) const { - if (!vorgMap) return false; + if (!vorgMap) return 0.f; uint32_t varidx = (this+vorgMap).map (glyph); - *delta = (this+varStore).get_delta (varidx, coords, coord_count); - return true; + return (this+varStore).get_delta (varidx, + coords, coord_count, + store_cache); } protected: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc index 8c695c41e24..4d594d587d8 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc @@ -286,10 +286,14 @@ hb_ot_var_normalize_variations (hb_face_t *face, hb_ot_var_axis_info_t info; if (hb_ot_var_find_axis_info (face, variations[i].tag, &info) && info.axis_index < coords_length) - coords[info.axis_index] = fvar.normalize_axis_value (info.axis_index, variations[i].value); + coords[info.axis_index] = roundf (fvar.normalize_axis_value (info.axis_index, variations[i].value) * 65536.0f); } - face->table.avar->map_coords (coords, coords_length); + face->table.avar->map_coords_16_16 (coords, coords_length); + + // Round to 2.14 + for (unsigned i = 0; i < coords_length; i++) + coords[i] = (coords[i] + 2) >> 2; } /** @@ -309,6 +313,10 @@ hb_ot_var_normalize_variations (hb_face_t *face, * Any additional scaling defined in the face's `avar` table is also * applied, as described at https://docs.microsoft.com/en-us/typography/opentype/spec/avar * + * Note: @coords_length must be the same as the number of axes in the face, as + * for example returned by hb_ot_var_get_axis_count(). + * Otherwise, the behavior is undefined. + * * Since: 1.4.2 **/ void @@ -319,9 +327,13 @@ hb_ot_var_normalize_coords (hb_face_t *face, { const OT::fvar &fvar = *face->table.fvar; for (unsigned int i = 0; i < coords_length; i++) - normalized_coords[i] = fvar.normalize_axis_value (i, design_coords[i]); + normalized_coords[i] = roundf (fvar.normalize_axis_value (i, design_coords[i]) * 65536.0f); - face->table.avar->map_coords (normalized_coords, coords_length); + face->table.avar->map_coords_16_16 (normalized_coords, coords_length); + + // Round to 2.14 + for (unsigned i = 0; i < coords_length; i++) + normalized_coords[i] = (normalized_coords[i] + 2) >> 2; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-vorg-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-vorg-table.hh index b2300a327da..ff7ce678e4e 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-vorg-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-vorg-table.hh @@ -61,6 +61,7 @@ struct VORG bool has_data () const { return version.to_int (); } + HB_ALWAYS_INLINE int get_y_origin (hb_codepoint_t glyph) const { unsigned int i; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-outline.cc b/src/java.desktop/share/native/libharfbuzz/hb-outline.cc index 85ffc793678..12963fe46e3 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-outline.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-outline.cc @@ -84,6 +84,15 @@ void hb_outline_t::replay (hb_draw_funcs_t *pen, void *pen_data) const } } +void hb_outline_t::translate (float dx, float dy) +{ + for (auto &p : points) + { + p.x += dx; + p.y += dy; + } +} + void hb_outline_t::slant (float slant_xy) { for (auto &p : points) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-outline.hh b/src/java.desktop/share/native/libharfbuzz/hb-outline.hh index c5b68c05dd7..9e394a68d9c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-outline.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-outline.hh @@ -69,6 +69,7 @@ struct hb_outline_t HB_INTERNAL void replay (hb_draw_funcs_t *pen, void *pen_data) const; HB_INTERNAL float control_area () const; + HB_INTERNAL void translate (float dx, float dy); HB_INTERNAL void slant (float slant_xy); HB_INTERNAL void embolden (float x_strength, float y_strength, float x_shift, float y_shift); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc b/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc index bc08c5a9e14..e867f37f3c5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc @@ -49,7 +49,7 @@ hb_paint_extents_push_transform (hb_paint_funcs_t *funcs HB_UNUSED, { hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data; - c->push_transform (hb_transform_t {xx, yx, xy, yy, dx, dy}); + c->push_transform (hb_transform_t<> {xx, yx, xy, yy, dx, dy}); } static void @@ -71,7 +71,7 @@ hb_paint_extents_push_clip_glyph (hb_paint_funcs_t *funcs HB_UNUSED, { hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data; - hb_extents_t extents; + hb_extents_t<> extents; hb_draw_funcs_t *draw_extent_funcs = hb_draw_extents_get_funcs (); hb_font_draw_glyph (font, glyph, draw_extent_funcs, &extents); c->push_clip (extents); @@ -85,7 +85,7 @@ hb_paint_extents_push_clip_rectangle (hb_paint_funcs_t *funcs HB_UNUSED, { hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data; - hb_extents_t extents = {xmin, ymin, xmax, ymax}; + hb_extents_t<> extents = {xmin, ymin, xmax, ymax}; c->push_clip (extents); } @@ -136,10 +136,10 @@ hb_paint_extents_paint_image (hb_paint_funcs_t *funcs HB_UNUSED, if (!glyph_extents) return false; // Happens with SVG images. - hb_extents_t extents = {(float) glyph_extents->x_bearing, - (float) glyph_extents->y_bearing + glyph_extents->height, - (float) glyph_extents->x_bearing + glyph_extents->width, - (float) glyph_extents->y_bearing}; + hb_extents_t<> extents = {(float) glyph_extents->x_bearing, + (float) glyph_extents->y_bearing + glyph_extents->height, + (float) glyph_extents->x_bearing + glyph_extents->width, + (float) glyph_extents->y_bearing}; c->push_clip (extents); c->paint (); c->pop_clip (); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh b/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh index 60374eaa2d2..531eb3c7c52 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh @@ -41,9 +41,9 @@ struct hb_paint_extents_context_t clips.clear (); groups.clear (); - transforms.push (hb_transform_t{}); - clips.push (hb_bounds_t{hb_bounds_t::UNBOUNDED}); - groups.push (hb_bounds_t{hb_bounds_t::EMPTY}); + transforms.push (hb_transform_t<>{}); + clips.push (hb_bounds_t<>{hb_bounds_t<>::UNBOUNDED}); + groups.push (hb_bounds_t<>{hb_bounds_t<>::EMPTY}); } hb_paint_extents_context_t () @@ -51,19 +51,19 @@ struct hb_paint_extents_context_t clear (); } - hb_extents_t get_extents () + hb_extents_t<> get_extents () { return groups.tail().extents; } bool is_bounded () { - return groups.tail().status != hb_bounds_t::UNBOUNDED; + return groups.tail().status != hb_bounds_t<>::UNBOUNDED; } - void push_transform (const hb_transform_t &trans) + void push_transform (const hb_transform_t<> &trans) { - hb_transform_t t = transforms.tail (); + hb_transform_t<> t = transforms.tail (); t.multiply (trans); transforms.push (t); } @@ -73,13 +73,13 @@ struct hb_paint_extents_context_t transforms.pop (); } - void push_clip (hb_extents_t extents) + void push_clip (hb_extents_t<> extents) { /* Transform extents and push a new clip. */ - const hb_transform_t &t = transforms.tail (); + const hb_transform_t<> &t = transforms.tail (); t.transform_extents (extents); - auto bounds = hb_bounds_t {extents}; + auto bounds = hb_bounds_t<> {extents}; bounds.intersect (clips.tail ()); clips.push (bounds); @@ -92,19 +92,19 @@ struct hb_paint_extents_context_t void push_group () { - groups.push (hb_bounds_t {hb_bounds_t::EMPTY}); + groups.push (hb_bounds_t<> {hb_bounds_t<>::EMPTY}); } void pop_group (hb_paint_composite_mode_t mode) { - const hb_bounds_t src_bounds = groups.pop (); - hb_bounds_t &backdrop_bounds = groups.tail (); + const hb_bounds_t<> src_bounds = groups.pop (); + hb_bounds_t<> &backdrop_bounds = groups.tail (); // https://learn.microsoft.com/en-us/typography/opentype/spec/colr#format-32-paintcomposite switch ((int) mode) { case HB_PAINT_COMPOSITE_MODE_CLEAR: - backdrop_bounds.status = hb_bounds_t::EMPTY; + backdrop_bounds.status = hb_bounds_t<>::EMPTY; break; case HB_PAINT_COMPOSITE_MODE_SRC: case HB_PAINT_COMPOSITE_MODE_SRC_OUT: @@ -125,16 +125,16 @@ struct hb_paint_extents_context_t void paint () { - const hb_bounds_t &clip = clips.tail (); - hb_bounds_t &group = groups.tail (); + const hb_bounds_t<> &clip = clips.tail (); + hb_bounds_t<> &group = groups.tail (); group.union_ (clip); } protected: - hb_vector_t transforms; - hb_vector_t clips; - hb_vector_t groups; + hb_vector_t> transforms; + hb_vector_t> clips; + hb_vector_t> groups; }; HB_INTERNAL hb_paint_funcs_t * diff --git a/src/java.desktop/share/native/libharfbuzz/hb-paint.hh b/src/java.desktop/share/native/libharfbuzz/hb-paint.hh index 2abadebab3c..aedbcbdcbe2 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-paint.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-paint.hh @@ -28,6 +28,7 @@ #include "hb.hh" #include "hb-face.hh" #include "hb-font.hh" +#include "hb-geometry.hh" #define HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS \ HB_PAINT_FUNC_IMPLEMENT (push_transform) \ @@ -72,7 +73,11 @@ struct hb_paint_funcs_t float xx, float yx, float xy, float yy, float dx, float dy) - { func.push_transform (this, paint_data, + { + // Handle -0.f to avoid -0.f == 0.f in the transform matrix. + if (dx == -0.f) dx = 0.f; + if (dy == -0.f) dy = 0.f; + func.push_transform (this, paint_data, xx, yx, xy, yy, dx, dy, !user_data ? nullptr : user_data->push_transform); } void pop_transform (void *paint_data) @@ -182,54 +187,59 @@ struct hb_paint_funcs_t 0, 0); } - HB_NODISCARD - bool push_translate (void *paint_data, + void push_transform (void *paint_data, hb_transform_t t) + { + push_transform (paint_data, t.xx, t.yx, t.xy, t.yy, t.x0, t.y0); + } + + void push_translate (void *paint_data, float dx, float dy) { - if (!dx && !dy) - return false; - push_transform (paint_data, - 1.f, 0.f, 0.f, 1.f, dx, dy); - return true; + hb_transform_t::translation (dx, dy)); } - HB_NODISCARD - bool push_scale (void *paint_data, + void push_scale (void *paint_data, float sx, float sy) { - if (sx == 1.f && sy == 1.f) - return false; - push_transform (paint_data, - sx, 0.f, 0.f, sy, 0.f, 0.f); - return true; + hb_transform_t::scaling (sx, sy)); + } + void push_scale_around_center (void *paint_data, + float sx, float sy, + float cx, float cy) + { + push_transform (paint_data, + hb_transform_t::scaling_around_center (sx, sy, cx, cy)); } - HB_NODISCARD - bool push_rotate (void *paint_data, + void push_rotate (void *paint_data, float a) { - if (!a) - return false; - - float cc = cosf (a * HB_PI); - float ss = sinf (a * HB_PI); - push_transform (paint_data, cc, ss, -ss, cc, 0.f, 0.f); - return true; + push_transform (paint_data, + hb_transform_t::rotation (a * HB_PI)); } - HB_NODISCARD - bool push_skew (void *paint_data, + void push_rotate_around_center (void *paint_data, + float a, + float cx, float cy) + { + push_transform (paint_data, + hb_transform_t::rotation_around_center (a * HB_PI, cx, cy)); + } + + void push_skew (void *paint_data, float sx, float sy) { - if (!sx && !sy) - return false; - - float x = tanf (-sx * HB_PI); - float y = tanf (+sy * HB_PI); - push_transform (paint_data, 1.f, y, x, 1.f, 0.f, 0.f); - return true; + push_transform (paint_data, + hb_transform_t::skewing (-sx * HB_PI, sy * HB_PI)); + } + void push_skew_around_center (void *paint_data, + float sx, float sy, + float cx, float cy) + { + push_transform (paint_data, + hb_transform_t::skewing_around_center (-sx * HB_PI, sy * HB_PI, cx, cy)); } }; DECLARE_NULL_INSTANCE (hb_paint_funcs_t); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-priority-queue.hh b/src/java.desktop/share/native/libharfbuzz/hb-priority-queue.hh index 274d5df4c54..753e86b8ca6 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-priority-queue.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-priority-queue.hh @@ -45,12 +45,22 @@ template struct hb_priority_queue_t { - private: + public: typedef hb_pair_t item_t; + + private: hb_vector_t heap; public: + hb_priority_queue_t () = default; + hb_priority_queue_t (hb_vector_t&& other) : heap (std::move (other)) + { + // Heapify the vector. + for (int i = (heap.length / 2) - 1; i >= 0; i--) + bubble_down (i); + } + void reset () { heap.resize (0); } bool in_error () const { return heap.in_error (); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-repacker.hh b/src/java.desktop/share/native/libharfbuzz/hb-repacker.hh index cb4fdeead2e..7d118b52169 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-repacker.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-repacker.hh @@ -217,11 +217,17 @@ bool _try_isolating_subgraphs (const hb_vector_t& over unsigned maximum_to_move = hb_max ((sorted_graph.num_roots_for_space (space) / 2u), 1u); if (roots_to_isolate.get_population () > maximum_to_move) { // Only move at most half of the roots in a space at a time. - unsigned extra = roots_to_isolate.get_population () - maximum_to_move; - while (extra--) { - uint32_t root = HB_SET_VALUE_INVALID; - roots_to_isolate.previous (&root); - roots_to_isolate.del (root); + // + // Note: this was ported from non-stable ids to stable ids. So to retain the same behaviour + // with regards to which roots are removed from the set we need to remove them in the topological + // order, not the object id order. + int extra = roots_to_isolate.get_population () - maximum_to_move; + for (unsigned id : sorted_graph.ordering_) { + if (!extra) break; + if (roots_to_isolate.has(id)) { + roots_to_isolate.del(id); + extra--; + } } } @@ -266,7 +272,7 @@ bool _resolve_shared_overflow(const hb_vector_t& overf result = sorted_graph.duplicate(&parents, r.child); } - if (result == (unsigned) -1) return result; + if (result == (unsigned) -1) return false; if (parents.get_population() > 1) { // If the duplicated node has more than one parent pre-emptively raise it's priority to the maximum. @@ -283,7 +289,7 @@ bool _resolve_shared_overflow(const hb_vector_t& overf sorted_graph.vertices_[result].give_max_priority(); } - return result; + return true; } static inline @@ -302,8 +308,11 @@ bool _process_overflows (const hb_vector_t& overflows, { // The child object is shared, we may be able to eliminate the overflow // by duplicating it. - if (!_resolve_shared_overflow(overflows, i, sorted_graph)) continue; - return true; + if (_resolve_shared_overflow(overflows, i, sorted_graph)) + return true; + + // Sometimes we can't duplicate a node which looks shared because it's not actually shared + // (eg. all links from the same parent) in this case continue on to other resolution options. } if (child.is_leaf () && !priority_bumped_parents.has (r.parent)) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-sanitize.hh b/src/java.desktop/share/native/libharfbuzz/hb-sanitize.hh index 1f8ba32bae2..1e9ee9ba960 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-sanitize.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-sanitize.hh @@ -64,9 +64,6 @@ * * - Cast blob content to T*, call sanitize() method of it, * - If sanitize succeeded, return blob. - * - Otherwise, if blob is not writable, try making it writable, - * or copy if cannot be made writable in-place, - * - Call sanitize() again. Return blob if sanitize succeeded. * - Return empty blob otherwise. * * @@ -98,6 +95,12 @@ * structure is so complicated that by checking all offsets at sanitize() time, * we make the code much simpler in other methods, as offsets and referenced * objects do not need to be validated at each use site. + * + * Note: + * Sanitize was named so because it used to try to recover from errors by + * modifying the data to make it valid. This is no longer the case, as it + * could make HarfBuzz hallucinate new rules if there was aliasing in the + * data. However, the name stuck. See: https://behdad.github.io/harfbust/ */ /* This limits sanitizing time on really broken fonts. */ @@ -120,12 +123,12 @@ struct hb_sanitize_context_t : hb_dispatch_context_t { - hb_sanitize_context_t () : - start (nullptr), end (nullptr), + hb_sanitize_context_t (const char *start_ = nullptr, const char *end_ = nullptr) : + start (start_), end (end_), length (0), max_ops (0), max_subtables (0), recursion_depth (0), - writable (false), edit_count (0), + writable (false), blob (nullptr), num_glyphs (65536), num_glyphs_set (false), @@ -212,14 +215,22 @@ struct hb_sanitize_context_t : void reset_object () { - this->start = this->blob->data; - this->end = this->start + this->blob->length; + if (this->blob) + { + this->start = this->blob->data; + this->end = this->start + this->blob->length; + } this->length = this->end - this->start; assert (this->start <= this->end); /* Must not overflow. */ } - void start_processing () + void start_processing (const char *start_ = nullptr, const char *end_ = nullptr) { + if (start_) + { + this->start = start_; + this->end = end_; + } reset_object (); unsigned m; if (unlikely (hb_unsigned_mul_overflows (this->end - this->start, HB_SANITIZE_MAX_OPS_FACTOR, &m))) @@ -228,7 +239,6 @@ struct hb_sanitize_context_t : this->max_ops = hb_clamp (m, (unsigned) HB_SANITIZE_MAX_OPS_MIN, (unsigned) HB_SANITIZE_MAX_OPS_MAX); - this->edit_count = 0; this->debug_depth = 0; this->recursion_depth = 0; @@ -241,8 +251,8 @@ struct hb_sanitize_context_t : void end_processing () { DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1, - "end [%p..%p] %u edit requests", - this->start, this->end, this->edit_count); + "end [%p..%p]", + this->start, this->end); hb_blob_destroy (this->blob); this->blob = nullptr; @@ -250,9 +260,6 @@ struct hb_sanitize_context_t : this->length = 0; } - unsigned get_edit_count () { return edit_count; } - - bool check_ops(unsigned count) { /* Avoid underflow */ @@ -396,35 +403,6 @@ struct hb_sanitize_context_t : return likely (this->check_point ((const char *) obj + obj->min_size)); } - bool may_edit (const void *base, unsigned int len) - { - if (this->edit_count >= HB_SANITIZE_MAX_EDITS) - return false; - - const char *p = (const char *) base; - this->edit_count++; - - DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, - "may_edit(%u) [%p..%p] (%u bytes) in [%p..%p] -> %s", - this->edit_count, - p, p + len, len, - this->start, this->end, - this->writable ? "GRANTED" : "DENIED"); - - return this->writable; - } - - template - bool try_set (const Type *obj, const ValueType &v) - { - if (this->may_edit (obj, hb_static_size (Type))) - { - * const_cast (obj) = v; - return true; - } - return false; - } - template hb_blob_t *sanitize_blob (hb_blob_t *blob) { @@ -432,7 +410,6 @@ struct hb_sanitize_context_t : init (blob); - retry: DEBUG_MSG_FUNC (SANITIZE, start, "start"); start_processing (); @@ -446,36 +423,6 @@ struct hb_sanitize_context_t : Type *t = reinterpret_cast (const_cast (start)); sane = t->sanitize (this); - if (sane) - { - if (edit_count) - { - DEBUG_MSG_FUNC (SANITIZE, start, "passed first round with %u edits; going for second round", edit_count); - - /* sanitize again to ensure no toe-stepping */ - edit_count = 0; - sane = t->sanitize (this); - if (edit_count) { - DEBUG_MSG_FUNC (SANITIZE, start, "requested %u edits in second round; FAILING", edit_count); - sane = false; - } - } - } - else - { - if (edit_count && !writable) { - start = hb_blob_get_data_writable (blob, nullptr); - end = start + blob->length; - - if (start) - { - writable = true; - /* ok, we made it writable by relocating. try again */ - DEBUG_MSG_FUNC (SANITIZE, start, "retry"); - goto retry; - } - } - } end_processing (); @@ -506,7 +453,6 @@ struct hb_sanitize_context_t : private: int recursion_depth; bool writable; - unsigned int edit_count; hb_blob_t *blob; unsigned int num_glyphs; bool num_glyphs_set; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-script-list.h b/src/java.desktop/share/native/libharfbuzz/hb-script-list.h index f811dbc3408..16347b9d84e 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-script-list.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-script-list.h @@ -223,6 +223,10 @@ HB_END_DECLS * @HB_SCRIPT_SUNUWAR: `Sunu`, Since: 10.0.0 * @HB_SCRIPT_TODHRI: `Todr`, Since: 10.0.0 * @HB_SCRIPT_TULU_TIGALARI: `Tutg`, Since: 10.0.0 + * @HB_SCRIPT_BERIA_ERFE: `Berf`, Since: 11.5.0 + * @HB_SCRIPT_SIDETIC: `Sidt`, Since: 11.5.0 + * @HB_SCRIPT_TAI_YO: `Tayo`, Since: 11.5.0 + * @HB_SCRIPT_TOLONG_SIKI: `Tols`, Since: 11.5.0 * @HB_SCRIPT_INVALID: No script set * * Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding @@ -461,6 +465,14 @@ typedef enum HB_SCRIPT_TODHRI = HB_TAG ('T','o','d','r'), /*16.0*/ HB_SCRIPT_TULU_TIGALARI = HB_TAG ('T','u','t','g'), /*16.0*/ + /* + * Since 11.5.0 + */ + HB_SCRIPT_BERIA_ERFE = HB_TAG ('B','e','r','f'), /*17.0*/ + HB_SCRIPT_SIDETIC = HB_TAG ('S','i','d','t'), /*17.0*/ + HB_SCRIPT_TAI_YO = HB_TAG ('T','a','y','o'), /*17.0*/ + HB_SCRIPT_TOLONG_SIKI = HB_TAG ('T','o','l','s'), /*17.0*/ + /* No script set. */ HB_SCRIPT_INVALID = HB_TAG_NONE, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh b/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh index 704d0ffd12b..9fe99c85ea7 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh @@ -34,7 +34,7 @@ #include "hb.hh" #include "hb-blob.hh" #include "hb-map.hh" -#include "hb-pool.hh" +#include "hb-free-pool.hh" #include "hb-subset-serialize.h" @@ -724,7 +724,7 @@ struct hb_serialize_context_t hb_requires (hb_is_iterator (Iterator)), typename ...Ts> void copy_all (Iterator it, Ts&&... ds) - { for (decltype (*it) _ : it) copy (_, std::forward (ds)...); } + { for (decltype (*it) _ : it) copy (_, ds...); } template hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; } @@ -794,7 +794,8 @@ struct hb_serialize_context_t template void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset) { - auto &off = * ((BEInt *) (parent->head + link.position)); + // XXX We should stop assuming big-endian! + auto &off = * ((HBInt *) (parent->head + link.position)); assert (0 == off); check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW); } @@ -814,7 +815,7 @@ struct hb_serialize_context_t } /* Object memory pool. */ - hb_pool_t object_pool; + hb_free_pool_t object_pool; /* Stack of currently under construction objects. */ object_t *current; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-set-digest.hh b/src/java.desktop/share/native/libharfbuzz/hb-set-digest.hh index f0416d5fa1d..f8cb0998260 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-set-digest.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-set-digest.hh @@ -55,11 +55,11 @@ * - For each glyph, if it doesn't match the subtable digest, * skip it. * - * The main filter we use is a combination of four bits-pattern + * The filter we use is a combination of three bits-pattern * filters. A bits-pattern filter checks a number of bits (5 or 6) - * of the input number (glyph-id in this case) and checks whether + * of the input number (glyph-id in most cases) and checks whether * its pattern is amongst the patterns of any of the accepted values. - * The accepted patterns are represented as a "long" integer. The + * The accepted patterns are represented as a "long" integer. Each * check is done using four bitwise operations only. */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shape.cc b/src/java.desktop/share/native/libharfbuzz/hb-shape.cc index d14f577be00..a36fa14fb28 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-shape.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-shape.cc @@ -149,14 +149,11 @@ hb_shape_full (hb_font_t *font, hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features); - if (buffer->max_ops <= 0) - buffer->shaping_failed = true; - hb_shape_plan_destroy (shape_plan); if (text_buffer) { - if (res && buffer->successful && !buffer->shaping_failed + if (res && buffer->successful && text_buffer->successful && !buffer->verify (text_buffer, font, @@ -199,6 +196,7 @@ hb_shape (hb_font_t *font, #ifdef HB_EXPERIMENTAL_API +#ifndef HB_NO_VAR static float buffer_advance (hb_buffer_t *buffer) @@ -440,7 +438,7 @@ hb_shape_justify (hb_font_t *font, return true; } - +#endif #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shaper-list.hh b/src/java.desktop/share/native/libharfbuzz/hb-shaper-list.hh index f079caf4d35..cb386f26827 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-shaper-list.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-shaper-list.hh @@ -57,6 +57,14 @@ HB_SHAPER_IMPLEMENT (directwrite) HB_SHAPER_IMPLEMENT (coretext) #endif +#ifdef HAVE_HARFRUST +HB_SHAPER_IMPLEMENT (harfrust) +#endif + +#ifdef HAVE_KBTS +HB_SHAPER_IMPLEMENT (kbts) +#endif + #ifndef HB_NO_FALLBACK_SHAPE HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */ #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-static.cc b/src/java.desktop/share/native/libharfbuzz/hb-static.cc index 4e70e413651..06cc80b5f38 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-static.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-static.cc @@ -113,27 +113,4 @@ hb_face_t::load_upem () const return ret; } - -#ifndef HB_NO_VAR -bool -_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical, - int *lsb) -{ - return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb); -} - -unsigned -_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) -{ - return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical); -} -#endif - -bool -_glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb) -{ - return face->table.glyf->get_leading_bearing_without_var_unscaled (gid, is_vertical, lsb); -} - - #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-string-array.hh b/src/java.desktop/share/native/libharfbuzz/hb-string-array.hh index 9d00cae6c32..51413b6da44 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-string-array.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-string-array.hh @@ -45,25 +45,25 @@ static const union HB_STRING_ARRAY_TYPE_NAME { * but C++ does not allow that. * https://stackoverflow.com/q/28433862 */ -#define _S(s) char HB_PASTE (str, __LINE__)[sizeof (s)]; +#define HB_STR(s) char HB_PASTE (str, __LINE__)[sizeof (s)]; #include HB_STRING_ARRAY_LIST -#undef _S +#undef HB_STR } st; char str[HB_VAR_ARRAY]; } HB_STRING_ARRAY_POOL_NAME = { { -#define _S(s) s, +#define HB_STR(s) s, #include HB_STRING_ARRAY_LIST -#undef _S +#undef HB_STR } }; static const unsigned int HB_STRING_ARRAY_OFFS_NAME[] = { -#define _S(s) offsetof (union HB_STRING_ARRAY_TYPE_NAME, st.HB_PASTE(str, __LINE__)), +#define HB_STR(s) offsetof (union HB_STRING_ARRAY_TYPE_NAME, st.HB_PASTE(str, __LINE__)), #include HB_STRING_ARRAY_LIST -#undef _S +#undef HB_STR sizeof (HB_STRING_ARRAY_TYPE_NAME) }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh index e7bddaef723..843ad69f2f9 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh @@ -861,8 +861,7 @@ struct subr_subsetter_t { // Hack to point vector to static string. auto &b = buffArray.arrayZ[last]; - b.length = 1; - b.arrayZ = const_cast(endchar_str); + b.set_storage (const_cast(endchar_str), 1); } last++; // Skip over gid @@ -877,8 +876,7 @@ struct subr_subsetter_t { // Hack to point vector to static string. auto &b = buffArray.arrayZ[last]; - b.length = 1; - b.arrayZ = const_cast(endchar_str); + b.set_storage (const_cast(endchar_str), 1); } return true; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-iup.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-iup.hh index 01987bd258d..8ee02c07dbe 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-iup.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-iup.hh @@ -26,12 +26,27 @@ #define HB_SUBSET_INSTANCER_IUP_HH #include "hb-subset-plan.hh" + +struct iup_scratch_t +{ + hb_vector_t end_points; + hb_vector_t interp_x_deltas; + hb_vector_t interp_y_deltas; + hb_vector_t costs; + hb_vector_t chain; + hb_vector_t rot_indices; + hb_vector_t rot_x_deltas; + hb_vector_t rot_y_deltas; + contour_point_vector_t rot_points; +}; + /* given contour points and deltas, optimize a set of referenced points within error * tolerance. Returns optimized referenced point indices */ HB_INTERNAL bool iup_delta_optimize (const contour_point_vector_t& contour_points, const hb_vector_t& x_deltas, const hb_vector_t& y_deltas, hb_vector_t& opt_indices, /* OUT */ + iup_scratch_t &scratch, double tolerance = 0.0); #endif /* HB_SUBSET_INSTANCER_IUP_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.cc index c67fee421c2..15227bdab48 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.cc @@ -62,9 +62,10 @@ static inline double supportScalar (double coord, const Triple &tent) return (end - coord) / (end - peak); } -static inline rebase_tent_result_t -_solve (Triple tent, Triple axisLimit, bool negative = false) +static inline void +_solve (Triple tent, Triple axisLimit, rebase_tent_result_t &out, bool negative = false) { + out.reset(); double axisMin = axisLimit.minimum; double axisDef = axisLimit.middle; double axisMax = axisLimit.maximum; @@ -75,14 +76,12 @@ _solve (Triple tent, Triple axisLimit, bool negative = false) // Mirror the problem such that axisDef <= peak if (axisDef > peak) { - rebase_tent_result_t vec = _solve (_reverse_negate (tent), - _reverse_negate (axisLimit), - !negative); + _solve (_reverse_negate (tent), _reverse_negate (axisLimit), out, !negative); - for (auto &p : vec) + for (auto &p : out) p = hb_pair (p.first, _reverse_negate (p.second)); - return vec; + return; } // axisDef <= peak @@ -98,7 +97,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false) * axisMin axisDef axisMax lower upper */ if (axisMax <= lower && axisMax < peak) - return rebase_tent_result_t{}; // No overlap + return; // No overlap /* case 2: Only the peak and outermost bound fall outside the new limit; * we keep the deltaset, update peak and outermost bound and scale deltas @@ -133,18 +132,18 @@ _solve (Triple tent, Triple axisLimit, bool negative = false) double mult = supportScalar (axisMax, tent); tent = Triple{lower, axisMax, axisMax}; - rebase_tent_result_t vec = _solve (tent, axisLimit); + _solve (tent, axisLimit, out); - for (auto &p : vec) + for (auto &p : out) p = hb_pair (p.first * mult, p.second); - return vec; + return; } // lower <= axisDef <= peak <= axisMax double gain = supportScalar (axisDef, tent); - rebase_tent_result_t out {hb_pair (gain, Triple{})}; + out.push(hb_pair (gain, Triple{})); // First, the positive side @@ -362,8 +361,6 @@ _solve (Triple tent, Triple axisLimit, bool negative = false) out.push (hb_pair (scalar1 - gain, loc1)); out.push (hb_pair (scalar2 - gain, loc2)); } - - return out; } static inline TripleDistances _reverse_triple_distances (const TripleDistances &v) @@ -405,18 +402,21 @@ double renormalizeValue (double v, const Triple &triple, return (-v_distance) /total_distance; } -rebase_tent_result_t -rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances) +void +rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances, + rebase_tent_result_t &out, + rebase_tent_result_t &scratch) { assert (-1.0 <= axisLimit.minimum && axisLimit.minimum <= axisLimit.middle && axisLimit.middle <= axisLimit.maximum && axisLimit.maximum <= +1.0); assert (-2.0 <= tent.minimum && tent.minimum <= tent.middle && tent.middle <= tent.maximum && tent.maximum <= +2.0); assert (tent.middle != 0.0); - rebase_tent_result_t sols = _solve (tent, axisLimit); + rebase_tent_result_t &sols = scratch; + _solve (tent, axisLimit, sols); auto n = [&axisLimit, &axis_triple_distances] (double v) { return renormalizeValue (v, axisLimit, axis_triple_distances); }; - rebase_tent_result_t out; + out.reset(); for (auto &p : sols) { if (!p.first) continue; @@ -429,6 +429,4 @@ rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distance out.push (hb_pair (p.first, Triple{n (t.minimum), n (t.middle), n (t.maximum)})); } - - return out; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.hh index 9764dcc1725..574d58d53d8 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.hh @@ -42,10 +42,9 @@ struct TripleDistances double positive; }; -struct Triple { - - Triple () : - minimum (0.0), middle (0.0), maximum (0.0) {} +struct Triple +{ + Triple () = default; Triple (double minimum_, double middle_, double maximum_) : minimum (minimum_), middle (middle_), maximum (maximum_) {} @@ -81,10 +80,9 @@ struct Triple { return current; } - - double minimum; - double middle; - double maximum; + double minimum = 0; + double middle = 0; + double maximum = 0; }; using rebase_tent_result_item_t = hb_pair_t; @@ -107,8 +105,10 @@ HB_INTERNAL double renormalizeValue (double v, const Triple &triple, * If tent value is Triple{}, that is a special deltaset that should * be always-enabled (called "gain"). */ -HB_INTERNAL rebase_tent_result_t rebase_tent (Triple tent, - Triple axisLimit, - TripleDistances axis_triple_distances); +HB_INTERNAL void rebase_tent (Triple tent, + Triple axisLimit, + TripleDistances axis_triple_distances, + rebase_tent_result_t &out, + rebase_tent_result_t &scratch); #endif /* HB_SUBSET_INSTANCER_SOLVER_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan-member-list.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan-member-list.hh index ade8278c40f..398fe81eca9 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan-member-list.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan-member-list.hh @@ -81,6 +81,10 @@ HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(>), gpo HB_SUBSET_PLAN_MEMBER (hb_map_t, gsub_features) HB_SUBSET_PLAN_MEMBER (hb_map_t, gpos_features) +//active features(with duplicates) old index -> new index mapping +HB_SUBSET_PLAN_MEMBER (hb_map_t, gsub_features_w_duplicates) +HB_SUBSET_PLAN_MEMBER (hb_map_t, gpos_features_w_duplicates) + //active feature variation records/condition index with variations HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(>), gsub_feature_record_cond_idx_map) HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(>), gpos_feature_record_cond_idx_map) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc index 3ba726d925e..8c3fd97899b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc @@ -418,7 +418,8 @@ _nameid_closure (hb_subset_plan_t* plan, hb_set_t* drop_tables) { #ifndef HB_NO_STYLE - plan->source->table.STAT->collect_name_ids (&plan->user_axes_location, &plan->name_ids); + if (!drop_tables->has (HB_OT_TAG_STAT)) + plan->source->table.STAT->collect_name_ids (&plan->user_axes_location, &plan->name_ids); #endif #ifndef HB_NO_VAR if (!plan->all_axes_pinned) @@ -676,7 +677,8 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, return; #ifndef HB_NO_VAR - normalize_axes_location (face, this); + if (!check_success (normalize_axes_location (face, this))) + return; #endif _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, this); @@ -697,6 +699,15 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, return; } +#ifdef HB_EXPERIMENTAL_API + if ((input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS) && + (input->flags & HB_SUBSET_FLAGS_RETAIN_NUM_GLYPHS)) { + // We've been requested to maintain the num glyphs count from the + // input face. + _num_output_glyphs = source->get_num_glyphs (); + } +#endif + _create_glyph_map_gsub ( &_glyphset_gsub, glyph_map, @@ -710,10 +721,10 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, glyph_map->get(unicode_to_new_gid_list.arrayZ[i].second); } - bounds_width_vec.resize (_num_output_glyphs, false); + bounds_width_vec.resize_dirty (_num_output_glyphs); for (auto &v : bounds_width_vec) v = 0xFFFFFFFF; - bounds_height_vec.resize (_num_output_glyphs, false); + bounds_height_vec.resize_dirty (_num_output_glyphs); for (auto &v : bounds_height_vec) v = 0xFFFFFFFF; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh index 8a6574365ed..0362ed7292e 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh @@ -300,6 +300,7 @@ struct hb_subset_plan_t // compile times more reasonable: // - hb-subset-plan.cc // - hb-subset-plan-layout.cc +// - hb-subset-plan-var.cc // // The functions below are those needed to connect the split files // above together. @@ -332,7 +333,7 @@ generate_varstore_inner_maps (const hb_set_t& varidx_set, unsigned subtable_count, hb_vector_t &inner_maps /* OUT */); -HB_INTERNAL void +HB_INTERNAL bool normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan); HB_INTERNAL void diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset.cc index 079c94eddfe..51134ed09ce 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset.cc @@ -25,65 +25,19 @@ */ #include "hb.hh" + #include "hb-open-type.hh" +#include "hb-open-file.hh" #include "hb-subset.hh" - -#include "hb-open-file.hh" -#include "hb-ot-cmap-table.hh" -#include "hb-ot-glyf-table.hh" -#include "hb-ot-hdmx-table.hh" -#include "hb-ot-head-table.hh" -#include "hb-ot-hhea-table.hh" -#include "hb-ot-hmtx-table.hh" -#include "hb-ot-maxp-table.hh" -#include "OT/Color/CBDT/CBDT.hh" -#include "OT/Color/COLR/COLR.hh" -#include "OT/Color/CPAL/CPAL.hh" -#include "OT/Color/sbix/sbix.hh" -#include "hb-ot-os2-table.hh" -#include "hb-ot-post-table.hh" -#include "hb-ot-post-table-v2subset.hh" -#include "hb-ot-cff1-table.hh" -#include "hb-ot-cff2-table.hh" -#include "hb-ot-vorg-table.hh" -#include "hb-ot-name-table.hh" -#include "hb-ot-layout-base-table.hh" -#include "hb-ot-layout-gsub-table.hh" -#include "hb-ot-layout-gpos-table.hh" -#include "hb-ot-var-avar-table.hh" -#include "hb-ot-var-cvar-table.hh" -#include "hb-ot-var-fvar-table.hh" -#include "hb-ot-var-gvar-table.hh" -#include "hb-ot-var-hvar-table.hh" -#include "hb-ot-var-mvar-table.hh" -#include "hb-ot-math-table.hh" -#include "hb-ot-stat-table.hh" -#include "hb-repacker.hh" +#include "hb-subset-table.hh" #include "hb-subset-accelerator.hh" -using OT::Layout::GSUB; -using OT::Layout::GPOS; - - -#ifndef HB_NO_SUBSET_CFF -template<> -struct hb_subset_plan_t::source_table_loader -{ - auto operator () (hb_subset_plan_t *plan) - HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff1_accel : - plan->inprogress_accelerator ? plan->inprogress_accelerator->cff1_accel : - plan->cff1_accel) -}; -template<> -struct hb_subset_plan_t::source_table_loader -{ - auto operator () (hb_subset_plan_t *plan) - HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff2_accel : - plan->inprogress_accelerator ? plan->inprogress_accelerator->cff2_accel : - plan->cff2_accel) -}; -#endif +#include "hb-ot-cmap-table.hh" +#include "hb-ot-var-cvar-table.hh" +#include "hb-ot-head-table.hh" +#include "hb-ot-stat-table.hh" +#include "hb-ot-post-table-v2subset.hh" /** @@ -116,56 +70,56 @@ hb_user_data_key_t _hb_subset_accelerator_user_data_key = {}; * if we are unable to list the tables in a face. */ static hb_tag_t known_tables[] { - HB_TAG ('a', 'v', 'a', 'r'), - HB_OT_TAG_BASE, - HB_OT_TAG_CBDT, - HB_OT_TAG_CBLC, - HB_OT_TAG_CFF1, - HB_OT_TAG_CFF2, - HB_OT_TAG_cmap, - HB_OT_TAG_COLR, - HB_OT_TAG_CPAL, - HB_TAG ('c', 'v', 'a', 'r'), - HB_TAG ('c', 'v', 't', ' '), - HB_TAG ('D', 'S', 'I', 'G'), - HB_TAG ('E', 'B', 'D', 'T'), - HB_TAG ('E', 'B', 'L', 'C'), - HB_TAG ('E', 'B', 'S', 'C'), - HB_TAG ('f', 'p', 'g', 'm'), - HB_TAG ('f', 'v', 'a', 'r'), - HB_TAG ('g', 'a', 's', 'p'), - HB_OT_TAG_GDEF, - HB_OT_TAG_glyf, - HB_OT_TAG_GPOS, - HB_OT_TAG_GSUB, - HB_OT_TAG_gvar, - HB_OT_TAG_hdmx, - HB_OT_TAG_head, - HB_OT_TAG_hhea, - HB_OT_TAG_hmtx, - HB_OT_TAG_HVAR, - HB_OT_TAG_JSTF, - HB_TAG ('k', 'e', 'r', 'n'), - HB_OT_TAG_loca, - HB_TAG ('L', 'T', 'S', 'H'), - HB_OT_TAG_MATH, - HB_OT_TAG_maxp, - HB_TAG ('M', 'E', 'R', 'G'), - HB_TAG ('m', 'e', 't', 'a'), - HB_TAG ('M', 'V', 'A', 'R'), - HB_TAG ('P', 'C', 'L', 'T'), - HB_OT_TAG_post, - HB_TAG ('p', 'r', 'e', 'p'), - HB_OT_TAG_sbix, - HB_TAG ('S', 'T', 'A', 'T'), - HB_TAG ('S', 'V', 'G', ' '), - HB_TAG ('V', 'D', 'M', 'X'), - HB_OT_TAG_vhea, - HB_OT_TAG_vmtx, - HB_OT_TAG_VORG, - HB_OT_TAG_VVAR, - HB_OT_TAG_name, - HB_OT_TAG_OS2 + HB_TAG('a','v','a','r'), + HB_TAG('B','A','S','E'), + HB_TAG('C','B','D','T'), + HB_TAG('C','B','L','C'), + HB_TAG('C','F','F',' '), + HB_TAG('C','F','F','2'), + HB_TAG('c','m','a','p'), + HB_TAG('C','O','L','R'), + HB_TAG('C','P','A','L'), + HB_TAG('c','v','a','r'), + HB_TAG('c','v','t',' '), + HB_TAG('D','S','I','G'), + HB_TAG('E','B','D','T'), + HB_TAG('E','B','L','C'), + HB_TAG('E','B','S','C'), + HB_TAG('f','p','g','m'), + HB_TAG('f','v','a','r'), + HB_TAG('g','a','s','p'), + HB_TAG('G','D','E','F'), + HB_TAG('g','l','y','f'), + HB_TAG('G','P','O','S'), + HB_TAG('G','S','U','B'), + HB_TAG('g','v','a','r'), + HB_TAG('h','d','m','x'), + HB_TAG('h','e','a','d'), + HB_TAG('h','h','e','a'), + HB_TAG('h','m','t','x'), + HB_TAG('H','V','A','R'), + HB_TAG('J','S','T','F'), + HB_TAG('k','e','r','n'), + HB_TAG('l','o','c','a'), + HB_TAG('L','T','S','H'), + HB_TAG('M','A','T','H'), + HB_TAG('m','a','x','p'), + HB_TAG('M','E','R','G'), + HB_TAG('m','e','t','a'), + HB_TAG('M','V','A','R'), + HB_TAG('P','C','L','T'), + HB_TAG('p','o','s','t'), + HB_TAG('p','r','e','p'), + HB_TAG('s','b','i','x'), + HB_TAG('S','T','A','T'), + HB_TAG('S','V','G',' '), + HB_TAG('V','D','M','X'), + HB_TAG('v','h','e','a'), + HB_TAG('v','m','t','x'), + HB_TAG('V','O','R','G'), + HB_TAG('V','V','A','R'), + HB_TAG('n','a','m','e'), + HB_TAG('O','S','/','2') }; static bool _table_is_empty (const hb_face_t *face, hb_tag_t tag) @@ -213,169 +167,6 @@ _get_table_tags (const hb_subset_plan_t* plan, } -static unsigned -_plan_estimate_subset_table_size (hb_subset_plan_t *plan, - unsigned table_len, - hb_tag_t table_tag) -{ - unsigned src_glyphs = plan->source->get_num_glyphs (); - unsigned dst_glyphs = plan->glyphset ()->get_population (); - - unsigned bulk = 8192; - /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's - * because those are expensive to subset, so giving them more room is fine. */ - bool same_size = table_tag == HB_OT_TAG_GSUB || - table_tag == HB_OT_TAG_GPOS || - table_tag == HB_OT_TAG_name; - - if (plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS) - { - if (table_tag == HB_OT_TAG_CFF1) - { - /* Add some extra room for the CFF charset. */ - bulk += src_glyphs * 16; - } - else if (table_tag == HB_OT_TAG_CFF2) - { - /* Just extra CharString offsets. */ - bulk += src_glyphs * 4; - } - } - - if (unlikely (!src_glyphs) || same_size) - return bulk + table_len; - - return bulk + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); -} - -/* - * Repack the serialization buffer if any offset overflows exist. - */ -static hb_blob_t* -_repack (hb_tag_t tag, const hb_serialize_context_t& c) -{ - if (!c.offset_overflow ()) - return c.copy_blob (); - - hb_blob_t* result = hb_resolve_overflows (c.object_graph (), tag); - - if (unlikely (!result)) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c offset overflow resolution failed.", - HB_UNTAG (tag)); - return nullptr; - } - - return result; -} - -template -static -bool -_try_subset (const TableType *table, - hb_vector_t* buf, - hb_subset_context_t* c /* OUT */) -{ - c->serializer->start_serialize (); - if (c->serializer->in_error ()) return false; - - bool needed = table->subset (c); - if (!c->serializer->ran_out_of_room ()) - { - c->serializer->end_serialize (); - return needed; - } - - unsigned buf_size = buf->allocated; - buf_size = buf_size * 2 + 16; - - - - - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", - HB_UNTAG (c->table_tag), buf_size); - - if (unlikely (buf_size > c->source_blob->length * 256 || - !buf->alloc_exact (buf_size))) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", - HB_UNTAG (c->table_tag), buf_size); - return needed; - } - - c->serializer->reset (buf->arrayZ, buf->allocated); - return _try_subset (table, buf, c); -} - -template -static auto _do_destroy (T &t, hb_priority<1>) HB_RETURN (void, t.destroy ()) - -template -static void _do_destroy (T &t, hb_priority<0>) {} - -template -static bool -_subset (hb_subset_plan_t *plan, hb_vector_t &buf) -{ - auto &&source_blob = plan->source_table (); - auto *table = source_blob.get (); - - hb_tag_t tag = TableType::tableTag; - hb_blob_t *blob = source_blob.get_blob(); - if (unlikely (!blob || !blob->data)) - { - DEBUG_MSG (SUBSET, nullptr, - "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); - _do_destroy (source_blob, hb_prioritize); - return false; - } - - unsigned buf_size = _plan_estimate_subset_table_size (plan, blob->length, TableType::tableTag); - DEBUG_MSG (SUBSET, nullptr, - "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); - if (unlikely (!buf.alloc (buf_size))) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size); - _do_destroy (source_blob, hb_prioritize); - return false; - } - - bool needed = false; - hb_serialize_context_t serializer (buf.arrayZ, buf.allocated); - { - hb_subset_context_t c (blob, plan, &serializer, tag); - needed = _try_subset (table, &buf, &c); - } - _do_destroy (source_blob, hb_prioritize); - - if (serializer.in_error () && !serializer.only_offset_overflow ()) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset FAILED!", HB_UNTAG (tag)); - return false; - } - - if (!needed) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag)); - return true; - } - - bool result = false; - hb_blob_t *dest_blob = _repack (tag, serializer); - if (dest_blob) - { - DEBUG_MSG (SUBSET, nullptr, - "OT::%c%c%c%c final subset table size: %u bytes.", - HB_UNTAG (tag), dest_blob->length); - result = plan->add_table (tag, dest_blob); - hb_blob_destroy (dest_blob); - } - - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset %s", - HB_UNTAG (tag), result ? "success" : "FAILED!"); - return result; -} - static bool _is_table_present (hb_face_t *source, hb_tag_t tag) { @@ -407,34 +198,34 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag) switch (tag) { - case HB_TAG ('c','v','a','r'): /* hint table, fallthrough */ + case HB_TAG('c','v','a','r'): /* hint table, fallthrough */ return plan->all_axes_pinned || (plan->flags & HB_SUBSET_FLAGS_NO_HINTING); - case HB_TAG ('c','v','t',' '): /* hint table, fallthrough */ - case HB_TAG ('f','p','g','m'): /* hint table, fallthrough */ - case HB_TAG ('p','r','e','p'): /* hint table, fallthrough */ - case HB_TAG ('h','d','m','x'): /* hint table, fallthrough */ - case HB_TAG ('V','D','M','X'): /* hint table, fallthrough */ + case HB_TAG('c','v','t',' '): /* hint table, fallthrough */ + case HB_TAG('f','p','g','m'): /* hint table, fallthrough */ + case HB_TAG('p','r','e','p'): /* hint table, fallthrough */ + case HB_TAG('h','d','m','x'): /* hint table, fallthrough */ + case HB_TAG('V','D','M','X'): /* hint table, fallthrough */ return plan->flags & HB_SUBSET_FLAGS_NO_HINTING; #ifdef HB_NO_SUBSET_LAYOUT // Drop Layout Tables if requested. - case HB_OT_TAG_GDEF: - case HB_OT_TAG_GPOS: - case HB_OT_TAG_GSUB: - case HB_TAG ('m','o','r','x'): - case HB_TAG ('m','o','r','t'): - case HB_TAG ('k','e','r','x'): - case HB_TAG ('k','e','r','n'): + case HB_TAG('G','D','E','F'): + case HB_TAG('G','P','O','S'): + case HB_TAG('G','S','U','B'): + case HB_TAG('m','o','r','x'): + case HB_TAG('m','o','r','t'): + case HB_TAG('k','e','r','x'): + case HB_TAG('k','e','r','n'): return true; #endif - case HB_TAG ('a','v','a','r'): - case HB_TAG ('f','v','a','r'): - case HB_TAG ('g','v','a','r'): - case HB_OT_TAG_HVAR: - case HB_OT_TAG_VVAR: - case HB_TAG ('M','V','A','R'): + case HB_TAG('a','v','a','r'): + case HB_TAG('f','v','a','r'): + case HB_TAG('g','v','a','r'): + case HB_TAG('H','V','A','R'): + case HB_TAG('V','V','A','R'): + case HB_TAG('M','V','A','R'): return plan->all_axes_pinned; default: @@ -442,15 +233,6 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag) } } -static bool -_passthrough (hb_subset_plan_t *plan, hb_tag_t tag) -{ - hb_blob_t *source_table = hb_face_reference_table (plan->source, tag); - bool result = plan->add_table (tag, source_table); - hb_blob_destroy (source_table); - return result; -} - static bool _dependencies_satisfied (hb_subset_plan_t *plan, hb_tag_t tag, const hb_set_t &subsetted_tags, @@ -458,13 +240,13 @@ _dependencies_satisfied (hb_subset_plan_t *plan, hb_tag_t tag, { switch (tag) { - case HB_OT_TAG_hmtx: - case HB_OT_TAG_vmtx: - case HB_OT_TAG_maxp: - case HB_OT_TAG_OS2: - return !plan->normalized_coords || !pending_subset_tags.has (HB_OT_TAG_glyf); - case HB_OT_TAG_GPOS: - return plan->all_axes_pinned || !pending_subset_tags.has (HB_OT_TAG_GDEF); + case HB_TAG('h','m','t','x'): + case HB_TAG('v','m','t','x'): + case HB_TAG('m','a','x','p'): + case HB_TAG('O','S','/','2'): + return !plan->normalized_coords || !pending_subset_tags.has (HB_TAG('g','l','y','f')); + case HB_TAG('G','P','O','S'): + return plan->all_axes_pinned || !pending_subset_tags.has (HB_TAG('G','D','E','F')); default: return true; } @@ -476,88 +258,48 @@ _subset_table (hb_subset_plan_t *plan, hb_tag_t tag) { if (plan->no_subset_tables.has (tag)) { - return _passthrough (plan, tag); + return _hb_subset_table_passthrough (plan, tag); } DEBUG_MSG (SUBSET, nullptr, "subset %c%c%c%c", HB_UNTAG (tag)); + + bool success; + if (_hb_subset_table_layout (plan, buf, tag, &success) || + _hb_subset_table_var (plan, buf, tag, &success) || + _hb_subset_table_cff (plan, buf, tag, &success) || + _hb_subset_table_color (plan, buf, tag, &success) || + _hb_subset_table_other (plan, buf, tag, &success)) + return success; + + switch (tag) { - case HB_OT_TAG_glyf: return _subset (plan, buf); - case HB_OT_TAG_hdmx: return _subset (plan, buf); - case HB_OT_TAG_name: return _subset (plan, buf); - case HB_OT_TAG_head: - if (_is_table_present (plan->source, HB_OT_TAG_glyf) && !_should_drop_table (plan, HB_OT_TAG_glyf)) + case HB_TAG('h','e','a','d'): + if (_is_table_present (plan->source, HB_TAG('g','l','y','f')) && !_should_drop_table (plan, HB_TAG('g','l','y','f'))) return true; /* skip head, handled by glyf */ - return _subset (plan, buf); - case HB_OT_TAG_hhea: return true; /* skip hhea, handled by hmtx */ - case HB_OT_TAG_hmtx: return _subset (plan, buf); - case HB_OT_TAG_vhea: return true; /* skip vhea, handled by vmtx */ - case HB_OT_TAG_vmtx: return _subset (plan, buf); - case HB_OT_TAG_maxp: return _subset (plan, buf); - case HB_OT_TAG_sbix: return _subset (plan, buf); - case HB_OT_TAG_loca: return true; /* skip loca, handled by glyf */ - case HB_OT_TAG_cmap: return _subset (plan, buf); - case HB_OT_TAG_OS2 : return _subset (plan, buf); - case HB_OT_TAG_post: return _subset (plan, buf); - case HB_OT_TAG_COLR: return _subset (plan, buf); - case HB_OT_TAG_CPAL: return _subset (plan, buf); - case HB_OT_TAG_CBLC: return _subset (plan, buf); - case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */ - case HB_OT_TAG_MATH: return _subset (plan, buf); - case HB_OT_TAG_BASE: return _subset (plan, buf); + return _hb_subset_table (plan, buf); -#ifndef HB_NO_SUBSET_CFF - case HB_OT_TAG_CFF1: return _subset (plan, buf); - case HB_OT_TAG_CFF2: return _subset (plan, buf); - case HB_OT_TAG_VORG: return _subset (plan, buf); -#endif - -#ifndef HB_NO_SUBSET_LAYOUT - case HB_OT_TAG_GDEF: return _subset (plan, buf); - case HB_OT_TAG_GSUB: return _subset (plan, buf); - case HB_OT_TAG_GPOS: return _subset (plan, buf); - case HB_OT_TAG_gvar: return _subset (plan, buf); - case HB_OT_TAG_HVAR: return _subset (plan, buf); - case HB_OT_TAG_VVAR: return _subset (plan, buf); -#endif + case HB_TAG('S','T','A','T'): + if (!plan->user_axes_location.is_empty ()) return _hb_subset_table (plan, buf); + else return _hb_subset_table_passthrough (plan, tag); + case HB_TAG('c','v','t',' '): #ifndef HB_NO_VAR - case HB_OT_TAG_fvar: - if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag); - return _subset (plan, buf); - case HB_OT_TAG_avar: - if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag); - return _subset (plan, buf); - case HB_OT_TAG_cvar: - if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag); - return _subset (plan, buf); - case HB_OT_TAG_MVAR: - if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag); - return _subset (plan, buf); -#endif - - case HB_OT_TAG_STAT: - if (!plan->user_axes_location.is_empty ()) return _subset (plan, buf); - else return _passthrough (plan, tag); - - case HB_TAG ('c', 'v', 't', ' '): -#ifndef HB_NO_VAR - if (_is_table_present (plan->source, HB_OT_TAG_cvar) && + if (_is_table_present (plan->source, HB_TAG('c','v','a','r')) && plan->normalized_coords && !plan->pinned_at_default) { auto &cvar = *plan->source->table.cvar; return OT::cvar::add_cvt_and_apply_deltas (plan, cvar.get_tuple_var_data (), &cvar); } #endif - return _passthrough (plan, tag); - - default: - if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED) - return _passthrough (plan, tag); - - // Drop table - return true; + return _hb_subset_table_passthrough (plan, tag); } + + if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED) + return _hb_subset_table_passthrough (plan, tag); + + // Drop table + return true; } static void _attach_accelerator_data (hb_subset_plan_t* plan, @@ -707,108 +449,4 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan) end: return success ? hb_face_reference (plan->dest) : nullptr; -} - - -#ifdef HB_EXPERIMENTAL_API - -#include "hb-ot-cff1-table.hh" - -template -static hb_blob_t* get_charstrings_data(accel_t& accel, hb_codepoint_t glyph_index) { - if (!accel.is_valid()) { - return hb_blob_get_empty (); - } - - hb_ubytes_t bytes = (*accel.charStrings)[glyph_index]; - if (!bytes) { - return hb_blob_get_empty (); - } - - hb_blob_t* cff_blob = accel.get_blob(); - uint32_t length; - const char* cff_data = hb_blob_get_data(cff_blob, &length) ; - - long int offset = (const char*) bytes.arrayZ - cff_data; - if (offset < 0 || offset > INT32_MAX) { - return hb_blob_get_empty (); - } - - return hb_blob_create_sub_blob(cff_blob, (uint32_t) offset, bytes.length); -} - -template -static hb_blob_t* get_charstrings_index(accel_t& accel) { - if (!accel.is_valid()) { - return hb_blob_get_empty (); - } - - const char* charstrings_start = (const char*) accel.charStrings; - unsigned charstrings_length = accel.charStrings->get_size(); - - hb_blob_t* cff_blob = accel.get_blob(); - uint32_t length; - const char* cff_data = hb_blob_get_data(cff_blob, &length) ; - - long int offset = charstrings_start - cff_data; - if (offset < 0 || offset > INT32_MAX) { - return hb_blob_get_empty (); - } - - return hb_blob_create_sub_blob(cff_blob, (uint32_t) offset, charstrings_length); -} - -/** - * hb_subset_cff_get_charstring_data: - * @face: A face object - * @glyph_index: Glyph index to get data for. - * - * Returns the raw outline data from the CFF/CFF2 table associated with the given glyph index. - * - * XSince: EXPERIMENTAL - **/ -HB_EXTERN hb_blob_t* -hb_subset_cff_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph_index) { - return get_charstrings_data(*face->table.cff1, glyph_index); -} - -/** - * hb_subset_cff_get_charstrings_index: - * @face: A face object - * - * Returns the raw CFF CharStrings INDEX from the CFF table. - * - * XSince: EXPERIMENTAL - **/ -HB_EXTERN hb_blob_t* -hb_subset_cff_get_charstrings_index (hb_face_t* face) { - return get_charstrings_index (*face->table.cff1); -} - -/** - * hb_subset_cff2_get_charstring_data: - * @face: A face object - * @glyph_index: Glyph index to get data for. - * - * Returns the raw outline data from the CFF/CFF2 table associated with the given glyph index. - * - * XSince: EXPERIMENTAL - **/ -HB_EXTERN hb_blob_t* -hb_subset_cff2_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph_index) { - return get_charstrings_data(*face->table.cff2, glyph_index); -} - -/** - * hb_subset_cff2_get_charstrings_index: - * @face: A face object - * - * Returns the raw CFF2 CharStrings INDEX from the CFF2 table. - * - * XSince: EXPERIMENTAL - **/ -HB_EXTERN hb_blob_t* -hb_subset_cff2_get_charstrings_index (hb_face_t* face) { - return get_charstrings_index (*face->table.cff2); -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset.h b/src/java.desktop/share/native/libharfbuzz/hb-subset.h index 3eccd25738e..fd2908e8308 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset.h @@ -80,6 +80,10 @@ typedef struct hb_subset_plan_t hb_subset_plan_t; * @HB_SUBSET_FLAGS_IFTB_REQUIREMENTS: If set enforce requirements on the output subset * to allow it to be used with incremental font transfer IFTB patches. Primarily, * this forces all outline data to use long (32 bit) offsets. Since: EXPERIMENTAL + * @HB_SUBSET_FLAGS_RETAIN_NUM_GLYPHS: If this flag is set along side + * HB_SUBSET_FLAGS_RETAIN_GIDS then the number of glyphs in the font won't + * be reduced as a result of subsetting. If necessary empty glyphs will be + * included at the end of the font to keep the number of glyphs unchanged. * * List of boolean properties that can be configured on the subset input. * @@ -101,6 +105,7 @@ typedef enum { /*< flags >*/ HB_SUBSET_FLAGS_NO_BIDI_CLOSURE = 0x00000800u, #ifdef HB_EXPERIMENTAL_API HB_SUBSET_FLAGS_IFTB_REQUIREMENTS = 0x00001000u, + HB_SUBSET_FLAGS_RETAIN_NUM_GLYPHS = 0x00002000u, #endif } hb_subset_flags_t; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset.hh index bc7c24c94de..009919764f5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset.hh @@ -70,5 +70,4 @@ struct hb_subset_context_t : table_tag (table_tag_) {} }; - #endif /* HB_SUBSET_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh index 8731a0bcf8d..868428ab1e7 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh @@ -2,9 +2,9 @@ /* * The following table is generated by running: * - * ./gen-ucd-table.py ucd.nounihan.grouped.xml + * ./gen-ucd-table.py ucd.nounihan.grouped.xml hb-script-list.h * - * on file with this description: Unicode 16.0.0 + * on file with this description: Unicode 17.0.0 */ #ifndef HB_UCD_TABLE_HH @@ -12,8 +12,9 @@ #include "hb.hh" -static const hb_script_t -_hb_ucd_sc_map[172] = +#include + +static const hb_script_t _hb_ucd_sc_map[176]= { HB_SCRIPT_COMMON, HB_SCRIPT_INHERITED, HB_SCRIPT_UNKNOWN, HB_SCRIPT_ARABIC, @@ -101,1040 +102,805 @@ _hb_ucd_sc_map[172] = HB_SCRIPT_GURUNG_KHEMA, HB_SCRIPT_KIRAT_RAI, HB_SCRIPT_OL_ONAL, HB_SCRIPT_SUNUWAR, HB_SCRIPT_TODHRI, HB_SCRIPT_TULU_TIGALARI, + HB_SCRIPT_BERIA_ERFE, HB_SCRIPT_SIDETIC, + HB_SCRIPT_TAI_YO, HB_SCRIPT_TOLONG_SIKI, }; -static const uint16_t -_hb_ucd_dm1_p0_map[825] = +static const uint16_t _hb_ucd_dm1_p0_map[825]= { - 0x003Bu, 0x004Bu, 0x0060u, 0x00B4u, 0x00B7u, 0x00C5u, 0x02B9u, 0x0300u, - 0x0301u, 0x0313u, 0x0385u, 0x0386u, 0x0388u, 0x0389u, 0x038Au, 0x038Cu, - 0x038Eu, 0x038Fu, 0x0390u, 0x03A9u, 0x03ACu, 0x03ADu, 0x03AEu, 0x03AFu, - 0x03B0u, 0x03B9u, 0x03CCu, 0x03CDu, 0x03CEu, 0x2002u, 0x2003u, 0x3008u, - 0x3009u, 0x349Eu, 0x34B9u, 0x34BBu, 0x34DFu, 0x3515u, 0x36EEu, 0x36FCu, - 0x3781u, 0x382Fu, 0x3862u, 0x387Cu, 0x38C7u, 0x38E3u, 0x391Cu, 0x393Au, - 0x3A2Eu, 0x3A6Cu, 0x3AE4u, 0x3B08u, 0x3B19u, 0x3B49u, 0x3B9Du, 0x3C18u, - 0x3C4Eu, 0x3D33u, 0x3D96u, 0x3EACu, 0x3EB8u, 0x3F1Bu, 0x3FFCu, 0x4008u, - 0x4018u, 0x4039u, 0x4046u, 0x4096u, 0x40E3u, 0x412Fu, 0x4202u, 0x4227u, - 0x42A0u, 0x4301u, 0x4334u, 0x4359u, 0x43D5u, 0x43D9u, 0x440Bu, 0x446Bu, - 0x452Bu, 0x455Du, 0x4561u, 0x456Bu, 0x45D7u, 0x45F9u, 0x4635u, 0x46BEu, - 0x46C7u, 0x4995u, 0x49E6u, 0x4A6Eu, 0x4A76u, 0x4AB2u, 0x4B33u, 0x4BCEu, - 0x4CCEu, 0x4CEDu, 0x4CF8u, 0x4D56u, 0x4E0Du, 0x4E26u, 0x4E32u, 0x4E38u, - 0x4E39u, 0x4E3Du, 0x4E41u, 0x4E82u, 0x4E86u, 0x4EAEu, 0x4EC0u, 0x4ECCu, - 0x4EE4u, 0x4F60u, 0x4F80u, 0x4F86u, 0x4F8Bu, 0x4FAEu, 0x4FBBu, 0x4FBFu, - 0x5002u, 0x502Bu, 0x507Au, 0x5099u, 0x50CFu, 0x50DAu, 0x50E7u, 0x5140u, - 0x5145u, 0x514Du, 0x5154u, 0x5164u, 0x5167u, 0x5168u, 0x5169u, 0x516Du, - 0x5177u, 0x5180u, 0x518Du, 0x5192u, 0x5195u, 0x5197u, 0x51A4u, 0x51ACu, - 0x51B5u, 0x51B7u, 0x51C9u, 0x51CCu, 0x51DCu, 0x51DEu, 0x51F5u, 0x5203u, - 0x5207u, 0x5217u, 0x5229u, 0x523Au, 0x523Bu, 0x5246u, 0x5272u, 0x5277u, - 0x5289u, 0x529Bu, 0x52A3u, 0x52B3u, 0x52C7u, 0x52C9u, 0x52D2u, 0x52DEu, - 0x52E4u, 0x52F5u, 0x52FAu, 0x5305u, 0x5306u, 0x5317u, 0x533Fu, 0x5349u, - 0x5351u, 0x535Au, 0x5373u, 0x5375u, 0x537Du, 0x537Fu, 0x53C3u, 0x53CAu, - 0x53DFu, 0x53E5u, 0x53EBu, 0x53F1u, 0x5406u, 0x540Fu, 0x541Du, 0x5438u, - 0x5442u, 0x5448u, 0x5468u, 0x549Eu, 0x54A2u, 0x54BDu, 0x54F6u, 0x5510u, - 0x5553u, 0x5555u, 0x5563u, 0x5584u, 0x5587u, 0x5599u, 0x559Du, 0x55ABu, - 0x55B3u, 0x55C0u, 0x55C2u, 0x55E2u, 0x5606u, 0x5651u, 0x5668u, 0x5674u, - 0x56F9u, 0x5716u, 0x5717u, 0x578Bu, 0x57CEu, 0x57F4u, 0x580Du, 0x5831u, - 0x5832u, 0x5840u, 0x585Au, 0x585Eu, 0x58A8u, 0x58ACu, 0x58B3u, 0x58D8u, - 0x58DFu, 0x58EEu, 0x58F2u, 0x58F7u, 0x5906u, 0x591Au, 0x5922u, 0x5944u, - 0x5948u, 0x5951u, 0x5954u, 0x5962u, 0x5973u, 0x59D8u, 0x59ECu, 0x5A1Bu, - 0x5A27u, 0x5A62u, 0x5A66u, 0x5AB5u, 0x5B08u, 0x5B28u, 0x5B3Eu, 0x5B85u, - 0x5BC3u, 0x5BD8u, 0x5BE7u, 0x5BEEu, 0x5BF3u, 0x5BFFu, 0x5C06u, 0x5C22u, - 0x5C3Fu, 0x5C60u, 0x5C62u, 0x5C64u, 0x5C65u, 0x5C6Eu, 0x5C8Du, 0x5CC0u, - 0x5D19u, 0x5D43u, 0x5D50u, 0x5D6Bu, 0x5D6Eu, 0x5D7Cu, 0x5DB2u, 0x5DBAu, - 0x5DE1u, 0x5DE2u, 0x5DFDu, 0x5E28u, 0x5E3Du, 0x5E69u, 0x5E74u, 0x5EA6u, - 0x5EB0u, 0x5EB3u, 0x5EB6u, 0x5EC9u, 0x5ECAu, 0x5ED2u, 0x5ED3u, 0x5ED9u, - 0x5EECu, 0x5EFEu, 0x5F04u, 0x5F22u, 0x5F53u, 0x5F62u, 0x5F69u, 0x5F6Bu, - 0x5F8Bu, 0x5F9Au, 0x5FA9u, 0x5FADu, 0x5FCDu, 0x5FD7u, 0x5FF5u, 0x5FF9u, - 0x6012u, 0x601Cu, 0x6075u, 0x6081u, 0x6094u, 0x60C7u, 0x60D8u, 0x60E1u, - 0x6108u, 0x6144u, 0x6148u, 0x614Cu, 0x614Eu, 0x6160u, 0x6168u, 0x617Au, - 0x618Eu, 0x6190u, 0x61A4u, 0x61AFu, 0x61B2u, 0x61DEu, 0x61F2u, 0x61F6u, - 0x6200u, 0x6210u, 0x621Bu, 0x622Eu, 0x6234u, 0x625Du, 0x62B1u, 0x62C9u, - 0x62CFu, 0x62D3u, 0x62D4u, 0x62FCu, 0x62FEu, 0x633Du, 0x6350u, 0x6368u, - 0x637Bu, 0x6383u, 0x63A0u, 0x63A9u, 0x63C4u, 0x63C5u, 0x63E4u, 0x641Cu, - 0x6422u, 0x6452u, 0x6469u, 0x6477u, 0x647Eu, 0x649Au, 0x649Du, 0x64C4u, - 0x654Fu, 0x6556u, 0x656Cu, 0x6578u, 0x6599u, 0x65C5u, 0x65E2u, 0x65E3u, - 0x6613u, 0x6649u, 0x6674u, 0x6688u, 0x6691u, 0x669Cu, 0x66B4u, 0x66C6u, - 0x66F4u, 0x66F8u, 0x6700u, 0x6717u, 0x671Bu, 0x6721u, 0x674Eu, 0x6753u, - 0x6756u, 0x675Eu, 0x677Bu, 0x6785u, 0x6797u, 0x67F3u, 0x67FAu, 0x6817u, - 0x681Fu, 0x6852u, 0x6881u, 0x6885u, 0x688Eu, 0x68A8u, 0x6914u, 0x6942u, - 0x69A3u, 0x69EAu, 0x6A02u, 0x6A13u, 0x6AA8u, 0x6AD3u, 0x6ADBu, 0x6B04u, - 0x6B21u, 0x6B54u, 0x6B72u, 0x6B77u, 0x6B79u, 0x6B9Fu, 0x6BAEu, 0x6BBAu, - 0x6BBBu, 0x6C4Eu, 0x6C67u, 0x6C88u, 0x6CBFu, 0x6CCCu, 0x6CCDu, 0x6CE5u, - 0x6D16u, 0x6D1Bu, 0x6D1Eu, 0x6D34u, 0x6D3Eu, 0x6D41u, 0x6D69u, 0x6D6Au, - 0x6D77u, 0x6D78u, 0x6D85u, 0x6DCBu, 0x6DDAu, 0x6DEAu, 0x6DF9u, 0x6E1Au, - 0x6E2Fu, 0x6E6Eu, 0x6E9Cu, 0x6EBAu, 0x6EC7u, 0x6ECBu, 0x6ED1u, 0x6EDBu, - 0x6F0Fu, 0x6F22u, 0x6F23u, 0x6F6Eu, 0x6FC6u, 0x6FEBu, 0x6FFEu, 0x701Bu, - 0x701Eu, 0x7039u, 0x704Au, 0x7070u, 0x7077u, 0x707Du, 0x7099u, 0x70ADu, - 0x70C8u, 0x70D9u, 0x7145u, 0x7149u, 0x716Eu, 0x719Cu, 0x71CEu, 0x71D0u, - 0x7210u, 0x721Bu, 0x7228u, 0x722Bu, 0x7235u, 0x7250u, 0x7262u, 0x7280u, - 0x7295u, 0x72AFu, 0x72C0u, 0x72FCu, 0x732Au, 0x7375u, 0x737Au, 0x7387u, - 0x738Bu, 0x73A5u, 0x73B2u, 0x73DEu, 0x7406u, 0x7409u, 0x7422u, 0x7447u, - 0x745Cu, 0x7469u, 0x7471u, 0x7485u, 0x7489u, 0x7498u, 0x74CAu, 0x7506u, - 0x7524u, 0x753Bu, 0x753Eu, 0x7559u, 0x7565u, 0x7570u, 0x75E2u, 0x7610u, - 0x761Du, 0x761Fu, 0x7642u, 0x7669u, 0x76CAu, 0x76DBu, 0x76E7u, 0x76F4u, - 0x7701u, 0x771Eu, 0x771Fu, 0x7740u, 0x774Au, 0x778Bu, 0x77A7u, 0x784Eu, - 0x786Bu, 0x788Cu, 0x7891u, 0x78CAu, 0x78CCu, 0x78FBu, 0x792Au, 0x793Cu, - 0x793Eu, 0x7948u, 0x7949u, 0x7950u, 0x7956u, 0x795Du, 0x795Eu, 0x7965u, - 0x797Fu, 0x798Du, 0x798Eu, 0x798Fu, 0x79AEu, 0x79CAu, 0x79EBu, 0x7A1Cu, - 0x7A40u, 0x7A4Au, 0x7A4Fu, 0x7A81u, 0x7AB1u, 0x7ACBu, 0x7AEEu, 0x7B20u, - 0x7BC0u, 0x7BC6u, 0x7BC9u, 0x7C3Eu, 0x7C60u, 0x7C7Bu, 0x7C92u, 0x7CBEu, - 0x7CD2u, 0x7CD6u, 0x7CE3u, 0x7CE7u, 0x7CE8u, 0x7D00u, 0x7D10u, 0x7D22u, - 0x7D2Fu, 0x7D5Bu, 0x7D63u, 0x7DA0u, 0x7DBEu, 0x7DC7u, 0x7DF4u, 0x7E02u, - 0x7E09u, 0x7E37u, 0x7E41u, 0x7E45u, 0x7F3Eu, 0x7F72u, 0x7F79u, 0x7F7Au, - 0x7F85u, 0x7F95u, 0x7F9Au, 0x7FBDu, 0x7FFAu, 0x8001u, 0x8005u, 0x8046u, - 0x8060u, 0x806Fu, 0x8070u, 0x807Eu, 0x808Bu, 0x80ADu, 0x80B2u, 0x8103u, - 0x813Eu, 0x81D8u, 0x81E8u, 0x81EDu, 0x8201u, 0x8204u, 0x8218u, 0x826Fu, - 0x8279u, 0x828Bu, 0x8291u, 0x829Du, 0x82B1u, 0x82B3u, 0x82BDu, 0x82E5u, - 0x82E6u, 0x831Du, 0x8323u, 0x8336u, 0x8352u, 0x8353u, 0x8363u, 0x83ADu, - 0x83BDu, 0x83C9u, 0x83CAu, 0x83CCu, 0x83DCu, 0x83E7u, 0x83EFu, 0x83F1u, - 0x843Du, 0x8449u, 0x8457u, 0x84EEu, 0x84F1u, 0x84F3u, 0x84FCu, 0x8516u, - 0x8564u, 0x85CDu, 0x85FAu, 0x8606u, 0x8612u, 0x862Du, 0x863Fu, 0x8650u, - 0x865Cu, 0x8667u, 0x8669u, 0x8688u, 0x86A9u, 0x86E2u, 0x870Eu, 0x8728u, - 0x876Bu, 0x8779u, 0x8786u, 0x87BAu, 0x87E1u, 0x8801u, 0x881Fu, 0x884Cu, - 0x8860u, 0x8863u, 0x88C2u, 0x88CFu, 0x88D7u, 0x88DEu, 0x88E1u, 0x88F8u, - 0x88FAu, 0x8910u, 0x8941u, 0x8964u, 0x8986u, 0x898Bu, 0x8996u, 0x8AA0u, - 0x8AAAu, 0x8ABFu, 0x8ACBu, 0x8AD2u, 0x8AD6u, 0x8AEDu, 0x8AF8u, 0x8AFEu, - 0x8B01u, 0x8B39u, 0x8B58u, 0x8B80u, 0x8B8Au, 0x8C48u, 0x8C55u, 0x8CABu, - 0x8CC1u, 0x8CC2u, 0x8CC8u, 0x8CD3u, 0x8D08u, 0x8D1Bu, 0x8D77u, 0x8DBCu, - 0x8DCBu, 0x8DEFu, 0x8DF0u, 0x8ECAu, 0x8ED4u, 0x8F26u, 0x8F2Au, 0x8F38u, - 0x8F3Bu, 0x8F62u, 0x8F9Eu, 0x8FB0u, 0x8FB6u, 0x9023u, 0x9038u, 0x9072u, - 0x907Cu, 0x908Fu, 0x9094u, 0x90CEu, 0x90DEu, 0x90F1u, 0x90FDu, 0x9111u, - 0x911Bu, 0x916Au, 0x9199u, 0x91B4u, 0x91CCu, 0x91CFu, 0x91D1u, 0x9234u, - 0x9238u, 0x9276u, 0x927Cu, 0x92D7u, 0x92D8u, 0x9304u, 0x934Au, 0x93F9u, - 0x9415u, 0x958Bu, 0x95ADu, 0x95B7u, 0x962Eu, 0x964Bu, 0x964Du, 0x9675u, - 0x9678u, 0x967Cu, 0x9686u, 0x96A3u, 0x96B7u, 0x96B8u, 0x96C3u, 0x96E2u, - 0x96E3u, 0x96F6u, 0x96F7u, 0x9723u, 0x9732u, 0x9748u, 0x9756u, 0x97DBu, - 0x97E0u, 0x97FFu, 0x980Bu, 0x9818u, 0x9829u, 0x983Bu, 0x985Eu, 0x98E2u, - 0x98EFu, 0x98FCu, 0x9928u, 0x9929u, 0x99A7u, 0x99C2u, 0x99F1u, 0x99FEu, - 0x9A6Au, 0x9B12u, 0x9B6Fu, 0x9C40u, 0x9C57u, 0x9CFDu, 0x9D67u, 0x9DB4u, - 0x9DFAu, 0x9E1Eu, 0x9E7Fu, 0x9E97u, 0x9E9Fu, 0x9EBBu, 0x9ECEu, 0x9EF9u, - 0x9EFEu, 0x9F05u, 0x9F0Fu, 0x9F16u, 0x9F3Bu, 0x9F43u, 0x9F8Du, 0x9F8Eu, - 0x9F9Cu, + 0x003B, 0x004B, 0x0060, 0x00B4, 0x00B7, 0x00C5, 0x02B9, 0x0300, + 0x0301, 0x0313, 0x0385, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, + 0x038E, 0x038F, 0x0390, 0x03A9, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B9, 0x03CC, 0x03CD, 0x03CE, 0x2002, 0x2003, 0x3008, + 0x3009, 0x349E, 0x34B9, 0x34BB, 0x34DF, 0x3515, 0x36EE, 0x36FC, + 0x3781, 0x382F, 0x3862, 0x387C, 0x38C7, 0x38E3, 0x391C, 0x393A, + 0x3A2E, 0x3A6C, 0x3AE4, 0x3B08, 0x3B19, 0x3B49, 0x3B9D, 0x3C18, + 0x3C4E, 0x3D33, 0x3D96, 0x3EAC, 0x3EB8, 0x3F1B, 0x3FFC, 0x4008, + 0x4018, 0x4039, 0x4046, 0x4096, 0x40E3, 0x412F, 0x4202, 0x4227, + 0x42A0, 0x4301, 0x4334, 0x4359, 0x43D5, 0x43D9, 0x440B, 0x446B, + 0x452B, 0x455D, 0x4561, 0x456B, 0x45D7, 0x45F9, 0x4635, 0x46BE, + 0x46C7, 0x4995, 0x49E6, 0x4A6E, 0x4A76, 0x4AB2, 0x4B33, 0x4BCE, + 0x4CCE, 0x4CED, 0x4CF8, 0x4D56, 0x4E0D, 0x4E26, 0x4E32, 0x4E38, + 0x4E39, 0x4E3D, 0x4E41, 0x4E82, 0x4E86, 0x4EAE, 0x4EC0, 0x4ECC, + 0x4EE4, 0x4F60, 0x4F80, 0x4F86, 0x4F8B, 0x4FAE, 0x4FBB, 0x4FBF, + 0x5002, 0x502B, 0x507A, 0x5099, 0x50CF, 0x50DA, 0x50E7, 0x5140, + 0x5145, 0x514D, 0x5154, 0x5164, 0x5167, 0x5168, 0x5169, 0x516D, + 0x5177, 0x5180, 0x518D, 0x5192, 0x5195, 0x5197, 0x51A4, 0x51AC, + 0x51B5, 0x51B7, 0x51C9, 0x51CC, 0x51DC, 0x51DE, 0x51F5, 0x5203, + 0x5207, 0x5217, 0x5229, 0x523A, 0x523B, 0x5246, 0x5272, 0x5277, + 0x5289, 0x529B, 0x52A3, 0x52B3, 0x52C7, 0x52C9, 0x52D2, 0x52DE, + 0x52E4, 0x52F5, 0x52FA, 0x5305, 0x5306, 0x5317, 0x533F, 0x5349, + 0x5351, 0x535A, 0x5373, 0x5375, 0x537D, 0x537F, 0x53C3, 0x53CA, + 0x53DF, 0x53E5, 0x53EB, 0x53F1, 0x5406, 0x540F, 0x541D, 0x5438, + 0x5442, 0x5448, 0x5468, 0x549E, 0x54A2, 0x54BD, 0x54F6, 0x5510, + 0x5553, 0x5555, 0x5563, 0x5584, 0x5587, 0x5599, 0x559D, 0x55AB, + 0x55B3, 0x55C0, 0x55C2, 0x55E2, 0x5606, 0x5651, 0x5668, 0x5674, + 0x56F9, 0x5716, 0x5717, 0x578B, 0x57CE, 0x57F4, 0x580D, 0x5831, + 0x5832, 0x5840, 0x585A, 0x585E, 0x58A8, 0x58AC, 0x58B3, 0x58D8, + 0x58DF, 0x58EE, 0x58F2, 0x58F7, 0x5906, 0x591A, 0x5922, 0x5944, + 0x5948, 0x5951, 0x5954, 0x5962, 0x5973, 0x59D8, 0x59EC, 0x5A1B, + 0x5A27, 0x5A62, 0x5A66, 0x5AB5, 0x5B08, 0x5B28, 0x5B3E, 0x5B85, + 0x5BC3, 0x5BD8, 0x5BE7, 0x5BEE, 0x5BF3, 0x5BFF, 0x5C06, 0x5C22, + 0x5C3F, 0x5C60, 0x5C62, 0x5C64, 0x5C65, 0x5C6E, 0x5C8D, 0x5CC0, + 0x5D19, 0x5D43, 0x5D50, 0x5D6B, 0x5D6E, 0x5D7C, 0x5DB2, 0x5DBA, + 0x5DE1, 0x5DE2, 0x5DFD, 0x5E28, 0x5E3D, 0x5E69, 0x5E74, 0x5EA6, + 0x5EB0, 0x5EB3, 0x5EB6, 0x5EC9, 0x5ECA, 0x5ED2, 0x5ED3, 0x5ED9, + 0x5EEC, 0x5EFE, 0x5F04, 0x5F22, 0x5F53, 0x5F62, 0x5F69, 0x5F6B, + 0x5F8B, 0x5F9A, 0x5FA9, 0x5FAD, 0x5FCD, 0x5FD7, 0x5FF5, 0x5FF9, + 0x6012, 0x601C, 0x6075, 0x6081, 0x6094, 0x60C7, 0x60D8, 0x60E1, + 0x6108, 0x6144, 0x6148, 0x614C, 0x614E, 0x6160, 0x6168, 0x617A, + 0x618E, 0x6190, 0x61A4, 0x61AF, 0x61B2, 0x61DE, 0x61F2, 0x61F6, + 0x6200, 0x6210, 0x621B, 0x622E, 0x6234, 0x625D, 0x62B1, 0x62C9, + 0x62CF, 0x62D3, 0x62D4, 0x62FC, 0x62FE, 0x633D, 0x6350, 0x6368, + 0x637B, 0x6383, 0x63A0, 0x63A9, 0x63C4, 0x63C5, 0x63E4, 0x641C, + 0x6422, 0x6452, 0x6469, 0x6477, 0x647E, 0x649A, 0x649D, 0x64C4, + 0x654F, 0x6556, 0x656C, 0x6578, 0x6599, 0x65C5, 0x65E2, 0x65E3, + 0x6613, 0x6649, 0x6674, 0x6688, 0x6691, 0x669C, 0x66B4, 0x66C6, + 0x66F4, 0x66F8, 0x6700, 0x6717, 0x671B, 0x6721, 0x674E, 0x6753, + 0x6756, 0x675E, 0x677B, 0x6785, 0x6797, 0x67F3, 0x67FA, 0x6817, + 0x681F, 0x6852, 0x6881, 0x6885, 0x688E, 0x68A8, 0x6914, 0x6942, + 0x69A3, 0x69EA, 0x6A02, 0x6A13, 0x6AA8, 0x6AD3, 0x6ADB, 0x6B04, + 0x6B21, 0x6B54, 0x6B72, 0x6B77, 0x6B79, 0x6B9F, 0x6BAE, 0x6BBA, + 0x6BBB, 0x6C4E, 0x6C67, 0x6C88, 0x6CBF, 0x6CCC, 0x6CCD, 0x6CE5, + 0x6D16, 0x6D1B, 0x6D1E, 0x6D34, 0x6D3E, 0x6D41, 0x6D69, 0x6D6A, + 0x6D77, 0x6D78, 0x6D85, 0x6DCB, 0x6DDA, 0x6DEA, 0x6DF9, 0x6E1A, + 0x6E2F, 0x6E6E, 0x6E9C, 0x6EBA, 0x6EC7, 0x6ECB, 0x6ED1, 0x6EDB, + 0x6F0F, 0x6F22, 0x6F23, 0x6F6E, 0x6FC6, 0x6FEB, 0x6FFE, 0x701B, + 0x701E, 0x7039, 0x704A, 0x7070, 0x7077, 0x707D, 0x7099, 0x70AD, + 0x70C8, 0x70D9, 0x7145, 0x7149, 0x716E, 0x719C, 0x71CE, 0x71D0, + 0x7210, 0x721B, 0x7228, 0x722B, 0x7235, 0x7250, 0x7262, 0x7280, + 0x7295, 0x72AF, 0x72C0, 0x72FC, 0x732A, 0x7375, 0x737A, 0x7387, + 0x738B, 0x73A5, 0x73B2, 0x73DE, 0x7406, 0x7409, 0x7422, 0x7447, + 0x745C, 0x7469, 0x7471, 0x7485, 0x7489, 0x7498, 0x74CA, 0x7506, + 0x7524, 0x753B, 0x753E, 0x7559, 0x7565, 0x7570, 0x75E2, 0x7610, + 0x761D, 0x761F, 0x7642, 0x7669, 0x76CA, 0x76DB, 0x76E7, 0x76F4, + 0x7701, 0x771E, 0x771F, 0x7740, 0x774A, 0x778B, 0x77A7, 0x784E, + 0x786B, 0x788C, 0x7891, 0x78CA, 0x78CC, 0x78FB, 0x792A, 0x793C, + 0x793E, 0x7948, 0x7949, 0x7950, 0x7956, 0x795D, 0x795E, 0x7965, + 0x797F, 0x798D, 0x798E, 0x798F, 0x79AE, 0x79CA, 0x79EB, 0x7A1C, + 0x7A40, 0x7A4A, 0x7A4F, 0x7A81, 0x7AB1, 0x7ACB, 0x7AEE, 0x7B20, + 0x7BC0, 0x7BC6, 0x7BC9, 0x7C3E, 0x7C60, 0x7C7B, 0x7C92, 0x7CBE, + 0x7CD2, 0x7CD6, 0x7CE3, 0x7CE7, 0x7CE8, 0x7D00, 0x7D10, 0x7D22, + 0x7D2F, 0x7D5B, 0x7D63, 0x7DA0, 0x7DBE, 0x7DC7, 0x7DF4, 0x7E02, + 0x7E09, 0x7E37, 0x7E41, 0x7E45, 0x7F3E, 0x7F72, 0x7F79, 0x7F7A, + 0x7F85, 0x7F95, 0x7F9A, 0x7FBD, 0x7FFA, 0x8001, 0x8005, 0x8046, + 0x8060, 0x806F, 0x8070, 0x807E, 0x808B, 0x80AD, 0x80B2, 0x8103, + 0x813E, 0x81D8, 0x81E8, 0x81ED, 0x8201, 0x8204, 0x8218, 0x826F, + 0x8279, 0x828B, 0x8291, 0x829D, 0x82B1, 0x82B3, 0x82BD, 0x82E5, + 0x82E6, 0x831D, 0x8323, 0x8336, 0x8352, 0x8353, 0x8363, 0x83AD, + 0x83BD, 0x83C9, 0x83CA, 0x83CC, 0x83DC, 0x83E7, 0x83EF, 0x83F1, + 0x843D, 0x8449, 0x8457, 0x84EE, 0x84F1, 0x84F3, 0x84FC, 0x8516, + 0x8564, 0x85CD, 0x85FA, 0x8606, 0x8612, 0x862D, 0x863F, 0x8650, + 0x865C, 0x8667, 0x8669, 0x8688, 0x86A9, 0x86E2, 0x870E, 0x8728, + 0x876B, 0x8779, 0x8786, 0x87BA, 0x87E1, 0x8801, 0x881F, 0x884C, + 0x8860, 0x8863, 0x88C2, 0x88CF, 0x88D7, 0x88DE, 0x88E1, 0x88F8, + 0x88FA, 0x8910, 0x8941, 0x8964, 0x8986, 0x898B, 0x8996, 0x8AA0, + 0x8AAA, 0x8ABF, 0x8ACB, 0x8AD2, 0x8AD6, 0x8AED, 0x8AF8, 0x8AFE, + 0x8B01, 0x8B39, 0x8B58, 0x8B80, 0x8B8A, 0x8C48, 0x8C55, 0x8CAB, + 0x8CC1, 0x8CC2, 0x8CC8, 0x8CD3, 0x8D08, 0x8D1B, 0x8D77, 0x8DBC, + 0x8DCB, 0x8DEF, 0x8DF0, 0x8ECA, 0x8ED4, 0x8F26, 0x8F2A, 0x8F38, + 0x8F3B, 0x8F62, 0x8F9E, 0x8FB0, 0x8FB6, 0x9023, 0x9038, 0x9072, + 0x907C, 0x908F, 0x9094, 0x90CE, 0x90DE, 0x90F1, 0x90FD, 0x9111, + 0x911B, 0x916A, 0x9199, 0x91B4, 0x91CC, 0x91CF, 0x91D1, 0x9234, + 0x9238, 0x9276, 0x927C, 0x92D7, 0x92D8, 0x9304, 0x934A, 0x93F9, + 0x9415, 0x958B, 0x95AD, 0x95B7, 0x962E, 0x964B, 0x964D, 0x9675, + 0x9678, 0x967C, 0x9686, 0x96A3, 0x96B7, 0x96B8, 0x96C3, 0x96E2, + 0x96E3, 0x96F6, 0x96F7, 0x9723, 0x9732, 0x9748, 0x9756, 0x97DB, + 0x97E0, 0x97FF, 0x980B, 0x9818, 0x9829, 0x983B, 0x985E, 0x98E2, + 0x98EF, 0x98FC, 0x9928, 0x9929, 0x99A7, 0x99C2, 0x99F1, 0x99FE, + 0x9A6A, 0x9B12, 0x9B6F, 0x9C40, 0x9C57, 0x9CFD, 0x9D67, 0x9DB4, + 0x9DFA, 0x9E1E, 0x9E7F, 0x9E97, 0x9E9F, 0x9EBB, 0x9ECE, 0x9EF9, + 0x9EFE, 0x9F05, 0x9F0F, 0x9F16, 0x9F3B, 0x9F43, 0x9F8D, 0x9F8E, + 0x9F9C, }; -static const uint16_t -_hb_ucd_dm1_p2_map[110] = +static const uint16_t _hb_ucd_dm1_p2_map[110]= { - 0x0122u, 0x051Cu, 0x0525u, 0x054Bu, 0x063Au, 0x0804u, 0x08DEu, 0x0A2Cu, - 0x0B63u, 0x14E4u, 0x16A8u, 0x16EAu, 0x19C8u, 0x1B18u, 0x1D0Bu, 0x1DE4u, - 0x1DE6u, 0x2183u, 0x219Fu, 0x2331u, 0x26D4u, 0x2844u, 0x284Au, 0x2B0Cu, - 0x2BF1u, 0x300Au, 0x32B8u, 0x335Fu, 0x3393u, 0x339Cu, 0x33C3u, 0x33D5u, - 0x346Du, 0x36A3u, 0x38A7u, 0x3A8Du, 0x3AFAu, 0x3CBCu, 0x3D1Eu, 0x3ED1u, - 0x3F5Eu, 0x3F8Eu, 0x4263u, 0x42EEu, 0x43ABu, 0x4608u, 0x4735u, 0x4814u, - 0x4C36u, 0x4C92u, 0x4FA1u, 0x4FB8u, 0x5044u, 0x50F2u, 0x50F3u, 0x5119u, - 0x5133u, 0x5249u, 0x541Du, 0x5626u, 0x569Au, 0x56C5u, 0x597Cu, 0x5AA7u, - 0x5BABu, 0x5C80u, 0x5CD0u, 0x5F86u, 0x61DAu, 0x6228u, 0x6247u, 0x62D9u, - 0x633Eu, 0x64DAu, 0x6523u, 0x65A8u, 0x67A7u, 0x67B5u, 0x6B3Cu, 0x6C36u, - 0x6CD5u, 0x6D6Bu, 0x6F2Cu, 0x6FB1u, 0x70D2u, 0x73CAu, 0x7667u, 0x78AEu, - 0x7966u, 0x7CA8u, 0x7ED3u, 0x7F2Fu, 0x85D2u, 0x85EDu, 0x872Eu, 0x8BFAu, - 0x8D77u, 0x9145u, 0x91DFu, 0x921Au, 0x940Au, 0x9496u, 0x95B6u, 0x9B30u, - 0xA0CEu, 0xA105u, 0xA20Eu, 0xA291u, 0xA392u, 0xA600u, + 0x0122, 0x051C, 0x0525, 0x054B, 0x063A, 0x0804, 0x08DE, 0x0A2C, + 0x0B63, 0x14E4, 0x16A8, 0x16EA, 0x19C8, 0x1B18, 0x1D0B, 0x1DE4, + 0x1DE6, 0x2183, 0x219F, 0x2331, 0x26D4, 0x2844, 0x284A, 0x2B0C, + 0x2BF1, 0x300A, 0x32B8, 0x335F, 0x3393, 0x339C, 0x33C3, 0x33D5, + 0x346D, 0x36A3, 0x38A7, 0x3A8D, 0x3AFA, 0x3CBC, 0x3D1E, 0x3ED1, + 0x3F5E, 0x3F8E, 0x4263, 0x42EE, 0x43AB, 0x4608, 0x4735, 0x4814, + 0x4C36, 0x4C92, 0x4FA1, 0x4FB8, 0x5044, 0x50F2, 0x50F3, 0x5119, + 0x5133, 0x5249, 0x541D, 0x5626, 0x569A, 0x56C5, 0x597C, 0x5AA7, + 0x5BAB, 0x5C80, 0x5CD0, 0x5F86, 0x61DA, 0x6228, 0x6247, 0x62D9, + 0x633E, 0x64DA, 0x6523, 0x65A8, 0x67A7, 0x67B5, 0x6B3C, 0x6C36, + 0x6CD5, 0x6D6B, 0x6F2C, 0x6FB1, 0x70D2, 0x73CA, 0x7667, 0x78AE, + 0x7966, 0x7CA8, 0x7ED3, 0x7F2F, 0x85D2, 0x85ED, 0x872E, 0x8BFA, + 0x8D77, 0x9145, 0x91DF, 0x921A, 0x940A, 0x9496, 0x95B6, 0x9B30, + 0xA0CE, 0xA105, 0xA20E, 0xA291, 0xA392, 0xA600, }; -static const uint32_t -_hb_ucd_dm2_u32_map[638] = +static const uint32_t _hb_ucd_dm2_u32_map[638]= { - HB_CODEPOINT_ENCODE3_11_7_14 (0x003Cu, 0x0338u, 0x226Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x003Du, 0x0338u, 0x2260u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x003Eu, 0x0338u, 0x226Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0300u, 0x00C0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0301u, 0x00C1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0302u, 0x00C2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0303u, 0x00C3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0304u, 0x0100u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0306u, 0x0102u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0307u, 0x0226u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0308u, 0x00C4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0309u, 0x1EA2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x030Au, 0x00C5u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x030Cu, 0x01CDu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x030Fu, 0x0200u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0311u, 0x0202u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0323u, 0x1EA0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0325u, 0x1E00u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0328u, 0x0104u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0042u, 0x0307u, 0x1E02u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0042u, 0x0323u, 0x1E04u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0042u, 0x0331u, 0x1E06u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x0301u, 0x0106u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x0302u, 0x0108u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x0307u, 0x010Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x030Cu, 0x010Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x0327u, 0x00C7u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x0307u, 0x1E0Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x030Cu, 0x010Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x0323u, 0x1E0Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x0327u, 0x1E10u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x032Du, 0x1E12u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x0331u, 0x1E0Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0300u, 0x00C8u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0301u, 0x00C9u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0302u, 0x00CAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0303u, 0x1EBCu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0304u, 0x0112u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0306u, 0x0114u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0307u, 0x0116u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0308u, 0x00CBu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0309u, 0x1EBAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x030Cu, 0x011Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x030Fu, 0x0204u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0311u, 0x0206u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0323u, 0x1EB8u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0327u, 0x0228u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0328u, 0x0118u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x032Du, 0x1E18u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0330u, 0x1E1Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0046u, 0x0307u, 0x1E1Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0301u, 0x01F4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0302u, 0x011Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0304u, 0x1E20u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0306u, 0x011Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0307u, 0x0120u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x030Cu, 0x01E6u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0327u, 0x0122u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0302u, 0x0124u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0307u, 0x1E22u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0308u, 0x1E26u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x030Cu, 0x021Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0323u, 0x1E24u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0327u, 0x1E28u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x032Eu, 0x1E2Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0300u, 0x00CCu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0301u, 0x00CDu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0302u, 0x00CEu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0303u, 0x0128u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0304u, 0x012Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0306u, 0x012Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0307u, 0x0130u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0308u, 0x00CFu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0309u, 0x1EC8u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x030Cu, 0x01CFu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x030Fu, 0x0208u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0311u, 0x020Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0323u, 0x1ECAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0328u, 0x012Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0330u, 0x1E2Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Au, 0x0302u, 0x0134u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x0301u, 0x1E30u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x030Cu, 0x01E8u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x0323u, 0x1E32u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x0327u, 0x0136u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x0331u, 0x1E34u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x0301u, 0x0139u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x030Cu, 0x013Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x0323u, 0x1E36u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x0327u, 0x013Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x032Du, 0x1E3Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x0331u, 0x1E3Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Du, 0x0301u, 0x1E3Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Du, 0x0307u, 0x1E40u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Du, 0x0323u, 0x1E42u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0300u, 0x01F8u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0301u, 0x0143u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0303u, 0x00D1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0307u, 0x1E44u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x030Cu, 0x0147u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0323u, 0x1E46u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0327u, 0x0145u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x032Du, 0x1E4Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0331u, 0x1E48u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0300u, 0x00D2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0301u, 0x00D3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0302u, 0x00D4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0303u, 0x00D5u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0304u, 0x014Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0306u, 0x014Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0307u, 0x022Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0308u, 0x00D6u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0309u, 0x1ECEu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x030Bu, 0x0150u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x030Cu, 0x01D1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x030Fu, 0x020Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0311u, 0x020Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x031Bu, 0x01A0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0323u, 0x1ECCu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0328u, 0x01EAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0050u, 0x0301u, 0x1E54u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0050u, 0x0307u, 0x1E56u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0301u, 0x0154u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0307u, 0x1E58u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x030Cu, 0x0158u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x030Fu, 0x0210u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0311u, 0x0212u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0323u, 0x1E5Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0327u, 0x0156u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0331u, 0x1E5Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0301u, 0x015Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0302u, 0x015Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0307u, 0x1E60u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x030Cu, 0x0160u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0323u, 0x1E62u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0326u, 0x0218u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0327u, 0x015Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0307u, 0x1E6Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x030Cu, 0x0164u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0323u, 0x1E6Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0326u, 0x021Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0327u, 0x0162u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x032Du, 0x1E70u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0331u, 0x1E6Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0300u, 0x00D9u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0301u, 0x00DAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0302u, 0x00DBu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0303u, 0x0168u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0304u, 0x016Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0306u, 0x016Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0308u, 0x00DCu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0309u, 0x1EE6u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x030Au, 0x016Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x030Bu, 0x0170u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x030Cu, 0x01D3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x030Fu, 0x0214u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0311u, 0x0216u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x031Bu, 0x01AFu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0323u, 0x1EE4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0324u, 0x1E72u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0328u, 0x0172u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x032Du, 0x1E76u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0330u, 0x1E74u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0056u, 0x0303u, 0x1E7Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0056u, 0x0323u, 0x1E7Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0300u, 0x1E80u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0301u, 0x1E82u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0302u, 0x0174u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0307u, 0x1E86u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0308u, 0x1E84u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0323u, 0x1E88u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0058u, 0x0307u, 0x1E8Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0058u, 0x0308u, 0x1E8Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0300u, 0x1EF2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0301u, 0x00DDu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0302u, 0x0176u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0303u, 0x1EF8u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0304u, 0x0232u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0307u, 0x1E8Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0308u, 0x0178u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0309u, 0x1EF6u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0323u, 0x1EF4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0301u, 0x0179u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0302u, 0x1E90u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0307u, 0x017Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x030Cu, 0x017Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0323u, 0x1E92u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0331u, 0x1E94u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0300u, 0x00E0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0301u, 0x00E1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0302u, 0x00E2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0303u, 0x00E3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0304u, 0x0101u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0306u, 0x0103u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0307u, 0x0227u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0308u, 0x00E4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0309u, 0x1EA3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x030Au, 0x00E5u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x030Cu, 0x01CEu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x030Fu, 0x0201u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0311u, 0x0203u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0323u, 0x1EA1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0325u, 0x1E01u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0328u, 0x0105u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0062u, 0x0307u, 0x1E03u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0062u, 0x0323u, 0x1E05u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0062u, 0x0331u, 0x1E07u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x0301u, 0x0107u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x0302u, 0x0109u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x0307u, 0x010Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x030Cu, 0x010Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x0327u, 0x00E7u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x0307u, 0x1E0Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x030Cu, 0x010Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x0323u, 0x1E0Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x0327u, 0x1E11u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x032Du, 0x1E13u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x0331u, 0x1E0Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0300u, 0x00E8u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0301u, 0x00E9u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0302u, 0x00EAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0303u, 0x1EBDu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0304u, 0x0113u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0306u, 0x0115u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0307u, 0x0117u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0308u, 0x00EBu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0309u, 0x1EBBu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x030Cu, 0x011Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x030Fu, 0x0205u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0311u, 0x0207u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0323u, 0x1EB9u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0327u, 0x0229u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0328u, 0x0119u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x032Du, 0x1E19u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0330u, 0x1E1Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0066u, 0x0307u, 0x1E1Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0301u, 0x01F5u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0302u, 0x011Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0304u, 0x1E21u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0306u, 0x011Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0307u, 0x0121u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x030Cu, 0x01E7u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0327u, 0x0123u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0302u, 0x0125u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0307u, 0x1E23u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0308u, 0x1E27u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x030Cu, 0x021Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0323u, 0x1E25u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0327u, 0x1E29u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x032Eu, 0x1E2Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0331u, 0x1E96u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0300u, 0x00ECu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0301u, 0x00EDu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0302u, 0x00EEu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0303u, 0x0129u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0304u, 0x012Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0306u, 0x012Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0308u, 0x00EFu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0309u, 0x1EC9u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x030Cu, 0x01D0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x030Fu, 0x0209u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0311u, 0x020Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0323u, 0x1ECBu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0328u, 0x012Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0330u, 0x1E2Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Au, 0x0302u, 0x0135u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Au, 0x030Cu, 0x01F0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x0301u, 0x1E31u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x030Cu, 0x01E9u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x0323u, 0x1E33u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x0327u, 0x0137u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x0331u, 0x1E35u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x0301u, 0x013Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x030Cu, 0x013Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x0323u, 0x1E37u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x0327u, 0x013Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x032Du, 0x1E3Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x0331u, 0x1E3Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Du, 0x0301u, 0x1E3Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Du, 0x0307u, 0x1E41u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Du, 0x0323u, 0x1E43u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0300u, 0x01F9u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0301u, 0x0144u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0303u, 0x00F1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0307u, 0x1E45u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x030Cu, 0x0148u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0323u, 0x1E47u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0327u, 0x0146u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x032Du, 0x1E4Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0331u, 0x1E49u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0300u, 0x00F2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0301u, 0x00F3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0302u, 0x00F4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0303u, 0x00F5u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0304u, 0x014Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0306u, 0x014Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0307u, 0x022Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0308u, 0x00F6u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0309u, 0x1ECFu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x030Bu, 0x0151u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x030Cu, 0x01D2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x030Fu, 0x020Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0311u, 0x020Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x031Bu, 0x01A1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0323u, 0x1ECDu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0328u, 0x01EBu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0070u, 0x0301u, 0x1E55u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0070u, 0x0307u, 0x1E57u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0301u, 0x0155u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0307u, 0x1E59u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x030Cu, 0x0159u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x030Fu, 0x0211u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0311u, 0x0213u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0323u, 0x1E5Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0327u, 0x0157u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0331u, 0x1E5Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0301u, 0x015Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0302u, 0x015Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0307u, 0x1E61u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x030Cu, 0x0161u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0323u, 0x1E63u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0326u, 0x0219u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0327u, 0x015Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0307u, 0x1E6Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0308u, 0x1E97u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x030Cu, 0x0165u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0323u, 0x1E6Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0326u, 0x021Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0327u, 0x0163u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x032Du, 0x1E71u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0331u, 0x1E6Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0300u, 0x00F9u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0301u, 0x00FAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0302u, 0x00FBu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0303u, 0x0169u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0304u, 0x016Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0306u, 0x016Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0308u, 0x00FCu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0309u, 0x1EE7u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x030Au, 0x016Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x030Bu, 0x0171u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x030Cu, 0x01D4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x030Fu, 0x0215u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0311u, 0x0217u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x031Bu, 0x01B0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0323u, 0x1EE5u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0324u, 0x1E73u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0328u, 0x0173u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x032Du, 0x1E77u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0330u, 0x1E75u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0076u, 0x0303u, 0x1E7Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0076u, 0x0323u, 0x1E7Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0300u, 0x1E81u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0301u, 0x1E83u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0302u, 0x0175u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0307u, 0x1E87u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0308u, 0x1E85u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x030Au, 0x1E98u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0323u, 0x1E89u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0078u, 0x0307u, 0x1E8Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0078u, 0x0308u, 0x1E8Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0300u, 0x1EF3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0301u, 0x00FDu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0302u, 0x0177u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0303u, 0x1EF9u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0304u, 0x0233u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0307u, 0x1E8Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0308u, 0x00FFu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0309u, 0x1EF7u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x030Au, 0x1E99u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0323u, 0x1EF5u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0301u, 0x017Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0302u, 0x1E91u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0307u, 0x017Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x030Cu, 0x017Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0323u, 0x1E93u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0331u, 0x1E95u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8u, 0x0300u, 0x1FEDu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8u, 0x0301u, 0x0385u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8u, 0x0342u, 0x1FC1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2u, 0x0300u, 0x1EA6u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2u, 0x0301u, 0x1EA4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2u, 0x0303u, 0x1EAAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2u, 0x0309u, 0x1EA8u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00C4u, 0x0304u, 0x01DEu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00C5u, 0x0301u, 0x01FAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00C6u, 0x0301u, 0x01FCu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00C6u, 0x0304u, 0x01E2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00C7u, 0x0301u, 0x1E08u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00CAu, 0x0300u, 0x1EC0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00CAu, 0x0301u, 0x1EBEu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00CAu, 0x0303u, 0x1EC4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00CAu, 0x0309u, 0x1EC2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00CFu, 0x0301u, 0x1E2Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4u, 0x0300u, 0x1ED2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4u, 0x0301u, 0x1ED0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4u, 0x0303u, 0x1ED6u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4u, 0x0309u, 0x1ED4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5u, 0x0301u, 0x1E4Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5u, 0x0304u, 0x022Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5u, 0x0308u, 0x1E4Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00D6u, 0x0304u, 0x022Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00D8u, 0x0301u, 0x01FEu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00DCu, 0x0300u, 0x01DBu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00DCu, 0x0301u, 0x01D7u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00DCu, 0x0304u, 0x01D5u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00DCu, 0x030Cu, 0x01D9u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2u, 0x0300u, 0x1EA7u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2u, 0x0301u, 0x1EA5u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2u, 0x0303u, 0x1EABu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2u, 0x0309u, 0x1EA9u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00E4u, 0x0304u, 0x01DFu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00E5u, 0x0301u, 0x01FBu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00E6u, 0x0301u, 0x01FDu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00E6u, 0x0304u, 0x01E3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00E7u, 0x0301u, 0x1E09u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00EAu, 0x0300u, 0x1EC1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00EAu, 0x0301u, 0x1EBFu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00EAu, 0x0303u, 0x1EC5u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00EAu, 0x0309u, 0x1EC3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00EFu, 0x0301u, 0x1E2Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4u, 0x0300u, 0x1ED3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4u, 0x0301u, 0x1ED1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4u, 0x0303u, 0x1ED7u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4u, 0x0309u, 0x1ED5u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5u, 0x0301u, 0x1E4Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5u, 0x0304u, 0x022Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5u, 0x0308u, 0x1E4Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00F6u, 0x0304u, 0x022Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00F8u, 0x0301u, 0x01FFu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00FCu, 0x0300u, 0x01DCu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00FCu, 0x0301u, 0x01D8u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00FCu, 0x0304u, 0x01D6u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x00FCu, 0x030Cu, 0x01DAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0102u, 0x0300u, 0x1EB0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0102u, 0x0301u, 0x1EAEu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0102u, 0x0303u, 0x1EB4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0102u, 0x0309u, 0x1EB2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0103u, 0x0300u, 0x1EB1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0103u, 0x0301u, 0x1EAFu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0103u, 0x0303u, 0x1EB5u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0103u, 0x0309u, 0x1EB3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0112u, 0x0300u, 0x1E14u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0112u, 0x0301u, 0x1E16u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0113u, 0x0300u, 0x1E15u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0113u, 0x0301u, 0x1E17u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x014Cu, 0x0300u, 0x1E50u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x014Cu, 0x0301u, 0x1E52u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x014Du, 0x0300u, 0x1E51u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x014Du, 0x0301u, 0x1E53u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x015Au, 0x0307u, 0x1E64u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x015Bu, 0x0307u, 0x1E65u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0160u, 0x0307u, 0x1E66u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0161u, 0x0307u, 0x1E67u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0168u, 0x0301u, 0x1E78u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0169u, 0x0301u, 0x1E79u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x016Au, 0x0308u, 0x1E7Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x016Bu, 0x0308u, 0x1E7Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x017Fu, 0x0307u, 0x1E9Bu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0300u, 0x1EDCu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0301u, 0x1EDAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0303u, 0x1EE0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0309u, 0x1EDEu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0323u, 0x1EE2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0300u, 0x1EDDu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0301u, 0x1EDBu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0303u, 0x1EE1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0309u, 0x1EDFu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0323u, 0x1EE3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0300u, 0x1EEAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0301u, 0x1EE8u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0303u, 0x1EEEu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0309u, 0x1EECu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0323u, 0x1EF0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0300u, 0x1EEBu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0301u, 0x1EE9u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0303u, 0x1EEFu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0309u, 0x1EEDu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0323u, 0x1EF1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01B7u, 0x030Cu, 0x01EEu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01EAu, 0x0304u, 0x01ECu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x01EBu, 0x0304u, 0x01EDu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0226u, 0x0304u, 0x01E0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0227u, 0x0304u, 0x01E1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0228u, 0x0306u, 0x1E1Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0229u, 0x0306u, 0x1E1Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x022Eu, 0x0304u, 0x0230u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x022Fu, 0x0304u, 0x0231u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0292u, 0x030Cu, 0x01EFu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0308u, 0x0301u, 0x0000u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0300u, 0x1FBAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0301u, 0x0386u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0304u, 0x1FB9u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0306u, 0x1FB8u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0313u, 0x1F08u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0314u, 0x1F09u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0345u, 0x1FBCu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0395u, 0x0300u, 0x1FC8u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0395u, 0x0301u, 0x0388u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0395u, 0x0313u, 0x1F18u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0395u, 0x0314u, 0x1F19u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0300u, 0x1FCAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0301u, 0x0389u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0313u, 0x1F28u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0314u, 0x1F29u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0345u, 0x1FCCu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0300u, 0x1FDAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0301u, 0x038Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0304u, 0x1FD9u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0306u, 0x1FD8u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0308u, 0x03AAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0313u, 0x1F38u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0314u, 0x1F39u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x039Fu, 0x0300u, 0x1FF8u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x039Fu, 0x0301u, 0x038Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x039Fu, 0x0313u, 0x1F48u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x039Fu, 0x0314u, 0x1F49u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03A1u, 0x0314u, 0x1FECu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0300u, 0x1FEAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0301u, 0x038Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0304u, 0x1FE9u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0306u, 0x1FE8u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0308u, 0x03ABu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0314u, 0x1F59u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0300u, 0x1FFAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0301u, 0x038Fu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0313u, 0x1F68u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0314u, 0x1F69u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0345u, 0x1FFCu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03ACu, 0x0345u, 0x1FB4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03AEu, 0x0345u, 0x1FC4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0300u, 0x1F70u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0301u, 0x03ACu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0304u, 0x1FB1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0306u, 0x1FB0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0313u, 0x1F00u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0314u, 0x1F01u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0342u, 0x1FB6u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0345u, 0x1FB3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5u, 0x0300u, 0x1F72u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5u, 0x0301u, 0x03ADu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5u, 0x0313u, 0x1F10u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5u, 0x0314u, 0x1F11u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0300u, 0x1F74u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0301u, 0x03AEu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0313u, 0x1F20u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0314u, 0x1F21u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0342u, 0x1FC6u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0345u, 0x1FC3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0300u, 0x1F76u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0301u, 0x03AFu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0304u, 0x1FD1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0306u, 0x1FD0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0308u, 0x03CAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0313u, 0x1F30u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0314u, 0x1F31u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0342u, 0x1FD6u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03BFu, 0x0300u, 0x1F78u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03BFu, 0x0301u, 0x03CCu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03BFu, 0x0313u, 0x1F40u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03BFu, 0x0314u, 0x1F41u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03C1u, 0x0313u, 0x1FE4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03C1u, 0x0314u, 0x1FE5u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0300u, 0x1F7Au), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0301u, 0x03CDu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0304u, 0x1FE1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0306u, 0x1FE0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0308u, 0x03CBu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0313u, 0x1F50u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0314u, 0x1F51u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0342u, 0x1FE6u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0300u, 0x1F7Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0301u, 0x03CEu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0313u, 0x1F60u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0314u, 0x1F61u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0342u, 0x1FF6u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0345u, 0x1FF3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03CAu, 0x0300u, 0x1FD2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03CAu, 0x0301u, 0x0390u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03CAu, 0x0342u, 0x1FD7u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03CBu, 0x0300u, 0x1FE2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03CBu, 0x0301u, 0x03B0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03CBu, 0x0342u, 0x1FE7u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03CEu, 0x0345u, 0x1FF4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03D2u, 0x0301u, 0x03D3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x03D2u, 0x0308u, 0x03D4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0406u, 0x0308u, 0x0407u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0410u, 0x0306u, 0x04D0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0410u, 0x0308u, 0x04D2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0413u, 0x0301u, 0x0403u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0415u, 0x0300u, 0x0400u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0415u, 0x0306u, 0x04D6u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0415u, 0x0308u, 0x0401u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0416u, 0x0306u, 0x04C1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0416u, 0x0308u, 0x04DCu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0417u, 0x0308u, 0x04DEu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0418u, 0x0300u, 0x040Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0418u, 0x0304u, 0x04E2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0418u, 0x0306u, 0x0419u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0418u, 0x0308u, 0x04E4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x041Au, 0x0301u, 0x040Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x041Eu, 0x0308u, 0x04E6u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0423u, 0x0304u, 0x04EEu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0423u, 0x0306u, 0x040Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0423u, 0x0308u, 0x04F0u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0423u, 0x030Bu, 0x04F2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0427u, 0x0308u, 0x04F4u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x042Bu, 0x0308u, 0x04F8u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x042Du, 0x0308u, 0x04ECu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0430u, 0x0306u, 0x04D1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0430u, 0x0308u, 0x04D3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0433u, 0x0301u, 0x0453u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0435u, 0x0300u, 0x0450u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0435u, 0x0306u, 0x04D7u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0435u, 0x0308u, 0x0451u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0436u, 0x0306u, 0x04C2u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0436u, 0x0308u, 0x04DDu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0437u, 0x0308u, 0x04DFu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0438u, 0x0300u, 0x045Du), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0438u, 0x0304u, 0x04E3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0438u, 0x0306u, 0x0439u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0438u, 0x0308u, 0x04E5u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x043Au, 0x0301u, 0x045Cu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x043Eu, 0x0308u, 0x04E7u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0443u, 0x0304u, 0x04EFu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0443u, 0x0306u, 0x045Eu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0443u, 0x0308u, 0x04F1u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0443u, 0x030Bu, 0x04F3u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0447u, 0x0308u, 0x04F5u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x044Bu, 0x0308u, 0x04F9u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x044Du, 0x0308u, 0x04EDu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0456u, 0x0308u, 0x0457u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0474u, 0x030Fu, 0x0476u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x0475u, 0x030Fu, 0x0477u), - HB_CODEPOINT_ENCODE3_11_7_14 (0x04D8u, 0x0308u, 0x04DAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x04D9u, 0x0308u, 0x04DBu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x04E8u, 0x0308u, 0x04EAu), - HB_CODEPOINT_ENCODE3_11_7_14 (0x04E9u, 0x0308u, 0x04EBu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x003C, 0x0338, 0x226E),HB_CODEPOINT_ENCODE3_11_7_14 (0x003D, 0x0338, 0x2260), + HB_CODEPOINT_ENCODE3_11_7_14 (0x003E, 0x0338, 0x226F),HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0300, 0x00C0), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0301, 0x00C1),HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0302, 0x00C2), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0303, 0x00C3),HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0304, 0x0100), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0306, 0x0102),HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0307, 0x0226), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0308, 0x00C4),HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0309, 0x1EA2), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x030A, 0x00C5),HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x030C, 0x01CD), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x030F, 0x0200),HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0311, 0x0202), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0323, 0x1EA0),HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0325, 0x1E00), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041, 0x0328, 0x0104),HB_CODEPOINT_ENCODE3_11_7_14 (0x0042, 0x0307, 0x1E02), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0042, 0x0323, 0x1E04),HB_CODEPOINT_ENCODE3_11_7_14 (0x0042, 0x0331, 0x1E06), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0043, 0x0301, 0x0106),HB_CODEPOINT_ENCODE3_11_7_14 (0x0043, 0x0302, 0x0108), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0043, 0x0307, 0x010A),HB_CODEPOINT_ENCODE3_11_7_14 (0x0043, 0x030C, 0x010C), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0043, 0x0327, 0x00C7),HB_CODEPOINT_ENCODE3_11_7_14 (0x0044, 0x0307, 0x1E0A), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0044, 0x030C, 0x010E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0044, 0x0323, 0x1E0C), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0044, 0x0327, 0x1E10),HB_CODEPOINT_ENCODE3_11_7_14 (0x0044, 0x032D, 0x1E12), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0044, 0x0331, 0x1E0E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0300, 0x00C8), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0301, 0x00C9),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0302, 0x00CA), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0303, 0x1EBC),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0304, 0x0112), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0306, 0x0114),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0307, 0x0116), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0308, 0x00CB),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0309, 0x1EBA), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x030C, 0x011A),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x030F, 0x0204), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0311, 0x0206),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0323, 0x1EB8), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0327, 0x0228),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0328, 0x0118), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x032D, 0x1E18),HB_CODEPOINT_ENCODE3_11_7_14 (0x0045, 0x0330, 0x1E1A), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0046, 0x0307, 0x1E1E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0047, 0x0301, 0x01F4), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0047, 0x0302, 0x011C),HB_CODEPOINT_ENCODE3_11_7_14 (0x0047, 0x0304, 0x1E20), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0047, 0x0306, 0x011E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0047, 0x0307, 0x0120), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0047, 0x030C, 0x01E6),HB_CODEPOINT_ENCODE3_11_7_14 (0x0047, 0x0327, 0x0122), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0048, 0x0302, 0x0124),HB_CODEPOINT_ENCODE3_11_7_14 (0x0048, 0x0307, 0x1E22), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0048, 0x0308, 0x1E26),HB_CODEPOINT_ENCODE3_11_7_14 (0x0048, 0x030C, 0x021E), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0048, 0x0323, 0x1E24),HB_CODEPOINT_ENCODE3_11_7_14 (0x0048, 0x0327, 0x1E28), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0048, 0x032E, 0x1E2A),HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0300, 0x00CC), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0301, 0x00CD),HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0302, 0x00CE), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0303, 0x0128),HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0304, 0x012A), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0306, 0x012C),HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0307, 0x0130), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0308, 0x00CF),HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0309, 0x1EC8), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x030C, 0x01CF),HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x030F, 0x0208), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0311, 0x020A),HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0323, 0x1ECA), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0328, 0x012E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0049, 0x0330, 0x1E2C), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004A, 0x0302, 0x0134),HB_CODEPOINT_ENCODE3_11_7_14 (0x004B, 0x0301, 0x1E30), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004B, 0x030C, 0x01E8),HB_CODEPOINT_ENCODE3_11_7_14 (0x004B, 0x0323, 0x1E32), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004B, 0x0327, 0x0136),HB_CODEPOINT_ENCODE3_11_7_14 (0x004B, 0x0331, 0x1E34), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004C, 0x0301, 0x0139),HB_CODEPOINT_ENCODE3_11_7_14 (0x004C, 0x030C, 0x013D), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004C, 0x0323, 0x1E36),HB_CODEPOINT_ENCODE3_11_7_14 (0x004C, 0x0327, 0x013B), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004C, 0x032D, 0x1E3C),HB_CODEPOINT_ENCODE3_11_7_14 (0x004C, 0x0331, 0x1E3A), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004D, 0x0301, 0x1E3E),HB_CODEPOINT_ENCODE3_11_7_14 (0x004D, 0x0307, 0x1E40), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004D, 0x0323, 0x1E42),HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x0300, 0x01F8), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x0301, 0x0143),HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x0303, 0x00D1), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x0307, 0x1E44),HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x030C, 0x0147), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x0323, 0x1E46),HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x0327, 0x0145), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x032D, 0x1E4A),HB_CODEPOINT_ENCODE3_11_7_14 (0x004E, 0x0331, 0x1E48), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0300, 0x00D2),HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0301, 0x00D3), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0302, 0x00D4),HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0303, 0x00D5), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0304, 0x014C),HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0306, 0x014E), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0307, 0x022E),HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0308, 0x00D6), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0309, 0x1ECE),HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x030B, 0x0150), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x030C, 0x01D1),HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x030F, 0x020C), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0311, 0x020E),HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x031B, 0x01A0), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0323, 0x1ECC),HB_CODEPOINT_ENCODE3_11_7_14 (0x004F, 0x0328, 0x01EA), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0050, 0x0301, 0x1E54),HB_CODEPOINT_ENCODE3_11_7_14 (0x0050, 0x0307, 0x1E56), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0052, 0x0301, 0x0154),HB_CODEPOINT_ENCODE3_11_7_14 (0x0052, 0x0307, 0x1E58), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0052, 0x030C, 0x0158),HB_CODEPOINT_ENCODE3_11_7_14 (0x0052, 0x030F, 0x0210), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0052, 0x0311, 0x0212),HB_CODEPOINT_ENCODE3_11_7_14 (0x0052, 0x0323, 0x1E5A), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0052, 0x0327, 0x0156),HB_CODEPOINT_ENCODE3_11_7_14 (0x0052, 0x0331, 0x1E5E), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0053, 0x0301, 0x015A),HB_CODEPOINT_ENCODE3_11_7_14 (0x0053, 0x0302, 0x015C), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0053, 0x0307, 0x1E60),HB_CODEPOINT_ENCODE3_11_7_14 (0x0053, 0x030C, 0x0160), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0053, 0x0323, 0x1E62),HB_CODEPOINT_ENCODE3_11_7_14 (0x0053, 0x0326, 0x0218), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0053, 0x0327, 0x015E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0054, 0x0307, 0x1E6A), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0054, 0x030C, 0x0164),HB_CODEPOINT_ENCODE3_11_7_14 (0x0054, 0x0323, 0x1E6C), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0054, 0x0326, 0x021A),HB_CODEPOINT_ENCODE3_11_7_14 (0x0054, 0x0327, 0x0162), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0054, 0x032D, 0x1E70),HB_CODEPOINT_ENCODE3_11_7_14 (0x0054, 0x0331, 0x1E6E), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0300, 0x00D9),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0301, 0x00DA), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0302, 0x00DB),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0303, 0x0168), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0304, 0x016A),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0306, 0x016C), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0308, 0x00DC),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0309, 0x1EE6), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x030A, 0x016E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x030B, 0x0170), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x030C, 0x01D3),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x030F, 0x0214), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0311, 0x0216),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x031B, 0x01AF), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0323, 0x1EE4),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0324, 0x1E72), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0328, 0x0172),HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x032D, 0x1E76), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055, 0x0330, 0x1E74),HB_CODEPOINT_ENCODE3_11_7_14 (0x0056, 0x0303, 0x1E7C), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0056, 0x0323, 0x1E7E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0057, 0x0300, 0x1E80), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0057, 0x0301, 0x1E82),HB_CODEPOINT_ENCODE3_11_7_14 (0x0057, 0x0302, 0x0174), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0057, 0x0307, 0x1E86),HB_CODEPOINT_ENCODE3_11_7_14 (0x0057, 0x0308, 0x1E84), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0057, 0x0323, 0x1E88),HB_CODEPOINT_ENCODE3_11_7_14 (0x0058, 0x0307, 0x1E8A), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0058, 0x0308, 0x1E8C),HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0300, 0x1EF2), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0301, 0x00DD),HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0302, 0x0176), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0303, 0x1EF8),HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0304, 0x0232), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0307, 0x1E8E),HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0308, 0x0178), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0309, 0x1EF6),HB_CODEPOINT_ENCODE3_11_7_14 (0x0059, 0x0323, 0x1EF4), + HB_CODEPOINT_ENCODE3_11_7_14 (0x005A, 0x0301, 0x0179),HB_CODEPOINT_ENCODE3_11_7_14 (0x005A, 0x0302, 0x1E90), + HB_CODEPOINT_ENCODE3_11_7_14 (0x005A, 0x0307, 0x017B),HB_CODEPOINT_ENCODE3_11_7_14 (0x005A, 0x030C, 0x017D), + HB_CODEPOINT_ENCODE3_11_7_14 (0x005A, 0x0323, 0x1E92),HB_CODEPOINT_ENCODE3_11_7_14 (0x005A, 0x0331, 0x1E94), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0300, 0x00E0),HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0301, 0x00E1), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0302, 0x00E2),HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0303, 0x00E3), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0304, 0x0101),HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0306, 0x0103), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0307, 0x0227),HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0308, 0x00E4), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0309, 0x1EA3),HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x030A, 0x00E5), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x030C, 0x01CE),HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x030F, 0x0201), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0311, 0x0203),HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0323, 0x1EA1), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0325, 0x1E01),HB_CODEPOINT_ENCODE3_11_7_14 (0x0061, 0x0328, 0x0105), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0062, 0x0307, 0x1E03),HB_CODEPOINT_ENCODE3_11_7_14 (0x0062, 0x0323, 0x1E05), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0062, 0x0331, 0x1E07),HB_CODEPOINT_ENCODE3_11_7_14 (0x0063, 0x0301, 0x0107), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0063, 0x0302, 0x0109),HB_CODEPOINT_ENCODE3_11_7_14 (0x0063, 0x0307, 0x010B), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0063, 0x030C, 0x010D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0063, 0x0327, 0x00E7), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0064, 0x0307, 0x1E0B),HB_CODEPOINT_ENCODE3_11_7_14 (0x0064, 0x030C, 0x010F), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0064, 0x0323, 0x1E0D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0064, 0x0327, 0x1E11), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0064, 0x032D, 0x1E13),HB_CODEPOINT_ENCODE3_11_7_14 (0x0064, 0x0331, 0x1E0F), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0300, 0x00E8),HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0301, 0x00E9), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0302, 0x00EA),HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0303, 0x1EBD), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0304, 0x0113),HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0306, 0x0115), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0307, 0x0117),HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0308, 0x00EB), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0309, 0x1EBB),HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x030C, 0x011B), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x030F, 0x0205),HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0311, 0x0207), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0323, 0x1EB9),HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0327, 0x0229), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0328, 0x0119),HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x032D, 0x1E19), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065, 0x0330, 0x1E1B),HB_CODEPOINT_ENCODE3_11_7_14 (0x0066, 0x0307, 0x1E1F), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0067, 0x0301, 0x01F5),HB_CODEPOINT_ENCODE3_11_7_14 (0x0067, 0x0302, 0x011D), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0067, 0x0304, 0x1E21),HB_CODEPOINT_ENCODE3_11_7_14 (0x0067, 0x0306, 0x011F), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0067, 0x0307, 0x0121),HB_CODEPOINT_ENCODE3_11_7_14 (0x0067, 0x030C, 0x01E7), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0067, 0x0327, 0x0123),HB_CODEPOINT_ENCODE3_11_7_14 (0x0068, 0x0302, 0x0125), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0068, 0x0307, 0x1E23),HB_CODEPOINT_ENCODE3_11_7_14 (0x0068, 0x0308, 0x1E27), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0068, 0x030C, 0x021F),HB_CODEPOINT_ENCODE3_11_7_14 (0x0068, 0x0323, 0x1E25), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0068, 0x0327, 0x1E29),HB_CODEPOINT_ENCODE3_11_7_14 (0x0068, 0x032E, 0x1E2B), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0068, 0x0331, 0x1E96),HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0300, 0x00EC), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0301, 0x00ED),HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0302, 0x00EE), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0303, 0x0129),HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0304, 0x012B), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0306, 0x012D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0308, 0x00EF), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0309, 0x1EC9),HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x030C, 0x01D0), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x030F, 0x0209),HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0311, 0x020B), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0323, 0x1ECB),HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0328, 0x012F), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069, 0x0330, 0x1E2D),HB_CODEPOINT_ENCODE3_11_7_14 (0x006A, 0x0302, 0x0135), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006A, 0x030C, 0x01F0),HB_CODEPOINT_ENCODE3_11_7_14 (0x006B, 0x0301, 0x1E31), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006B, 0x030C, 0x01E9),HB_CODEPOINT_ENCODE3_11_7_14 (0x006B, 0x0323, 0x1E33), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006B, 0x0327, 0x0137),HB_CODEPOINT_ENCODE3_11_7_14 (0x006B, 0x0331, 0x1E35), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006C, 0x0301, 0x013A),HB_CODEPOINT_ENCODE3_11_7_14 (0x006C, 0x030C, 0x013E), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006C, 0x0323, 0x1E37),HB_CODEPOINT_ENCODE3_11_7_14 (0x006C, 0x0327, 0x013C), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006C, 0x032D, 0x1E3D),HB_CODEPOINT_ENCODE3_11_7_14 (0x006C, 0x0331, 0x1E3B), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006D, 0x0301, 0x1E3F),HB_CODEPOINT_ENCODE3_11_7_14 (0x006D, 0x0307, 0x1E41), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006D, 0x0323, 0x1E43),HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x0300, 0x01F9), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x0301, 0x0144),HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x0303, 0x00F1), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x0307, 0x1E45),HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x030C, 0x0148), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x0323, 0x1E47),HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x0327, 0x0146), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x032D, 0x1E4B),HB_CODEPOINT_ENCODE3_11_7_14 (0x006E, 0x0331, 0x1E49), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0300, 0x00F2),HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0301, 0x00F3), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0302, 0x00F4),HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0303, 0x00F5), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0304, 0x014D),HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0306, 0x014F), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0307, 0x022F),HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0308, 0x00F6), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0309, 0x1ECF),HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x030B, 0x0151), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x030C, 0x01D2),HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x030F, 0x020D), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0311, 0x020F),HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x031B, 0x01A1), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0323, 0x1ECD),HB_CODEPOINT_ENCODE3_11_7_14 (0x006F, 0x0328, 0x01EB), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0070, 0x0301, 0x1E55),HB_CODEPOINT_ENCODE3_11_7_14 (0x0070, 0x0307, 0x1E57), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0072, 0x0301, 0x0155),HB_CODEPOINT_ENCODE3_11_7_14 (0x0072, 0x0307, 0x1E59), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0072, 0x030C, 0x0159),HB_CODEPOINT_ENCODE3_11_7_14 (0x0072, 0x030F, 0x0211), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0072, 0x0311, 0x0213),HB_CODEPOINT_ENCODE3_11_7_14 (0x0072, 0x0323, 0x1E5B), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0072, 0x0327, 0x0157),HB_CODEPOINT_ENCODE3_11_7_14 (0x0072, 0x0331, 0x1E5F), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0073, 0x0301, 0x015B),HB_CODEPOINT_ENCODE3_11_7_14 (0x0073, 0x0302, 0x015D), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0073, 0x0307, 0x1E61),HB_CODEPOINT_ENCODE3_11_7_14 (0x0073, 0x030C, 0x0161), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0073, 0x0323, 0x1E63),HB_CODEPOINT_ENCODE3_11_7_14 (0x0073, 0x0326, 0x0219), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0073, 0x0327, 0x015F),HB_CODEPOINT_ENCODE3_11_7_14 (0x0074, 0x0307, 0x1E6B), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0074, 0x0308, 0x1E97),HB_CODEPOINT_ENCODE3_11_7_14 (0x0074, 0x030C, 0x0165), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0074, 0x0323, 0x1E6D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0074, 0x0326, 0x021B), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0074, 0x0327, 0x0163),HB_CODEPOINT_ENCODE3_11_7_14 (0x0074, 0x032D, 0x1E71), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0074, 0x0331, 0x1E6F),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0300, 0x00F9), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0301, 0x00FA),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0302, 0x00FB), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0303, 0x0169),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0304, 0x016B), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0306, 0x016D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0308, 0x00FC), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0309, 0x1EE7),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x030A, 0x016F), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x030B, 0x0171),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x030C, 0x01D4), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x030F, 0x0215),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0311, 0x0217), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x031B, 0x01B0),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0323, 0x1EE5), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0324, 0x1E73),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0328, 0x0173), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x032D, 0x1E77),HB_CODEPOINT_ENCODE3_11_7_14 (0x0075, 0x0330, 0x1E75), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0076, 0x0303, 0x1E7D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0076, 0x0323, 0x1E7F), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0077, 0x0300, 0x1E81),HB_CODEPOINT_ENCODE3_11_7_14 (0x0077, 0x0301, 0x1E83), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0077, 0x0302, 0x0175),HB_CODEPOINT_ENCODE3_11_7_14 (0x0077, 0x0307, 0x1E87), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0077, 0x0308, 0x1E85),HB_CODEPOINT_ENCODE3_11_7_14 (0x0077, 0x030A, 0x1E98), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0077, 0x0323, 0x1E89),HB_CODEPOINT_ENCODE3_11_7_14 (0x0078, 0x0307, 0x1E8B), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0078, 0x0308, 0x1E8D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0300, 0x1EF3), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0301, 0x00FD),HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0302, 0x0177), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0303, 0x1EF9),HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0304, 0x0233), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0307, 0x1E8F),HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0308, 0x00FF), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0309, 0x1EF7),HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x030A, 0x1E99), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0079, 0x0323, 0x1EF5),HB_CODEPOINT_ENCODE3_11_7_14 (0x007A, 0x0301, 0x017A), + HB_CODEPOINT_ENCODE3_11_7_14 (0x007A, 0x0302, 0x1E91),HB_CODEPOINT_ENCODE3_11_7_14 (0x007A, 0x0307, 0x017C), + HB_CODEPOINT_ENCODE3_11_7_14 (0x007A, 0x030C, 0x017E),HB_CODEPOINT_ENCODE3_11_7_14 (0x007A, 0x0323, 0x1E93), + HB_CODEPOINT_ENCODE3_11_7_14 (0x007A, 0x0331, 0x1E95),HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8, 0x0300, 0x1FED), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8, 0x0301, 0x0385),HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8, 0x0342, 0x1FC1), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2, 0x0300, 0x1EA6),HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2, 0x0301, 0x1EA4), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2, 0x0303, 0x1EAA),HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2, 0x0309, 0x1EA8), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00C4, 0x0304, 0x01DE),HB_CODEPOINT_ENCODE3_11_7_14 (0x00C5, 0x0301, 0x01FA), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00C6, 0x0301, 0x01FC),HB_CODEPOINT_ENCODE3_11_7_14 (0x00C6, 0x0304, 0x01E2), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00C7, 0x0301, 0x1E08),HB_CODEPOINT_ENCODE3_11_7_14 (0x00CA, 0x0300, 0x1EC0), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00CA, 0x0301, 0x1EBE),HB_CODEPOINT_ENCODE3_11_7_14 (0x00CA, 0x0303, 0x1EC4), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00CA, 0x0309, 0x1EC2),HB_CODEPOINT_ENCODE3_11_7_14 (0x00CF, 0x0301, 0x1E2E), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4, 0x0300, 0x1ED2),HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4, 0x0301, 0x1ED0), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4, 0x0303, 0x1ED6),HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4, 0x0309, 0x1ED4), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5, 0x0301, 0x1E4C),HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5, 0x0304, 0x022C), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5, 0x0308, 0x1E4E),HB_CODEPOINT_ENCODE3_11_7_14 (0x00D6, 0x0304, 0x022A), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00D8, 0x0301, 0x01FE),HB_CODEPOINT_ENCODE3_11_7_14 (0x00DC, 0x0300, 0x01DB), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00DC, 0x0301, 0x01D7),HB_CODEPOINT_ENCODE3_11_7_14 (0x00DC, 0x0304, 0x01D5), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00DC, 0x030C, 0x01D9),HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2, 0x0300, 0x1EA7), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2, 0x0301, 0x1EA5),HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2, 0x0303, 0x1EAB), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2, 0x0309, 0x1EA9),HB_CODEPOINT_ENCODE3_11_7_14 (0x00E4, 0x0304, 0x01DF), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00E5, 0x0301, 0x01FB),HB_CODEPOINT_ENCODE3_11_7_14 (0x00E6, 0x0301, 0x01FD), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00E6, 0x0304, 0x01E3),HB_CODEPOINT_ENCODE3_11_7_14 (0x00E7, 0x0301, 0x1E09), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00EA, 0x0300, 0x1EC1),HB_CODEPOINT_ENCODE3_11_7_14 (0x00EA, 0x0301, 0x1EBF), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00EA, 0x0303, 0x1EC5),HB_CODEPOINT_ENCODE3_11_7_14 (0x00EA, 0x0309, 0x1EC3), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00EF, 0x0301, 0x1E2F),HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4, 0x0300, 0x1ED3), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4, 0x0301, 0x1ED1),HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4, 0x0303, 0x1ED7), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4, 0x0309, 0x1ED5),HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5, 0x0301, 0x1E4D), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5, 0x0304, 0x022D),HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5, 0x0308, 0x1E4F), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00F6, 0x0304, 0x022B),HB_CODEPOINT_ENCODE3_11_7_14 (0x00F8, 0x0301, 0x01FF), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00FC, 0x0300, 0x01DC),HB_CODEPOINT_ENCODE3_11_7_14 (0x00FC, 0x0301, 0x01D8), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00FC, 0x0304, 0x01D6),HB_CODEPOINT_ENCODE3_11_7_14 (0x00FC, 0x030C, 0x01DA), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0102, 0x0300, 0x1EB0),HB_CODEPOINT_ENCODE3_11_7_14 (0x0102, 0x0301, 0x1EAE), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0102, 0x0303, 0x1EB4),HB_CODEPOINT_ENCODE3_11_7_14 (0x0102, 0x0309, 0x1EB2), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0103, 0x0300, 0x1EB1),HB_CODEPOINT_ENCODE3_11_7_14 (0x0103, 0x0301, 0x1EAF), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0103, 0x0303, 0x1EB5),HB_CODEPOINT_ENCODE3_11_7_14 (0x0103, 0x0309, 0x1EB3), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0112, 0x0300, 0x1E14),HB_CODEPOINT_ENCODE3_11_7_14 (0x0112, 0x0301, 0x1E16), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0113, 0x0300, 0x1E15),HB_CODEPOINT_ENCODE3_11_7_14 (0x0113, 0x0301, 0x1E17), + HB_CODEPOINT_ENCODE3_11_7_14 (0x014C, 0x0300, 0x1E50),HB_CODEPOINT_ENCODE3_11_7_14 (0x014C, 0x0301, 0x1E52), + HB_CODEPOINT_ENCODE3_11_7_14 (0x014D, 0x0300, 0x1E51),HB_CODEPOINT_ENCODE3_11_7_14 (0x014D, 0x0301, 0x1E53), + HB_CODEPOINT_ENCODE3_11_7_14 (0x015A, 0x0307, 0x1E64),HB_CODEPOINT_ENCODE3_11_7_14 (0x015B, 0x0307, 0x1E65), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0160, 0x0307, 0x1E66),HB_CODEPOINT_ENCODE3_11_7_14 (0x0161, 0x0307, 0x1E67), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0168, 0x0301, 0x1E78),HB_CODEPOINT_ENCODE3_11_7_14 (0x0169, 0x0301, 0x1E79), + HB_CODEPOINT_ENCODE3_11_7_14 (0x016A, 0x0308, 0x1E7A),HB_CODEPOINT_ENCODE3_11_7_14 (0x016B, 0x0308, 0x1E7B), + HB_CODEPOINT_ENCODE3_11_7_14 (0x017F, 0x0307, 0x1E9B),HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0, 0x0300, 0x1EDC), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0, 0x0301, 0x1EDA),HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0, 0x0303, 0x1EE0), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0, 0x0309, 0x1EDE),HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0, 0x0323, 0x1EE2), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1, 0x0300, 0x1EDD),HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1, 0x0301, 0x1EDB), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1, 0x0303, 0x1EE1),HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1, 0x0309, 0x1EDF), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1, 0x0323, 0x1EE3),HB_CODEPOINT_ENCODE3_11_7_14 (0x01AF, 0x0300, 0x1EEA), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01AF, 0x0301, 0x1EE8),HB_CODEPOINT_ENCODE3_11_7_14 (0x01AF, 0x0303, 0x1EEE), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01AF, 0x0309, 0x1EEC),HB_CODEPOINT_ENCODE3_11_7_14 (0x01AF, 0x0323, 0x1EF0), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0, 0x0300, 0x1EEB),HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0, 0x0301, 0x1EE9), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0, 0x0303, 0x1EEF),HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0, 0x0309, 0x1EED), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0, 0x0323, 0x1EF1),HB_CODEPOINT_ENCODE3_11_7_14 (0x01B7, 0x030C, 0x01EE), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01EA, 0x0304, 0x01EC),HB_CODEPOINT_ENCODE3_11_7_14 (0x01EB, 0x0304, 0x01ED), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0226, 0x0304, 0x01E0),HB_CODEPOINT_ENCODE3_11_7_14 (0x0227, 0x0304, 0x01E1), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0228, 0x0306, 0x1E1C),HB_CODEPOINT_ENCODE3_11_7_14 (0x0229, 0x0306, 0x1E1D), + HB_CODEPOINT_ENCODE3_11_7_14 (0x022E, 0x0304, 0x0230),HB_CODEPOINT_ENCODE3_11_7_14 (0x022F, 0x0304, 0x0231), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0292, 0x030C, 0x01EF),HB_CODEPOINT_ENCODE3_11_7_14 (0x0308, 0x0301, 0x0000), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0391, 0x0300, 0x1FBA),HB_CODEPOINT_ENCODE3_11_7_14 (0x0391, 0x0301, 0x0386), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0391, 0x0304, 0x1FB9),HB_CODEPOINT_ENCODE3_11_7_14 (0x0391, 0x0306, 0x1FB8), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0391, 0x0313, 0x1F08),HB_CODEPOINT_ENCODE3_11_7_14 (0x0391, 0x0314, 0x1F09), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0391, 0x0345, 0x1FBC),HB_CODEPOINT_ENCODE3_11_7_14 (0x0395, 0x0300, 0x1FC8), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0395, 0x0301, 0x0388),HB_CODEPOINT_ENCODE3_11_7_14 (0x0395, 0x0313, 0x1F18), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0395, 0x0314, 0x1F19),HB_CODEPOINT_ENCODE3_11_7_14 (0x0397, 0x0300, 0x1FCA), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0397, 0x0301, 0x0389),HB_CODEPOINT_ENCODE3_11_7_14 (0x0397, 0x0313, 0x1F28), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0397, 0x0314, 0x1F29),HB_CODEPOINT_ENCODE3_11_7_14 (0x0397, 0x0345, 0x1FCC), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0399, 0x0300, 0x1FDA),HB_CODEPOINT_ENCODE3_11_7_14 (0x0399, 0x0301, 0x038A), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0399, 0x0304, 0x1FD9),HB_CODEPOINT_ENCODE3_11_7_14 (0x0399, 0x0306, 0x1FD8), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0399, 0x0308, 0x03AA),HB_CODEPOINT_ENCODE3_11_7_14 (0x0399, 0x0313, 0x1F38), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0399, 0x0314, 0x1F39),HB_CODEPOINT_ENCODE3_11_7_14 (0x039F, 0x0300, 0x1FF8), + HB_CODEPOINT_ENCODE3_11_7_14 (0x039F, 0x0301, 0x038C),HB_CODEPOINT_ENCODE3_11_7_14 (0x039F, 0x0313, 0x1F48), + HB_CODEPOINT_ENCODE3_11_7_14 (0x039F, 0x0314, 0x1F49),HB_CODEPOINT_ENCODE3_11_7_14 (0x03A1, 0x0314, 0x1FEC), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5, 0x0300, 0x1FEA),HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5, 0x0301, 0x038E), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5, 0x0304, 0x1FE9),HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5, 0x0306, 0x1FE8), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5, 0x0308, 0x03AB),HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5, 0x0314, 0x1F59), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9, 0x0300, 0x1FFA),HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9, 0x0301, 0x038F), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9, 0x0313, 0x1F68),HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9, 0x0314, 0x1F69), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9, 0x0345, 0x1FFC),HB_CODEPOINT_ENCODE3_11_7_14 (0x03AC, 0x0345, 0x1FB4), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03AE, 0x0345, 0x1FC4),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1, 0x0300, 0x1F70), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1, 0x0301, 0x03AC),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1, 0x0304, 0x1FB1), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1, 0x0306, 0x1FB0),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1, 0x0313, 0x1F00), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1, 0x0314, 0x1F01),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1, 0x0342, 0x1FB6), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1, 0x0345, 0x1FB3),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5, 0x0300, 0x1F72), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5, 0x0301, 0x03AD),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5, 0x0313, 0x1F10), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5, 0x0314, 0x1F11),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7, 0x0300, 0x1F74), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7, 0x0301, 0x03AE),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7, 0x0313, 0x1F20), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7, 0x0314, 0x1F21),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7, 0x0342, 0x1FC6), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7, 0x0345, 0x1FC3),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9, 0x0300, 0x1F76), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9, 0x0301, 0x03AF),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9, 0x0304, 0x1FD1), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9, 0x0306, 0x1FD0),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9, 0x0308, 0x03CA), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9, 0x0313, 0x1F30),HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9, 0x0314, 0x1F31), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9, 0x0342, 0x1FD6),HB_CODEPOINT_ENCODE3_11_7_14 (0x03BF, 0x0300, 0x1F78), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03BF, 0x0301, 0x03CC),HB_CODEPOINT_ENCODE3_11_7_14 (0x03BF, 0x0313, 0x1F40), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03BF, 0x0314, 0x1F41),HB_CODEPOINT_ENCODE3_11_7_14 (0x03C1, 0x0313, 0x1FE4), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C1, 0x0314, 0x1FE5),HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5, 0x0300, 0x1F7A), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5, 0x0301, 0x03CD),HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5, 0x0304, 0x1FE1), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5, 0x0306, 0x1FE0),HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5, 0x0308, 0x03CB), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5, 0x0313, 0x1F50),HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5, 0x0314, 0x1F51), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5, 0x0342, 0x1FE6),HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9, 0x0300, 0x1F7C), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9, 0x0301, 0x03CE),HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9, 0x0313, 0x1F60), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9, 0x0314, 0x1F61),HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9, 0x0342, 0x1FF6), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9, 0x0345, 0x1FF3),HB_CODEPOINT_ENCODE3_11_7_14 (0x03CA, 0x0300, 0x1FD2), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03CA, 0x0301, 0x0390),HB_CODEPOINT_ENCODE3_11_7_14 (0x03CA, 0x0342, 0x1FD7), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03CB, 0x0300, 0x1FE2),HB_CODEPOINT_ENCODE3_11_7_14 (0x03CB, 0x0301, 0x03B0), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03CB, 0x0342, 0x1FE7),HB_CODEPOINT_ENCODE3_11_7_14 (0x03CE, 0x0345, 0x1FF4), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03D2, 0x0301, 0x03D3),HB_CODEPOINT_ENCODE3_11_7_14 (0x03D2, 0x0308, 0x03D4), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0406, 0x0308, 0x0407),HB_CODEPOINT_ENCODE3_11_7_14 (0x0410, 0x0306, 0x04D0), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0410, 0x0308, 0x04D2),HB_CODEPOINT_ENCODE3_11_7_14 (0x0413, 0x0301, 0x0403), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0415, 0x0300, 0x0400),HB_CODEPOINT_ENCODE3_11_7_14 (0x0415, 0x0306, 0x04D6), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0415, 0x0308, 0x0401),HB_CODEPOINT_ENCODE3_11_7_14 (0x0416, 0x0306, 0x04C1), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0416, 0x0308, 0x04DC),HB_CODEPOINT_ENCODE3_11_7_14 (0x0417, 0x0308, 0x04DE), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0418, 0x0300, 0x040D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0418, 0x0304, 0x04E2), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0418, 0x0306, 0x0419),HB_CODEPOINT_ENCODE3_11_7_14 (0x0418, 0x0308, 0x04E4), + HB_CODEPOINT_ENCODE3_11_7_14 (0x041A, 0x0301, 0x040C),HB_CODEPOINT_ENCODE3_11_7_14 (0x041E, 0x0308, 0x04E6), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0423, 0x0304, 0x04EE),HB_CODEPOINT_ENCODE3_11_7_14 (0x0423, 0x0306, 0x040E), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0423, 0x0308, 0x04F0),HB_CODEPOINT_ENCODE3_11_7_14 (0x0423, 0x030B, 0x04F2), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0427, 0x0308, 0x04F4),HB_CODEPOINT_ENCODE3_11_7_14 (0x042B, 0x0308, 0x04F8), + HB_CODEPOINT_ENCODE3_11_7_14 (0x042D, 0x0308, 0x04EC),HB_CODEPOINT_ENCODE3_11_7_14 (0x0430, 0x0306, 0x04D1), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0430, 0x0308, 0x04D3),HB_CODEPOINT_ENCODE3_11_7_14 (0x0433, 0x0301, 0x0453), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0435, 0x0300, 0x0450),HB_CODEPOINT_ENCODE3_11_7_14 (0x0435, 0x0306, 0x04D7), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0435, 0x0308, 0x0451),HB_CODEPOINT_ENCODE3_11_7_14 (0x0436, 0x0306, 0x04C2), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0436, 0x0308, 0x04DD),HB_CODEPOINT_ENCODE3_11_7_14 (0x0437, 0x0308, 0x04DF), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0438, 0x0300, 0x045D),HB_CODEPOINT_ENCODE3_11_7_14 (0x0438, 0x0304, 0x04E3), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0438, 0x0306, 0x0439),HB_CODEPOINT_ENCODE3_11_7_14 (0x0438, 0x0308, 0x04E5), + HB_CODEPOINT_ENCODE3_11_7_14 (0x043A, 0x0301, 0x045C),HB_CODEPOINT_ENCODE3_11_7_14 (0x043E, 0x0308, 0x04E7), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0443, 0x0304, 0x04EF),HB_CODEPOINT_ENCODE3_11_7_14 (0x0443, 0x0306, 0x045E), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0443, 0x0308, 0x04F1),HB_CODEPOINT_ENCODE3_11_7_14 (0x0443, 0x030B, 0x04F3), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0447, 0x0308, 0x04F5),HB_CODEPOINT_ENCODE3_11_7_14 (0x044B, 0x0308, 0x04F9), + HB_CODEPOINT_ENCODE3_11_7_14 (0x044D, 0x0308, 0x04ED),HB_CODEPOINT_ENCODE3_11_7_14 (0x0456, 0x0308, 0x0457), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0474, 0x030F, 0x0476),HB_CODEPOINT_ENCODE3_11_7_14 (0x0475, 0x030F, 0x0477), + HB_CODEPOINT_ENCODE3_11_7_14 (0x04D8, 0x0308, 0x04DA),HB_CODEPOINT_ENCODE3_11_7_14 (0x04D9, 0x0308, 0x04DB), + HB_CODEPOINT_ENCODE3_11_7_14 (0x04E8, 0x0308, 0x04EA),HB_CODEPOINT_ENCODE3_11_7_14 (0x04E9, 0x0308, 0x04EB), }; -static const uint64_t -_hb_ucd_dm2_u64_map[408] = +static const uint64_t _hb_ucd_dm2_u64_map[408]= { - HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05B7u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05B8u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D1u, 0x05BCu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x05D1u, 0x05BFu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D2u, 0x05BCu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x05D3u, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D4u, 0x05BCu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x05D5u, 0x05B9u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D5u, 0x05BCu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x05D6u, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D8u, 0x05BCu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x05D9u, 0x05B4u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D9u, 0x05BCu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x05DAu, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05DBu, 0x05BCu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x05DBu, 0x05BFu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05DCu, 0x05BCu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x05DEu, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05E0u, 0x05BCu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x05E1u, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05E3u, 0x05BCu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x05E4u, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05E4u, 0x05BFu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x05E6u, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05E7u, 0x05BCu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x05E8u, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05E9u, 0x05BCu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x05E9u, 0x05C1u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05E9u, 0x05C2u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x05EAu, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05F2u, 0x05B7u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x0627u, 0x0653u, 0x0622u), HB_CODEPOINT_ENCODE3 (0x0627u, 0x0654u, 0x0623u), - HB_CODEPOINT_ENCODE3 (0x0627u, 0x0655u, 0x0625u), HB_CODEPOINT_ENCODE3 (0x0648u, 0x0654u, 0x0624u), - HB_CODEPOINT_ENCODE3 (0x064Au, 0x0654u, 0x0626u), HB_CODEPOINT_ENCODE3 (0x06C1u, 0x0654u, 0x06C2u), - HB_CODEPOINT_ENCODE3 (0x06D2u, 0x0654u, 0x06D3u), HB_CODEPOINT_ENCODE3 (0x06D5u, 0x0654u, 0x06C0u), - HB_CODEPOINT_ENCODE3 (0x0915u, 0x093Cu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0916u, 0x093Cu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x0917u, 0x093Cu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x091Cu, 0x093Cu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x0921u, 0x093Cu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0922u, 0x093Cu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x0928u, 0x093Cu, 0x0929u), HB_CODEPOINT_ENCODE3 (0x092Bu, 0x093Cu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x092Fu, 0x093Cu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0930u, 0x093Cu, 0x0931u), - HB_CODEPOINT_ENCODE3 (0x0933u, 0x093Cu, 0x0934u), HB_CODEPOINT_ENCODE3 (0x09A1u, 0x09BCu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x09A2u, 0x09BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x09AFu, 0x09BCu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x09C7u, 0x09BEu, 0x09CBu), HB_CODEPOINT_ENCODE3 (0x09C7u, 0x09D7u, 0x09CCu), - HB_CODEPOINT_ENCODE3 (0x0A16u, 0x0A3Cu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0A17u, 0x0A3Cu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x0A1Cu, 0x0A3Cu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0A2Bu, 0x0A3Cu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x0A32u, 0x0A3Cu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0A38u, 0x0A3Cu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x0B21u, 0x0B3Cu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0B22u, 0x0B3Cu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x0B47u, 0x0B3Eu, 0x0B4Bu), HB_CODEPOINT_ENCODE3 (0x0B47u, 0x0B56u, 0x0B48u), - HB_CODEPOINT_ENCODE3 (0x0B47u, 0x0B57u, 0x0B4Cu), HB_CODEPOINT_ENCODE3 (0x0B92u, 0x0BD7u, 0x0B94u), - HB_CODEPOINT_ENCODE3 (0x0BC6u, 0x0BBEu, 0x0BCAu), HB_CODEPOINT_ENCODE3 (0x0BC6u, 0x0BD7u, 0x0BCCu), - HB_CODEPOINT_ENCODE3 (0x0BC7u, 0x0BBEu, 0x0BCBu), HB_CODEPOINT_ENCODE3 (0x0C46u, 0x0C56u, 0x0C48u), - HB_CODEPOINT_ENCODE3 (0x0CBFu, 0x0CD5u, 0x0CC0u), HB_CODEPOINT_ENCODE3 (0x0CC6u, 0x0CC2u, 0x0CCAu), - HB_CODEPOINT_ENCODE3 (0x0CC6u, 0x0CD5u, 0x0CC7u), HB_CODEPOINT_ENCODE3 (0x0CC6u, 0x0CD6u, 0x0CC8u), - HB_CODEPOINT_ENCODE3 (0x0CCAu, 0x0CD5u, 0x0CCBu), HB_CODEPOINT_ENCODE3 (0x0D46u, 0x0D3Eu, 0x0D4Au), - HB_CODEPOINT_ENCODE3 (0x0D46u, 0x0D57u, 0x0D4Cu), HB_CODEPOINT_ENCODE3 (0x0D47u, 0x0D3Eu, 0x0D4Bu), - HB_CODEPOINT_ENCODE3 (0x0DD9u, 0x0DCAu, 0x0DDAu), HB_CODEPOINT_ENCODE3 (0x0DD9u, 0x0DCFu, 0x0DDCu), - HB_CODEPOINT_ENCODE3 (0x0DD9u, 0x0DDFu, 0x0DDEu), HB_CODEPOINT_ENCODE3 (0x0DDCu, 0x0DCAu, 0x0DDDu), - HB_CODEPOINT_ENCODE3 (0x0F40u, 0x0FB5u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0F42u, 0x0FB7u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x0F4Cu, 0x0FB7u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0F51u, 0x0FB7u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x0F56u, 0x0FB7u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0F5Bu, 0x0FB7u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x0F71u, 0x0F72u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0F71u, 0x0F74u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x0F71u, 0x0F80u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0F90u, 0x0FB5u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x0F92u, 0x0FB7u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0F9Cu, 0x0FB7u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x0FA1u, 0x0FB7u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0FA6u, 0x0FB7u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x0FABu, 0x0FB7u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0FB2u, 0x0F80u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x0FB3u, 0x0F80u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1025u, 0x102Eu, 0x1026u), - HB_CODEPOINT_ENCODE3 (0x1B05u, 0x1B35u, 0x1B06u), HB_CODEPOINT_ENCODE3 (0x1B07u, 0x1B35u, 0x1B08u), - HB_CODEPOINT_ENCODE3 (0x1B09u, 0x1B35u, 0x1B0Au), HB_CODEPOINT_ENCODE3 (0x1B0Bu, 0x1B35u, 0x1B0Cu), - HB_CODEPOINT_ENCODE3 (0x1B0Du, 0x1B35u, 0x1B0Eu), HB_CODEPOINT_ENCODE3 (0x1B11u, 0x1B35u, 0x1B12u), - HB_CODEPOINT_ENCODE3 (0x1B3Au, 0x1B35u, 0x1B3Bu), HB_CODEPOINT_ENCODE3 (0x1B3Cu, 0x1B35u, 0x1B3Du), - HB_CODEPOINT_ENCODE3 (0x1B3Eu, 0x1B35u, 0x1B40u), HB_CODEPOINT_ENCODE3 (0x1B3Fu, 0x1B35u, 0x1B41u), - HB_CODEPOINT_ENCODE3 (0x1B42u, 0x1B35u, 0x1B43u), HB_CODEPOINT_ENCODE3 (0x1E36u, 0x0304u, 0x1E38u), - HB_CODEPOINT_ENCODE3 (0x1E37u, 0x0304u, 0x1E39u), HB_CODEPOINT_ENCODE3 (0x1E5Au, 0x0304u, 0x1E5Cu), - HB_CODEPOINT_ENCODE3 (0x1E5Bu, 0x0304u, 0x1E5Du), HB_CODEPOINT_ENCODE3 (0x1E62u, 0x0307u, 0x1E68u), - HB_CODEPOINT_ENCODE3 (0x1E63u, 0x0307u, 0x1E69u), HB_CODEPOINT_ENCODE3 (0x1EA0u, 0x0302u, 0x1EACu), - HB_CODEPOINT_ENCODE3 (0x1EA0u, 0x0306u, 0x1EB6u), HB_CODEPOINT_ENCODE3 (0x1EA1u, 0x0302u, 0x1EADu), - HB_CODEPOINT_ENCODE3 (0x1EA1u, 0x0306u, 0x1EB7u), HB_CODEPOINT_ENCODE3 (0x1EB8u, 0x0302u, 0x1EC6u), - HB_CODEPOINT_ENCODE3 (0x1EB9u, 0x0302u, 0x1EC7u), HB_CODEPOINT_ENCODE3 (0x1ECCu, 0x0302u, 0x1ED8u), - HB_CODEPOINT_ENCODE3 (0x1ECDu, 0x0302u, 0x1ED9u), HB_CODEPOINT_ENCODE3 (0x1F00u, 0x0300u, 0x1F02u), - HB_CODEPOINT_ENCODE3 (0x1F00u, 0x0301u, 0x1F04u), HB_CODEPOINT_ENCODE3 (0x1F00u, 0x0342u, 0x1F06u), - HB_CODEPOINT_ENCODE3 (0x1F00u, 0x0345u, 0x1F80u), HB_CODEPOINT_ENCODE3 (0x1F01u, 0x0300u, 0x1F03u), - HB_CODEPOINT_ENCODE3 (0x1F01u, 0x0301u, 0x1F05u), HB_CODEPOINT_ENCODE3 (0x1F01u, 0x0342u, 0x1F07u), - HB_CODEPOINT_ENCODE3 (0x1F01u, 0x0345u, 0x1F81u), HB_CODEPOINT_ENCODE3 (0x1F02u, 0x0345u, 0x1F82u), - HB_CODEPOINT_ENCODE3 (0x1F03u, 0x0345u, 0x1F83u), HB_CODEPOINT_ENCODE3 (0x1F04u, 0x0345u, 0x1F84u), - HB_CODEPOINT_ENCODE3 (0x1F05u, 0x0345u, 0x1F85u), HB_CODEPOINT_ENCODE3 (0x1F06u, 0x0345u, 0x1F86u), - HB_CODEPOINT_ENCODE3 (0x1F07u, 0x0345u, 0x1F87u), HB_CODEPOINT_ENCODE3 (0x1F08u, 0x0300u, 0x1F0Au), - HB_CODEPOINT_ENCODE3 (0x1F08u, 0x0301u, 0x1F0Cu), HB_CODEPOINT_ENCODE3 (0x1F08u, 0x0342u, 0x1F0Eu), - HB_CODEPOINT_ENCODE3 (0x1F08u, 0x0345u, 0x1F88u), HB_CODEPOINT_ENCODE3 (0x1F09u, 0x0300u, 0x1F0Bu), - HB_CODEPOINT_ENCODE3 (0x1F09u, 0x0301u, 0x1F0Du), HB_CODEPOINT_ENCODE3 (0x1F09u, 0x0342u, 0x1F0Fu), - HB_CODEPOINT_ENCODE3 (0x1F09u, 0x0345u, 0x1F89u), HB_CODEPOINT_ENCODE3 (0x1F0Au, 0x0345u, 0x1F8Au), - HB_CODEPOINT_ENCODE3 (0x1F0Bu, 0x0345u, 0x1F8Bu), HB_CODEPOINT_ENCODE3 (0x1F0Cu, 0x0345u, 0x1F8Cu), - HB_CODEPOINT_ENCODE3 (0x1F0Du, 0x0345u, 0x1F8Du), HB_CODEPOINT_ENCODE3 (0x1F0Eu, 0x0345u, 0x1F8Eu), - HB_CODEPOINT_ENCODE3 (0x1F0Fu, 0x0345u, 0x1F8Fu), HB_CODEPOINT_ENCODE3 (0x1F10u, 0x0300u, 0x1F12u), - HB_CODEPOINT_ENCODE3 (0x1F10u, 0x0301u, 0x1F14u), HB_CODEPOINT_ENCODE3 (0x1F11u, 0x0300u, 0x1F13u), - HB_CODEPOINT_ENCODE3 (0x1F11u, 0x0301u, 0x1F15u), HB_CODEPOINT_ENCODE3 (0x1F18u, 0x0300u, 0x1F1Au), - HB_CODEPOINT_ENCODE3 (0x1F18u, 0x0301u, 0x1F1Cu), HB_CODEPOINT_ENCODE3 (0x1F19u, 0x0300u, 0x1F1Bu), - HB_CODEPOINT_ENCODE3 (0x1F19u, 0x0301u, 0x1F1Du), HB_CODEPOINT_ENCODE3 (0x1F20u, 0x0300u, 0x1F22u), - HB_CODEPOINT_ENCODE3 (0x1F20u, 0x0301u, 0x1F24u), HB_CODEPOINT_ENCODE3 (0x1F20u, 0x0342u, 0x1F26u), - HB_CODEPOINT_ENCODE3 (0x1F20u, 0x0345u, 0x1F90u), HB_CODEPOINT_ENCODE3 (0x1F21u, 0x0300u, 0x1F23u), - HB_CODEPOINT_ENCODE3 (0x1F21u, 0x0301u, 0x1F25u), HB_CODEPOINT_ENCODE3 (0x1F21u, 0x0342u, 0x1F27u), - HB_CODEPOINT_ENCODE3 (0x1F21u, 0x0345u, 0x1F91u), HB_CODEPOINT_ENCODE3 (0x1F22u, 0x0345u, 0x1F92u), - HB_CODEPOINT_ENCODE3 (0x1F23u, 0x0345u, 0x1F93u), HB_CODEPOINT_ENCODE3 (0x1F24u, 0x0345u, 0x1F94u), - HB_CODEPOINT_ENCODE3 (0x1F25u, 0x0345u, 0x1F95u), HB_CODEPOINT_ENCODE3 (0x1F26u, 0x0345u, 0x1F96u), - HB_CODEPOINT_ENCODE3 (0x1F27u, 0x0345u, 0x1F97u), HB_CODEPOINT_ENCODE3 (0x1F28u, 0x0300u, 0x1F2Au), - HB_CODEPOINT_ENCODE3 (0x1F28u, 0x0301u, 0x1F2Cu), HB_CODEPOINT_ENCODE3 (0x1F28u, 0x0342u, 0x1F2Eu), - HB_CODEPOINT_ENCODE3 (0x1F28u, 0x0345u, 0x1F98u), HB_CODEPOINT_ENCODE3 (0x1F29u, 0x0300u, 0x1F2Bu), - HB_CODEPOINT_ENCODE3 (0x1F29u, 0x0301u, 0x1F2Du), HB_CODEPOINT_ENCODE3 (0x1F29u, 0x0342u, 0x1F2Fu), - HB_CODEPOINT_ENCODE3 (0x1F29u, 0x0345u, 0x1F99u), HB_CODEPOINT_ENCODE3 (0x1F2Au, 0x0345u, 0x1F9Au), - HB_CODEPOINT_ENCODE3 (0x1F2Bu, 0x0345u, 0x1F9Bu), HB_CODEPOINT_ENCODE3 (0x1F2Cu, 0x0345u, 0x1F9Cu), - HB_CODEPOINT_ENCODE3 (0x1F2Du, 0x0345u, 0x1F9Du), HB_CODEPOINT_ENCODE3 (0x1F2Eu, 0x0345u, 0x1F9Eu), - HB_CODEPOINT_ENCODE3 (0x1F2Fu, 0x0345u, 0x1F9Fu), HB_CODEPOINT_ENCODE3 (0x1F30u, 0x0300u, 0x1F32u), - HB_CODEPOINT_ENCODE3 (0x1F30u, 0x0301u, 0x1F34u), HB_CODEPOINT_ENCODE3 (0x1F30u, 0x0342u, 0x1F36u), - HB_CODEPOINT_ENCODE3 (0x1F31u, 0x0300u, 0x1F33u), HB_CODEPOINT_ENCODE3 (0x1F31u, 0x0301u, 0x1F35u), - HB_CODEPOINT_ENCODE3 (0x1F31u, 0x0342u, 0x1F37u), HB_CODEPOINT_ENCODE3 (0x1F38u, 0x0300u, 0x1F3Au), - HB_CODEPOINT_ENCODE3 (0x1F38u, 0x0301u, 0x1F3Cu), HB_CODEPOINT_ENCODE3 (0x1F38u, 0x0342u, 0x1F3Eu), - HB_CODEPOINT_ENCODE3 (0x1F39u, 0x0300u, 0x1F3Bu), HB_CODEPOINT_ENCODE3 (0x1F39u, 0x0301u, 0x1F3Du), - HB_CODEPOINT_ENCODE3 (0x1F39u, 0x0342u, 0x1F3Fu), HB_CODEPOINT_ENCODE3 (0x1F40u, 0x0300u, 0x1F42u), - HB_CODEPOINT_ENCODE3 (0x1F40u, 0x0301u, 0x1F44u), HB_CODEPOINT_ENCODE3 (0x1F41u, 0x0300u, 0x1F43u), - HB_CODEPOINT_ENCODE3 (0x1F41u, 0x0301u, 0x1F45u), HB_CODEPOINT_ENCODE3 (0x1F48u, 0x0300u, 0x1F4Au), - HB_CODEPOINT_ENCODE3 (0x1F48u, 0x0301u, 0x1F4Cu), HB_CODEPOINT_ENCODE3 (0x1F49u, 0x0300u, 0x1F4Bu), - HB_CODEPOINT_ENCODE3 (0x1F49u, 0x0301u, 0x1F4Du), HB_CODEPOINT_ENCODE3 (0x1F50u, 0x0300u, 0x1F52u), - HB_CODEPOINT_ENCODE3 (0x1F50u, 0x0301u, 0x1F54u), HB_CODEPOINT_ENCODE3 (0x1F50u, 0x0342u, 0x1F56u), - HB_CODEPOINT_ENCODE3 (0x1F51u, 0x0300u, 0x1F53u), HB_CODEPOINT_ENCODE3 (0x1F51u, 0x0301u, 0x1F55u), - HB_CODEPOINT_ENCODE3 (0x1F51u, 0x0342u, 0x1F57u), HB_CODEPOINT_ENCODE3 (0x1F59u, 0x0300u, 0x1F5Bu), - HB_CODEPOINT_ENCODE3 (0x1F59u, 0x0301u, 0x1F5Du), HB_CODEPOINT_ENCODE3 (0x1F59u, 0x0342u, 0x1F5Fu), - HB_CODEPOINT_ENCODE3 (0x1F60u, 0x0300u, 0x1F62u), HB_CODEPOINT_ENCODE3 (0x1F60u, 0x0301u, 0x1F64u), - HB_CODEPOINT_ENCODE3 (0x1F60u, 0x0342u, 0x1F66u), HB_CODEPOINT_ENCODE3 (0x1F60u, 0x0345u, 0x1FA0u), - HB_CODEPOINT_ENCODE3 (0x1F61u, 0x0300u, 0x1F63u), HB_CODEPOINT_ENCODE3 (0x1F61u, 0x0301u, 0x1F65u), - HB_CODEPOINT_ENCODE3 (0x1F61u, 0x0342u, 0x1F67u), HB_CODEPOINT_ENCODE3 (0x1F61u, 0x0345u, 0x1FA1u), - HB_CODEPOINT_ENCODE3 (0x1F62u, 0x0345u, 0x1FA2u), HB_CODEPOINT_ENCODE3 (0x1F63u, 0x0345u, 0x1FA3u), - HB_CODEPOINT_ENCODE3 (0x1F64u, 0x0345u, 0x1FA4u), HB_CODEPOINT_ENCODE3 (0x1F65u, 0x0345u, 0x1FA5u), - HB_CODEPOINT_ENCODE3 (0x1F66u, 0x0345u, 0x1FA6u), HB_CODEPOINT_ENCODE3 (0x1F67u, 0x0345u, 0x1FA7u), - HB_CODEPOINT_ENCODE3 (0x1F68u, 0x0300u, 0x1F6Au), HB_CODEPOINT_ENCODE3 (0x1F68u, 0x0301u, 0x1F6Cu), - HB_CODEPOINT_ENCODE3 (0x1F68u, 0x0342u, 0x1F6Eu), HB_CODEPOINT_ENCODE3 (0x1F68u, 0x0345u, 0x1FA8u), - HB_CODEPOINT_ENCODE3 (0x1F69u, 0x0300u, 0x1F6Bu), HB_CODEPOINT_ENCODE3 (0x1F69u, 0x0301u, 0x1F6Du), - HB_CODEPOINT_ENCODE3 (0x1F69u, 0x0342u, 0x1F6Fu), HB_CODEPOINT_ENCODE3 (0x1F69u, 0x0345u, 0x1FA9u), - HB_CODEPOINT_ENCODE3 (0x1F6Au, 0x0345u, 0x1FAAu), HB_CODEPOINT_ENCODE3 (0x1F6Bu, 0x0345u, 0x1FABu), - HB_CODEPOINT_ENCODE3 (0x1F6Cu, 0x0345u, 0x1FACu), HB_CODEPOINT_ENCODE3 (0x1F6Du, 0x0345u, 0x1FADu), - HB_CODEPOINT_ENCODE3 (0x1F6Eu, 0x0345u, 0x1FAEu), HB_CODEPOINT_ENCODE3 (0x1F6Fu, 0x0345u, 0x1FAFu), - HB_CODEPOINT_ENCODE3 (0x1F70u, 0x0345u, 0x1FB2u), HB_CODEPOINT_ENCODE3 (0x1F74u, 0x0345u, 0x1FC2u), - HB_CODEPOINT_ENCODE3 (0x1F7Cu, 0x0345u, 0x1FF2u), HB_CODEPOINT_ENCODE3 (0x1FB6u, 0x0345u, 0x1FB7u), - HB_CODEPOINT_ENCODE3 (0x1FBFu, 0x0300u, 0x1FCDu), HB_CODEPOINT_ENCODE3 (0x1FBFu, 0x0301u, 0x1FCEu), - HB_CODEPOINT_ENCODE3 (0x1FBFu, 0x0342u, 0x1FCFu), HB_CODEPOINT_ENCODE3 (0x1FC6u, 0x0345u, 0x1FC7u), - HB_CODEPOINT_ENCODE3 (0x1FF6u, 0x0345u, 0x1FF7u), HB_CODEPOINT_ENCODE3 (0x1FFEu, 0x0300u, 0x1FDDu), - HB_CODEPOINT_ENCODE3 (0x1FFEu, 0x0301u, 0x1FDEu), HB_CODEPOINT_ENCODE3 (0x1FFEu, 0x0342u, 0x1FDFu), - HB_CODEPOINT_ENCODE3 (0x2190u, 0x0338u, 0x219Au), HB_CODEPOINT_ENCODE3 (0x2192u, 0x0338u, 0x219Bu), - HB_CODEPOINT_ENCODE3 (0x2194u, 0x0338u, 0x21AEu), HB_CODEPOINT_ENCODE3 (0x21D0u, 0x0338u, 0x21CDu), - HB_CODEPOINT_ENCODE3 (0x21D2u, 0x0338u, 0x21CFu), HB_CODEPOINT_ENCODE3 (0x21D4u, 0x0338u, 0x21CEu), - HB_CODEPOINT_ENCODE3 (0x2203u, 0x0338u, 0x2204u), HB_CODEPOINT_ENCODE3 (0x2208u, 0x0338u, 0x2209u), - HB_CODEPOINT_ENCODE3 (0x220Bu, 0x0338u, 0x220Cu), HB_CODEPOINT_ENCODE3 (0x2223u, 0x0338u, 0x2224u), - HB_CODEPOINT_ENCODE3 (0x2225u, 0x0338u, 0x2226u), HB_CODEPOINT_ENCODE3 (0x223Cu, 0x0338u, 0x2241u), - HB_CODEPOINT_ENCODE3 (0x2243u, 0x0338u, 0x2244u), HB_CODEPOINT_ENCODE3 (0x2245u, 0x0338u, 0x2247u), - HB_CODEPOINT_ENCODE3 (0x2248u, 0x0338u, 0x2249u), HB_CODEPOINT_ENCODE3 (0x224Du, 0x0338u, 0x226Du), - HB_CODEPOINT_ENCODE3 (0x2261u, 0x0338u, 0x2262u), HB_CODEPOINT_ENCODE3 (0x2264u, 0x0338u, 0x2270u), - HB_CODEPOINT_ENCODE3 (0x2265u, 0x0338u, 0x2271u), HB_CODEPOINT_ENCODE3 (0x2272u, 0x0338u, 0x2274u), - HB_CODEPOINT_ENCODE3 (0x2273u, 0x0338u, 0x2275u), HB_CODEPOINT_ENCODE3 (0x2276u, 0x0338u, 0x2278u), - HB_CODEPOINT_ENCODE3 (0x2277u, 0x0338u, 0x2279u), HB_CODEPOINT_ENCODE3 (0x227Au, 0x0338u, 0x2280u), - HB_CODEPOINT_ENCODE3 (0x227Bu, 0x0338u, 0x2281u), HB_CODEPOINT_ENCODE3 (0x227Cu, 0x0338u, 0x22E0u), - HB_CODEPOINT_ENCODE3 (0x227Du, 0x0338u, 0x22E1u), HB_CODEPOINT_ENCODE3 (0x2282u, 0x0338u, 0x2284u), - HB_CODEPOINT_ENCODE3 (0x2283u, 0x0338u, 0x2285u), HB_CODEPOINT_ENCODE3 (0x2286u, 0x0338u, 0x2288u), - HB_CODEPOINT_ENCODE3 (0x2287u, 0x0338u, 0x2289u), HB_CODEPOINT_ENCODE3 (0x2291u, 0x0338u, 0x22E2u), - HB_CODEPOINT_ENCODE3 (0x2292u, 0x0338u, 0x22E3u), HB_CODEPOINT_ENCODE3 (0x22A2u, 0x0338u, 0x22ACu), - HB_CODEPOINT_ENCODE3 (0x22A8u, 0x0338u, 0x22ADu), HB_CODEPOINT_ENCODE3 (0x22A9u, 0x0338u, 0x22AEu), - HB_CODEPOINT_ENCODE3 (0x22ABu, 0x0338u, 0x22AFu), HB_CODEPOINT_ENCODE3 (0x22B2u, 0x0338u, 0x22EAu), - HB_CODEPOINT_ENCODE3 (0x22B3u, 0x0338u, 0x22EBu), HB_CODEPOINT_ENCODE3 (0x22B4u, 0x0338u, 0x22ECu), - HB_CODEPOINT_ENCODE3 (0x22B5u, 0x0338u, 0x22EDu), HB_CODEPOINT_ENCODE3 (0x2ADDu, 0x0338u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x3046u, 0x3099u, 0x3094u), HB_CODEPOINT_ENCODE3 (0x304Bu, 0x3099u, 0x304Cu), - HB_CODEPOINT_ENCODE3 (0x304Du, 0x3099u, 0x304Eu), HB_CODEPOINT_ENCODE3 (0x304Fu, 0x3099u, 0x3050u), - HB_CODEPOINT_ENCODE3 (0x3051u, 0x3099u, 0x3052u), HB_CODEPOINT_ENCODE3 (0x3053u, 0x3099u, 0x3054u), - HB_CODEPOINT_ENCODE3 (0x3055u, 0x3099u, 0x3056u), HB_CODEPOINT_ENCODE3 (0x3057u, 0x3099u, 0x3058u), - HB_CODEPOINT_ENCODE3 (0x3059u, 0x3099u, 0x305Au), HB_CODEPOINT_ENCODE3 (0x305Bu, 0x3099u, 0x305Cu), - HB_CODEPOINT_ENCODE3 (0x305Du, 0x3099u, 0x305Eu), HB_CODEPOINT_ENCODE3 (0x305Fu, 0x3099u, 0x3060u), - HB_CODEPOINT_ENCODE3 (0x3061u, 0x3099u, 0x3062u), HB_CODEPOINT_ENCODE3 (0x3064u, 0x3099u, 0x3065u), - HB_CODEPOINT_ENCODE3 (0x3066u, 0x3099u, 0x3067u), HB_CODEPOINT_ENCODE3 (0x3068u, 0x3099u, 0x3069u), - HB_CODEPOINT_ENCODE3 (0x306Fu, 0x3099u, 0x3070u), HB_CODEPOINT_ENCODE3 (0x306Fu, 0x309Au, 0x3071u), - HB_CODEPOINT_ENCODE3 (0x3072u, 0x3099u, 0x3073u), HB_CODEPOINT_ENCODE3 (0x3072u, 0x309Au, 0x3074u), - HB_CODEPOINT_ENCODE3 (0x3075u, 0x3099u, 0x3076u), HB_CODEPOINT_ENCODE3 (0x3075u, 0x309Au, 0x3077u), - HB_CODEPOINT_ENCODE3 (0x3078u, 0x3099u, 0x3079u), HB_CODEPOINT_ENCODE3 (0x3078u, 0x309Au, 0x307Au), - HB_CODEPOINT_ENCODE3 (0x307Bu, 0x3099u, 0x307Cu), HB_CODEPOINT_ENCODE3 (0x307Bu, 0x309Au, 0x307Du), - HB_CODEPOINT_ENCODE3 (0x309Du, 0x3099u, 0x309Eu), HB_CODEPOINT_ENCODE3 (0x30A6u, 0x3099u, 0x30F4u), - HB_CODEPOINT_ENCODE3 (0x30ABu, 0x3099u, 0x30ACu), HB_CODEPOINT_ENCODE3 (0x30ADu, 0x3099u, 0x30AEu), - HB_CODEPOINT_ENCODE3 (0x30AFu, 0x3099u, 0x30B0u), HB_CODEPOINT_ENCODE3 (0x30B1u, 0x3099u, 0x30B2u), - HB_CODEPOINT_ENCODE3 (0x30B3u, 0x3099u, 0x30B4u), HB_CODEPOINT_ENCODE3 (0x30B5u, 0x3099u, 0x30B6u), - HB_CODEPOINT_ENCODE3 (0x30B7u, 0x3099u, 0x30B8u), HB_CODEPOINT_ENCODE3 (0x30B9u, 0x3099u, 0x30BAu), - HB_CODEPOINT_ENCODE3 (0x30BBu, 0x3099u, 0x30BCu), HB_CODEPOINT_ENCODE3 (0x30BDu, 0x3099u, 0x30BEu), - HB_CODEPOINT_ENCODE3 (0x30BFu, 0x3099u, 0x30C0u), HB_CODEPOINT_ENCODE3 (0x30C1u, 0x3099u, 0x30C2u), - HB_CODEPOINT_ENCODE3 (0x30C4u, 0x3099u, 0x30C5u), HB_CODEPOINT_ENCODE3 (0x30C6u, 0x3099u, 0x30C7u), - HB_CODEPOINT_ENCODE3 (0x30C8u, 0x3099u, 0x30C9u), HB_CODEPOINT_ENCODE3 (0x30CFu, 0x3099u, 0x30D0u), - HB_CODEPOINT_ENCODE3 (0x30CFu, 0x309Au, 0x30D1u), HB_CODEPOINT_ENCODE3 (0x30D2u, 0x3099u, 0x30D3u), - HB_CODEPOINT_ENCODE3 (0x30D2u, 0x309Au, 0x30D4u), HB_CODEPOINT_ENCODE3 (0x30D5u, 0x3099u, 0x30D6u), - HB_CODEPOINT_ENCODE3 (0x30D5u, 0x309Au, 0x30D7u), HB_CODEPOINT_ENCODE3 (0x30D8u, 0x3099u, 0x30D9u), - HB_CODEPOINT_ENCODE3 (0x30D8u, 0x309Au, 0x30DAu), HB_CODEPOINT_ENCODE3 (0x30DBu, 0x3099u, 0x30DCu), - HB_CODEPOINT_ENCODE3 (0x30DBu, 0x309Au, 0x30DDu), HB_CODEPOINT_ENCODE3 (0x30EFu, 0x3099u, 0x30F7u), - HB_CODEPOINT_ENCODE3 (0x30F0u, 0x3099u, 0x30F8u), HB_CODEPOINT_ENCODE3 (0x30F1u, 0x3099u, 0x30F9u), - HB_CODEPOINT_ENCODE3 (0x30F2u, 0x3099u, 0x30FAu), HB_CODEPOINT_ENCODE3 (0x30FDu, 0x3099u, 0x30FEu), - HB_CODEPOINT_ENCODE3 (0xFB49u, 0x05C1u, 0x0000u), HB_CODEPOINT_ENCODE3 (0xFB49u, 0x05C2u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x105D2u, 0x0307u, 0x105C9u), HB_CODEPOINT_ENCODE3 (0x105DAu, 0x0307u, 0x105E4u), - HB_CODEPOINT_ENCODE3 (0x11099u, 0x110BAu, 0x1109Au),HB_CODEPOINT_ENCODE3 (0x1109Bu, 0x110BAu, 0x1109Cu), - HB_CODEPOINT_ENCODE3 (0x110A5u, 0x110BAu, 0x110ABu),HB_CODEPOINT_ENCODE3 (0x11131u, 0x11127u, 0x1112Eu), - HB_CODEPOINT_ENCODE3 (0x11132u, 0x11127u, 0x1112Fu),HB_CODEPOINT_ENCODE3 (0x11347u, 0x1133Eu, 0x1134Bu), - HB_CODEPOINT_ENCODE3 (0x11347u, 0x11357u, 0x1134Cu),HB_CODEPOINT_ENCODE3 (0x11382u, 0x113C9u, 0x11383u), - HB_CODEPOINT_ENCODE3 (0x11384u, 0x113BBu, 0x11385u),HB_CODEPOINT_ENCODE3 (0x1138Bu, 0x113C2u, 0x1138Eu), - HB_CODEPOINT_ENCODE3 (0x11390u, 0x113C9u, 0x11391u),HB_CODEPOINT_ENCODE3 (0x113C2u, 0x113B8u, 0x113C7u), - HB_CODEPOINT_ENCODE3 (0x113C2u, 0x113C2u, 0x113C5u),HB_CODEPOINT_ENCODE3 (0x113C2u, 0x113C9u, 0x113C8u), - HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114B0u, 0x114BCu),HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114BAu, 0x114BBu), - HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114BDu, 0x114BEu),HB_CODEPOINT_ENCODE3 (0x115B8u, 0x115AFu, 0x115BAu), - HB_CODEPOINT_ENCODE3 (0x115B9u, 0x115AFu, 0x115BBu),HB_CODEPOINT_ENCODE3 (0x11935u, 0x11930u, 0x11938u), - HB_CODEPOINT_ENCODE3 (0x1611Eu, 0x1611Eu, 0x16121u),HB_CODEPOINT_ENCODE3 (0x1611Eu, 0x1611Fu, 0x16123u), - HB_CODEPOINT_ENCODE3 (0x1611Eu, 0x16120u, 0x16125u),HB_CODEPOINT_ENCODE3 (0x1611Eu, 0x16129u, 0x16122u), - HB_CODEPOINT_ENCODE3 (0x16121u, 0x1611Fu, 0x16126u),HB_CODEPOINT_ENCODE3 (0x16121u, 0x16120u, 0x16128u), - HB_CODEPOINT_ENCODE3 (0x16122u, 0x1611Fu, 0x16127u),HB_CODEPOINT_ENCODE3 (0x16129u, 0x1611Fu, 0x16124u), - HB_CODEPOINT_ENCODE3 (0x16D63u, 0x16D67u, 0x16D69u),HB_CODEPOINT_ENCODE3 (0x16D67u, 0x16D67u, 0x16D68u), - HB_CODEPOINT_ENCODE3 (0x16D69u, 0x16D67u, 0x16D6Au), HB_CODEPOINT_ENCODE3 (0x1D157u, 0x1D165u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x1D158u, 0x1D165u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D16Eu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D16Fu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D170u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D171u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D172u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x1D1B9u, 0x1D165u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BAu, 0x1D165u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x1D1BBu, 0x1D16Eu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BBu, 0x1D16Fu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x1D1BCu, 0x1D16Eu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BCu, 0x1D16Fu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x05D0, 0x05B7, 0x0000), HB_CODEPOINT_ENCODE3 (0x05D0, 0x05B8, 0x0000), + HB_CODEPOINT_ENCODE3 (0x05D0, 0x05BC, 0x0000), HB_CODEPOINT_ENCODE3 (0x05D1, 0x05BC, 0x0000), + HB_CODEPOINT_ENCODE3 (0x05D1, 0x05BF, 0x0000), HB_CODEPOINT_ENCODE3 (0x05D2, 0x05BC, 0x0000), + HB_CODEPOINT_ENCODE3 (0x05D3, 0x05BC, 0x0000), HB_CODEPOINT_ENCODE3 (0x05D4, 0x05BC, 0x0000), + HB_CODEPOINT_ENCODE3 (0x05D5, 0x05B9, 0x0000), HB_CODEPOINT_ENCODE3 (0x05D5, 0x05BC, 0x0000), + HB_CODEPOINT_ENCODE3 (0x05D6, 0x05BC, 0x0000), HB_CODEPOINT_ENCODE3 (0x05D8, 0x05BC, 0x0000), + HB_CODEPOINT_ENCODE3 (0x05D9, 0x05B4, 0x0000), HB_CODEPOINT_ENCODE3 (0x05D9, 0x05BC, 0x0000), + HB_CODEPOINT_ENCODE3 (0x05DA, 0x05BC, 0x0000), HB_CODEPOINT_ENCODE3 (0x05DB, 0x05BC, 0x0000), + HB_CODEPOINT_ENCODE3 (0x05DB, 0x05BF, 0x0000), HB_CODEPOINT_ENCODE3 (0x05DC, 0x05BC, 0x0000), + HB_CODEPOINT_ENCODE3 (0x05DE, 0x05BC, 0x0000), HB_CODEPOINT_ENCODE3 (0x05E0, 0x05BC, 0x0000), + HB_CODEPOINT_ENCODE3 (0x05E1, 0x05BC, 0x0000), HB_CODEPOINT_ENCODE3 (0x05E3, 0x05BC, 0x0000), + HB_CODEPOINT_ENCODE3 (0x05E4, 0x05BC, 0x0000), HB_CODEPOINT_ENCODE3 (0x05E4, 0x05BF, 0x0000), + HB_CODEPOINT_ENCODE3 (0x05E6, 0x05BC, 0x0000), HB_CODEPOINT_ENCODE3 (0x05E7, 0x05BC, 0x0000), + HB_CODEPOINT_ENCODE3 (0x05E8, 0x05BC, 0x0000), HB_CODEPOINT_ENCODE3 (0x05E9, 0x05BC, 0x0000), + HB_CODEPOINT_ENCODE3 (0x05E9, 0x05C1, 0x0000), HB_CODEPOINT_ENCODE3 (0x05E9, 0x05C2, 0x0000), + HB_CODEPOINT_ENCODE3 (0x05EA, 0x05BC, 0x0000), HB_CODEPOINT_ENCODE3 (0x05F2, 0x05B7, 0x0000), + HB_CODEPOINT_ENCODE3 (0x0627, 0x0653, 0x0622), HB_CODEPOINT_ENCODE3 (0x0627, 0x0654, 0x0623), + HB_CODEPOINT_ENCODE3 (0x0627, 0x0655, 0x0625), HB_CODEPOINT_ENCODE3 (0x0648, 0x0654, 0x0624), + HB_CODEPOINT_ENCODE3 (0x064A, 0x0654, 0x0626), HB_CODEPOINT_ENCODE3 (0x06C1, 0x0654, 0x06C2), + HB_CODEPOINT_ENCODE3 (0x06D2, 0x0654, 0x06D3), HB_CODEPOINT_ENCODE3 (0x06D5, 0x0654, 0x06C0), + HB_CODEPOINT_ENCODE3 (0x0915, 0x093C, 0x0000), HB_CODEPOINT_ENCODE3 (0x0916, 0x093C, 0x0000), + HB_CODEPOINT_ENCODE3 (0x0917, 0x093C, 0x0000), HB_CODEPOINT_ENCODE3 (0x091C, 0x093C, 0x0000), + HB_CODEPOINT_ENCODE3 (0x0921, 0x093C, 0x0000), HB_CODEPOINT_ENCODE3 (0x0922, 0x093C, 0x0000), + HB_CODEPOINT_ENCODE3 (0x0928, 0x093C, 0x0929), HB_CODEPOINT_ENCODE3 (0x092B, 0x093C, 0x0000), + HB_CODEPOINT_ENCODE3 (0x092F, 0x093C, 0x0000), HB_CODEPOINT_ENCODE3 (0x0930, 0x093C, 0x0931), + HB_CODEPOINT_ENCODE3 (0x0933, 0x093C, 0x0934), HB_CODEPOINT_ENCODE3 (0x09A1, 0x09BC, 0x0000), + HB_CODEPOINT_ENCODE3 (0x09A2, 0x09BC, 0x0000), HB_CODEPOINT_ENCODE3 (0x09AF, 0x09BC, 0x0000), + HB_CODEPOINT_ENCODE3 (0x09C7, 0x09BE, 0x09CB), HB_CODEPOINT_ENCODE3 (0x09C7, 0x09D7, 0x09CC), + HB_CODEPOINT_ENCODE3 (0x0A16, 0x0A3C, 0x0000), HB_CODEPOINT_ENCODE3 (0x0A17, 0x0A3C, 0x0000), + HB_CODEPOINT_ENCODE3 (0x0A1C, 0x0A3C, 0x0000), HB_CODEPOINT_ENCODE3 (0x0A2B, 0x0A3C, 0x0000), + HB_CODEPOINT_ENCODE3 (0x0A32, 0x0A3C, 0x0000), HB_CODEPOINT_ENCODE3 (0x0A38, 0x0A3C, 0x0000), + HB_CODEPOINT_ENCODE3 (0x0B21, 0x0B3C, 0x0000), HB_CODEPOINT_ENCODE3 (0x0B22, 0x0B3C, 0x0000), + HB_CODEPOINT_ENCODE3 (0x0B47, 0x0B3E, 0x0B4B), HB_CODEPOINT_ENCODE3 (0x0B47, 0x0B56, 0x0B48), + HB_CODEPOINT_ENCODE3 (0x0B47, 0x0B57, 0x0B4C), HB_CODEPOINT_ENCODE3 (0x0B92, 0x0BD7, 0x0B94), + HB_CODEPOINT_ENCODE3 (0x0BC6, 0x0BBE, 0x0BCA), HB_CODEPOINT_ENCODE3 (0x0BC6, 0x0BD7, 0x0BCC), + HB_CODEPOINT_ENCODE3 (0x0BC7, 0x0BBE, 0x0BCB), HB_CODEPOINT_ENCODE3 (0x0C46, 0x0C56, 0x0C48), + HB_CODEPOINT_ENCODE3 (0x0CBF, 0x0CD5, 0x0CC0), HB_CODEPOINT_ENCODE3 (0x0CC6, 0x0CC2, 0x0CCA), + HB_CODEPOINT_ENCODE3 (0x0CC6, 0x0CD5, 0x0CC7), HB_CODEPOINT_ENCODE3 (0x0CC6, 0x0CD6, 0x0CC8), + HB_CODEPOINT_ENCODE3 (0x0CCA, 0x0CD5, 0x0CCB), HB_CODEPOINT_ENCODE3 (0x0D46, 0x0D3E, 0x0D4A), + HB_CODEPOINT_ENCODE3 (0x0D46, 0x0D57, 0x0D4C), HB_CODEPOINT_ENCODE3 (0x0D47, 0x0D3E, 0x0D4B), + HB_CODEPOINT_ENCODE3 (0x0DD9, 0x0DCA, 0x0DDA), HB_CODEPOINT_ENCODE3 (0x0DD9, 0x0DCF, 0x0DDC), + HB_CODEPOINT_ENCODE3 (0x0DD9, 0x0DDF, 0x0DDE), HB_CODEPOINT_ENCODE3 (0x0DDC, 0x0DCA, 0x0DDD), + HB_CODEPOINT_ENCODE3 (0x0F40, 0x0FB5, 0x0000), HB_CODEPOINT_ENCODE3 (0x0F42, 0x0FB7, 0x0000), + HB_CODEPOINT_ENCODE3 (0x0F4C, 0x0FB7, 0x0000), HB_CODEPOINT_ENCODE3 (0x0F51, 0x0FB7, 0x0000), + HB_CODEPOINT_ENCODE3 (0x0F56, 0x0FB7, 0x0000), HB_CODEPOINT_ENCODE3 (0x0F5B, 0x0FB7, 0x0000), + HB_CODEPOINT_ENCODE3 (0x0F71, 0x0F72, 0x0000), HB_CODEPOINT_ENCODE3 (0x0F71, 0x0F74, 0x0000), + HB_CODEPOINT_ENCODE3 (0x0F71, 0x0F80, 0x0000), HB_CODEPOINT_ENCODE3 (0x0F90, 0x0FB5, 0x0000), + HB_CODEPOINT_ENCODE3 (0x0F92, 0x0FB7, 0x0000), HB_CODEPOINT_ENCODE3 (0x0F9C, 0x0FB7, 0x0000), + HB_CODEPOINT_ENCODE3 (0x0FA1, 0x0FB7, 0x0000), HB_CODEPOINT_ENCODE3 (0x0FA6, 0x0FB7, 0x0000), + HB_CODEPOINT_ENCODE3 (0x0FAB, 0x0FB7, 0x0000), HB_CODEPOINT_ENCODE3 (0x0FB2, 0x0F80, 0x0000), + HB_CODEPOINT_ENCODE3 (0x0FB3, 0x0F80, 0x0000), HB_CODEPOINT_ENCODE3 (0x1025, 0x102E, 0x1026), + HB_CODEPOINT_ENCODE3 (0x1B05, 0x1B35, 0x1B06), HB_CODEPOINT_ENCODE3 (0x1B07, 0x1B35, 0x1B08), + HB_CODEPOINT_ENCODE3 (0x1B09, 0x1B35, 0x1B0A), HB_CODEPOINT_ENCODE3 (0x1B0B, 0x1B35, 0x1B0C), + HB_CODEPOINT_ENCODE3 (0x1B0D, 0x1B35, 0x1B0E), HB_CODEPOINT_ENCODE3 (0x1B11, 0x1B35, 0x1B12), + HB_CODEPOINT_ENCODE3 (0x1B3A, 0x1B35, 0x1B3B), HB_CODEPOINT_ENCODE3 (0x1B3C, 0x1B35, 0x1B3D), + HB_CODEPOINT_ENCODE3 (0x1B3E, 0x1B35, 0x1B40), HB_CODEPOINT_ENCODE3 (0x1B3F, 0x1B35, 0x1B41), + HB_CODEPOINT_ENCODE3 (0x1B42, 0x1B35, 0x1B43), HB_CODEPOINT_ENCODE3 (0x1E36, 0x0304, 0x1E38), + HB_CODEPOINT_ENCODE3 (0x1E37, 0x0304, 0x1E39), HB_CODEPOINT_ENCODE3 (0x1E5A, 0x0304, 0x1E5C), + HB_CODEPOINT_ENCODE3 (0x1E5B, 0x0304, 0x1E5D), HB_CODEPOINT_ENCODE3 (0x1E62, 0x0307, 0x1E68), + HB_CODEPOINT_ENCODE3 (0x1E63, 0x0307, 0x1E69), HB_CODEPOINT_ENCODE3 (0x1EA0, 0x0302, 0x1EAC), + HB_CODEPOINT_ENCODE3 (0x1EA0, 0x0306, 0x1EB6), HB_CODEPOINT_ENCODE3 (0x1EA1, 0x0302, 0x1EAD), + HB_CODEPOINT_ENCODE3 (0x1EA1, 0x0306, 0x1EB7), HB_CODEPOINT_ENCODE3 (0x1EB8, 0x0302, 0x1EC6), + HB_CODEPOINT_ENCODE3 (0x1EB9, 0x0302, 0x1EC7), HB_CODEPOINT_ENCODE3 (0x1ECC, 0x0302, 0x1ED8), + HB_CODEPOINT_ENCODE3 (0x1ECD, 0x0302, 0x1ED9), HB_CODEPOINT_ENCODE3 (0x1F00, 0x0300, 0x1F02), + HB_CODEPOINT_ENCODE3 (0x1F00, 0x0301, 0x1F04), HB_CODEPOINT_ENCODE3 (0x1F00, 0x0342, 0x1F06), + HB_CODEPOINT_ENCODE3 (0x1F00, 0x0345, 0x1F80), HB_CODEPOINT_ENCODE3 (0x1F01, 0x0300, 0x1F03), + HB_CODEPOINT_ENCODE3 (0x1F01, 0x0301, 0x1F05), HB_CODEPOINT_ENCODE3 (0x1F01, 0x0342, 0x1F07), + HB_CODEPOINT_ENCODE3 (0x1F01, 0x0345, 0x1F81), HB_CODEPOINT_ENCODE3 (0x1F02, 0x0345, 0x1F82), + HB_CODEPOINT_ENCODE3 (0x1F03, 0x0345, 0x1F83), HB_CODEPOINT_ENCODE3 (0x1F04, 0x0345, 0x1F84), + HB_CODEPOINT_ENCODE3 (0x1F05, 0x0345, 0x1F85), HB_CODEPOINT_ENCODE3 (0x1F06, 0x0345, 0x1F86), + HB_CODEPOINT_ENCODE3 (0x1F07, 0x0345, 0x1F87), HB_CODEPOINT_ENCODE3 (0x1F08, 0x0300, 0x1F0A), + HB_CODEPOINT_ENCODE3 (0x1F08, 0x0301, 0x1F0C), HB_CODEPOINT_ENCODE3 (0x1F08, 0x0342, 0x1F0E), + HB_CODEPOINT_ENCODE3 (0x1F08, 0x0345, 0x1F88), HB_CODEPOINT_ENCODE3 (0x1F09, 0x0300, 0x1F0B), + HB_CODEPOINT_ENCODE3 (0x1F09, 0x0301, 0x1F0D), HB_CODEPOINT_ENCODE3 (0x1F09, 0x0342, 0x1F0F), + HB_CODEPOINT_ENCODE3 (0x1F09, 0x0345, 0x1F89), HB_CODEPOINT_ENCODE3 (0x1F0A, 0x0345, 0x1F8A), + HB_CODEPOINT_ENCODE3 (0x1F0B, 0x0345, 0x1F8B), HB_CODEPOINT_ENCODE3 (0x1F0C, 0x0345, 0x1F8C), + HB_CODEPOINT_ENCODE3 (0x1F0D, 0x0345, 0x1F8D), HB_CODEPOINT_ENCODE3 (0x1F0E, 0x0345, 0x1F8E), + HB_CODEPOINT_ENCODE3 (0x1F0F, 0x0345, 0x1F8F), HB_CODEPOINT_ENCODE3 (0x1F10, 0x0300, 0x1F12), + HB_CODEPOINT_ENCODE3 (0x1F10, 0x0301, 0x1F14), HB_CODEPOINT_ENCODE3 (0x1F11, 0x0300, 0x1F13), + HB_CODEPOINT_ENCODE3 (0x1F11, 0x0301, 0x1F15), HB_CODEPOINT_ENCODE3 (0x1F18, 0x0300, 0x1F1A), + HB_CODEPOINT_ENCODE3 (0x1F18, 0x0301, 0x1F1C), HB_CODEPOINT_ENCODE3 (0x1F19, 0x0300, 0x1F1B), + HB_CODEPOINT_ENCODE3 (0x1F19, 0x0301, 0x1F1D), HB_CODEPOINT_ENCODE3 (0x1F20, 0x0300, 0x1F22), + HB_CODEPOINT_ENCODE3 (0x1F20, 0x0301, 0x1F24), HB_CODEPOINT_ENCODE3 (0x1F20, 0x0342, 0x1F26), + HB_CODEPOINT_ENCODE3 (0x1F20, 0x0345, 0x1F90), HB_CODEPOINT_ENCODE3 (0x1F21, 0x0300, 0x1F23), + HB_CODEPOINT_ENCODE3 (0x1F21, 0x0301, 0x1F25), HB_CODEPOINT_ENCODE3 (0x1F21, 0x0342, 0x1F27), + HB_CODEPOINT_ENCODE3 (0x1F21, 0x0345, 0x1F91), HB_CODEPOINT_ENCODE3 (0x1F22, 0x0345, 0x1F92), + HB_CODEPOINT_ENCODE3 (0x1F23, 0x0345, 0x1F93), HB_CODEPOINT_ENCODE3 (0x1F24, 0x0345, 0x1F94), + HB_CODEPOINT_ENCODE3 (0x1F25, 0x0345, 0x1F95), HB_CODEPOINT_ENCODE3 (0x1F26, 0x0345, 0x1F96), + HB_CODEPOINT_ENCODE3 (0x1F27, 0x0345, 0x1F97), HB_CODEPOINT_ENCODE3 (0x1F28, 0x0300, 0x1F2A), + HB_CODEPOINT_ENCODE3 (0x1F28, 0x0301, 0x1F2C), HB_CODEPOINT_ENCODE3 (0x1F28, 0x0342, 0x1F2E), + HB_CODEPOINT_ENCODE3 (0x1F28, 0x0345, 0x1F98), HB_CODEPOINT_ENCODE3 (0x1F29, 0x0300, 0x1F2B), + HB_CODEPOINT_ENCODE3 (0x1F29, 0x0301, 0x1F2D), HB_CODEPOINT_ENCODE3 (0x1F29, 0x0342, 0x1F2F), + HB_CODEPOINT_ENCODE3 (0x1F29, 0x0345, 0x1F99), HB_CODEPOINT_ENCODE3 (0x1F2A, 0x0345, 0x1F9A), + HB_CODEPOINT_ENCODE3 (0x1F2B, 0x0345, 0x1F9B), HB_CODEPOINT_ENCODE3 (0x1F2C, 0x0345, 0x1F9C), + HB_CODEPOINT_ENCODE3 (0x1F2D, 0x0345, 0x1F9D), HB_CODEPOINT_ENCODE3 (0x1F2E, 0x0345, 0x1F9E), + HB_CODEPOINT_ENCODE3 (0x1F2F, 0x0345, 0x1F9F), HB_CODEPOINT_ENCODE3 (0x1F30, 0x0300, 0x1F32), + HB_CODEPOINT_ENCODE3 (0x1F30, 0x0301, 0x1F34), HB_CODEPOINT_ENCODE3 (0x1F30, 0x0342, 0x1F36), + HB_CODEPOINT_ENCODE3 (0x1F31, 0x0300, 0x1F33), HB_CODEPOINT_ENCODE3 (0x1F31, 0x0301, 0x1F35), + HB_CODEPOINT_ENCODE3 (0x1F31, 0x0342, 0x1F37), HB_CODEPOINT_ENCODE3 (0x1F38, 0x0300, 0x1F3A), + HB_CODEPOINT_ENCODE3 (0x1F38, 0x0301, 0x1F3C), HB_CODEPOINT_ENCODE3 (0x1F38, 0x0342, 0x1F3E), + HB_CODEPOINT_ENCODE3 (0x1F39, 0x0300, 0x1F3B), HB_CODEPOINT_ENCODE3 (0x1F39, 0x0301, 0x1F3D), + HB_CODEPOINT_ENCODE3 (0x1F39, 0x0342, 0x1F3F), HB_CODEPOINT_ENCODE3 (0x1F40, 0x0300, 0x1F42), + HB_CODEPOINT_ENCODE3 (0x1F40, 0x0301, 0x1F44), HB_CODEPOINT_ENCODE3 (0x1F41, 0x0300, 0x1F43), + HB_CODEPOINT_ENCODE3 (0x1F41, 0x0301, 0x1F45), HB_CODEPOINT_ENCODE3 (0x1F48, 0x0300, 0x1F4A), + HB_CODEPOINT_ENCODE3 (0x1F48, 0x0301, 0x1F4C), HB_CODEPOINT_ENCODE3 (0x1F49, 0x0300, 0x1F4B), + HB_CODEPOINT_ENCODE3 (0x1F49, 0x0301, 0x1F4D), HB_CODEPOINT_ENCODE3 (0x1F50, 0x0300, 0x1F52), + HB_CODEPOINT_ENCODE3 (0x1F50, 0x0301, 0x1F54), HB_CODEPOINT_ENCODE3 (0x1F50, 0x0342, 0x1F56), + HB_CODEPOINT_ENCODE3 (0x1F51, 0x0300, 0x1F53), HB_CODEPOINT_ENCODE3 (0x1F51, 0x0301, 0x1F55), + HB_CODEPOINT_ENCODE3 (0x1F51, 0x0342, 0x1F57), HB_CODEPOINT_ENCODE3 (0x1F59, 0x0300, 0x1F5B), + HB_CODEPOINT_ENCODE3 (0x1F59, 0x0301, 0x1F5D), HB_CODEPOINT_ENCODE3 (0x1F59, 0x0342, 0x1F5F), + HB_CODEPOINT_ENCODE3 (0x1F60, 0x0300, 0x1F62), HB_CODEPOINT_ENCODE3 (0x1F60, 0x0301, 0x1F64), + HB_CODEPOINT_ENCODE3 (0x1F60, 0x0342, 0x1F66), HB_CODEPOINT_ENCODE3 (0x1F60, 0x0345, 0x1FA0), + HB_CODEPOINT_ENCODE3 (0x1F61, 0x0300, 0x1F63), HB_CODEPOINT_ENCODE3 (0x1F61, 0x0301, 0x1F65), + HB_CODEPOINT_ENCODE3 (0x1F61, 0x0342, 0x1F67), HB_CODEPOINT_ENCODE3 (0x1F61, 0x0345, 0x1FA1), + HB_CODEPOINT_ENCODE3 (0x1F62, 0x0345, 0x1FA2), HB_CODEPOINT_ENCODE3 (0x1F63, 0x0345, 0x1FA3), + HB_CODEPOINT_ENCODE3 (0x1F64, 0x0345, 0x1FA4), HB_CODEPOINT_ENCODE3 (0x1F65, 0x0345, 0x1FA5), + HB_CODEPOINT_ENCODE3 (0x1F66, 0x0345, 0x1FA6), HB_CODEPOINT_ENCODE3 (0x1F67, 0x0345, 0x1FA7), + HB_CODEPOINT_ENCODE3 (0x1F68, 0x0300, 0x1F6A), HB_CODEPOINT_ENCODE3 (0x1F68, 0x0301, 0x1F6C), + HB_CODEPOINT_ENCODE3 (0x1F68, 0x0342, 0x1F6E), HB_CODEPOINT_ENCODE3 (0x1F68, 0x0345, 0x1FA8), + HB_CODEPOINT_ENCODE3 (0x1F69, 0x0300, 0x1F6B), HB_CODEPOINT_ENCODE3 (0x1F69, 0x0301, 0x1F6D), + HB_CODEPOINT_ENCODE3 (0x1F69, 0x0342, 0x1F6F), HB_CODEPOINT_ENCODE3 (0x1F69, 0x0345, 0x1FA9), + HB_CODEPOINT_ENCODE3 (0x1F6A, 0x0345, 0x1FAA), HB_CODEPOINT_ENCODE3 (0x1F6B, 0x0345, 0x1FAB), + HB_CODEPOINT_ENCODE3 (0x1F6C, 0x0345, 0x1FAC), HB_CODEPOINT_ENCODE3 (0x1F6D, 0x0345, 0x1FAD), + HB_CODEPOINT_ENCODE3 (0x1F6E, 0x0345, 0x1FAE), HB_CODEPOINT_ENCODE3 (0x1F6F, 0x0345, 0x1FAF), + HB_CODEPOINT_ENCODE3 (0x1F70, 0x0345, 0x1FB2), HB_CODEPOINT_ENCODE3 (0x1F74, 0x0345, 0x1FC2), + HB_CODEPOINT_ENCODE3 (0x1F7C, 0x0345, 0x1FF2), HB_CODEPOINT_ENCODE3 (0x1FB6, 0x0345, 0x1FB7), + HB_CODEPOINT_ENCODE3 (0x1FBF, 0x0300, 0x1FCD), HB_CODEPOINT_ENCODE3 (0x1FBF, 0x0301, 0x1FCE), + HB_CODEPOINT_ENCODE3 (0x1FBF, 0x0342, 0x1FCF), HB_CODEPOINT_ENCODE3 (0x1FC6, 0x0345, 0x1FC7), + HB_CODEPOINT_ENCODE3 (0x1FF6, 0x0345, 0x1FF7), HB_CODEPOINT_ENCODE3 (0x1FFE, 0x0300, 0x1FDD), + HB_CODEPOINT_ENCODE3 (0x1FFE, 0x0301, 0x1FDE), HB_CODEPOINT_ENCODE3 (0x1FFE, 0x0342, 0x1FDF), + HB_CODEPOINT_ENCODE3 (0x2190, 0x0338, 0x219A), HB_CODEPOINT_ENCODE3 (0x2192, 0x0338, 0x219B), + HB_CODEPOINT_ENCODE3 (0x2194, 0x0338, 0x21AE), HB_CODEPOINT_ENCODE3 (0x21D0, 0x0338, 0x21CD), + HB_CODEPOINT_ENCODE3 (0x21D2, 0x0338, 0x21CF), HB_CODEPOINT_ENCODE3 (0x21D4, 0x0338, 0x21CE), + HB_CODEPOINT_ENCODE3 (0x2203, 0x0338, 0x2204), HB_CODEPOINT_ENCODE3 (0x2208, 0x0338, 0x2209), + HB_CODEPOINT_ENCODE3 (0x220B, 0x0338, 0x220C), HB_CODEPOINT_ENCODE3 (0x2223, 0x0338, 0x2224), + HB_CODEPOINT_ENCODE3 (0x2225, 0x0338, 0x2226), HB_CODEPOINT_ENCODE3 (0x223C, 0x0338, 0x2241), + HB_CODEPOINT_ENCODE3 (0x2243, 0x0338, 0x2244), HB_CODEPOINT_ENCODE3 (0x2245, 0x0338, 0x2247), + HB_CODEPOINT_ENCODE3 (0x2248, 0x0338, 0x2249), HB_CODEPOINT_ENCODE3 (0x224D, 0x0338, 0x226D), + HB_CODEPOINT_ENCODE3 (0x2261, 0x0338, 0x2262), HB_CODEPOINT_ENCODE3 (0x2264, 0x0338, 0x2270), + HB_CODEPOINT_ENCODE3 (0x2265, 0x0338, 0x2271), HB_CODEPOINT_ENCODE3 (0x2272, 0x0338, 0x2274), + HB_CODEPOINT_ENCODE3 (0x2273, 0x0338, 0x2275), HB_CODEPOINT_ENCODE3 (0x2276, 0x0338, 0x2278), + HB_CODEPOINT_ENCODE3 (0x2277, 0x0338, 0x2279), HB_CODEPOINT_ENCODE3 (0x227A, 0x0338, 0x2280), + HB_CODEPOINT_ENCODE3 (0x227B, 0x0338, 0x2281), HB_CODEPOINT_ENCODE3 (0x227C, 0x0338, 0x22E0), + HB_CODEPOINT_ENCODE3 (0x227D, 0x0338, 0x22E1), HB_CODEPOINT_ENCODE3 (0x2282, 0x0338, 0x2284), + HB_CODEPOINT_ENCODE3 (0x2283, 0x0338, 0x2285), HB_CODEPOINT_ENCODE3 (0x2286, 0x0338, 0x2288), + HB_CODEPOINT_ENCODE3 (0x2287, 0x0338, 0x2289), HB_CODEPOINT_ENCODE3 (0x2291, 0x0338, 0x22E2), + HB_CODEPOINT_ENCODE3 (0x2292, 0x0338, 0x22E3), HB_CODEPOINT_ENCODE3 (0x22A2, 0x0338, 0x22AC), + HB_CODEPOINT_ENCODE3 (0x22A8, 0x0338, 0x22AD), HB_CODEPOINT_ENCODE3 (0x22A9, 0x0338, 0x22AE), + HB_CODEPOINT_ENCODE3 (0x22AB, 0x0338, 0x22AF), HB_CODEPOINT_ENCODE3 (0x22B2, 0x0338, 0x22EA), + HB_CODEPOINT_ENCODE3 (0x22B3, 0x0338, 0x22EB), HB_CODEPOINT_ENCODE3 (0x22B4, 0x0338, 0x22EC), + HB_CODEPOINT_ENCODE3 (0x22B5, 0x0338, 0x22ED), HB_CODEPOINT_ENCODE3 (0x2ADD, 0x0338, 0x0000), + HB_CODEPOINT_ENCODE3 (0x3046, 0x3099, 0x3094), HB_CODEPOINT_ENCODE3 (0x304B, 0x3099, 0x304C), + HB_CODEPOINT_ENCODE3 (0x304D, 0x3099, 0x304E), HB_CODEPOINT_ENCODE3 (0x304F, 0x3099, 0x3050), + HB_CODEPOINT_ENCODE3 (0x3051, 0x3099, 0x3052), HB_CODEPOINT_ENCODE3 (0x3053, 0x3099, 0x3054), + HB_CODEPOINT_ENCODE3 (0x3055, 0x3099, 0x3056), HB_CODEPOINT_ENCODE3 (0x3057, 0x3099, 0x3058), + HB_CODEPOINT_ENCODE3 (0x3059, 0x3099, 0x305A), HB_CODEPOINT_ENCODE3 (0x305B, 0x3099, 0x305C), + HB_CODEPOINT_ENCODE3 (0x305D, 0x3099, 0x305E), HB_CODEPOINT_ENCODE3 (0x305F, 0x3099, 0x3060), + HB_CODEPOINT_ENCODE3 (0x3061, 0x3099, 0x3062), HB_CODEPOINT_ENCODE3 (0x3064, 0x3099, 0x3065), + HB_CODEPOINT_ENCODE3 (0x3066, 0x3099, 0x3067), HB_CODEPOINT_ENCODE3 (0x3068, 0x3099, 0x3069), + HB_CODEPOINT_ENCODE3 (0x306F, 0x3099, 0x3070), HB_CODEPOINT_ENCODE3 (0x306F, 0x309A, 0x3071), + HB_CODEPOINT_ENCODE3 (0x3072, 0x3099, 0x3073), HB_CODEPOINT_ENCODE3 (0x3072, 0x309A, 0x3074), + HB_CODEPOINT_ENCODE3 (0x3075, 0x3099, 0x3076), HB_CODEPOINT_ENCODE3 (0x3075, 0x309A, 0x3077), + HB_CODEPOINT_ENCODE3 (0x3078, 0x3099, 0x3079), HB_CODEPOINT_ENCODE3 (0x3078, 0x309A, 0x307A), + HB_CODEPOINT_ENCODE3 (0x307B, 0x3099, 0x307C), HB_CODEPOINT_ENCODE3 (0x307B, 0x309A, 0x307D), + HB_CODEPOINT_ENCODE3 (0x309D, 0x3099, 0x309E), HB_CODEPOINT_ENCODE3 (0x30A6, 0x3099, 0x30F4), + HB_CODEPOINT_ENCODE3 (0x30AB, 0x3099, 0x30AC), HB_CODEPOINT_ENCODE3 (0x30AD, 0x3099, 0x30AE), + HB_CODEPOINT_ENCODE3 (0x30AF, 0x3099, 0x30B0), HB_CODEPOINT_ENCODE3 (0x30B1, 0x3099, 0x30B2), + HB_CODEPOINT_ENCODE3 (0x30B3, 0x3099, 0x30B4), HB_CODEPOINT_ENCODE3 (0x30B5, 0x3099, 0x30B6), + HB_CODEPOINT_ENCODE3 (0x30B7, 0x3099, 0x30B8), HB_CODEPOINT_ENCODE3 (0x30B9, 0x3099, 0x30BA), + HB_CODEPOINT_ENCODE3 (0x30BB, 0x3099, 0x30BC), HB_CODEPOINT_ENCODE3 (0x30BD, 0x3099, 0x30BE), + HB_CODEPOINT_ENCODE3 (0x30BF, 0x3099, 0x30C0), HB_CODEPOINT_ENCODE3 (0x30C1, 0x3099, 0x30C2), + HB_CODEPOINT_ENCODE3 (0x30C4, 0x3099, 0x30C5), HB_CODEPOINT_ENCODE3 (0x30C6, 0x3099, 0x30C7), + HB_CODEPOINT_ENCODE3 (0x30C8, 0x3099, 0x30C9), HB_CODEPOINT_ENCODE3 (0x30CF, 0x3099, 0x30D0), + HB_CODEPOINT_ENCODE3 (0x30CF, 0x309A, 0x30D1), HB_CODEPOINT_ENCODE3 (0x30D2, 0x3099, 0x30D3), + HB_CODEPOINT_ENCODE3 (0x30D2, 0x309A, 0x30D4), HB_CODEPOINT_ENCODE3 (0x30D5, 0x3099, 0x30D6), + HB_CODEPOINT_ENCODE3 (0x30D5, 0x309A, 0x30D7), HB_CODEPOINT_ENCODE3 (0x30D8, 0x3099, 0x30D9), + HB_CODEPOINT_ENCODE3 (0x30D8, 0x309A, 0x30DA), HB_CODEPOINT_ENCODE3 (0x30DB, 0x3099, 0x30DC), + HB_CODEPOINT_ENCODE3 (0x30DB, 0x309A, 0x30DD), HB_CODEPOINT_ENCODE3 (0x30EF, 0x3099, 0x30F7), + HB_CODEPOINT_ENCODE3 (0x30F0, 0x3099, 0x30F8), HB_CODEPOINT_ENCODE3 (0x30F1, 0x3099, 0x30F9), + HB_CODEPOINT_ENCODE3 (0x30F2, 0x3099, 0x30FA), HB_CODEPOINT_ENCODE3 (0x30FD, 0x3099, 0x30FE), + HB_CODEPOINT_ENCODE3 (0xFB49, 0x05C1, 0x0000), HB_CODEPOINT_ENCODE3 (0xFB49, 0x05C2, 0x0000), + HB_CODEPOINT_ENCODE3 (0x105D2, 0x0307, 0x105C9), HB_CODEPOINT_ENCODE3 (0x105DA, 0x0307, 0x105E4), + HB_CODEPOINT_ENCODE3 (0x11099, 0x110BA, 0x1109A),HB_CODEPOINT_ENCODE3 (0x1109B, 0x110BA, 0x1109C), + HB_CODEPOINT_ENCODE3 (0x110A5, 0x110BA, 0x110AB),HB_CODEPOINT_ENCODE3 (0x11131, 0x11127, 0x1112E), + HB_CODEPOINT_ENCODE3 (0x11132, 0x11127, 0x1112F),HB_CODEPOINT_ENCODE3 (0x11347, 0x1133E, 0x1134B), + HB_CODEPOINT_ENCODE3 (0x11347, 0x11357, 0x1134C),HB_CODEPOINT_ENCODE3 (0x11382, 0x113C9, 0x11383), + HB_CODEPOINT_ENCODE3 (0x11384, 0x113BB, 0x11385),HB_CODEPOINT_ENCODE3 (0x1138B, 0x113C2, 0x1138E), + HB_CODEPOINT_ENCODE3 (0x11390, 0x113C9, 0x11391),HB_CODEPOINT_ENCODE3 (0x113C2, 0x113B8, 0x113C7), + HB_CODEPOINT_ENCODE3 (0x113C2, 0x113C2, 0x113C5),HB_CODEPOINT_ENCODE3 (0x113C2, 0x113C9, 0x113C8), + HB_CODEPOINT_ENCODE3 (0x114B9, 0x114B0, 0x114BC),HB_CODEPOINT_ENCODE3 (0x114B9, 0x114BA, 0x114BB), + HB_CODEPOINT_ENCODE3 (0x114B9, 0x114BD, 0x114BE),HB_CODEPOINT_ENCODE3 (0x115B8, 0x115AF, 0x115BA), + HB_CODEPOINT_ENCODE3 (0x115B9, 0x115AF, 0x115BB),HB_CODEPOINT_ENCODE3 (0x11935, 0x11930, 0x11938), + HB_CODEPOINT_ENCODE3 (0x1611E, 0x1611E, 0x16121),HB_CODEPOINT_ENCODE3 (0x1611E, 0x1611F, 0x16123), + HB_CODEPOINT_ENCODE3 (0x1611E, 0x16120, 0x16125),HB_CODEPOINT_ENCODE3 (0x1611E, 0x16129, 0x16122), + HB_CODEPOINT_ENCODE3 (0x16121, 0x1611F, 0x16126),HB_CODEPOINT_ENCODE3 (0x16121, 0x16120, 0x16128), + HB_CODEPOINT_ENCODE3 (0x16122, 0x1611F, 0x16127),HB_CODEPOINT_ENCODE3 (0x16129, 0x1611F, 0x16124), + HB_CODEPOINT_ENCODE3 (0x16D63, 0x16D67, 0x16D69),HB_CODEPOINT_ENCODE3 (0x16D67, 0x16D67, 0x16D68), + HB_CODEPOINT_ENCODE3 (0x16D69, 0x16D67, 0x16D6A), HB_CODEPOINT_ENCODE3 (0x1D157, 0x1D165, 0x0000), + HB_CODEPOINT_ENCODE3 (0x1D158, 0x1D165, 0x0000), HB_CODEPOINT_ENCODE3 (0x1D15F, 0x1D16E, 0x0000), + HB_CODEPOINT_ENCODE3 (0x1D15F, 0x1D16F, 0x0000), HB_CODEPOINT_ENCODE3 (0x1D15F, 0x1D170, 0x0000), + HB_CODEPOINT_ENCODE3 (0x1D15F, 0x1D171, 0x0000), HB_CODEPOINT_ENCODE3 (0x1D15F, 0x1D172, 0x0000), + HB_CODEPOINT_ENCODE3 (0x1D1B9, 0x1D165, 0x0000), HB_CODEPOINT_ENCODE3 (0x1D1BA, 0x1D165, 0x0000), + HB_CODEPOINT_ENCODE3 (0x1D1BB, 0x1D16E, 0x0000), HB_CODEPOINT_ENCODE3 (0x1D1BB, 0x1D16F, 0x0000), + HB_CODEPOINT_ENCODE3 (0x1D1BC, 0x1D16E, 0x0000), HB_CODEPOINT_ENCODE3 (0x1D1BC, 0x1D16F, 0x0000), }; #ifndef HB_OPTIMIZE_SIZE -static const uint8_t -_hb_ucd_u8[17612] = +#include + +static const uint8_t _hb_ucd_u8[19868]= { - 0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 6, 5, 5, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 5, 17, 15, 18, 19, 20, 21, 22, 23, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 24, 25, 26, 5, 27, 28, - 5, 29, 30, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 31, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 32, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 33, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 17, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 33, 41, 42, 43, 44, 45, - 46, 47, 48, 39, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 49, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 50, 17, 17, 17, 51, 17, 52, 53, 54, 55, 56, 57, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 58, 59, 59, 59, 59, 59, 59, 59, 59, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 17, 61, 62, 17, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 17, 72, 73, 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 17, 17, 17, 97, 98, 99,100,100,100,100,100,100,100,100,100,101, - 17, 17, 17, 17,102, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17,103, 17, 17,104,100,100,100,100,100,100,100,100,100, - 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, - 100,105,100,100,100,100,100,100, 17, 17,106,107,100,108,109,110, - 17, 17, 17, 17, 17, 17, 17,111, 17, 17, 17, 17,112,113,100,100, - 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,114, - 17,115,116,100,100,100,100,100,100,100,100,100,117,100,100,100, - 100,100,100,100,100,100,100,100,100,100,100,100,118, 39,119,120, - 121,122,123,124,125,126,127,128, 39, 39,129,100,100,100,100,130, - 131,132,133,100,134,135,100,136,137,138,100,100,139,140,141,100, - 142,143,144,145, 39, 39,146,147,148, 39,149,150,100,100,100,100, - 17, 17, 17, 17, 17, 17,151, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17,152,153, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,154, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,155, 17, 17,156,100, - 100,100,100,100,100,100,100,100, 17, 17,157,100,100,100,100,100, - 17, 17, 17,158, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17,159,100,100,100,100,100,100,100,100,100,100,100,100, - 160,161,100,100,100,100,100,100,100,100,100,100,100,100,100,100, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,162, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,163, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 27, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 28, 26, 29, 30, 31, 32, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 33, 34, 34, 34, 34, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 26, 56, 57, 58, 58, 58, 58, 59, 26, 26, 60, 26, 26, 26, 26, 26, + 26, 61, 26, 62, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 63, 58, 58, 58, 26, 64, 65, 66, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 67, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 68, 69, 70, 58, 58, 58, 58, 71, 58, + 58, 58, 58, 58, 58, 58, 72, 73, 74, 75, 76, 77, 78, 79, 58, 80, + 81, 82, 83, 84, 85, 58, 86, 87, 88, 89, 78, 90, 91, 92, 58, 58, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 93, 26, 26, 26, 26, 26, 26, 26, 26, 94, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 95, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 96, 26, 97, 58, 58, 58, 58, 26, 98, 58, 58, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 99, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,100, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 101, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,102, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2, 7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, @@ -1148,496 +914,529 @@ _hb_ucd_u8[17612] = 34, 11, 34, 34, 32, 35, 32, 16, 36, 36, 37, 34, 38, 37, 34, 34, 34, 34, 34, 34, 34, 34, 16, 32, 34, 38, 32, 11, 32, 32, 32, 32, 32, 32, 16, 16, 16, 11, 34, 32, 34, 34, 11, 32, 32, 32, 32, 32, - 16, 16, 39, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 41, 41, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, - 40, 40, 42, 41, 41, 41, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, - 43, 43, 43, 43, 43, 43, 43, 43, 32, 32, 42, 32, 44, 45, 16, 10, - 44, 44, 41, 46, 11, 47, 47, 11, 34, 11, 11, 11, 11, 11, 11, 11, - 11, 48, 11, 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 34, - 16, 11, 32, 16, 32, 32, 32, 32, 16, 16, 32, 49, 34, 32, 34, 11, - 32, 50, 43, 43, 51, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16, - 48, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 47, 52, 2, 2, 2, - 16, 16, 16, 16, 53, 54, 55, 56, 57, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 43, 43, 43, 43, 43, 58, 59, 60, 43, 59, 44, 44, 44, 44, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 62, - 36, 63, 64, 44, 44, 44, 44, 44, 65, 65, 65, 8, 9, 66, 2, 67, - 43, 43, 43, 43, 43, 60, 68, 2, 69, 36, 36, 36, 36, 70, 43, 43, - 7, 7, 7, 7, 7, 2, 2, 36, 71, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 72, 43, 43, 43, 73, 50, 43, 43, 74, 75, 76, 43, 43, 36, - 7, 7, 7, 7, 7, 36, 77, 78, 2, 2, 2, 2, 2, 2, 2, 79, - 70, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 80, 62, 36, - 36, 36, 36, 43, 43, 43, 43, 43, 71, 44, 44, 44, 44, 44, 44, 44, - 7, 7, 7, 7, 7, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43, - 43, 43, 40, 21, 2, 81, 57, 20, 36, 36, 36, 43, 43, 75, 43, 43, - 43, 43, 75, 43, 75, 43, 43, 44, 2, 2, 2, 2, 2, 2, 2, 64, - 36, 36, 36, 36, 70, 43, 44, 64, 36, 36, 36, 36, 36, 61, 44, 44, - 36, 36, 36, 36, 82, 36, 36, 61, 65, 44, 44, 57, 43, 43, 43, 43, - 36, 36, 36, 36, 83, 43, 43, 43, 43, 84, 43, 43, 43, 43, 43, 43, - 43, 85, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 85, 71, 86, - 87, 43, 43, 43, 85, 86, 87, 86, 70, 43, 43, 43, 36, 36, 36, 36, - 36, 43, 2, 7, 7, 7, 7, 7, 88, 36, 36, 36, 36, 36, 36, 36, - 70, 86, 62, 36, 36, 36, 61, 62, 61, 62, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 61, 36, 36, 36, 61, 61, 44, 36, 36, 44, 71, 86, - 87, 43, 80, 89, 90, 89, 87, 61, 44, 44, 44, 89, 44, 44, 36, 62, - 36, 43, 44, 7, 7, 7, 7, 7, 36, 20, 27, 27, 27, 56, 63, 80, - 57, 85, 62, 36, 36, 61, 44, 62, 61, 36, 62, 61, 36, 44, 80, 86, - 87, 80, 44, 57, 80, 57, 43, 44, 57, 44, 44, 44, 62, 36, 61, 61, - 44, 44, 44, 7, 7, 7, 7, 7, 43, 36, 70, 64, 44, 44, 44, 44, - 57, 85, 62, 36, 36, 36, 36, 62, 36, 62, 36, 36, 36, 36, 36, 36, - 61, 36, 62, 36, 36, 44, 71, 86, 87, 43, 43, 57, 85, 89, 87, 44, - 61, 44, 44, 44, 44, 44, 44, 44, 66, 44, 44, 44, 62, 43, 43, 43, - 57, 86, 62, 36, 36, 36, 61, 62, 61, 36, 62, 36, 36, 44, 71, 87, - 87, 43, 80, 89, 90, 89, 87, 44, 44, 44, 57, 85, 44, 44, 36, 62, - 78, 27, 27, 27, 44, 44, 44, 44, 44, 71, 62, 36, 36, 61, 44, 36, - 61, 36, 36, 44, 62, 61, 61, 36, 44, 62, 61, 44, 36, 61, 44, 36, - 36, 36, 36, 36, 36, 44, 44, 86, 85, 90, 44, 86, 90, 86, 87, 44, - 61, 44, 44, 89, 44, 44, 44, 44, 27, 91, 67, 67, 56, 92, 44, 44, - 85, 86, 71, 36, 36, 36, 61, 36, 61, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 44, 71, 43, 85, 86, 90, 43, 80, 43, 43, 44, - 44, 44, 57, 80, 36, 61, 62, 44, 44, 44, 44, 93, 27, 27, 27, 91, - 70, 86, 72, 36, 36, 36, 61, 36, 36, 36, 62, 36, 36, 44, 71, 87, - 86, 86, 90, 85, 90, 86, 43, 44, 44, 44, 89, 90, 44, 44, 62, 61, - 62, 94, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36, - 36, 36, 36, 36, 36, 70, 71, 86, 87, 43, 80, 86, 90, 86, 87, 77, - 44, 44, 36, 94, 27, 27, 27, 95, 27, 27, 27, 27, 91, 36, 36, 36, - 57, 86, 62, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 36, 36, 36, - 36, 62, 36, 36, 36, 36, 62, 44, 36, 36, 36, 61, 44, 80, 44, 89, - 86, 43, 80, 80, 86, 86, 86, 86, 44, 86, 64, 44, 44, 44, 44, 44, - 62, 36, 36, 36, 36, 36, 36, 36, 70, 36, 43, 43, 43, 80, 44, 96, - 36, 36, 36, 75, 43, 43, 43, 60, 7, 7, 7, 7, 7, 2, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 62, 61, 61, 36, 36, 61, 36, 36, - 36, 36, 62, 62, 36, 36, 36, 36, 70, 36, 43, 43, 43, 43, 71, 44, - 36, 36, 61, 81, 43, 43, 43, 80, 7, 7, 7, 7, 7, 44, 36, 36, - 77, 67, 2, 2, 2, 2, 2, 2, 2, 97, 97, 67, 43, 67, 67, 67, - 7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 50, 50, 50, 4, 4, 86, - 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, - 57, 43, 43, 43, 43, 43, 43, 85, 43, 43, 60, 43, 36, 36, 70, 43, - 43, 43, 43, 43, 57, 43, 43, 43, 43, 43, 43, 43, 43, 43, 80, 67, - 67, 67, 67, 76, 67, 67, 92, 67, 2, 2, 97, 67, 21, 64, 44, 44, - 36, 36, 36, 36, 36, 94, 87, 43, 85, 43, 43, 43, 87, 85, 87, 71, - 7, 7, 7, 7, 7, 2, 2, 2, 36, 36, 36, 86, 43, 36, 36, 43, - 71, 86, 98, 94, 86, 86, 86, 36, 70, 43, 71, 36, 36, 36, 36, 36, - 36, 85, 87, 85, 86, 86, 87, 94, 7, 7, 7, 7, 7, 86, 87, 67, - 11, 11, 11, 48, 44, 44, 48, 44, 16, 16, 16, 16, 16, 53, 45, 16, - 36, 36, 36, 36, 61, 36, 36, 44, 36, 36, 36, 61, 61, 36, 36, 44, - 61, 36, 36, 44, 36, 36, 36, 61, 61, 36, 36, 44, 36, 36, 36, 36, - 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 57, 43, - 2, 2, 2, 2, 99, 27, 27, 27, 27, 27, 27, 27, 27, 27,100, 44, - 67, 67, 67, 67, 67, 44, 44, 44, 11, 11, 11, 44, 16, 16, 16, 44, - 101, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 77, 72, - 102, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,103,104, 44, - 36, 36, 36, 36, 36, 63, 2,105,106, 36, 36, 36, 61, 44, 44, 44, - 36, 43, 85, 44, 44, 44, 44, 62, 36, 43,107, 64, 44, 44, 44, 44, - 36, 43, 44, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 61, 36, - 61, 43, 44, 44, 44, 44, 44, 44, 36, 36, 43, 87, 43, 43, 43, 86, - 86, 86, 86, 85, 87, 43, 43, 43, 43, 43, 2, 88, 2, 66, 70, 44, - 7, 7, 7, 7, 7, 44, 44, 44, 27, 27, 27, 27, 27, 44, 44, 44, - 2, 2, 2,108, 2, 59, 43, 84, 36, 83, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 61, 44, 44, 44, 36, 36, 70, 71, 36, 36, 36, 36, - 36, 36, 36, 36, 70, 61, 44, 44, 36, 36, 36, 44, 44, 44, 44, 44, - 36, 36, 36, 36, 36, 36, 36, 61, 43, 85, 86, 87, 85, 86, 44, 44, - 86, 85, 86, 86, 87, 43, 44, 44, 92, 44, 2, 7, 7, 7, 7, 7, - 36, 36, 36, 36, 36, 36, 36, 44, 36, 36, 61, 44, 44, 44, 44, 44, - 36, 36, 36, 36, 36, 36, 44, 44, 36, 36, 36, 36, 36, 44, 44, 44, - 7, 7, 7, 7, 7,100, 44, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 36, 36, 36, 70, 85, 87, 44, 2, 36, 36, 94, 85, 43, 43, 43, 80, - 85, 85, 87, 43, 43, 43, 85, 86, 86, 87, 43, 43, 43, 43, 80, 57, - 2, 2, 2, 88, 2, 2, 2, 44, 43, 43, 43, 43, 43, 43, 43,109, - 43, 43, 43, 43, 43, 43, 43, 80, 43, 43, 98, 36, 36, 36, 36, 36, - 36, 36, 85, 43, 43, 85, 85, 86, 86, 85, 98, 36, 36, 36, 61, 2, - 97, 67, 67, 67, 67, 50, 43, 43, 43, 43, 67, 67, 67, 67, 21, 2, - 43, 98, 36, 36, 36, 36, 36, 36, 94, 43, 43, 86, 43, 87, 43, 36, - 36, 36, 36, 85, 43, 86, 87, 87, 43, 86, 44, 44, 44, 44, 2, 2, - 36, 36, 86, 86, 86, 86, 43, 43, 43, 43, 86, 43, 44, 93, 2, 2, - 7, 7, 7, 7, 7, 44, 62, 36, 36, 36, 36, 36, 40, 40, 40, 2, - 16, 16, 16, 16, 34,110, 44, 44, 11, 11, 11, 11, 11, 47, 48, 11, - 2, 2, 2, 2, 44, 44, 44, 44, 43, 60, 43, 43, 43, 43, 43, 43, - 85, 43, 43, 43, 71, 36, 70, 36, 36, 36, 71, 94, 43, 61, 44, 44, - 16, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 45, 16, 16, - 16, 16, 16, 16, 45, 16, 16, 16, 16, 16, 16, 16, 16,111, 40, 40, - 32, 32, 32, 16, 16, 16, 16, 32, 16, 16, 16, 16, 11, 11, 11, 11, - 16, 16, 16, 44, 11, 11, 11, 44, 16, 16, 16, 16, 48, 48, 48, 48, - 16, 16, 16, 16, 16, 16, 16, 44, 16, 16, 16, 16,112,112,112,112, - 16, 16,110, 16, 11, 11,113,114, 41, 16,110, 16, 11, 11,113, 41, - 16, 16, 44, 16, 11, 11,115, 41, 16, 16, 16, 16, 11, 11,116, 41, - 44, 16,110, 16, 11, 11,113,117,118,118,118,118,118,119, 65, 65, - 120,120,120, 2,121,122,121,122, 2, 2, 2, 2,123, 65, 65,124, - 2, 2, 2, 2,125,126, 2,127,128, 2,129,130, 2, 2, 2, 2, - 2, 9,128, 2, 2, 2, 2,131, 65, 65,132, 65, 65, 65, 65, 65, - 133, 44, 27, 27, 27, 8,129,134, 27, 27, 27, 27, 27, 8,129,104, - 40, 40, 40, 40, 40, 40, 81, 44, 20, 20, 20, 20, 20, 20, 20, 20, - 135, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 43, 43,136, 51, - 109, 51,109, 43, 43, 43, 43, 43, 80, 44, 44, 44, 44, 44, 44, 44, - 67,137, 67,138, 67, 34, 11, 16, 11, 32,138, 67, 49, 11, 11, 67, - 67, 67,137,137,137, 11, 11,139, 11, 11, 35, 36, 39, 67, 16, 11, - 8, 8, 49, 16, 16, 26, 67,140, 27, 27, 27, 27, 27, 27, 27, 27, - 105,105,105,105,105,105,105,105,105,141,142,105,143, 67, 44, 44, - 8, 8,144, 67, 67, 8, 67, 67,144, 26, 67,144, 67, 67, 67,144, - 67, 67, 67, 67, 67, 67, 67, 8, 67,144,144, 67, 67, 67, 67, 67, - 67, 67, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 67, 67, 67, 67, 4, 4, 67, 67, 8, 67, 67, 67,145,146, 67, 67, - 67, 67, 67, 67, 67, 67,144, 67, 67, 67, 67, 67, 67, 26, 8, 8, - 8, 8, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 8, 8, - 8, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 92, 44, 44, - 27, 27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, - 67, 67, 67, 26, 67, 67, 67, 67, 26, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 8, 8, 8, 8, 67, 67, 67, 67, 67, 67, 67, 26, - 67, 67, 67, 67, 4, 4, 4, 4, 4, 4, 4, 27, 27, 27, 27, 27, - 27, 27, 67, 67, 67, 67, 67, 67, 8, 8,129,147, 8, 8, 8, 8, - 8, 8, 8, 4, 4, 4, 4, 4, 8,129,148,148,148,148,148,148, - 148,148,148,148,147, 8, 8, 8, 8, 8, 8, 8, 4, 4, 8, 8, - 8, 8, 8, 8, 8, 8, 4, 8, 8, 8,144, 26, 8, 8,144, 67, - 67, 67, 44, 67, 67, 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 67, - 32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 40, 11, - 32, 32,140, 67, 67,138, 34,149, 43, 32, 44, 44, 93, 2, 99, 2, - 16, 16, 16,150, 44, 44,150, 44, 36, 36, 36, 36, 44, 44, 44, 52, - 64, 44, 44, 44, 44, 44, 44, 57, 36, 36, 36, 61, 44, 44, 44, 44, - 36, 36, 36, 61, 36, 36, 36, 61, 2,121,121, 2,125,126,121, 2, - 2, 2, 2, 6, 2,108,121, 2,121, 4, 4, 4, 4, 2, 2, 88, - 2, 2, 2, 2, 2,120, 2, 2,108,151, 2, 2, 2, 2, 2, 2, - 67, 2,152,148,148,148,153, 44, 67, 67, 67, 67, 67, 55, 67, 67, - 67, 67, 44, 44, 44, 44, 44, 44, 67, 67, 67, 44, 44, 44, 44, 44, - 1, 2,154,155, 4, 4, 4, 4, 4, 67, 4, 4, 4, 4,156,157, - 158,105,105,105,105, 43, 43, 86,159, 40, 40, 67,105,160, 63, 67, - 36, 36, 36, 61, 57,161,162, 69, 36, 36, 36, 36, 36, 63, 40, 69, - 44, 44, 62, 36, 36, 36, 36, 36, 67, 27, 27, 67, 67, 67, 67, 67, - 67, 67, 67, 44, 44, 44, 44, 55, 67, 67, 67, 67, 67, 67, 67, 92, - 27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, 27, - 163, 27, 27, 27, 27, 27, 27, 27, 36, 36, 83, 36, 36, 36, 36, 36, - 67, 67, 67, 92, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36,164, 2, - 7, 7, 7, 7, 7, 36, 44, 44, 32, 32, 32, 32, 32, 32, 32, 70, - 51,165, 43, 43, 43, 43, 43, 88, 32, 32, 32, 32, 32, 32, 40, 43, - 36, 36, 36,105,105,105,105,105, 43, 2, 2, 2, 44, 44, 44, 44, - 41, 41, 41,162, 40, 40, 40, 40, 41, 32, 32, 32, 32, 32, 32, 32, - 16, 32, 32, 32, 32, 32, 32, 32, 45, 16, 16, 16, 34, 34, 34, 32, - 32, 32, 32, 32, 42,166, 34, 35, 32, 32, 16, 32, 32, 32, 32, 32, + 16, 16, 36, 16, 16, 16, 16, 16, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 40, 40, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, + 39, 39, 41, 40, 40, 40, 41, 41, 40, 40, 40, 40, 40, 40, 40, 40, + 42, 42, 42, 42, 42, 42, 42, 42, 32, 32, 41, 32, 43, 44, 16, 10, + 43, 43, 40, 45, 11, 46, 46, 11, 34, 11, 11, 11, 11, 11, 11, 11, + 11, 47, 11, 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 34, + 16, 11, 32, 16, 32, 32, 32, 32, 16, 16, 32, 48, 34, 32, 34, 11, + 32, 49, 42, 42, 50, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16, + 47, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 46, 51, 2, 2, 2, + 16, 16, 16, 16, 52, 53, 54, 55, 56, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 57, 58, 59, 42, 58, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43, 61, + 36, 62, 63, 43, 43, 43, 43, 43, 64, 64, 64, 8, 9, 65, 2, 66, + 42, 42, 42, 42, 42, 59, 67, 2, 68, 36, 36, 36, 36, 69, 42, 42, + 7, 7, 7, 7, 7, 2, 2, 36, 70, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 71, 42, 42, 42, 72, 49, 42, 42, 73, 74, 75, 42, 42, 36, + 7, 7, 7, 7, 7, 36, 76, 77, 2, 2, 2, 2, 2, 2, 2, 78, + 69, 36, 36, 36, 36, 36, 36, 36, 42, 42, 42, 42, 42, 79, 61, 36, + 36, 36, 36, 42, 42, 42, 42, 42, 70, 43, 43, 43, 43, 43, 43, 43, + 7, 7, 7, 7, 7, 36, 36, 36, 36, 36, 36, 36, 36, 69, 42, 42, + 42, 42, 39, 21, 2, 80, 56, 20, 36, 36, 36, 42, 42, 74, 42, 42, + 42, 42, 74, 42, 74, 42, 42, 43, 2, 2, 2, 2, 2, 2, 2, 63, + 36, 36, 36, 36, 69, 42, 43, 63, 36, 36, 36, 36, 36, 60, 43, 43, + 36, 36, 36, 36, 81, 36, 36, 36, 64, 43, 43, 56, 42, 42, 42, 42, + 36, 36, 36, 36, 82, 42, 42, 42, 42, 83, 42, 42, 42, 42, 42, 42, + 42, 84, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 84, 70, 85, + 86, 42, 42, 42, 84, 85, 86, 85, 69, 42, 42, 42, 36, 36, 36, 36, + 36, 42, 2, 7, 7, 7, 7, 7, 87, 36, 36, 36, 36, 36, 36, 36, + 69, 85, 61, 36, 36, 36, 60, 61, 60, 61, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 60, 36, 36, 36, 60, 60, 43, 36, 36, 43, 70, 85, + 86, 42, 79, 88, 89, 88, 86, 60, 43, 43, 43, 88, 43, 43, 36, 61, + 36, 42, 43, 7, 7, 7, 7, 7, 36, 20, 27, 27, 27, 55, 62, 79, + 56, 84, 61, 36, 36, 60, 43, 61, 60, 36, 61, 60, 36, 43, 79, 85, + 86, 79, 43, 56, 79, 56, 42, 43, 56, 43, 43, 43, 61, 36, 60, 60, + 43, 43, 43, 7, 7, 7, 7, 7, 42, 36, 69, 63, 43, 43, 43, 43, + 56, 84, 61, 36, 36, 36, 36, 61, 36, 61, 36, 36, 36, 36, 36, 36, + 60, 36, 61, 36, 36, 43, 70, 85, 86, 42, 42, 56, 84, 88, 86, 43, + 60, 43, 43, 43, 43, 43, 43, 43, 65, 43, 43, 43, 61, 42, 42, 42, + 56, 85, 61, 36, 36, 36, 60, 61, 60, 36, 61, 36, 36, 43, 70, 86, + 86, 42, 79, 88, 89, 88, 86, 43, 43, 43, 56, 84, 43, 43, 36, 61, + 77, 27, 27, 27, 43, 43, 43, 43, 43, 70, 61, 36, 36, 60, 43, 36, + 60, 36, 36, 43, 61, 60, 60, 36, 43, 61, 60, 43, 36, 60, 43, 36, + 36, 36, 36, 36, 36, 43, 43, 85, 84, 89, 43, 85, 89, 85, 86, 43, + 60, 43, 43, 88, 43, 43, 43, 43, 27, 90, 66, 66, 55, 91, 43, 43, + 84, 85, 70, 36, 36, 36, 60, 36, 60, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 43, 70, 42, 84, 85, 89, 42, 79, 42, 42, 43, + 43, 43, 56, 79, 36, 60, 36, 43, 43, 43, 43, 92, 27, 27, 27, 90, + 69, 85, 71, 36, 36, 36, 60, 36, 36, 36, 61, 36, 36, 43, 70, 86, + 85, 85, 89, 84, 89, 85, 42, 43, 43, 43, 88, 89, 43, 43, 36, 60, + 61, 93, 43, 43, 43, 43, 43, 43, 42, 85, 36, 36, 36, 36, 60, 36, + 36, 36, 36, 36, 36, 69, 70, 85, 86, 42, 79, 85, 89, 85, 86, 76, + 43, 43, 36, 93, 27, 27, 27, 94, 27, 27, 27, 27, 90, 36, 36, 36, + 56, 85, 61, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43, 36, 36, 36, + 36, 61, 36, 36, 36, 36, 61, 43, 36, 36, 36, 60, 43, 79, 43, 88, + 85, 42, 79, 79, 85, 85, 85, 85, 43, 85, 63, 43, 43, 43, 43, 43, + 61, 36, 36, 36, 36, 36, 36, 36, 69, 36, 42, 42, 42, 79, 43, 95, + 36, 36, 36, 74, 42, 42, 42, 59, 7, 7, 7, 7, 7, 2, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 61, 60, 60, 36, 36, 60, 36, 36, + 36, 36, 61, 61, 36, 36, 36, 36, 69, 36, 42, 42, 42, 42, 70, 43, + 36, 36, 60, 80, 42, 42, 42, 79, 7, 7, 7, 7, 7, 43, 36, 36, + 76, 66, 2, 2, 2, 2, 2, 2, 2, 96, 96, 66, 42, 66, 66, 66, + 7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 49, 49, 49, 4, 4, 85, + 36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43, + 56, 42, 42, 42, 42, 42, 42, 84, 42, 42, 59, 42, 36, 36, 69, 42, + 42, 42, 42, 42, 56, 42, 42, 42, 42, 42, 42, 42, 42, 42, 79, 66, + 66, 66, 66, 75, 66, 66, 91, 66, 2, 2, 96, 66, 21, 63, 43, 43, + 36, 36, 36, 36, 36, 93, 86, 42, 84, 42, 42, 42, 86, 84, 86, 70, + 7, 7, 7, 7, 7, 2, 2, 2, 36, 36, 36, 85, 42, 36, 36, 42, + 70, 85, 97, 93, 85, 85, 85, 36, 69, 42, 70, 36, 36, 36, 36, 36, + 36, 84, 86, 84, 85, 85, 86, 93, 7, 7, 7, 7, 7, 85, 86, 66, + 11, 11, 11, 47, 43, 43, 47, 43, 16, 16, 16, 16, 16, 52, 44, 16, + 36, 36, 36, 36, 60, 36, 36, 43, 36, 36, 36, 60, 60, 36, 36, 43, + 60, 36, 36, 43, 36, 36, 36, 60, 60, 36, 36, 43, 36, 36, 36, 36, + 36, 36, 36, 60, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 56, 42, + 2, 2, 2, 2, 98, 27, 27, 27, 27, 27, 27, 27, 27, 27, 99, 43, + 66, 66, 66, 66, 66, 43, 43, 43, 11, 11, 11, 43, 16, 16, 16, 43, + 100, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 76, 71, + 101, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,102,103, 43, + 36, 36, 36, 36, 36, 62, 2,104,105, 36, 36, 36, 60, 43, 43, 43, + 36, 42, 84, 43, 43, 43, 43, 61, 36, 42,106, 63, 43, 43, 43, 43, + 36, 42, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36, 60, 36, + 60, 42, 43, 43, 43, 43, 43, 43, 36, 36, 42, 86, 42, 42, 42, 85, + 85, 85, 85, 84, 86, 42, 42, 42, 42, 42, 2, 87, 2, 65, 69, 43, + 7, 7, 7, 7, 7, 43, 43, 43, 27, 27, 27, 27, 27, 43, 43, 43, + 2, 2, 2,107, 2, 58, 42, 83, 36, 82, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 60, 43, 43, 43, 36, 36, 69, 70, 36, 36, 36, 36, + 36, 36, 36, 36, 69, 60, 43, 43, 36, 36, 36, 43, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 36, 36, 60, 42, 84, 85, 86, 84, 85, 43, 43, + 85, 84, 85, 85, 86, 42, 43, 43, 91, 43, 2, 7, 7, 7, 7, 7, + 36, 36, 36, 36, 36, 36, 36, 43, 36, 36, 60, 43, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 36, 43, 43, 36, 36, 36, 36, 36, 43, 43, 43, + 7, 7, 7, 7, 7, 99, 43, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 36, 36, 36, 69, 84, 86, 43, 2, 36, 36, 93, 84, 42, 42, 42, 79, + 84, 84, 86, 42, 42, 42, 84, 85, 85, 86, 42, 42, 42, 42, 79, 56, + 2, 2, 2, 87, 2, 2, 2, 43, 42, 42, 42, 42, 42, 42, 42,108, + 42, 42, 42, 42, 42, 42, 42, 43, 42, 42, 42, 42, 42, 42, 43, 43, + 42, 42, 97, 36, 36, 36, 36, 36, 36, 36, 84, 42, 42, 84, 84, 85, + 85, 84, 97, 36, 36, 36, 60, 2, 96, 66, 66, 66, 66, 49, 42, 42, + 42, 42, 66, 66, 66, 66, 21, 2, 42, 97, 36, 36, 36, 36, 36, 36, + 93, 42, 42, 85, 42, 86, 42, 36, 36, 36, 36, 84, 42, 85, 86, 86, + 42, 85, 43, 43, 43, 43, 2, 2, 36, 36, 85, 85, 85, 85, 42, 42, + 42, 42, 85, 42, 43, 92, 2, 2, 7, 7, 7, 7, 7, 43, 61, 36, + 36, 36, 36, 36, 39, 39, 39, 2, 16, 16, 16, 16, 34,109, 43, 43, + 11, 11, 11, 11, 11, 46, 47, 11, 2, 2, 2, 2, 43, 43, 43, 43, + 42, 59, 42, 42, 42, 42, 42, 42, 84, 42, 42, 42, 70, 36, 69, 36, + 36, 36, 70, 93, 42, 60, 43, 43, 16, 16, 16, 16, 16, 16, 39, 39, + 39, 39, 39, 39, 39, 44, 16, 16, 16, 16, 16, 16, 44, 16, 16, 16, + 16, 16, 16, 16, 16,110, 39, 39, 32, 32, 32, 16, 16, 16, 16, 32, + 16, 16, 16, 16, 11, 11, 11, 11, 16, 16, 16, 43, 11, 11, 11, 43, + 16, 16, 16, 16, 47, 47, 47, 47, 16, 16, 16, 16, 16, 16, 16, 43, + 16, 16, 16, 16,111,111,111,111, 16, 16,109, 16, 11, 11,112,113, + 40, 16,109, 16, 11, 11,112, 40, 16, 16, 43, 16, 11, 11,114, 40, + 16, 16, 16, 16, 11, 11,115, 40, 43, 16,109, 16, 11, 11,112,116, + 117,117,117,117,117,118, 64, 64,119,119,119, 2,120,121,120,121, + 2, 2, 2, 2,122, 64, 64,123, 2, 2, 2, 2,124,125, 2,126, + 127, 2,128,129, 2, 2, 2, 2, 2, 9,127, 2, 2, 2, 2,130, + 64, 64,131, 64, 64, 64, 64, 64,132, 43, 27, 27, 27, 8,128,133, + 27, 27, 27, 27, 27, 8,128,103, 39, 39, 39, 39, 39, 39, 80, 43, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 43, 43, 43, 43, 43, 43, 43, + 42, 42, 42, 42, 42, 42,134, 50,108, 50,108, 42, 42, 42, 42, 42, + 79, 43, 43, 43, 43, 43, 43, 43, 66,135, 66,136, 66, 34, 11, 16, + 11, 32,136, 66, 48, 11, 11, 66, 66, 66,135,135,135, 11, 11,137, + 11, 11, 35, 36,138, 66, 16, 11, 8, 8, 48, 16, 16, 26, 66,139, + 27, 27, 27, 27, 27, 27, 27, 27,104,104,104,104,104,104,104,104, + 104,140,141,104,142, 66, 43, 43, 8, 8,143, 66, 66, 8, 66, 66, + 143, 26, 66,143, 66, 66, 66,143, 66, 66, 66, 66, 66, 66, 66, 8, + 66,143,143, 66, 66, 66, 66, 66, 66, 66, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 66, 66, 66, 66, 4, 4, 66, 66, + 8, 66, 66, 66,144,145, 66, 66, 66, 66, 66, 66, 66, 66,143, 66, + 66, 66, 66, 66, 66, 26, 8, 8, 8, 8, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 8, 8, 8, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 91, 43, 43, 27, 27, 27, 27, 27, 27, 66, 66, + 66, 66, 66, 66, 66, 27, 27, 27, 66, 66, 66, 26, 66, 66, 66, 66, + 26, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 8, 8, 8, 8, + 66, 66, 66, 66, 66, 66, 66, 26, 66, 66, 66, 66, 4, 4, 4, 4, + 4, 4, 4, 27, 27, 27, 27, 27, 27, 27, 66, 66, 66, 66, 66, 66, + 8, 8,128,146, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, + 8,128,147,147,147,147,147,147,147,147,147,147,146, 8, 8, 8, + 8, 8, 8, 8, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8, + 8, 8,143, 26, 8, 8,143, 66, 66, 66, 43, 66, 66, 66, 66, 66, + 32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 39, 11, + 32, 32,139, 66, 66,136, 34,148, 42, 32, 43, 43, 92, 2, 98, 2, + 16, 16, 16,149, 43, 43,149, 43, 36, 36, 36, 36, 43, 43, 43, 51, + 63, 43, 43, 43, 43, 43, 43, 56, 36, 36, 36, 60, 43, 43, 43, 43, + 36, 36, 36, 60, 36, 36, 36, 60, 2,120,120, 2,124,125,120, 2, + 2, 2, 2, 6, 2,107,120, 2,120, 4, 4, 4, 4, 2, 2, 87, + 2, 2, 2, 2, 2,119, 2, 2,107,150, 2, 2, 2, 2, 2, 2, + 66, 2,151,147,147,147,152, 43, 66, 66, 66, 66, 66, 54, 66, 66, + 66, 66, 43, 43, 43, 43, 43, 43, 66, 66, 66, 43, 43, 43, 43, 43, + 1, 2,153,154, 4, 4, 4, 4, 4, 66, 4, 4, 4, 4,155,156, + 157,104,104,104,104, 42, 42, 85,158, 39, 39, 66,104,159, 62, 66, + 36, 36, 36, 60, 56,160,161, 68, 36, 36, 36, 36, 36, 62, 39, 68, + 43, 43, 61, 36, 36, 36, 36, 36, 66, 27, 27, 66, 66, 66, 66, 66, + 66, 66, 66, 43, 43, 43, 43, 54, 66, 66, 66, 66, 66, 66, 66, 91, + 27, 27, 27, 27, 27, 66, 66, 66, 66, 66, 66, 66, 27, 27, 27, 27, + 162, 27, 27, 27, 27, 27, 27, 27, 36, 36, 82, 36, 36, 36, 36, 36, + 66, 66, 66, 91, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36,163, 2, + 7, 7, 7, 7, 7, 36, 43, 43, 32, 32, 32, 32, 32, 32, 32, 69, + 50,164, 42, 42, 42, 42, 42, 87, 32, 32, 32, 32, 32, 32, 39, 42, + 36, 36, 36,104,104,104,104,104, 42, 2, 2, 2, 43, 43, 43, 43, + 40, 40, 40,161, 39, 39, 39, 39, 40, 32, 32, 32, 32, 32, 32, 32, + 16, 32, 32, 32, 32, 32, 32, 32, 44, 16, 16, 16, 34, 34, 34, 32, + 32, 32, 32, 32, 41,165, 34, 35, 32, 32, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 11, 11, 32, 11, 11, 32, 32, 32, 32, 32, 32, - 32, 32, 11, 11, 34, 34, 32, 44, 32,150,150, 32, 32, 32, 47, 44, - 44, 40,167, 35, 40, 35, 36, 36, 36, 71, 36, 71, 36, 70, 36, 36, - 36, 94, 87, 85, 67, 67, 80, 44, 27, 27, 27, 67,168, 44, 44, 44, - 36, 36, 2, 2, 44, 44, 44, 44, 86, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 86, 86, 86, 86, 86, 86, 86, 86, 43, 44, 44, 44, 44, 2, - 43, 36, 36, 36, 2, 72, 72, 70, 36, 36, 36, 43, 43, 43, 43, 2, - 36, 36, 36, 70, 43, 43, 43, 43, 43, 86, 44, 44, 44, 44, 44, 93, - 36, 70, 86, 43, 43, 86, 43, 86,107, 2, 2, 2, 2, 2, 2, 52, - 7, 7, 7, 7, 7, 44, 44, 2, 36, 36, 70, 69, 36, 36, 36, 36, - 7, 7, 7, 7, 7, 36, 36, 61, 36, 36, 36, 36, 70, 43, 43, 85, - 87, 85, 87, 80, 44, 44, 44, 44, 36, 70, 36, 36, 36, 36, 85, 44, - 7, 7, 7, 7, 7, 44, 2, 2, 69, 36, 36, 77, 67, 94, 85, 36, - 71, 43, 71, 70, 71, 36, 36, 43, 70, 61, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 62, 83, 2, 36, 36, 36, 36, 36, 94, 43, 86, - 2, 83,169, 80, 44, 44, 44, 44, 62, 36, 36, 61, 62, 36, 36, 61, - 62, 36, 36, 61, 44, 44, 44, 44, 16, 16, 16, 16, 16,114, 40, 40, - 16, 16, 16, 16,111, 41, 44, 44, 36, 94, 87, 86, 85,107, 87, 44, - 36, 36, 44, 44, 44, 44, 44, 44, 36, 36, 36, 61, 44, 62, 36, 36, - 170,170,170,170,170,170,170,170,171,171,171,171,171,171,171,171, - 16, 16, 16,110, 44, 44, 44, 44, 44,150, 16, 16, 44, 44, 62, 71, - 36, 36, 36, 36,172, 36, 36, 36, 36, 36, 36, 61, 36, 36, 61, 61, - 36, 62, 61, 36, 36, 36, 36, 36, 36, 41, 41, 41, 41, 41, 41, 41, - 41,117, 44, 44, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36,148, 44, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 44, 44, 44, 55, 36, 36, 36, 36, 36, 36,168, 67, - 2, 2, 2,152,130, 44, 44, 44, 6,173,174,148,148,148,148,148, - 148,148,130,152,130, 2,127,175, 2, 64, 2, 2,156,148,148,130, - 2,176, 8,177, 66, 2, 44, 44, 36, 36, 61, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 61, 79, 93, 2, 3, 2, 4, 5, 6, 2, - 16, 16, 16, 16, 16, 17, 18,129,130, 4, 2, 36, 36, 36, 36, 36, - 69, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 40, - 44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 61, 44, - 20,178, 56,135, 26, 8,144, 92, 44, 44, 44, 44, 79, 65, 67, 44, - 36, 36, 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 61, 36, 62, - 2, 64, 44,179, 27, 27, 27, 27, 27, 27, 44, 55, 67, 67, 67, 67, - 105,105,143, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 27, 67, 92, - 67, 67, 67, 67, 67, 67, 92, 44, 92, 44, 44, 44, 44, 44, 44, 44, - 67, 67, 67, 67, 67, 67, 50, 44,180, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 44, 44, 27, 27, 44, 44, 44, 44, 62, 36, - 155, 36, 36, 36, 36,181, 44, 44, 36, 36, 36, 43, 43, 80, 44, 44, - 36, 36, 36, 36, 36, 36, 36, 93, 36, 36, 44, 44, 36, 36, 36, 36, - 182,105,105, 44, 44, 44, 44, 44, 11, 11, 11, 11, 16, 16, 16, 16, - 11, 11, 44, 44, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 44, 44, - 36, 36, 36, 36, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44, 44, 93, - 11, 11, 11, 11, 11, 47, 11, 11, 11, 47, 11,150, 16, 16, 16, 16, - 16,150, 16, 16, 16, 16, 16, 16, 16,150, 16, 16, 16,150,110, 44, - 40, 40, 40, 52, 40, 40, 40, 40, 81, 40, 40, 40, 40, 81, 44, 44, - 36, 36, 36, 44, 61, 36, 36, 36, 36, 36, 36, 62, 61, 44, 61, 62, - 36, 36, 36, 93, 27, 27, 27, 27, 36, 36, 36, 77,163, 27, 27, 27, - 44, 44, 44,179, 27, 27, 27, 27, 36, 61, 36, 44, 44,179, 27, 27, - 36, 36, 36, 27, 27, 27, 44, 93, 36, 36, 36, 36, 36, 44, 44, 93, - 36, 36, 36, 36, 44, 44, 27, 36, 44, 27, 27, 27, 27, 27, 27, 27, - 70, 43, 57, 80, 44, 44, 43, 43, 36, 36, 62, 36, 62, 36, 36, 36, - 36, 36, 36, 44, 43, 80, 44, 57, 27, 27, 27, 27,100, 44, 44, 44, - 2, 2, 2, 2, 64, 44, 44, 44, 36, 36, 36, 36, 36, 36,183, 30, - 36, 36, 36, 36, 36, 36,183, 27, 36, 36, 36, 36, 78, 36, 36, 36, - 36, 36, 70, 80, 44,179, 27, 27, 2, 2, 2, 64, 44, 44, 44, 44, - 36, 36, 36, 44, 93, 2, 2, 2, 36, 36, 36, 44, 27, 27, 27, 27, - 36, 61, 44, 44, 27, 27, 27, 27, 36, 44, 44, 44, 93, 2, 64, 44, - 44, 44, 44, 44,179, 27, 27, 27, 11, 47, 44, 44, 44, 44, 44, 44, - 16,110, 44, 44, 44, 27, 27, 27, 36, 36, 43, 43, 44, 44, 44, 44, - 7, 7, 7, 7, 7, 36, 36, 69, 11, 11, 11, 44, 57, 43, 43,159, - 16, 16, 16, 44, 44, 44, 44, 8, 27, 27, 27, 27, 27, 27, 27,100, - 36, 36, 36, 36, 36, 57,184, 44, 36, 44, 44, 44, 44, 44, 44, 44, - 44, 36, 61, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 43, 43, - 27, 27, 27, 95, 44, 44, 44, 44,180, 27, 30, 2, 2, 44, 44, 44, - 36, 43, 43, 2, 2, 44, 44, 44, 36, 36,183, 27, 27, 27, 44, 44, - 87, 98, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, - 43, 43, 43, 60, 2, 2, 2, 44, 27, 27, 27, 7, 7, 7, 7, 7, - 71, 70, 71, 44, 44, 44, 44, 57, 86, 87, 43, 85, 87, 60,185, 2, - 2, 80, 44, 44, 44, 44, 79, 44, 43, 71, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 70, 43, 43, 87, 43, 43, 43, 80, 7, 7, 7, 7, 7, - 2, 2, 94, 98, 44, 44, 44, 44, 36, 70, 2, 61, 44, 44, 44, 44, - 36, 94, 86, 43, 43, 43, 43, 85, 98, 36, 63, 2, 59, 43, 60, 87, - 7, 7, 7, 7, 7, 63, 63, 2,179, 27, 27, 27, 27, 27, 27, 27, - 27, 27,100, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 86, 87, - 43, 86, 85, 43, 2, 2, 2, 71, 70, 44, 44, 44, 44, 44, 44, 44, - 36, 36, 36, 61, 61, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 62, - 36, 36, 36, 36, 63, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 70, - 86, 87, 43, 43, 43, 80, 44, 44, 43, 86, 62, 36, 36, 36, 61, 62, - 61, 36, 62, 36, 36, 57, 71, 86, 85, 86, 90, 89, 90, 89, 86, 44, - 61, 44, 44, 89, 44, 44, 62, 36, 36, 86, 44, 43, 43, 43, 80, 44, - 43, 43, 80, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 62, 44, 61, - 36, 36, 36, 62, 86, 87, 43, 43, 80, 90, 89, 89, 86, 90, 86, 85, - 71, 71, 2, 93, 64, 44, 44, 44, 57, 80, 44, 44, 44, 44, 44, 44, - 36, 36, 94, 86, 43, 43, 43, 43, 86, 43, 85, 71, 36, 63, 2, 2, - 7, 7, 7, 7, 7, 2, 93, 71, 86, 87, 43, 43, 85, 85, 86, 87, - 85, 43, 36, 72, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 94, - 86, 43, 43, 44, 86, 86, 43, 87, 60, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 36, 36, 43, 44, 86, 87, 43, 43, 43, 85, 87, 87, - 60, 2, 61, 44, 44, 44, 44, 44, 2, 2, 2, 2, 2, 2, 64, 44, - 36, 36, 36, 36, 36, 70, 87, 86, 43, 43, 43, 87, 63, 44, 44, 44, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 44, 44, 44, 44, - 36, 36, 36, 36, 36, 61, 57, 87, 86, 43, 43, 87, 43, 43, 44, 44, - 7, 7, 7, 7, 7, 27, 2, 97, 43, 43, 43, 43, 87, 60, 44, 44, - 27,100, 44, 44, 44, 44, 44, 62, 36, 36, 36, 61, 62, 44, 36, 36, - 36, 36, 62, 61, 36, 36, 36, 36, 86, 86, 86, 89, 90, 57, 85, 71, - 98, 87, 2, 64, 44, 44, 44, 44, 36, 36, 36, 36, 44, 36, 36, 36, - 94, 86, 43, 43, 44, 43, 86, 86, 71, 72, 90, 44, 44, 44, 44, 44, - 70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 85, 70, 43, 60, - 2, 2, 2, 59, 44, 44, 44, 44, 70, 43, 43, 85, 87, 43, 36, 36, - 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 85, 43, 2, 72, 2, - 2, 64, 44, 44, 44, 44, 44, 44, 2, 2, 2, 2, 2, 44, 44, 44, - 63, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 80, 43, 43, 43, 87, - 63, 2, 2, 44, 44, 44, 44, 44, 2, 36, 36, 36, 36, 36, 36, 36, - 44, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 89, 43, 43, 43, - 85, 43, 87, 80, 44, 44, 44, 44, 36, 36, 36, 61, 36, 62, 36, 36, - 70, 43, 43, 80, 44, 80, 43, 57, 43, 43, 43, 70, 44, 44, 44, 44, - 36, 36, 36, 62, 61, 36, 36, 36, 36, 36, 36, 36, 36, 86, 86, 90, - 43, 89, 87, 87, 61, 44, 44, 44, 36, 70, 85,107, 64, 44, 44, 44, - 43, 94, 36, 36, 36, 36, 36, 36, 36, 36, 86, 43, 43, 80, 44, 86, - 85, 60, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 80, 44, 44, - 27, 27, 91, 67, 67, 67, 56, 20,168, 67, 67, 67, 67, 67, 67, 67, - 67, 44, 44, 44, 44, 44, 44, 93,105,105,105,105,105,105,105,181, - 2, 2, 64, 44, 44, 44, 44, 44, 63, 64, 44, 44, 44, 44, 44, 44, - 65, 65, 65, 65, 65, 65, 65, 65, 71, 36, 36, 70, 43, 43, 43, 43, - 43, 43, 43, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 43, - 43, 43, 43, 43, 43, 86, 87, 43, 43, 43, 60, 44, 44, 44, 44, 44, - 43, 43, 43, 60, 2, 2, 67, 67, 40, 40, 97, 44, 44, 44, 44, 44, - 7, 7, 7, 7, 7,179, 27, 27, 27, 62, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 44, 44, 62, 36, 40, 69, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 83,164, 2, 27, 27, 27, 30, 2, 64, 44, 44, - 36, 36, 36, 36, 36, 61, 44, 57, 94, 86, 86, 86, 86, 86, 86, 86, - 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 44, 44, 44, 57, - 43, 74, 40, 40, 40, 40, 40, 40, 40, 88, 80, 44, 44, 44, 44, 44, - 86, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 62, - 40, 40, 52, 40, 40, 40, 52, 81, 36, 61, 44, 44, 44, 44, 44, 44, - 44, 61, 44, 44, 44, 44, 44, 44, 36, 61, 62, 44, 44, 44, 44, 44, - 44, 44, 36, 36, 44, 44, 44, 44, 36, 36, 36, 36, 36, 44, 50, 60, - 65, 65, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 43, 43, 43, 44, - 43, 43, 43, 80, 44, 44, 44, 44, 67, 67, 67, 92, 55, 67, 67, 67, - 67, 67,186, 87, 43, 67,186, 86, 86,187, 65, 65, 65, 84, 43, 43, - 43, 76, 50, 43, 43, 43, 67, 67, 67, 67, 67, 67, 67, 43, 43, 67, - 67, 43, 76, 44, 44, 44, 44, 44, 27, 27, 44, 44, 44, 44, 44, 44, - 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 16, 16, 16,110, 16, 16, 16, 16, 16, - 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 47, 11, - 44, 47, 48, 47, 48, 11, 47, 11, 11, 11, 11, 16, 16,150,150, 16, - 16, 16,150, 16, 16, 16, 16, 16, 16, 16, 11, 48, 11, 47, 48, 11, - 11, 11, 47, 11, 11, 11, 47, 16, 16, 16, 16, 16, 11, 48, 11, 47, - 11, 11, 47, 47, 44, 11, 11, 11, 47, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, - 16, 16, 16, 44, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, - 11, 11, 31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, - 16, 16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, - 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, - 16, 33, 16, 16, 16, 32, 44, 7, 43, 43, 43, 76, 67, 50, 43, 43, - 43, 43, 43, 43, 43, 43, 76, 67, 67, 67, 50, 67, 67, 67, 67, 67, - 67, 67, 76, 21, 2, 2, 44, 44, 44, 44, 44, 44, 44, 57, 43, 43, - 16, 16, 16, 16, 16, 39, 16, 16, 16, 16, 16, 16, 16, 16, 16,110, - 44, 44,150, 16, 16,110, 44, 44, 43, 43, 43, 80, 43, 43, 43, 43, - 43, 43, 43, 43, 80, 57, 43, 43, 43, 57, 80, 43, 43, 80, 44, 44, - 40, 40, 40, 40, 40, 40, 40, 44, 44, 44, 44, 44, 44, 44, 44, 57, - 43, 43, 43, 74, 40, 40, 40, 44, 7, 7, 7, 7, 7, 44, 44, 77, - 36, 36, 36, 36, 36, 36, 36, 80, 36, 36, 36, 36, 36, 36, 43, 43, - 7, 7, 7, 7, 7, 44, 44, 96, 36, 36, 36, 36, 36, 83, 43, 43, - 188, 7, 7, 7, 7,189, 44, 93, 36, 36, 36, 61, 36, 36, 62, 61, - 36, 36, 61,179, 27, 27, 27, 27, 16, 16, 43, 43, 43, 74, 44, 44, - 27, 27, 27, 27, 27, 27,163, 27,190, 27,100, 44, 44, 44, 44, 44, - 27, 27, 27, 27, 27, 27, 27,163, 27, 27, 27, 27, 27, 27, 27, 44, - 36, 36, 62, 36, 36, 36, 36, 36, 62, 61, 61, 62, 62, 36, 36, 36, - 36, 61, 36, 36, 62, 62, 44, 44, 44, 61, 44, 62, 62, 62, 62, 36, - 62, 61, 61, 62, 62, 62, 62, 62, 62, 61, 61, 62, 36, 61, 36, 36, - 36, 61, 36, 36, 62, 36, 61, 61, 36, 36, 36, 36, 36, 62, 36, 36, - 62, 36, 62, 36, 36, 62, 36, 36, 8, 44, 44, 44, 44, 44, 44, 44, - 67, 67, 67, 67, 67, 67, 44, 44, 55, 67, 67, 67, 67, 67, 67, 67, - 27, 27, 27, 27, 27, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 44, - 44, 44, 44, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44, 44, 44, - 67, 67, 67, 67, 92, 44, 44, 44, 67, 44, 44, 44, 44, 44, 44, 44, - 67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 67, 67, - 67, 67, 67, 92, 44, 55, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, - 67, 67, 67, 67, 67, 44, 44, 55, 67, 67, 67, 92, 44, 44, 44, 67, - 67, 67, 67, 67, 67, 67, 92, 55, 67, 92, 67, 67, 67, 67, 67, 67, - 79, 44, 44, 44, 44, 44, 44, 44,171,171,171,171,171,171,171, 44, - 171,171,171,171,171,171,171, 0, 0, 0, 29, 21, 21, 21, 23, 21, - 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9, - 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0, - 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15, - 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7, - 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12, - 2, 2, 6, 5, 9, 21, 9, 2, 2, 9, 25, 9, 26, 12, 11, 11, - 2, 6, 5, 21, 17, 2, 2, 26, 26, 23, 2, 12, 17, 12, 21, 12, - 12, 21, 7, 2, 2, 7, 7, 21, 21, 2, 1, 1, 21, 23, 26, 26, - 1, 21, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1, 12, 6, 6, 12, - 12, 26, 7, 26, 26, 7, 2, 1, 12, 2, 6, 2, 24, 7, 7, 6, - 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, 2, 10, 10, 2, 15, 26, - 26, 2, 2, 21, 7, 10, 15, 7, 2, 23, 21, 26, 10, 7, 21, 15, - 15, 2, 17, 7, 29, 7, 7, 22, 18, 2, 14, 14, 14, 7, 10, 21, - 17, 21, 11, 12, 5, 2, 5, 6, 8, 8, 8, 24, 5, 24, 2, 24, - 9, 24, 24, 2, 29, 29, 29, 1, 17, 17, 20, 19, 22, 20, 27, 28, - 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, - 1, 2, 15, 6, 18, 6, 23, 2, 12, 11, 9, 26, 26, 9, 26, 5, - 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25, - 18, 22, 5, 12, 2, 5, 22, 21, 21, 22, 18, 17, 26, 6, 7, 14, - 17, 22, 18, 18, 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, 26, 15, - 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, 6, 10, 4, 4, 3, 3, - 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 25, 2, 25, 24, 2, 15, - 12, 15, 14, 2, 21, 14, 7, 15, 12, 17, 21, 1, 26, 10, 10, 1, - 7, 13, 13, 2, 23, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, 15, 0, 16, 0, + 32, 32, 11, 11, 34, 34, 32, 32, 32, 32, 32, 32, 32, 32, 46, 43, + 51, 39,166, 35, 39, 35, 36, 36, 36, 70, 36, 70, 36, 69, 36, 36, + 36, 93, 86, 84, 66, 66, 79, 43, 27, 27, 27, 66,167, 43, 43, 43, + 36, 36, 2, 2, 43, 43, 43, 43, 85, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 85, 85, 85, 85, 85, 85, 85, 85, 42, 43, 43, 43, 43, 2, + 42, 36, 36, 36, 2, 71, 71, 69, 36, 36, 36, 42, 42, 42, 42, 2, + 36, 36, 36, 69, 42, 42, 42, 42, 42, 85, 43, 43, 43, 43, 43, 92, + 36, 69, 85, 42, 42, 85, 42, 85,106, 2, 2, 2, 2, 2, 2, 51, + 7, 7, 7, 7, 7, 43, 43, 2, 36, 36, 69, 68, 36, 36, 36, 36, + 7, 7, 7, 7, 7, 36, 36, 60, 36, 36, 36, 36, 69, 42, 42, 84, + 86, 84, 86, 79, 43, 43, 43, 43, 36, 69, 36, 36, 36, 36, 84, 43, + 7, 7, 7, 7, 7, 43, 2, 2, 68, 36, 36, 76, 66, 93, 84, 36, + 70, 42, 70, 69, 70, 36, 36, 42, 69, 60, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 61, 82, 2, 36, 36, 36, 36, 36, 93, 42, 85, + 2, 82,168, 79, 43, 43, 43, 43, 61, 36, 36, 60, 61, 36, 36, 60, + 61, 36, 36, 60, 43, 43, 43, 43, 16, 16, 16, 16, 16,113, 39, 39, + 16, 16, 16, 16,110, 40, 43, 43, 36, 93, 86, 85, 84,106, 86, 43, + 36, 36, 43, 43, 43, 43, 43, 43, 36, 36, 36, 60, 43, 61, 36, 36, + 169,169,169,169,169,169,169,169,170,170,170,170,170,170,170,170, + 16, 16, 16,109, 43, 43, 43, 43, 43,149, 16, 16, 43, 43, 61, 70, + 36, 36, 36, 36,171, 36, 36, 36, 36, 36, 36, 60, 36, 36, 60, 60, + 36, 61, 60, 36, 36, 36, 36, 36, 36, 40, 40, 40, 40, 40, 40, 40, + 40, 22, 66, 66, 66, 66, 66, 66, 66, 77, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36,147, 66, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 66, 66, 66, 66, 36, 36, 36, 36, 36, 36,167, 66, + 2, 2, 2,151,129, 43, 43, 43, 6,172,173,147,147,147,147,147, + 147,147,129,151,129, 2,126,174, 2, 63, 2, 2,155,147,147,129, + 2,175, 8,176, 65, 2, 43, 43, 36, 36, 60, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 60, 78, 92, 2, 3, 2, 4, 5, 6, 2, + 16, 16, 16, 16, 16, 17, 18,128,129, 4, 2, 36, 36, 36, 36, 36, + 68, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 39, + 43, 36, 36, 36, 43, 36, 36, 36, 43, 36, 36, 36, 43, 36, 60, 43, + 20,177, 55,178, 26, 8,143, 91, 43, 43, 43, 43, 78, 64, 66, 43, + 36, 36, 36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 60, 36, 61, + 2, 63, 43,179, 27, 27, 27, 27, 27, 27, 43, 54, 66, 66, 66, 66, + 104,104,142, 27, 90, 66, 66, 66, 66, 66, 66, 66, 66, 27, 66, 91, + 66, 66, 66, 66, 66, 66, 91, 43, 91, 43, 43, 43, 43, 43, 43, 43, + 66, 66, 66, 66, 66, 66, 49, 43,180, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 43, 43, 27, 27, 43, 43, 43, 43, 61, 36, + 154, 36, 36, 36, 36,181, 43, 43, 36, 36, 36, 42, 42, 79, 43, 43, + 36, 36, 36, 36, 36, 36, 36, 92, 36, 36, 43, 43, 36, 36, 36, 36, + 182,104,104, 43, 43, 43, 43, 43, 11, 11, 11, 11, 16, 16, 16, 16, + 11, 11, 43, 43, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 43, 43, + 36, 36, 36, 36, 43, 43, 43, 43, 36, 36, 43, 43, 43, 43, 43, 92, + 11, 11, 11, 11, 11, 46, 11, 11, 11, 46, 11,149, 16, 16, 16, 16, + 16,149, 16, 16, 16, 16, 16, 16, 16,149, 16, 16, 16,149,109, 43, + 39, 39, 39, 51, 39, 39, 39, 39, 80, 39, 39, 39, 39, 80, 43, 43, + 36, 36, 36, 43, 60, 36, 36, 36, 36, 36, 36, 61, 60, 43, 60, 61, + 36, 36, 36, 92, 27, 27, 27, 27, 36, 36, 36, 76,162, 27, 27, 27, + 43, 43, 43,179, 27, 27, 27, 27, 36, 60, 36, 43, 43,179, 27, 27, + 36, 36, 36, 27, 27, 27, 43, 92, 36, 36, 36, 36, 36, 43, 43, 92, + 36, 36, 36, 36, 43, 43, 27, 36, 43, 27, 27, 27, 27, 27, 27, 27, + 69, 42, 56, 79, 43, 43, 42, 42, 36, 36, 61, 36, 61, 36, 36, 36, + 36, 36, 36, 43, 42, 79, 43, 56, 27, 27, 27, 27, 99, 43, 43, 43, + 2, 2, 2, 2, 63, 43, 43, 43, 36, 36, 36, 36, 36, 36,183, 30, + 36, 36, 36, 36, 36, 36,183, 27, 36, 36, 36, 36, 77, 36, 36, 36, + 36, 36, 69, 79, 43,179, 27, 27, 2, 2, 2, 63, 43, 43, 43, 43, + 36, 36, 36, 43, 92, 2, 2, 2, 36, 36, 36, 43, 27, 27, 27, 27, + 36, 60, 43, 43, 27, 27, 27, 27, 36, 43, 43, 43, 92, 2, 63, 43, + 43, 43, 43, 43,179, 27, 27, 27, 11, 46, 43, 43, 43, 43, 43, 43, + 16,109, 43, 43, 43, 27, 27, 27, 36, 36, 42, 42, 43, 43, 43, 43, + 7, 7, 7, 7, 7, 36, 36, 68, 11, 11, 11, 43, 56, 42, 42,158, + 16, 16, 16, 43, 43, 43, 43, 8, 27, 27, 27, 27, 27, 27, 27, 99, + 36, 36, 36, 36, 36, 56,184, 43, 36, 43, 43, 43, 43, 43, 43, 43, + 43, 36, 82, 36, 43, 43, 43, 43, 96, 66, 66, 66, 91, 43, 43, 43, + 43, 43, 43, 43, 43, 42, 42, 42, 27, 27, 27, 94, 43, 43, 43, 43, + 180, 27, 30, 2, 2, 43, 43, 43, 36, 42, 42, 2, 2, 43, 43, 43, + 36, 36,183, 27, 27, 27, 43, 43, 86, 97, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 42, 42, 42, 42, 42, 42, 42, 59, 2, 2, 2, 43, + 27, 27, 27, 7, 7, 7, 7, 7, 70, 69, 70, 43, 43, 43, 43, 56, + 85, 86, 42, 84, 86, 59,185, 2, 2, 79, 43, 43, 43, 43, 78, 43, + 42, 70, 36, 36, 36, 36, 36, 36, 36, 36, 36, 69, 42, 42, 86, 42, + 42, 42, 79, 7, 7, 7, 7, 7, 2, 2, 93, 97, 43, 43, 43, 43, + 36, 69, 2, 60, 43, 43, 43, 43, 36, 93, 85, 42, 42, 42, 42, 84, + 97, 36, 62, 2, 58, 42, 59, 86, 7, 7, 7, 7, 7, 62, 62, 2, + 179, 27, 27, 27, 27, 27, 27, 27, 27, 27, 99, 43, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 36, 85, 86, 42, 85, 84, 42, 2, 2, 2, 70, + 69, 43, 43, 43, 43, 43, 43, 43, 36, 36, 36, 60, 60, 36, 36, 61, + 36, 36, 36, 36, 36, 36, 36, 61, 36, 36, 36, 36, 62, 43, 43, 43, + 36, 36, 36, 36, 36, 36, 36, 69, 85, 86, 42, 42, 42, 79, 43, 43, + 42, 85, 61, 36, 36, 36, 60, 61, 60, 36, 61, 36, 36, 56, 70, 85, + 84, 85, 89, 88, 89, 88, 85, 43, 60, 43, 43, 88, 43, 43, 61, 36, + 36, 85, 43, 42, 42, 42, 79, 43, 42, 42, 79, 43, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 61, 43, 60, 36, 36, 36, 61, 85, 86, 42, 42, + 79, 89, 88, 88, 85, 89, 85, 84, 70, 70, 2, 92, 63, 43, 43, 43, + 56, 79, 43, 43, 43, 43, 43, 43, 36, 36, 93, 85, 42, 42, 42, 42, + 85, 42, 84, 70, 36, 62, 2, 2, 7, 7, 7, 7, 7, 2, 92, 70, + 85, 86, 42, 42, 84, 84, 85, 86, 84, 42, 36, 71, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 36, 36, 93, 85, 42, 42, 43, 85, 85, 42, 86, + 59, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 36, 42, 43, + 85, 86, 42, 42, 42, 84, 86, 86, 59, 2, 60, 43, 43, 43, 43, 43, + 2, 2, 2, 2, 2, 2, 63, 43, 36, 36, 36, 36, 36, 69, 86, 85, + 42, 42, 42, 86, 62, 43, 43, 43, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 60, 56, 86, + 85, 42, 42, 86, 42, 42, 43, 43, 7, 7, 7, 7, 7, 27, 2, 96, + 42, 42, 42, 42, 86, 59, 43, 43, 27, 99, 43, 43, 43, 43, 43, 61, + 36, 36, 36, 60, 61, 43, 36, 36, 36, 36, 61, 60, 36, 36, 36, 36, + 85, 85, 85, 88, 89, 56, 84, 70, 97, 86, 2, 63, 43, 43, 43, 43, + 36, 36, 36, 36, 43, 36, 36, 36, 93, 85, 42, 42, 43, 42, 85, 85, + 70, 71, 89, 43, 43, 43, 43, 43, 69, 42, 42, 42, 42, 70, 36, 36, + 36, 69, 42, 42, 84, 69, 42, 59, 2, 2, 2, 58, 43, 43, 43, 43, + 69, 42, 42, 84, 86, 42, 36, 36, 36, 36, 36, 36, 36, 42, 42, 42, + 42, 42, 42, 84, 42, 2, 71, 2, 2, 63, 43, 43, 43, 43, 43, 43, + 2, 2, 2, 2, 2, 43, 43, 43, 84, 42, 84, 84, 43, 43, 43, 43, + 62, 43, 43, 43, 43, 43, 43, 43, 42, 42, 42, 79, 42, 42, 42, 86, + 62, 2, 2, 43, 43, 43, 43, 43, 2, 36, 36, 36, 36, 36, 36, 36, + 43, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 88, 42, 42, 42, + 84, 42, 86, 79, 43, 43, 43, 43, 36, 36, 36, 60, 36, 61, 36, 36, + 69, 42, 42, 79, 43, 79, 42, 56, 42, 42, 42, 69, 43, 43, 43, 43, + 36, 36, 36, 61, 60, 36, 36, 36, 36, 36, 36, 36, 36, 85, 85, 89, + 42, 88, 86, 86, 60, 43, 43, 43, 36, 36, 36, 36, 82, 36, 43, 43, + 36, 69, 84,106, 63, 43, 43, 43, 42, 93, 36, 36, 36, 36, 36, 36, + 36, 36, 85, 42, 42, 79, 43, 85, 84, 59, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 79, 43, 43, 27, 27, 90, 66, 66, 66, 55, 20, + 167, 66, 66, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43, 43, 43, 92, + 104,104,104,104,104,104,104,181, 2, 2, 63, 43, 43, 43, 43, 43, + 62, 63, 43, 43, 43, 43, 43, 43, 64, 64, 64, 64, 64, 64, 64, 64, + 70, 36, 36, 69, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 36, 36, 42, 42, 42, 42, 42, 42, 85, 86, 42, + 42, 42, 59, 43, 43, 43, 43, 43, 42, 42, 42, 59, 2, 2, 66, 66, + 39, 39, 96, 43, 43, 43, 43, 43, 7, 7, 7, 7, 7,179, 27, 27, + 27, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 61, 36, + 39, 68, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 82,163, 2, + 27, 27, 27, 30, 2, 63, 43, 43, 11, 11, 11, 11, 46,149, 16, 16, + 16, 16, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 60, 43, 56, + 93, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 43, 43, 43, 56, 42, 73, 39, 39, 39, 39, 39, 39, + 39, 87, 79, 43, 43, 43, 43, 43, 85, 39,104,181, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 61, 36, 60, 43, 43, 43, 43, 43, 43, + 39, 39, 51, 39, 39, 39, 51, 80, 43, 60, 43, 43, 43, 43, 43, 43, + 36, 60, 61, 43, 43, 43, 43, 43, 43, 43, 36, 36, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 43, 49, 59, 64, 64, 43, 43, 43, 43, 43, 43, + 7, 7, 7, 7, 7, 66, 91, 43, 66, 66, 43, 43, 43, 66, 66, 66, + 176, 43, 43, 43, 43, 43, 43, 43, 42, 42, 42, 79, 43, 43, 43, 43, + 66, 66, 66, 91, 54, 66, 66, 66, 66, 66,186, 86, 42, 66,186, 85, + 85,187, 64, 64, 64, 83, 42, 42, 42, 75, 49, 42, 42, 42, 66, 66, + 66, 66, 66, 66, 66, 42, 42, 66, 66, 42, 75, 43, 43, 43, 43, 43, + 27, 27, 43, 43, 43, 43, 43, 43, 11, 11, 11, 11, 11, 16, 16, 16, + 16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 16, + 16, 16,109, 16, 16, 16, 16, 16, 11, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 46, 11, 43, 46, 47, 46, 47, 11, 46, 11, + 11, 11, 11, 16, 16,149,149, 16, 16, 16,149, 16, 16, 16, 16, 16, + 16, 16, 11, 47, 11, 46, 47, 11, 11, 11, 46, 11, 11, 11, 46, 16, + 16, 16, 16, 16, 11, 47, 11, 46, 11, 11, 46, 46, 43, 11, 11, 11, + 46, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 11, 11, + 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 43, 11, 11, 11, 11, + 31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, 16, 16, + 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, 16, 16, + 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, + 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 32, 43, 7, + 42, 42, 42, 75, 66, 49, 42, 42, 42, 42, 42, 42, 42, 42, 75, 66, + 66, 66, 49, 66, 66, 66, 66, 66, 66, 66, 75, 21, 2, 2, 43, 43, + 43, 43, 43, 43, 43, 56, 42, 42, 16, 16, 16, 16, 16,138, 16, 16, + 16, 16, 16, 16, 16, 16, 16,109, 43, 43,149, 16, 16,109, 43, 43, + 42, 42, 42, 79, 42, 42, 42, 42, 42, 42, 42, 42, 79, 56, 42, 42, + 42, 56, 79, 42, 42, 79, 43, 43, 39, 39, 39, 39, 39, 39, 39, 43, + 43, 43, 43, 43, 43, 43, 43, 56, 42, 42, 42, 73, 39, 39, 39, 43, + 7, 7, 7, 7, 7, 43, 43, 76, 36, 36, 36, 36, 36, 36, 36, 79, + 36, 36, 36, 36, 36, 36, 42, 42, 7, 7, 7, 7, 7, 43, 43, 95, + 36, 36, 36, 36, 36, 82, 42, 42,188, 7, 7, 7, 7,189, 43, 92, + 36, 69, 36, 70, 36, 36, 36, 42, 36, 36, 69, 43, 43, 43, 43, 82, + 36, 36, 36, 60, 36, 36, 61, 60, 36, 36, 60,179, 27, 27, 27, 27, + 16, 16, 42, 42, 42, 73, 43, 43, 27, 27, 27, 27, 27, 27,162, 27, + 190, 27, 99, 43, 43, 43, 43, 43, 27, 27, 27, 27, 27, 27, 27,162, + 27, 27, 27, 27, 27, 27, 27, 43, 36, 36, 61, 36, 36, 36, 36, 36, + 61, 60, 60, 61, 61, 36, 36, 36, 36, 60, 36, 36, 61, 61, 43, 43, + 43, 60, 43, 61, 61, 61, 61, 36, 61, 60, 60, 61, 61, 61, 61, 61, + 61, 60, 60, 61, 36, 60, 36, 36, 36, 60, 36, 36, 61, 36, 60, 60, + 36, 36, 36, 36, 36, 61, 36, 36, 61, 36, 61, 36, 36, 61, 36, 36, + 8, 43, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 66, 66, 43, 43, + 54, 66, 66, 66, 66, 66, 66, 66, 27, 27, 27, 27, 27, 27, 90, 66, + 66, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43, 66, 66, 66, 66, 66, + 66, 91, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 91, 43, 43, 43, + 66, 43, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 66, 25, 40, 40, + 66, 66, 66, 66, 91, 43, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43, + 8, 8, 8, 8,176, 43, 43, 43, 66, 66, 66, 66, 66, 91, 43, 66, + 66, 66, 66, 91, 91, 43, 54, 66, 66, 66, 66, 66, 66, 66, 91, 54, + 66, 66, 66, 66, 66, 91, 43, 54, 66, 91, 66, 66, 66, 66, 66, 66, + 7, 7, 7, 7, 7, 91, 43, 43, 78, 43, 43, 43, 43, 43, 43, 43, + 170,170,170,170,170,170,170, 43,170,170,170,170,170,170,170, 0, + 0, 0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13, + 25, 25, 25, 21, 21, 9, 9, 9, 9, 22, 21, 18, 24, 16, 24, 5, + 5, 5, 5, 22, 25, 18, 25, 0, 23, 23, 26, 21, 24, 26, 7, 20, + 25, 1, 26, 24, 26, 25, 15, 15, 24, 15, 7, 19, 15, 21, 9, 25, + 9, 5, 5, 25, 5, 9, 5, 7, 7, 7, 9, 8, 8, 5, 6, 6, + 24, 24, 6, 24, 12, 12, 2, 2, 6, 5, 9, 21, 9, 2, 2, 9, + 25, 9, 26, 12, 11, 11, 2, 6, 5, 21, 17, 2, 2, 26, 26, 23, + 2, 12, 17, 12, 21, 12, 12, 21, 7, 2, 2, 7, 7, 21, 21, 2, + 1, 1, 21, 23, 26, 26, 1, 21, 6, 7, 7, 12, 12, 7, 21, 7, + 12, 1, 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, 2, 1, 12, 2, + 6, 2, 24, 7, 7, 6, 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, + 2, 10, 10, 2, 15, 26, 26, 2, 2, 21, 7, 10, 15, 7, 2, 23, + 21, 26, 10, 7, 21, 15, 15, 2, 17, 7, 29, 7, 7, 22, 18, 2, + 14, 14, 14, 7, 10, 21, 17, 21, 11, 12, 5, 2, 5, 6, 8, 8, + 8, 24, 5, 24, 2, 24, 9, 24, 24, 2, 29, 29, 29, 1, 17, 17, + 20, 19, 22, 20, 27, 28, 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, + 25, 22, 18, 21, 21, 29, 1, 2, 15, 6, 18, 6, 12, 11, 9, 26, + 26, 9, 26, 5, 7, 5, 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, + 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 2, 5, 22, 21, 21, 22, + 18, 17, 26, 6, 7, 14, 17, 22, 18, 18, 26, 14, 17, 6, 14, 6, + 12, 24, 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, + 6, 10, 4, 4, 3, 3, 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, + 25, 2, 25, 24, 23, 2, 2, 15, 12, 15, 14, 2, 21, 14, 7, 15, + 12, 17, 21, 1, 26, 10, 10, 1, 7, 13, 13, 2, 23, 15, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, + 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 0, + 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, + 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, + 0, 0, 0, 36, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 36, 0, 37, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, + 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, + 6, 7, 8, 0, 9, 0, 10, 11, 0, 0, 12, 13, 14, 15, 16, 0, + 0, 0, 0, 17, 18, 19, 20, 0, 21, 0, 22, 23, 0, 24, 25, 0, + 0, 24, 26, 27, 0, 24, 26, 0, 0, 24, 26, 0, 0, 24, 26, 0, + 0, 0, 26, 0, 0, 24, 28, 0, 0, 24, 26, 0, 0, 29, 26, 0, + 0, 0, 30, 0, 0, 31, 32, 0, 0, 33, 34, 0, 35, 36, 0, 37, + 38, 0, 39, 0, 0, 40, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 0, + 0, 0, 45, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 47, 0, 0, + 0, 0, 0, 0, 48, 0, 0, 49, 0, 50, 51, 52, 0, 53, 54, 55, + 0, 56, 0, 57, 0, 58, 0, 0, 0, 0, 59, 60, 0, 0, 0, 0, + 0, 0, 61, 62, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 66, + 0, 0, 0, 67, 0, 68, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 70, 71, 0, 0, 72, 0, 0, 0, 0, + 0, 0, 0, 0, 73, 74, 0, 0, 0, 0, 54, 75, 0, 76, 77, 0, + 0, 78, 79, 0, 0, 0, 0, 0, 0, 80, 81, 82, 0, 0, 0, 0, + 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, + 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 86, 0, 0, 0, 87, + 0, 0, 0, 0, 88, 89, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 92, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 0, 94, 0, 0, 95, 0, + 96, 0, 0, 0, 0, 0, 73, 97, 0, 98, 0, 0, 99,100, 0, 78, + 0, 0,101, 0, 0,102, 0, 0, 0, 0, 0,103, 0,104, 26,105, + 0, 0,106, 0, 0, 0,107, 0, 0, 0,108, 0, 0, 0, 0, 0, + 0, 66,109, 0, 0, 66, 0, 0, 0,110, 0, 0, 0,111, 0, 0, + 0, 0, 0, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0,112,113, 0, + 0, 0, 0, 79, 0, 44,114, 0,115, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0,116, 0, + 117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,119, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120, 0,121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 40, - 0, 0, 0, 0, 0, 0, 41, 42, 43, 0, 44, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 3, 0, - 0, 0, 4, 5, 6, 7, 0, 8, 9, 10, 0, 11, 12, 13, 14, 15, - 16, 17, 16, 18, 16, 19, 16, 19, 16, 19, 0, 19, 16, 20, 16, 19, - 21, 19, 0, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 32, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, - 34, 0, 0, 35, 0, 0, 36, 0, 37, 0, 0, 0, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 0, 0, 47, 0, 0, 0, 48, 0, 0, 0, 49, - 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0, 52, 53, 0, 54, 0, - 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 58, 0, 0, 59, - 60, 61, 62, 63, 0, 0, 64, 65, 0, 0, 0, 66, 0, 0, 0, 0, - 67, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 0, 72, 0, 0, 73, - 0, 0, 0, 0, 0, 0, 0, 0, 74, 75, 0, 0, 0, 0, 76, 77, - 0, 78, 79, 0, 0, 80, 81, 0, 82, 62, 0, 83, 84, 0, 0, 85, - 86, 87, 0, 88, 0, 89, 0, 90, 0, 0, 51, 91, 51, 0, 92, 0, - 93, 0, 0, 0, 81, 0, 0, 0, 94, 95, 0, 96, 97, 98, 99, 0, - 0, 0, 0, 0, 51, 0, 0, 0, 0,100,101, 0, 0, 0, 0, 0, - 0,102, 0, 0, 0, 0, 0, 0,103, 0, 0, 0, 0, 0, 0,104, - 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,106, 0, 0,107, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,108,109, 0, 0,110, 0, 0, - 0, 0, 0, 0,111, 0,112, 0,105, 0, 0, 0, 0, 0,113,114, - 0, 0, 0, 0, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0,117, - 0,118, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, - 8, 0, 0, 0, 0, 9, 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, - 14, 15, 0, 16, 0, 17, 18, 0, 0, 19, 0, 20, 21, 0, 0, 0, - 0, 0, 22, 23, 0, 24, 25, 0, 0, 26, 0, 0, 0, 27, 0, 0, - 28, 29, 30, 31, 0, 0, 0, 32, 33, 34, 0, 0, 33, 0, 0, 35, - 33, 0, 0, 0, 33, 36, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, - 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, - 0, 43, 0, 44, 0, 0, 0, 45, 46, 0, 0, 0, 47, 0, 0, 0, - 0, 0, 0, 48, 49, 0, 0, 0, 0, 50, 0, 0, 0, 51, 0, 52, - 0, 53, 0, 0, 0, 0, 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, - 0, 0, 57, 58, 0, 0, 0, 59, 60, 0, 0, 0, 0, 0, 0, 61, - 52, 0, 62, 63, 0, 0, 64, 0, 0, 0, 65, 66, 0, 0, 0, 67, - 0, 68, 69, 70, 71, 72, 1, 73, 0, 74, 75, 76, 0, 0, 77, 78, - 0, 0, 0, 79, 0, 0, 1, 1, 0, 0, 80, 0, 0, 81, 0, 0, - 0, 0, 77, 82, 0, 83, 0, 0, 0, 0, 0, 78, 84, 0, 85, 0, - 52, 0, 1, 78, 0, 0, 86, 0, 0, 87, 0, 0, 0, 0, 0, 88, - 57, 0, 0, 0, 0, 0, 0, 89, 90, 0, 0, 84, 0, 0, 33, 0, - 0, 91, 0, 0, 0, 0, 92, 0, 0, 0, 0, 49, 0, 0, 93, 0, - 0, 0, 0, 94, 95, 0, 0, 96, 0, 0, 97, 0, 0, 0, 98, 0, - 0, 0, 99, 0, 0, 0,100, 0, 0, 0, 0,101,102, 93, 0, 0, - 103, 0, 0, 0, 84, 0, 0,104, 0, 0, 0,105,106, 0, 0,107, - 108, 0, 0, 0, 0, 0, 0,109, 0, 0,110, 0, 0, 0, 0,111, - 33, 0,112,113,114, 57, 0, 0,115, 35, 0, 0,116, 0, 0, 0, - 117, 0, 0, 0, 0, 0, 0,118, 0, 0,119, 0, 0, 0, 0,120, - 88, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 52,121, 0, 0, 0, - 0,122, 0, 0,123, 0, 0, 0, 0,121, 0, 0,124, 0, 0, 0, - 0, 0, 79, 0, 0, 0, 0,125, 0, 0, 0,126, 0, 0, 0,127, - 0,128, 0, 0, 0, 0,129,130,131, 0,132, 0,133, 0, 0, 0, - 134,135,136, 0, 77, 0, 0, 0, 0, 0, 35, 0, 0, 0,137, 0, - 0, 0,138, 0, 0, 0,139, 0, 0,140, 0, 0,141, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 4, - 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, - 19, 1, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, 27, 28, - 29, 30, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, 1, 36, - 37, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, 42, 0, 0, 0, - 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 19, 1, 21, 0, 0, 47, - 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 51, 0, 0, 19, 52, 1, - 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52, 54, 21, 35, 1, - 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 59, - 0, 60, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, 64, 0, - 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 68, 0, - 0, 69, 70, 0, 71, 72, 73, 74, 75, 76, 0, 0, 0, 77, 0, 0, - 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 49, 0, 80, 0, 0, - 0, 62, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, 83, 0, - 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85, 1, 52, 15, 86, - 36, 10, 21, 87, 0, 55, 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, - 0, 0, 88, 0, 0, 89, 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, - 87, 9, 12, 4, 90, 8, 91, 47, 0, 58, 50, 0, 21, 1, 21, 92, - 93, 1, 1, 1, 1, 94, 95, 96, 97, 1, 98, 58, 81, 99,100, 4, - 58, 0, 0, 0, 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, - 0, 0,101,102, 0, 0,103, 0, 0, 1, 1, 50, 0, 0, 0, 38, - 0, 63, 0, 0, 0, 0, 0, 62, 0, 0,104, 68, 61, 0, 0, 0, - 78, 0, 0, 0,105,106, 58, 38, 81, 0, 0, 0, 0, 0, 0,107, - 1, 14, 4, 12, 84, 0, 0, 0, 0, 38, 87, 0, 0, 0, 0,108, - 0, 0,109, 61, 0,110, 0, 0, 0, 1, 0, 0, 0, 0, 49, 50, - 0, 0, 19, 58, 0, 0, 0, 51, 0,111, 14, 52,112, 41, 0, 0, - 62, 0, 0, 61, 0, 0,113, 0, 87, 0, 0, 0, 61, 62, 0, 0, - 62, 0, 89, 0, 0,113, 0, 0, 0, 0,114, 0, 0, 0, 78, 55, - 0, 38, 1, 58, 1, 58, 0, 0, 0, 0, 0, 88, 63, 89, 0, 0, - 115, 0, 0, 0, 55, 0, 0, 0, 0,115, 0, 0, 0, 0, 61, 0, - 0, 0, 0, 79, 0, 61, 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, - 79, 0, 0, 0, 8, 91, 0, 0, 1, 87, 0, 0,116, 0, 0, 0, - 0, 0, 0,117, 0,118,119,120,121, 0,104, 4,122, 49, 23, 0, - 0, 0, 38, 50, 38, 58, 0, 0, 1, 87, 1, 1, 1, 1, 39, 1, - 48,105, 87, 0, 0, 0, 0, 1, 0, 0, 0,123, 0, 0, 0,112, - 4,122, 0, 0, 0, 1,124, 0, 0, 0, 0, 0,230,230,230,230, - 230,232,220,220,220,220,232,216,220,220,220,220,220,202,202,220, - 220,220,220,202,202,220,220,220, 1, 1, 1, 1, 1,220,220,220, - 220,230,230,230,230,240,230,220,220,220,230,230,230,220,220, 0, - 230,230,230,220,220,220,220,230,232,220,220,230,233,234,234,233, - 234,234,233,230, 0, 0, 0,230, 0,220,230,230,230,230,220,230, - 230,230,222,220,230,230,220,220,230,222,228,230, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0, - 230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31, - 32, 33, 34,230,230,220,220,230,220,230,230,220, 35, 0, 0, 0, - 0, 0,230,230,230, 0, 0,230,230, 0,220,230,230,220, 0, 0, - 0, 36, 0, 0,230,220,230,230,220,220,230,220,220,230,220,230, - 220,230,230, 0, 0,220, 0, 0,230,230, 0,230, 0,230,230,230, - 230,230, 0, 0, 0,220,220,220,230,220,220,220,230,230, 0,220, - 27, 28, 29,230, 7, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230, - 230, 0, 0, 0, 0, 0,230, 0, 0, 84, 91, 0, 0, 0, 0, 9, - 9, 0, 0, 0, 0, 0, 9, 0,103,103, 9, 0,107,107,107,107, - 118,118, 9, 0,122,122,122,122,220,220, 0, 0, 0,220, 0,220, - 0,216, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130, - 130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0,220, 0, - 0, 0, 0, 7, 0, 9, 9, 0, 9, 9, 0, 0, 0,230, 0, 0, - 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0,230, 0, 0,220, - 230,220, 0,220,230,230,230, 0, 0, 0, 9, 9, 0, 0, 7, 0, + 0, 0, 0,122, 0, 0, 0, 0,123, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, + 125,126, 0, 0, 0, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,128,129, 0, 0,130, 0, 0, 0, 0,121, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,131, 0,132, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,133, 0, 0, 0, 0, + 0, 0, 0,134, 0, 0, 0, 0, 0, 0, 0,135, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,136, 0, 0, 0,137, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 2, 3, 4, 5, 6, 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, + 14, 15, 16, 17, 18, 1, 1, 1, 0, 0, 0, 0, 19, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, + 25, 26, 27, 28, 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, 1, 36, 0, 0, 0, 0, + 37, 0, 0, 0, 0, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, + 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, + 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 0, 0, 0, 0, 19, 1, + 21, 0, 0, 47, 0, 0, 0, 0, 0, 38, 48, 1, 1, 49, 49, 50, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, + 0, 19, 52, 1, 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52, + 54, 21, 35, 1, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 56, + 57, 58, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 59, 0, 0, 0, 56, 0, 60, 0, 0, 0, 0, 0, 0, + 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 68, 0, 0, 0, 0, 0, 0, 69, 70, 0, 0, 0, 0, 0, + 71, 72, 73, 74, 75, 76, 0, 0, 0, 0, 0, 0, 0, 77, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, + 0, 80, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, + 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 83, 0, 0, 0, 0, 0, 0, 19, 84, 0, 62, 0, 0, 0, + 0, 49, 1, 85, 0, 0, 0, 0, 1, 52, 15, 86, 36, 10, 21, 1, + 1, 1, 1, 41, 1, 21, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 55, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 19, 10, + 1, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 89, 0, 0, + 88, 0, 0, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, + 90, 9, 12, 4, 91, 8, 92, 47, 0, 58, 50, 0, 21, 1, 21, 93, + 94, 1, 1, 1, 1, 1, 1, 1, 1, 95, 96, 97, 0, 0, 0, 0, + 98, 1, 99, 58, 81,100,101, 4, 58, 0, 0, 0, 0, 0, 0, 19, + 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 0,102,103, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,104, 0, 0, 0, 0, 19, 0, 1, 1, 50, 0, 0, 0, 0, + 0, 0, 0, 38, 0, 0, 0, 0, 50, 0, 0, 0, 0, 63, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 1, 1, 1, 1, + 50, 0, 0, 0, 0, 0,105, 68, 0, 0, 0, 0, 0, 0, 0, 0, + 61, 0, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, 62, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,106,107, 58, 38, 81, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, + 0, 0, 0,108, 1, 14, 4, 12, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 47, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 38, 90, 0, 0, 0, 0,109, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,110, 61, 0,111, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 49, 50, 0, 0, 0, 0, 0, 0, 19, 58, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,112, 51, 0,112, 14, 52, + 84, 0, 0, 0,113, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 62, 0, 0, 61, 0, 0, 0, 0, 0, 0,114, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,114, 0, 0, 0, 0,115, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 55, 0, 38, 1, 58, + 1, 58, 0, 0, 0, 0, 0, 88, 62, 0, 0, 0, 63, 89, 0, 0, + 0, 0, 0, 59,116, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,116, 0, 0, 0, 0, 61, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 78, 0, 0, 0, + 0, 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 56, 0, 89, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 61, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 92, 0, 0, 0, 0, 0, 0, + 1, 90, 0, 0, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,118, 0,119,120,121,122, 0,105, 4,123, 49, 23, 0, + 0, 0, 0, 0, 0, 0, 38, 50, 0, 0, 0, 0, 38, 58, 0, 0, + 0, 0, 0, 0, 1, 90, 1, 1, 1, 1, 39, 1, 48,106, 90, 0, + 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 59, + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,124, + 0, 0, 0, 0, 0, 0, 0,113, 0, 0, 0, 0, 19, 59, 0, 38, + 0, 81, 0, 0, 0, 0, 0, 0, 4,123, 0, 0, 0, 1,125, 0, + 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,230,232,220,220, + 220,220,232,216,220,220,220,220,220,202,202,220,220,220,220,202, + 202,220,220,220, 1, 1, 1, 1, 1,220,220,220,220,230,230,230, + 230,240,230,220,220,220,230,230,230,220,220, 0,230,230,230,220, + 220,220,220,230,232,220,220,230,233,234,234,233,234,234,233,230, + 0, 0, 0,230, 0,220,230,230,230,230,220,230,230,230,222,220, + 230,230,220,220,230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18, + 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230, + 230,220,220,230,220,230,230,220, 35, 0, 0, 0, 0, 0,230,230, + 230, 0, 0,230,230, 0,220,230,230,220, 0, 0, 0, 36, 0, 0, + 230,220,230,230,220,220,230,220,220,230,220,230,220,230,230, 0, + 0,220, 0, 0,230,230, 0,230, 0,230,230,230,230,230, 0, 0, + 0,220,220,220,230,220,220,220,230,230, 0,220, 27, 28, 29,230, + 7, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0, + 0, 0,230, 0, 0, 84, 91, 0, 0, 0, 0, 9, 9, 0, 0, 0, + 0, 0, 9, 0,103,103, 9, 0,107,107,107,107,118,118, 9, 0, + 122,122,122,122,220,220, 0, 0, 0,220, 0,220, 0,216, 0, 0, + 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130,130,130, 0, 0, + 130, 0,230,230, 9, 0,230,230, 0, 0,220, 0, 0, 0, 0, 7, + 0, 9, 9, 0, 9, 9, 0, 0, 0,230, 0, 0, 0,228, 0, 0, + 0,222,230,220,220, 0, 0, 0,230, 0, 0,220,230,220, 0,220, + 230,230,230,234, 0, 0, 9, 9, 0, 0, 7, 0,230,230,230, 0, 230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220,202,230,230,230, 230,230,232,228,228,220,218,230,233,220,230,220,230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, 0, 0,218,228, @@ -1683,63 +1482,81 @@ _hb_ucd_u8[17612] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 34, 9, 0, 0, 20, 20, 1, 20, 20, 0, 0, 0, 0, 0, 0, 0, 26, 21, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 13, 13, 13, 13, 13, 14, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 16, 17, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 20, 20, 20, 20, 20, 20, - 20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 20, 33, - 34, 35, 34, 34, 36, 37, 20, 20, 20, 20, 20, 20, 38, 20, 39, 40, - 41, 41, 41, 41, 41, 42, 43, 44, 20, 20, 20, 20, 20, 20, 20, 45, - 46, 20, 20, 47, 20, 20, 20, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 20, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 9, 10, 11, 11, 11, 11, 12, 13, + 13, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 13, 13, 13, + 24, 25, 26, 26, 26, 27, 13, 13, 13, 28, 29, 30, 13, 31, 32, 33, + 34, 35, 36, 37, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 38, 7, 7, 39, 7, 40, 7, 7, + 7, 41, 13, 42, 7, 7, 43, 7, 7, 7, 44, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 60, 13, 13, - 13, 61, 62, 13, 13, 13, 13, 63, 13, 13, 13, 13, 13, 13, 64, 65, - 20, 20, 66, 20, 13, 13, 13, 13, 67, 13, 13, 13, 68, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 45, 0, 0, 1, 2, 2, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 37, + 37, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 2, 2, 53, 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, 59, + 59, 59, 59, 59, 59, 59, 61, 61, 59, 59, 59, 59, 62, 59, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 59, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 78, 69, 69, 69, 69, 79, 79, 79, 79, 79, 79, 79, 79, 79, 80, + 81, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 94, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 69, 69, 96, 97, 98, 99, 99, 99, + 100,101,102,103,104,105,106,107,108,109, 95,110,111,112,113,114, + 115,116,117,117,118,119,120,121,122,123,124,125,126,127,128,129, + 130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145, + 95,146,147,148,149, 95,150,151,152,153,154,155,156,157,158,159, + 160,161, 95,162,163,164,165,165,165,165,165,165,165,166,167,165, + 168, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95,169,170,170,170,170,170,170,170,170,171,170, + 170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, + 170,170,170,170,170,170,170,170,170,170,170,170,170,172,173,173, + 173,173,174, 95, 95, 95, 95, 95,175, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95,176,176,176,176,177,178,179,180, 95, 95, + 181, 95,182,183,184,185,186,186,186,186,186,186,186,186,186,186, + 186,186,186,186,186,186,186,186,186,186,186,186,187,187,187,188, + 189,190, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95,191,192,193,194,195,195,196, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,197,198, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 59,199, + 59, 59, 59,200,201,202, 59,203,204,205,206,207,208, 95,209,210, + 211, 59, 59,212, 59,213,214,214,214,214,214,215, 95, 95, 95, 95, + 95, 95, 95, 95,216, 95,217,218,219, 95, 95,220, 95, 95, 95,221, + 95,222, 95,223, 95,224,225,226,227, 95, 95, 95, 95, 95,228,229, + 230, 95,231,232, 95, 95,233,234, 59,235,236, 95, 59, 59, 59, 59, + 59, 59, 59,237, 59,238,239,240, 59, 59,241,242, 59,243, 95, 95, + 95, 95, 95, 95, 95, 95, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69,244, 69, 69,245, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69,246, 69, 69, 69, 69, 69, 69, 69, 69, 69,247, 69, 69, + 69, 69,248, 95, 95, 95, 69, 69, 69, 69,249, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 69, 69, 69, 69, 69, 69,250, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,251, 95, + 95, 95, 95, 95, 95, 95,252, 95,253,254, 0, 1, 2, 2, 0, 1, + 2, 2, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19, @@ -1764,46 +1581,46 @@ _hb_ucd_u8[17612] = 64, 2, 2, 64, 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90, 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 2, 2, 95, 2, 37, 37, - 37, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, - 2, 2, 2, 2, 2, 3, 3, 3, 0, 3, 3, 3, 3, 3, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 7, 7, - 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, - 5, 5, 5, 2, 2, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 2, - 5, 2, 2, 2, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 2, - 2, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, - 2, 2, 5, 5, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 2, 2, 11, 11, 11, 2, 11, 11, 11, 11, 11, - 11, 2, 2, 2, 2, 11, 11, 2, 2, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 11, 11, 11, 11, 11, 2, - 11, 11, 2, 11, 11, 2, 11, 11, 2, 2, 11, 2, 11, 11, 11, 2, - 2, 11, 11, 11, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, - 11, 11, 11, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 2, - 10, 10, 2, 10, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, 10, 10, - 2, 10, 10, 10, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10, - 10, 10, 2, 2, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 10, - 10, 10, 10, 10, 10, 10, 2, 21, 21, 21, 2, 21, 21, 21, 21, 21, - 21, 21, 21, 2, 2, 21, 21, 2, 2, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 2, - 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, 21, 2, - 2, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 2, 2, - 2, 2, 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, 2, - 22, 22, 2, 22, 22, 22, 22, 22, 22, 2, 2, 2, 22, 22, 22, 2, - 22, 22, 22, 22, 2, 2, 2, 22, 22, 2, 22, 2, 22, 22, 2, 2, - 2, 22, 22, 2, 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 2, 2, 2, 2, 22, 22, 22, 2, 2, 2, 2, 2, 2, 22, 2, 2, - 2, 2, 2, 2, 22, 22, 22, 22, 22, 2, 2, 2, 2, 2, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 2, 23, 23, 23, 2, - 23, 23, 23, 23, 23, 23, 23, 23, 2, 2, 23, 23, 23, 23, 23, 2, - 23, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, 23, - 23, 2, 2, 23, 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 2, 2, - 2, 2, 2, 2, 2, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 2, 16, 16, 16, 2, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 2, 16, 16, 16, 16, 16, 2, 2, 16, 16, 16, 16, 16, 2, - 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 16, 16, 2, 16, 16, + 37, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, + 0, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, + 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 5, 5, + 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2, + 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, + 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5, + 2, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 2, 2, 2, + 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 5, 5, 2, 5, 5, 5, + 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 11, + 11, 11, 2, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2, + 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, + 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11, + 2, 2, 11, 2, 11, 11, 11, 2, 2, 11, 11, 11, 2, 2, 2, 11, + 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 2, 11, 2, 2, 2, + 2, 2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 10, + 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, + 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, + 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10, 10, + 2, 2, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 2, 2, 10, 2, + 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, + 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 2, 21, + 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, + 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, + 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, 21, 21, 21, 21, + 2, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 2, 2, 2, 2, + 2, 2, 2, 21, 21, 21, 2, 2, 2, 2, 21, 21, 2, 21, 21, 21, + 21, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22, + 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22, + 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, 22, 22, 22, 2, + 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, + 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 23, 23, + 2, 2, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, 2, 2, 2, 2, + 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 23, 23, 2, 2, 23, 23, + 23, 23, 2, 2, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 2, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16, + 2, 2, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 2, 2, 2, 2, + 2, 2, 2, 16, 16, 2, 2, 2, 2, 2, 16, 16, 16, 2, 16, 16, 16, 16, 2, 2, 16, 16, 2, 16, 16, 16, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, 20, 20, 20, 20, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, @@ -1850,137 +1667,135 @@ _hb_ucd_u8[17612] = 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 2, 2, 91, 91, 91, 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, 91, 91, 2, 2, 1, 1, - 1, 1, 1, 1, 1, 2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 2, 62, 62, 76, 76, 76, 76, 76, 76, 76, 76, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 2, 2, 2, 2, 2, 2, - 2, 2, 93, 93, 93, 93, 70, 70, 70, 70, 70, 70, 70, 70, 2, 2, - 2, 70, 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 73, 73, - 73, 73, 73, 73, 73, 73, 6, 6, 6, 2, 2, 2, 2, 2, 8, 8, - 8, 2, 2, 8, 8, 8, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, - 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 19, 19, - 19, 19, 19, 19, 9, 9, 9, 9, 9, 6, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 9, 9, 9, 9, - 9, 19, 19, 19, 19, 19, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 9, 9, 9, 9, 9, 9, 9, 2, 2, 2, 9, - 2, 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, - 9, 9, 2, 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 2, 2, - 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, - 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 19, - 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, - 0, 0, 0, 0, 0, 2, 19, 19, 19, 19, 19, 2, 2, 2, 0, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, - 0, 0, 0, 0, 9, 0, 0, 0, 19, 19, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 19, 0, 19, 0, 0, 0, 2, 2, 2, 2, 0, 0, - 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 27, 27, - 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, 56, 56, 56, 56, 56, 56, 56, 56, 55, 55, - 55, 55, 2, 2, 2, 2, 2, 55, 55, 55, 55, 55, 55, 55, 61, 61, - 61, 61, 61, 61, 61, 61, 2, 2, 2, 2, 2, 2, 2, 61, 61, 2, - 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 2, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 2, 2, 0, 0, - 0, 0, 0, 13, 0, 13, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 1, 1, 1, 1, 12, 12, 13, 13, 13, 13, 0, 0, 0, 0, 2, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 2, 2, 1, 1, 0, 0, 15, 15, 15, 0, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 0, 0, 17, 17, 17, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 0, 12, 12, - 12, 12, 12, 12, 12, 0, 17, 17, 17, 17, 17, 17, 17, 0, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 2, 2, 2, 39, 39, - 39, 39, 39, 39, 39, 2, 86, 86, 86, 86, 86, 86, 86, 86, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2, 2, 2, 2, 79, 79, - 79, 79, 79, 79, 79, 79, 0, 0, 19, 19, 19, 19, 19, 19, 0, 0, - 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 2, 2, 19, 19, - 2, 19, 2, 19, 19, 19, 2, 2, 19, 19, 19, 19, 19, 19, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 2, 2, 2, 65, 65, - 65, 65, 65, 65, 65, 65, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 2, 2, 75, 75, 75, 75, - 2, 2, 2, 2, 2, 2, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 74, 12, 12, - 12, 12, 12, 2, 2, 2, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2, 84, 84, 33, 33, - 33, 33, 33, 33, 33, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 2, 68, 68, 68, 68, 68, 68, 2, 2, 68, 68, - 2, 2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, - 92, 2, 2, 2, 2, 2, 2, 2, 2, 92, 92, 92, 92, 92, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 2, 2, 30, - 30, 30, 30, 30, 30, 2, 19, 19, 19, 0, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 9, 19, 19, 19, 19, 0, 0, 2, 2, 2, 2, 87, 87, - 87, 87, 87, 87, 2, 2, 87, 87, 2, 2, 2, 2, 2, 2, 12, 12, - 12, 12, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 13, 13, - 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2, - 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 2, 14, 14, 14, 14, 14, 2, 14, 2, 14, 14, - 2, 14, 14, 2, 14, 14, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, - 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 2, 2, - 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 1, 1, - 1, 1, 1, 1, 6, 6, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, - 0, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, - 3, 3, 3, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 2, 2, - 12, 12, 12, 12, 12, 12, 2, 2, 12, 12, 12, 2, 2, 2, 2, 0, - 0, 0, 0, 0, 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, - 49, 2, 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 2, 2, 49, 49, - 49, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, - 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 2, - 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 2, 2, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 2, 2, 2, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 2, 2, 2, 2, 2, 2, 2, 1, 0, - 0, 0, 0, 0, 0, 0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 42, 42, 42, 41, 41, - 41, 41, 41, 41, 41, 41, 41, 41, 41, 2, 2, 2, 2, 2,118,118, - 118,118,118,118,118,118,118,118,118, 2, 2, 2, 2, 2, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 2, 53, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 2, 2, 2, 2, 59, 59, - 59, 59, 59, 59, 2, 2, 40, 40, 40, 40, 40, 40, 40, 40, 51, 51, - 51, 51, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, - 50, 50, 50, 50, 2, 2, 50, 50, 2, 2, 2, 2, 2, 2,135,135, - 135,135,135,135,135,135,135,135,135,135, 2, 2, 2, 2,106,106, - 106,106,106,106,106,106,104,104,104,104,104,104,104,104,104,104, - 104,104, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,104,161,161, - 161,161,161,161,161,161,161,161,161, 2,161,161,161,161,161,161, - 161, 2,161,161, 2,161,161,161, 2,161,161,161,161,161,161,161, - 2,161,161, 2, 2, 2,170,170,170,170,170,170,170,170,170,170, - 170,170, 2, 2, 2, 2,110,110,110,110,110,110,110,110,110,110, - 110,110,110,110,110, 2,110,110,110,110,110,110, 2, 2, 19, 19, - 19, 19, 19, 19, 2, 19, 19, 2, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 2, 2, 2, 2, 2, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, 2, 2, 47, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 2, 81,120,120, - 120,120,120,120,120,120,116,116,116,116,116,116,116,116,116,116, - 116,116,116,116,116, 2, 2, 2, 2, 2, 2, 2, 2,116,128,128, - 128,128,128,128,128,128,128,128,128, 2,128,128, 2, 2, 2, 2, - 2,128,128,128,128,128, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 2, 2, 2, 66, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, 98, 98, 98, 98, 97, 97, - 97, 97, 97, 97, 97, 97, 2, 2, 2, 2, 97, 97, 97, 97, 2, 2, - 97, 97, 97, 97, 97, 97, 57, 57, 57, 57, 2, 57, 57, 2, 2, 2, - 2, 2, 57, 57, 57, 57, 57, 57, 57, 57, 2, 57, 57, 57, 2, 57, - 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, - 57, 57, 57, 57, 2, 2, 57, 57, 57, 2, 2, 2, 2, 57, 57, 2, - 2, 2, 2, 2, 2, 2, 88, 88, 88, 88, 88, 88, 88, 88,117,117, - 117,117,117,117,117,117,112,112,112,112,112,112,112,112,112,112, - 112,112,112,112,112, 2, 2, 2, 2,112,112,112,112,112, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 2, 2, 2, 78, - 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, - 83, 83, 83, 83, 2, 2, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, - 82, 2, 2, 2, 2, 2,122,122,122,122,122,122,122,122,122,122, - 2, 2, 2, 2, 2, 2, 2,122,122,122,122, 2, 2, 2, 2,122, - 122,122,122,122,122,122, 89, 89, 89, 89, 89, 89, 89, 89, 89, 2, - 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,130,130,130,130, - 130, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,144,144, - 144,144,144,144,144,144,144,144, 2, 2, 2, 2, 2, 2,165,165, - 165,165,165,165,165,165,165,165,165,165,165,165, 2, 2, 2,165, - 165,165,165,165,165,165, 2, 2, 2, 2, 2, 2,165,165,156,156, + 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 2, 62, 62, 76, 76, + 76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 2, 2, 2, 2, 2, 2, 2, 2, 93, 93, 93, 93, 70, 70, + 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 70, 70, 70, 70, + 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 73, 73, 73, 73, 6, 6, + 6, 2, 2, 2, 2, 2, 8, 8, 8, 2, 2, 8, 8, 8, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, + 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, 9, + 19, 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 19, 6, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9, + 9, 9, 9, 9, 2, 2, 2, 9, 2, 9, 2, 9, 2, 9, 9, 9, + 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9, 9, + 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, 2, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 0, 19, 2, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 2, 19, 19, + 19, 19, 19, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, + 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 19, 0, + 0, 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 27, 27, + 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 2, 2, 0, 0, 56, 56, + 56, 56, 56, 56, 56, 56, 55, 55, 55, 55, 2, 2, 2, 2, 2, 55, + 55, 55, 55, 55, 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 2, 2, + 2, 2, 2, 2, 2, 61, 61, 2, 2, 2, 2, 2, 2, 2, 0, 0, + 0, 0, 0, 0, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 13, 13, + 13, 13, 13, 13, 2, 2, 0, 0, 0, 0, 0, 13, 0, 13, 0, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 13, 13, + 13, 13, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 1, + 1, 0, 0, 15, 15, 15, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 17, 17, 17, 2, 2, + 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, + 2, 2, 2, 2, 2, 0, 12, 12, 12, 12, 12, 12, 12, 0, 17, 17, + 17, 17, 17, 17, 17, 0, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 86, 86, + 86, 86, 86, 86, 86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 2, 2, 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, + 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 19, 19, 19, 19, 2, 19, + 19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 2, 2, 2, 65, 65, 65, 65, 65, 65, 65, 65, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2, + 2, 2, 2, 2, 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 0, 69, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 74, 12, 12, 12, 12, 12, 2, 2, 2, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 2, 0, 84, 84, + 2, 2, 2, 2, 84, 84, 33, 33, 33, 33, 33, 33, 33, 2, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68, + 68, 68, 68, 68, 2, 2, 68, 68, 2, 2, 68, 68, 68, 68, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 2, 2, 2, 2, 2, 2, 2, + 2, 92, 92, 92, 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 2, 2, 30, 30, 30, 30, 30, 30, 2, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 19, 19, 19, 19, + 0, 0, 2, 2, 2, 2, 87, 87, 87, 87, 87, 87, 2, 2, 87, 87, + 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, + 2, 12, 12, 12, 12, 12, 13, 13, 2, 2, 2, 2, 2, 2, 19, 19, + 19, 19, 19, 19, 19, 2, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2, + 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, 14, + 14, 14, 14, 2, 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 3, 3, + 3, 3, 3, 3, 0, 0, 1, 1, 1, 1, 1, 1, 6, 6, 0, 0, + 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, + 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, + 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 12, 12, 12, 12, 2, 2, + 12, 12, 12, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 2, 49, 49, 49, 2, 49, 49, 2, 49, 49, 49, + 49, 49, 49, 49, 2, 2, 49, 49, 49, 2, 2, 2, 2, 2, 0, 0, + 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, + 0, 0, 0, 2, 2, 2, 9, 2, 2, 2, 2, 2, 2, 2, 0, 0, + 0, 0, 0, 1, 2, 2, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 2, 2, 2, 67, 67, 67, 67, 67, 67, 67, 67, 67, 2, + 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 42, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 2, 2, 2, 2, 2,118,118,118,118,118,118,118,118,118,118, + 118, 2, 2, 2, 2, 2, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 2, 2, 2, 2, 59, 59, 59, 59, 59, 59, 2, 2, 40, 40, + 40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51, 51, 51, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 2, 2, 50, 50, + 2, 2, 2, 2, 2, 2,135,135,135,135,135,135,135,135,135,135, + 135,135, 2, 2, 2, 2,106,106,106,106,106,106,106,106,104,104, + 104,104,104,104,104,104,104,104,104,104, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2,104,161,161,161,161,161,161,161,161,161,161, + 161, 2,161,161,161,161,161,161,161, 2,161,161, 2,161,161,161, + 2,161,161,161,161,161,161,161, 2,161,161, 2, 2, 2,170,170, + 170,170,170,170,170,170,170,170,170,170, 2, 2, 2, 2,110,110, + 110,110,110,110,110,110,110,110,110,110,110,110,110, 2,110,110, + 110,110,110,110, 2, 2, 19, 19, 19, 19, 19, 19, 2, 19, 19, 2, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2, 2, 2, 47, 47, + 47, 47, 47, 47, 2, 2, 47, 2, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 2, 47, 47, 2, + 2, 2, 47, 2, 2, 47, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 2, 81,120,120,120,120,120,120,120,120,116,116, + 116,116,116,116,116,116,116,116,116,116,116,116,116, 2, 2, 2, + 2, 2, 2, 2, 2,116,128,128,128,128,128,128,128,128,128,128, + 128, 2,128,128, 2, 2, 2, 2, 2,128,128,128,128,128, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 2, 2, 2, 66, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 2, 2, 2, 2, 2, 72,173,173, + 173,173,173,173,173,173,173,173, 2, 2, 2, 2, 2, 2, 98, 98, + 98, 98, 98, 98, 98, 98, 97, 97, 97, 97, 97, 97, 97, 97, 2, 2, + 2, 2, 97, 97, 97, 97, 2, 2, 97, 97, 97, 97, 97, 97, 57, 57, + 57, 57, 2, 57, 57, 2, 2, 2, 2, 2, 57, 57, 57, 57, 57, 57, + 57, 57, 2, 57, 57, 57, 2, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 2, 2, 57, 57, + 57, 2, 2, 2, 2, 57, 57, 2, 2, 2, 2, 2, 2, 2, 88, 88, + 88, 88, 88, 88, 88, 88,117,117,117,117,117,117,117,117,112,112, + 112,112,112,112,112,112,112,112,112,112,112,112,112, 2, 2, 2, + 2,112,112,112,112,112, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 2, 2, 2, 78, 78, 78, 78, 78, 78, 78, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 2, 2, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 2, 2, 2, 2, 2,122,122, + 122,122,122,122,122,122,122,122, 2, 2, 2, 2, 2, 2, 2,122, + 122,122,122, 2, 2, 2, 2,122,122,122,122,122,122,122, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 2, 2, 2, 2, 2, 2, 2,130,130, + 130,130,130,130,130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2, + 130,130,130,130,130,130,144,144,144,144,144,144,144,144,144,144, + 2, 2, 2, 2, 2, 2,165,165,165,165,165,165,165,165,165,165, + 165,165,165,165, 2, 2, 2,165,165,165,165,165,165,165, 2, 2, + 2, 2, 2, 2,165,165, 3, 3, 3, 3, 3, 3, 3, 2,156,156, 156,156,156,156,156,156,156,156, 2,156,156,156, 2, 2,156,156, - 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, - 2, 2, 3, 3, 3, 3,147,147,147,147,147,147,147,147,148,148, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, + 2, 2, 2, 2, 2, 2,147,147,147,147,147,147,147,147,148,148, 148,148,148,148,148,148,148,148, 2, 2, 2, 2, 2, 2,158,158, 158,158,158,158,158,158,158,158, 2, 2, 2, 2, 2, 2,153,153, 153,153,153,153,153,153,153,153,153,153, 2, 2, 2, 2,149,149, @@ -2039,46 +1854,51 @@ _hb_ucd_u8[17612] = 143,143,143,143, 2,143,143, 2,143,143,143,143,143,143,143,143, 143,143,143,143,143,143,143,143,143,143,143,143,143, 2,143,143, 2,143,143,143,143,143,143, 2, 2, 2, 2, 2, 2, 2,143,143, - 2, 2, 2, 2, 2, 2,145,145,145,145,145,145,145,145,145, 2, - 2, 2, 2, 2, 2, 2,163,163,163,163,163,163,163,163,163, 2, - 163,163,163,163,163,163,163,163,163, 2, 2, 2,163,163,163,163, - 163, 2, 2, 2, 2, 2, 86, 2, 2, 2, 2, 2, 2, 2, 22, 22, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, 2, 2, 2, 2, 2, 2, 63, 63, - 63, 63, 63, 63, 63, 2, 63, 63, 63, 63, 63, 2, 2, 2, 63, 63, - 63, 63, 2, 2, 2, 2,157,157,157,157,157,157,157,157,157,157, - 157, 2, 2, 2, 2, 2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 2, 2, 80, 80, 80, 2, 2, 2, 2, 2,127,127, - 127,127,127,127,127,127,127,127,127,127,127,127,127, 2,166,166, - 166,166,166,166,166,166,166,166, 2, 2, 2, 2, 2, 2, 79, 2, - 2, 2, 2, 2, 2, 2,115,115,115,115,115,115,115,115,115,115, - 115,115,115,115,115, 2,115,115, 2, 2, 2, 2,115,115,159,159, - 159,159,159,159,159,159,159,159,159,159,159,159,159, 2,159,159, - 2, 2, 2, 2, 2, 2,103,103,103,103,103,103,103,103,103,103, - 103,103,103,103, 2, 2,119,119,119,119,119,119,119,119,119,119, - 119,119,119,119, 2, 2,119,119, 2,119,119,119,119,119, 2, 2, - 2, 2, 2,119,119,119,167,167,167,167,167,167,167,167,167,167, - 2, 2, 2, 2, 2, 2,146,146,146,146,146,146,146,146,146,146, - 146, 2, 2, 2, 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 2, 2, 2, 2, 2, 2,175,175,175,175,175,175,175,175,175,175, + 175,175, 2, 2, 2, 2,175,175, 2, 2, 2, 2, 2, 2,145,145, + 145,145,145,145,145,145,145, 2, 2, 2, 2, 2, 2, 2,163,163, + 163,163,163,163,163,163,163, 2,163,163,163,163,163,163,163,163, + 163, 2, 2, 2,163,163,163,163,163, 2, 2, 2, 2, 2, 86, 2, + 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 22, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63, 63, 2, 63, 63, + 63, 63, 63, 2, 2, 2, 63, 63, 63, 63, 2, 2, 2, 2,157,157, + 157,157,157,157,157,157,157,157,157, 2, 2, 2, 2, 2, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 2, 2, 80, 80, + 80, 2, 2, 2, 2, 2,127,127,127,127,127,127,127,127,127,127, + 127,127,127,127,127, 2,166,166,166,166,166,166,166,166,166,166, + 2, 2, 2, 2, 2, 2, 79, 2, 2, 2, 2, 2, 2, 2,115,115, + 115,115,115,115,115,115,115,115,115,115,115,115,115, 2,115,115, + 2, 2, 2, 2,115,115,159,159,159,159,159,159,159,159,159,159, + 159,159,159,159,159, 2,159,159, 2, 2, 2, 2, 2, 2,103,103, + 103,103,103,103,103,103,103,103,103,103,103,103, 2, 2,119,119, + 119,119,119,119,119,119,119,119,119,119,119,119, 2, 2,119,119, + 2,119,119,119,119,119, 2, 2, 2, 2, 2,119,119,119,167,167, + 167,167,167,167,167,167,167,167, 2, 2, 2, 2, 2, 2,146,146, + 146,146,146,146,146,146,146,146,146, 2, 2, 2, 2, 2,172,172, + 172,172,172,172,172,172,172, 2, 2,172,172,172,172,172,172,172, + 172,172, 2, 2, 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2, 2, 99, 2, 2, 2, 2, 2, 2, 2, 99,136,139, - 13, 13,155, 2, 2, 2,136,136,136,136,136,136,136,136,155,155, - 155,155,155,155,155,155,155,155,155,155,155,155, 2, 2, 2, 2, - 2, 2, 2, 2, 2,155,136, 2, 2, 2, 2, 2, 2, 2, 17, 17, + 13, 13,155, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 2,136,136, + 136,136,136,136,136,136,155,155,155,155,155,155,155,155,155,155, + 155,155,155,155, 2, 2, 2, 2, 2, 2, 2, 2, 2,155,136,136, + 136,136,136,136,136, 2,136,136,136, 2, 2, 2, 2, 2, 17, 17, 17, 17, 2, 17, 17, 17, 17, 17, 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 15, 15, 15, 15, 17, 17, 17, 2, 2, 2, 2, 2, 2, 2, 15, 2, 2, 2, 2, 2, 15, 15, 15, 2, 2, 17, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17,139,139,139,139,139,139,139,139,139,139, 139,139, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105, 105, 2, 2, 2, 2, 2,105,105,105,105,105, 2, 2, 2,105, 2, - 2, 2, 2, 2, 2, 2,105,105, 2, 2,105,105,105,105, 1, 1, - 1, 1, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 2, 2, 2, 2, 2, 2,105,105, 2, 2,105,105,105,105, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 1, 1, + 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 2, 2, 0, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 2, 2, - 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,131,131, + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, + 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, + 0, 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0,131,131, 131,131,131,131,131,131,131,131,131,131, 2, 2, 2, 2, 2, 2, 2,131,131,131,131,131, 2,131,131,131,131,131,131,131, 2, 2, 2, 2, 2, 19, 19, 19, 56, 56, 56, 56, 56, 56, 56, 2, 56, 2, @@ -2090,7 +1910,9 @@ _hb_ucd_u8[17612] = 160,160,160,160,160, 2,152,152,152,152,152,152,152,152,152,152, 2, 2, 2, 2, 2,152,164,164,164,164,164,164,164,164,164,164, 2, 2, 2, 2, 2, 2,168,168,168,168,168,168,168,168,168,168, - 168, 2, 2, 2, 2,168, 30, 30, 30, 30, 2, 30, 30, 2,113,113, + 168, 2, 2, 2, 2,168,174,174,174,174,174,174,174,174,174,174, + 174,174,174,174,174, 2,174,174,174,174,174,174, 2, 2, 2, 2, + 2, 2, 2, 2,174,174, 30, 30, 30, 30, 2, 30, 30, 2,113,113, 113,113,113,113,113,113,113,113,113,113,113, 2, 2,113,113,113, 113,113,113,113,113, 2,132,132,132,132,132,132,132,132,132,132, 132,132, 2, 2, 2, 2,132,132, 2, 2, 2, 2,132,132, 3, 3, @@ -2101,8 +1923,8 @@ _hb_ucd_u8[17612] = 3, 3, 3, 2, 3, 2, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 15, 0, - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, - 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 13, 2, 2, 2, 2, 2, 2, 2, 13, 13, 13, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, 9, 11, 12, 13, @@ -2186,8 +2008,7 @@ _hb_ucd_u8[17612] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, }; -static const uint16_t -_hb_ucd_u16[10400] = +static const uint16_t _hb_ucd_u16[10832]= { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12, 13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23, @@ -2210,27 +2031,29 @@ _hb_ucd_u16[10400] = 48, 48, 48, 48, 168, 169, 48, 48, 168, 48, 48, 170, 171, 172, 48, 48, 48, 171, 48, 48, 48, 173, 174, 175, 48, 176, 9, 9, 9, 9, 9, 177, 178, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 179, 48, 180, 181, 48, 48, 48, 48, 182, 183, 48, 184, 48, 185, 48, 186, 187, 188, 48, 48, 48, 189, 190, 191, 192, 193, 194, 192, 48, 48, 195, 48, 48, 196, 197, 48, 198, 48, 48, 48, 48, 199, 48, 200, 201, 202, 203, 48, 204, 205, 48, 48, 206, 48, 207, 208, 209, 209, - 48, 210, 48, 48, 48, 211, 212, 213, 192, 192, 214, 215, 216, 140, 140, 140, - 217, 48, 48, 218, 219, 160, 220, 221, 222, 48, 223, 64, 48, 48, 224, 225, - 48, 48, 226, 227, 228, 64, 48, 229, 230, 9, 9, 231, 232, 233, 234, 235, - 11, 11, 236, 27, 27, 27, 237, 238, 11, 239, 27, 27, 32, 32, 32, 32, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 240, 13, 13, 13, 13, 13, 13, - 241, 242, 241, 241, 242, 243, 241, 244, 245, 245, 245, 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, 271, 272, 272, 273, 274, 275, 209, 276, 277, 209, 278, - 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, - 280, 209, 281, 209, 209, 209, 209, 282, 209, 283, 279, 284, 209, 285, 286, 209, - 209, 209, 176, 140, 287, 140, 271, 271, 271, 288, 209, 209, 209, 209, 289, 271, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 290, 291, 209, 209, 292, - 209, 209, 209, 209, 209, 209, 293, 209, 209, 209, 209, 209, 209, 209, 209, 209, - 209, 209, 209, 209, 209, 209, 294, 295, 271, 296, 209, 209, 297, 279, 298, 279, + 48, 210, 48, 48, 48, 211, 212, 213, 192, 192, 214, 215, 32, 216, 217, 140, + 218, 48, 48, 219, 220, 160, 221, 222, 223, 48, 224, 64, 48, 48, 225, 226, + 48, 48, 227, 228, 229, 64, 48, 230, 231, 9, 9, 232, 233, 234, 235, 236, + 11, 11, 237, 27, 27, 27, 238, 239, 11, 240, 27, 27, 32, 32, 32, 32, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 241, 13, 13, 13, 13, 13, 13, + 242, 243, 242, 242, 243, 244, 242, 245, 246, 246, 246, 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 273, 274, 275, 276, 209, 277, 278, 209, 279, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 281, 209, 282, 209, 209, 209, 209, 283, 209, 284, 280, 285, 209, 286, 287, 209, + 209, 209, 176, 140, 288, 140, 272, 272, 272, 289, 209, 209, 209, 209, 290, 272, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 291, 292, 209, 209, 293, + 209, 209, 209, 209, 209, 209, 294, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 295, 296, 272, 297, 209, 209, 298, 280, 299, 280, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, - 279, 279, 279, 279, 279, 279, 279, 279, 299, 300, 279, 279, 279, 301, 279, 302, - 209, 209, 209, 279, 303, 209, 209, 304, 209, 305, 209, 209, 209, 209, 209, 209, + 280, 280, 280, 280, 280, 280, 280, 280, 300, 301, 280, 280, 280, 302, 280, 303, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 209, 209, 209, 280, 304, 209, 209, 305, 209, 209, 209, 209, 209, 209, 209, 209, 9, 9, 9, 11, 11, 11, 306, 307, 13, 13, 13, 13, 13, 13, 308, 309, 11, 11, 310, 48, 48, 48, 311, 312, 48, 313, 314, 314, 314, 314, 32, 32, 315, 316, 317, 318, 319, 320, 140, 140, 209, 321, 209, 209, 209, 209, 209, 322, @@ -2238,226 +2061,201 @@ _hb_ucd_u16[10400] = 324, 325, 326, 327, 136, 48, 48, 48, 48, 328, 178, 48, 48, 48, 48, 329, 330, 48, 48, 136, 48, 48, 48, 48, 200, 331, 48, 48, 209, 209, 332, 48, 209, 333, 334, 209, 335, 336, 209, 209, 334, 209, 209, 336, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 209, 209, 209, 209, 48, 337, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 151, 209, 209, 209, 338, 48, 48, 229, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 151, 209, 209, 209, 338, 48, 48, 230, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 339, 48, 340, 140, 13, 13, 341, 342, 13, 343, 48, 48, 48, 48, 344, 345, 31, 346, 347, 348, 13, 13, 13, 349, 350, 351, 352, 353, 354, 355, 140, 356, 357, 48, 358, 359, 48, 48, 48, 360, 361, 48, 48, 362, 363, 192, 32, 364, 64, 48, 365, 48, 366, 367, 48, 151, 76, 48, 48, 368, 369, 370, 371, 372, 48, 48, 373, 374, 375, 376, 48, 377, 48, 48, 48, 378, 379, 380, 381, 382, 383, 384, 314, 11, 11, 385, 386, 11, 11, 11, 11, 11, 48, 48, 387, 192, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 388, 48, 389, 48, 48, 206, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, + 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 204, 48, 48, 48, 48, 48, 48, 207, 140, 140, 392, 393, 394, 395, 396, 48, 48, 48, 48, 48, 48, 397, 398, 399, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 400, 209, 48, 48, 48, 48, 401, 48, 48, 402, 140, 140, 403, 32, 404, 32, 405, 406, 407, 408, 409, 48, 48, 48, 48, 48, 48, 48, 410, 411, 2, 3, 4, 5, 412, 413, 414, 48, 415, 48, 200, 416, 417, 418, 419, 420, 48, 172, 421, 204, 204, 140, 140, 48, 48, 48, 48, 48, 48, 48, 71, - 422, 271, 271, 423, 272, 272, 272, 424, 425, 426, 427, 140, 140, 209, 209, 428, + 422, 272, 272, 423, 273, 273, 273, 424, 425, 426, 427, 140, 140, 209, 209, 428, 140, 140, 140, 140, 140, 140, 140, 140, 48, 151, 48, 48, 48, 100, 429, 430, 48, 48, 431, 48, 432, 48, 48, 433, 48, 434, 48, 48, 435, 436, 140, 140, 9, 9, 437, 11, 11, 48, 48, 48, 48, 204, 192, 9, 9, 438, 11, 439, 48, 48, 440, 48, 48, 48, 441, 442, 442, 443, 444, 445, 48, 48, 48, 388, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 313, 48, 199, 440, 140, 446, 27, 27, 447, 140, 140, 140, 140, 448, 48, 48, 449, 48, 450, 48, 451, 48, 200, 452, 140, 140, 140, 48, 453, - 48, 454, 48, 455, 140, 140, 140, 140, 48, 48, 48, 456, 271, 457, 271, 271, + 48, 454, 48, 455, 48, 207, 140, 140, 48, 48, 48, 456, 272, 457, 272, 272, 458, 459, 48, 460, 461, 462, 48, 463, 48, 464, 140, 140, 465, 48, 466, 467, 48, 48, 48, 468, 48, 469, 48, 470, 48, 471, 472, 140, 140, 140, 140, 140, 48, 48, 48, 48, 196, 140, 140, 140, 9, 9, 9, 473, 11, 11, 11, 474, 48, 48, 475, 192, 476, 9, 477, 11, 478, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 271, 479, 48, 48, 480, 481, 482, 140, 140, 483, - 48, 464, 484, 48, 62, 485, 140, 48, 486, 140, 140, 48, 487, 140, 48, 313, - 488, 48, 48, 489, 490, 457, 491, 492, 222, 48, 48, 493, 494, 48, 196, 192, - 495, 48, 496, 497, 498, 48, 48, 499, 222, 48, 48, 500, 501, 502, 503, 504, - 48, 97, 505, 506, 507, 140, 140, 140, 508, 509, 510, 48, 48, 511, 512, 192, - 513, 83, 84, 514, 515, 516, 517, 518, 519, 48, 48, 520, 521, 522, 523, 140, - 48, 48, 48, 524, 525, 526, 481, 140, 48, 48, 48, 527, 528, 192, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 529, 530, 531, 532, 140, 140, - 48, 48, 48, 533, 534, 192, 535, 140, 48, 48, 536, 537, 192, 538, 539, 140, - 48, 540, 541, 542, 313, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 48, 505, 543, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 544, - 545, 546, 48, 547, 548, 192, 140, 140, 140, 140, 549, 48, 48, 550, 551, 140, - 552, 48, 48, 553, 554, 555, 48, 48, 556, 557, 558, 48, 48, 48, 48, 196, - 559, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 560, 192, - 84, 48, 529, 561, 562, 148, 175, 563, 48, 564, 565, 566, 140, 140, 140, 140, - 567, 48, 48, 568, 569, 192, 570, 48, 571, 572, 192, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 573, - 574, 115, 48, 575, 576, 577, 140, 140, 140, 140, 140, 100, 271, 578, 579, 580, + 140, 140, 140, 140, 140, 140, 272, 479, 48, 48, 480, 481, 482, 483, 140, 484, + 48, 464, 485, 48, 62, 486, 140, 48, 487, 140, 140, 48, 488, 140, 48, 313, + 489, 48, 48, 490, 491, 457, 492, 493, 223, 48, 48, 494, 495, 48, 196, 192, + 496, 48, 497, 498, 499, 48, 48, 500, 223, 48, 48, 501, 502, 503, 504, 505, + 48, 97, 506, 507, 508, 140, 140, 140, 509, 510, 511, 48, 48, 512, 513, 192, + 514, 83, 84, 515, 516, 517, 518, 519, 520, 48, 48, 521, 522, 523, 524, 140, + 48, 48, 48, 525, 526, 527, 481, 140, 48, 48, 48, 528, 529, 192, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 530, 531, 532, 533, 140, 140, + 48, 48, 48, 534, 535, 192, 536, 140, 48, 48, 537, 538, 192, 539, 540, 140, + 48, 541, 542, 543, 313, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 48, 48, 506, 544, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 545, + 546, 547, 48, 548, 549, 192, 140, 140, 140, 140, 550, 48, 48, 551, 552, 140, + 553, 48, 48, 554, 555, 556, 48, 48, 557, 558, 559, 48, 48, 48, 48, 196, + 560, 140, 140, 140, 140, 140, 561, 140, 140, 140, 140, 140, 48, 48, 562, 192, + 84, 48, 530, 563, 564, 148, 175, 565, 48, 566, 567, 568, 140, 140, 140, 140, + 569, 48, 48, 570, 571, 192, 572, 48, 573, 574, 192, 48, 48, 575, 192, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 576, + 577, 115, 48, 578, 579, 580, 140, 140, 140, 140, 140, 100, 272, 581, 582, 583, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 207, 140, 140, 140, 140, 140, 140, - 272, 272, 272, 272, 272, 272, 581, 582, 48, 48, 48, 48, 48, 48, 48, 48, + 273, 273, 273, 273, 273, 273, 584, 585, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 388, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 583, - 48, 48, 48, 584, 585, 586, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 586, + 48, 48, 48, 587, 588, 589, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 71, 48, 48, 48, 48, 313, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 587, 588, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 589, - 48, 48, 48, 590, 591, 592, 593, 594, 48, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 595, 48, 596, 192, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 9, 9, 11, 11, 271, 597, 140, 140, 140, 140, 140, 140, - 48, 48, 48, 48, 598, 599, 600, 600, 601, 602, 140, 140, 140, 140, 603, 604, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 440, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 199, 140, 605, - 196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 606, - 48, 48, 607, 608, 140, 609, 610, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 48, 590, 591, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 592, + 48, 48, 48, 593, 594, 595, 596, 597, 48, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 598, 48, 599, 192, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 9, 9, 11, 11, 272, 600, 9, 601, 11, 602, 140, 140, + 48, 48, 48, 48, 603, 604, 605, 605, 606, 607, 140, 140, 140, 140, 608, 609, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 199, 140, 610, + 48, 200, 140, 140, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 48, 611, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 612, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 611, 613, 140, 614, 615, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 206, - 48, 48, 48, 48, 48, 48, 71, 151, 196, 611, 612, 140, 140, 140, 140, 140, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 192, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 322, 140, 140, 140, 140, - 32, 32, 613, 32, 614, 209, 209, 209, 209, 209, 209, 209, 322, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 48, 48, 48, 48, 48, 48, 71, 151, 196, 616, 617, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 618, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 619, 209, 427, 209, 620, + 32, 32, 216, 32, 621, 209, 209, 209, 209, 209, 209, 209, 322, 140, 140, 140, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 323, - 209, 209, 615, 209, 209, 209, 616, 617, 618, 209, 619, 209, 209, 209, 287, 140, - 209, 209, 209, 209, 620, 140, 140, 140, 140, 140, 140, 140, 271, 621, 271, 621, - 209, 209, 209, 209, 209, 338, 271, 461, 140, 140, 140, 140, 140, 140, 140, 140, - 9, 622, 11, 623, 624, 625, 241, 9, 626, 627, 628, 629, 630, 9, 622, 11, - 631, 632, 11, 633, 634, 635, 636, 9, 637, 11, 9, 622, 11, 623, 624, 11, - 241, 9, 626, 636, 9, 637, 11, 9, 622, 11, 638, 9, 639, 640, 641, 642, - 11, 643, 9, 644, 645, 646, 647, 11, 648, 9, 649, 11, 650, 538, 538, 538, - 32, 32, 32, 651, 32, 32, 652, 653, 654, 655, 45, 140, 140, 140, 140, 140, - 656, 657, 658, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 659, 660, 661, 27, 27, 27, 662, 140, 663, 140, 140, 140, 140, 140, 140, 140, - 48, 48, 151, 664, 665, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 666, 140, 48, 48, 667, 668, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 669, 192, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 587, 670, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 671, 200, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 672, 614, 140, 140, - 9, 9, 626, 11, 673, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 503, 271, 271, 674, 675, 140, 140, 140, 140, - 503, 271, 676, 677, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 678, 48, 679, 680, 681, 682, 683, 684, 685, 206, 686, 206, 140, 140, 140, 687, - 209, 209, 688, 209, 209, 209, 209, 209, 209, 322, 333, 689, 689, 689, 209, 323, - 690, 209, 209, 209, 209, 209, 209, 209, 209, 209, 691, 140, 140, 140, 692, 209, - 693, 209, 209, 688, 694, 695, 323, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 696, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 697, 426, 426, - 209, 209, 209, 209, 209, 209, 209, 698, 209, 209, 209, 209, 209, 176, 688, 427, - 688, 209, 209, 209, 699, 176, 209, 209, 699, 209, 691, 688, 695, 140, 140, 140, - 209, 209, 209, 209, 209, 322, 691, 426, 700, 209, 209, 209, 701, 702, 176, 694, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 703, 209, 209, 209, 209, 209, 192, + 209, 209, 622, 209, 209, 209, 623, 624, 625, 209, 626, 209, 209, 209, 288, 140, + 209, 209, 209, 209, 627, 140, 140, 140, 140, 140, 140, 140, 272, 628, 272, 628, + 209, 209, 209, 209, 209, 338, 272, 461, 140, 140, 140, 140, 140, 140, 140, 140, + 9, 629, 11, 630, 631, 632, 242, 9, 633, 634, 635, 636, 637, 9, 629, 11, + 638, 639, 11, 640, 641, 642, 643, 9, 644, 11, 9, 629, 11, 630, 631, 11, + 242, 9, 633, 643, 9, 644, 11, 9, 629, 11, 645, 9, 646, 647, 648, 649, + 11, 650, 9, 651, 652, 653, 654, 11, 655, 9, 656, 11, 657, 539, 539, 539, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 32, 32, 32, 658, 32, 32, 659, 660, 661, 662, 45, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 663, 664, 665, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 666, 667, 668, 27, 27, 27, 669, 140, 670, 140, 140, 140, 140, 140, 140, 140, + 48, 48, 151, 671, 672, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 673, 140, 48, 48, 674, 675, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 676, 192, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 590, 677, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 200, 678, 679, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 680, 200, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 681, 621, 140, 140, + 9, 9, 633, 11, 682, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 504, 272, 272, 683, 684, 140, 140, 140, 140, + 504, 272, 685, 686, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 687, 48, 688, 689, 690, 691, 692, 693, 694, 206, 695, 206, 140, 140, 140, 696, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 209, 209, 697, 209, 209, 209, 209, 209, 209, 322, 333, 698, 698, 698, 209, 323, + 699, 209, 209, 209, 209, 209, 209, 209, 209, 209, 700, 140, 140, 140, 701, 209, + 702, 209, 209, 697, 703, 704, 323, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 705, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 706, 426, 426, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 176, 697, 427, + 697, 209, 209, 209, 707, 176, 209, 209, 707, 209, 700, 697, 704, 708, 140, 140, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 707, 700, 426, 709, 209, 209, 209, 710, 711, 712, 703, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 713, 209, 209, 209, 209, 209, 714, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 140, 140, - 48, 48, 48, 207, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 481, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 204, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 100, 48, 48, 48, 48, 48, 48, 204, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 204, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 48, 48, 48, 71, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 140, 140, 140, 140, 140, - 704, 140, 584, 584, 584, 584, 584, 584, 140, 140, 140, 140, 140, 140, 140, 140, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 140, - 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 705, - 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 706, - 0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10, - 11, 11, 12, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 57, 58, 59, 60, 60, 60, 60, 61, 62, 63, 64, 65, 66, 67, 68, - 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 7, 4, 4, 4, 4, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 108, 109, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 110, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 112, 112, 112, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 114, 0, - 115, 116, 117, 118, 119, 120, 121, 122, 0, 123, 124, 125, 126, 126, 126, 127, - 128, 129, 130, 131, 132, 60, 133, 134, 135, 136, 0, 137, 138, 139, 0, 0, - 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 0, 126, 126, 126, 126, 126, 126, 126, 126, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 141, 142, 143, 143, 143, 143, 144, 11, 145, 146, 147, 4, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 166, 167, - 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, - 168, 168, 168, 168, 126, 126, 126, 126, 126, 169, 126, 170, 171, 172, 19, 173, - 19, 19, 19, 19, 174, 19, 175, 176, 177, 178, 19, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 168, 168, 192, 193, 194, 195, 196, 197, - 198, 199, 200, 201, 202, 203, 204, 205, 206, 206, 206, 206, 207, 208, 209, 168, - 210, 211, 212, 213, 214, 168, 215, 216, 217, 218, 219, 220, 221, 222, 223, 168, - 224, 225, 226, 227, 228, 229, 230, 168, 168, 231, 232, 233, 234, 235, 236, 237, - 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, - 254, 255, 256, 257, 168, 168, 258, 259, 260, 261, 262, 263, 264, 265, 168, 168, - 266, 168, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 168, 168, 278, - 279, 280, 281, 168, 282, 283, 284, 168, 168, 168, 168, 285, 286, 287, 288, 289, - 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 291, 168, - 290, 292, 290, 290, 290, 293, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, - 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 294, 295, - 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, - 296, 297, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, - 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 298, - 299, 299, 299, 299, 299, 299, 299, 299, 299, 300, 168, 168, 168, 168, 168, 168, - 168, 168, 168, 168, 301, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, - 302, 302, 302, 302, 302, 302, 302, 302, 303, 304, 305, 306, 307, 308, 309, 168, - 168, 168, 168, 168, 168, 310, 168, 168, 168, 311, 312, 168, 313, 314, 315, 316, - 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, - 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 318, - 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 319, 319, 319, 319, - 319, 319, 319, 320, 321, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, - 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 322, - 323, 324, 324, 324, 325, 326, 327, 327, 327, 327, 327, 328, 168, 168, 168, 168, - 329, 330, 331, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, - 0, 0, 0, 332, 0, 0, 0, 0, 0, 0, 333, 168, 334, 335, 0, 336, - 0, 0, 0, 337, 338, 339, 340, 341, 189, 342, 168, 343, 0, 344, 168, 168, - 0, 345, 346, 347, 348, 349, 0, 0, 0, 0, 350, 0, 0, 0, 0, 351, - 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 353, 168, 168, 168, 168, 168, - 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 354, 168, 168, 168, - 355, 356, 357, 168, 358, 359, 168, 168, 168, 168, 360, 361, 168, 168, 168, 168, - 168, 168, 168, 362, 168, 168, 168, 363, 168, 168, 168, 168, 168, 168, 168, 364, - 365, 365, 365, 366, 367, 368, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, - 168, 369, 370, 168, 371, 168, 168, 168, 372, 373, 374, 375, 168, 168, 168, 168, - 376, 0, 377, 378, 0, 0, 379, 380, 381, 382, 168, 168, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 383, 0, 384, 0, 385, - 386, 387, 388, 389, 0, 0, 0, 0, 0, 390, 391, 392, 0, 0, 393, 332, - 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 394, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 395, 126, 126, 126, - 396, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 397, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 398, - 126, 126, 126, 126, 126, 126, 126, 126, 126, 399, 168, 168, 168, 168, 168, 168, - 126, 126, 126, 126, 126, 126, 126, 126, 399, 168, 168, 168, 168, 168, 168, 168, - 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 400, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 401, 168, - 402, 0, 168, 168, 7, 7, 7, 403, 0, 1, 2, 3, 4, 4, 4, 4, + 48, 204, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 71, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 207, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 715, 140, 587, 587, 587, 587, 587, 587, 140, 140, 140, 140, 140, 140, 140, 140, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 140, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 716, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 717, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3, 0, 0, 0, 0, 0, 4, 0, 4, 2, 2, 5, 2, 2, 2, 5, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, - 0, 0, 0, 0, 7, 8, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 10, 11, 12, 13, 14, 14, 15, 14, 14, 14, - 14, 14, 14, 14, 16, 17, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18, - 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 20, 21, - 21, 21, 22, 20, 21, 21, 21, 21, 21, 23, 24, 25, 25, 25, 25, 25, - 25, 26, 25, 25, 25, 27, 28, 26, 29, 30, 31, 32, 31, 31, 31, 31, - 33, 34, 35, 31, 31, 31, 36, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 29, 31, 31, 31, 31, 37, 38, 37, 37, 37, 37, 37, 37, - 37, 39, 31, 31, 31, 31, 31, 31, 40, 40, 40, 40, 40, 40, 41, 26, - 42, 42, 42, 42, 42, 42, 42, 43, 44, 44, 44, 44, 44, 45, 44, 46, - 47, 47, 47, 48, 37, 49, 31, 31, 31, 50, 51, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 52, 31, 31, 31, 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 54, 53, 55, 53, 53, 53, 56, 57, 58, 59, 59, 60, 61, 62, - 57, 63, 64, 65, 66, 59, 59, 67, 68, 69, 70, 71, 71, 72, 73, 74, - 69, 75, 76, 77, 78, 71, 79, 26, 80, 81, 82, 83, 83, 84, 85, 86, - 81, 87, 88, 26, 89, 83, 90, 91, 92, 93, 94, 95, 95, 96, 97, 98, - 93, 99, 100, 101, 102, 95, 95, 26, 103, 104, 105, 106, 107, 104, 108, 109, - 104, 105, 110, 26, 111, 108, 108, 112, 113, 114, 115, 113, 113, 115, 113, 116, - 114, 117, 118, 119, 120, 113, 121, 113, 122, 123, 124, 122, 122, 124, 125, 126, - 123, 127, 128, 128, 129, 122, 130, 26, 131, 132, 133, 131, 131, 131, 131, 131, - 132, 133, 134, 131, 135, 131, 131, 131, 136, 137, 138, 139, 137, 137, 140, 141, - 138, 142, 143, 137, 144, 137, 145, 26, 146, 147, 147, 147, 147, 147, 147, 148, - 147, 147, 147, 149, 26, 26, 26, 26, 150, 151, 152, 152, 153, 152, 152, 154, - 155, 156, 152, 157, 26, 26, 26, 26, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 159, 158, 158, 158, 160, 159, 158, 158, 158, 158, 159, 158, 158, 158, 161, - 158, 161, 162, 163, 26, 26, 26, 26, 164, 164, 164, 164, 164, 164, 164, 164, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 6, 0, 0, 0, 0, 7, 8, 0, 0, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 11, + 12, 13, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14, 16, 17, 14, 14, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 20, 21, 21, 21, 22, 20, 21, 21, 21, 21, + 21, 23, 24, 25, 25, 25, 25, 25, 25, 26, 25, 25, 25, 27, 28, 26, + 29, 30, 31, 32, 31, 31, 31, 31, 33, 34, 35, 31, 31, 31, 36, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 29, 31, 31, 31, 31, + 37, 38, 37, 37, 37, 37, 37, 37, 37, 39, 31, 31, 31, 31, 31, 31, + 40, 40, 40, 40, 40, 40, 41, 26, 42, 42, 42, 42, 42, 42, 42, 43, + 44, 44, 44, 44, 44, 45, 44, 46, 47, 47, 47, 48, 37, 49, 31, 31, + 31, 31, 50, 31, 31, 31, 31, 31, 31, 31, 31, 31, 51, 31, 31, 31, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 53, 52, 54, 52, 52, 52, + 55, 56, 57, 58, 58, 59, 60, 61, 56, 62, 63, 64, 65, 58, 58, 66, + 67, 68, 69, 70, 70, 71, 72, 73, 68, 74, 75, 76, 77, 70, 78, 26, + 79, 80, 81, 82, 82, 83, 84, 85, 80, 86, 87, 26, 88, 82, 89, 90, + 91, 92, 93, 94, 94, 95, 96, 97, 92, 98, 99, 100, 101, 94, 94, 26, + 102, 103, 104, 105, 106, 103, 107, 108, 103, 104, 109, 26, 110, 107, 107, 111, + 112, 113, 114, 112, 112, 114, 112, 115, 113, 116, 117, 118, 119, 112, 120, 112, + 121, 122, 123, 121, 121, 123, 124, 125, 122, 126, 127, 128, 129, 121, 130, 26, + 131, 132, 133, 131, 131, 131, 131, 131, 132, 133, 134, 131, 135, 131, 131, 131, + 136, 137, 138, 139, 137, 137, 140, 141, 138, 142, 143, 137, 144, 137, 145, 26, + 146, 147, 147, 147, 147, 147, 147, 148, 147, 147, 147, 149, 26, 26, 26, 26, + 150, 151, 152, 152, 153, 152, 152, 154, 155, 156, 152, 157, 26, 26, 26, 26, + 158, 158, 158, 158, 158, 158, 158, 158, 158, 159, 158, 158, 158, 160, 159, 158, + 158, 158, 158, 159, 158, 158, 158, 161, 158, 161, 162, 163, 26, 26, 26, 26, + 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 165, 165, 165, 165, 166, 167, 165, 165, 165, 165, 165, 168, - 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170, 170, 170, - 170, 171, 172, 171, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 171, 172, - 171, 170, 172, 170, 170, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 170, - 170, 170, 170, 173, 170, 170, 170, 174, 170, 170, 170, 175, 176, 176, 176, 176, - 176, 176, 176, 176, 176, 176, 177, 177, 178, 178, 178, 178, 178, 178, 178, 178, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 170, 170, 170, 170, 170, 170, 170, 170, 170, 171, 172, 171, 170, 170, 170, 170, + 170, 171, 170, 170, 170, 170, 171, 172, 171, 170, 172, 170, 170, 170, 170, 170, + 170, 170, 171, 170, 170, 170, 170, 170, 170, 170, 170, 173, 170, 170, 170, 174, + 170, 170, 170, 175, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 177, 177, + 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 179, 179, 179, 180, 181, 181, 181, 181, 181, 181, 181, 181, 181, 182, 181, 183, 184, 184, 185, 186, 187, 187, 188, 26, 189, 189, 190, 26, 191, 192, 193, 26, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 195, 194, 196, 194, 196, @@ -2466,165 +2264,215 @@ _hb_ucd_u16[10400] = 203, 203, 203, 204, 203, 205, 203, 205, 206, 203, 207, 207, 207, 208, 209, 26, 210, 210, 210, 210, 210, 211, 210, 210, 210, 212, 210, 213, 194, 194, 194, 194, 214, 214, 214, 215, 216, 216, 216, 216, 216, 216, 216, 217, 216, 216, 216, 218, - 216, 219, 216, 219, 216, 220, 9, 9, 9, 221, 26, 26, 26, 26, 26, 26, - 222, 222, 222, 222, 222, 222, 222, 222, 222, 223, 222, 222, 222, 222, 222, 222, - 224, 224, 224, 224, 224, 224, 224, 224, 225, 225, 225, 225, 225, 225, 226, 227, - 228, 228, 228, 228, 228, 228, 228, 229, 228, 230, 231, 231, 231, 231, 231, 231, - 18, 232, 165, 165, 165, 165, 165, 233, 224, 26, 234, 9, 235, 236, 237, 238, - 2, 2, 2, 2, 239, 240, 2, 2, 2, 2, 2, 241, 242, 243, 2, 244, - 2, 2, 2, 2, 2, 2, 2, 245, 14, 14, 246, 246, 14, 14, 14, 14, - 246, 246, 14, 247, 14, 14, 14, 246, 14, 14, 14, 14, 14, 14, 248, 14, - 248, 14, 249, 250, 14, 14, 251, 252, 0, 253, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 254, 0, 255, 256, 0, 257, 2, 258, 0, 0, 0, 0, - 259, 26, 9, 9, 9, 9, 260, 26, 0, 0, 0, 0, 261, 262, 4, 0, - 0, 263, 0, 0, 2, 2, 2, 2, 2, 264, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 265, 26, 26, 0, 266, 26, 26, 0, 0, 0, 0, - 267, 267, 267, 267, 267, 267, 267, 267, 0, 0, 0, 0, 0, 0, 268, 0, - 0, 0, 269, 0, 0, 0, 0, 0, 270, 270, 270, 270, 270, 270, 270, 270, - 270, 270, 270, 270, 2, 2, 2, 2, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 271, 272, 165, 165, 165, 165, 166, 167, 273, 273, - 273, 273, 273, 273, 273, 274, 275, 274, 170, 170, 172, 26, 172, 172, 172, 172, - 172, 172, 172, 172, 18, 18, 18, 18, 0, 0, 0, 276, 26, 26, 26, 26, - 277, 277, 277, 278, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 279, 26, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280, 26, 26, 26, 0, 0, - 281, 0, 0, 0, 282, 283, 0, 284, 285, 286, 286, 286, 286, 286, 286, 286, - 286, 286, 287, 288, 289, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 291, - 292, 293, 293, 293, 293, 293, 294, 169, 169, 295, 0, 0, 293, 293, 293, 293, - 0, 0, 0, 0, 276, 296, 290, 290, 169, 169, 169, 295, 0, 0, 0, 0, - 0, 0, 0, 0, 169, 169, 169, 297, 0, 0, 290, 290, 290, 290, 290, 298, - 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 0, 0, 0, 0, 0, - 299, 299, 299, 299, 299, 299, 299, 299, 299, 300, 299, 299, 299, 299, 299, 299, - 301, 26, 302, 302, 302, 302, 302, 302, 303, 303, 303, 303, 303, 303, 303, 303, - 303, 303, 303, 303, 303, 304, 26, 26, 18, 18, 18, 18, 305, 305, 305, 305, - 305, 305, 305, 305, 305, 305, 305, 26, 0, 0, 0, 0, 306, 2, 2, 2, - 2, 307, 2, 2, 2, 2, 2, 2, 2, 308, 309, 258, 26, 26, 310, 2, - 311, 311, 311, 311, 311, 312, 0, 265, 313, 313, 313, 313, 313, 313, 313, 26, - 314, 314, 314, 314, 314, 314, 314, 314, 315, 316, 314, 317, 53, 53, 53, 53, - 318, 318, 318, 318, 318, 319, 320, 320, 320, 320, 321, 322, 169, 169, 169, 323, - 324, 324, 324, 324, 324, 324, 324, 324, 324, 325, 324, 326, 164, 164, 164, 327, - 328, 328, 328, 328, 328, 328, 329, 26, 328, 330, 328, 331, 164, 164, 164, 164, - 332, 332, 332, 332, 332, 332, 332, 332, 333, 26, 26, 334, 335, 335, 336, 26, - 337, 337, 337, 26, 172, 172, 2, 2, 2, 2, 2, 338, 339, 340, 176, 176, - 176, 176, 176, 176, 176, 176, 176, 176, 335, 335, 335, 335, 335, 341, 335, 342, - 169, 169, 169, 169, 343, 26, 169, 169, 295, 344, 169, 169, 169, 169, 169, 343, - 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 280, 277, 277, - 277, 277, 277, 345, 26, 26, 26, 26, 346, 26, 347, 348, 25, 25, 349, 350, - 351, 25, 31, 31, 31, 31, 31, 31, 352, 26, 353, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 354, 31, 31, 355, 31, 31, 31, 31, 31, - 31, 356, 26, 26, 26, 26, 31, 31, 9, 9, 0, 265, 9, 357, 0, 0, - 0, 0, 358, 0, 257, 359, 360, 31, 31, 31, 31, 31, 31, 31, 31, 361, - 362, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3, 363, 290, 289, 290, - 290, 290, 290, 364, 169, 169, 169, 295, 365, 365, 365, 366, 257, 257, 26, 367, - 368, 369, 368, 368, 370, 368, 368, 371, 368, 372, 368, 372, 26, 26, 26, 26, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 373, - 374, 0, 0, 0, 0, 0, 375, 0, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 252, 0, 376, 377, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 378, - 379, 379, 379, 380, 381, 381, 381, 381, 381, 381, 382, 26, 383, 0, 0, 359, - 384, 384, 384, 384, 385, 386, 387, 387, 387, 388, 389, 389, 389, 389, 389, 390, - 391, 391, 391, 392, 393, 393, 393, 393, 394, 393, 395, 26, 26, 26, 26, 26, - 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 397, 397, 397, 397, 397, 397, - 398, 398, 398, 399, 398, 400, 401, 401, 401, 401, 402, 401, 401, 401, 401, 402, - 403, 403, 403, 403, 403, 26, 404, 404, 404, 404, 404, 404, 405, 406, 407, 408, - 407, 408, 409, 407, 410, 407, 410, 411, 412, 412, 412, 412, 412, 412, 413, 26, - 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 415, 26, - 414, 414, 416, 26, 414, 26, 26, 26, 417, 2, 2, 2, 2, 2, 418, 419, - 420, 421, 422, 422, 422, 422, 423, 424, 425, 425, 426, 425, 427, 427, 427, 427, - 428, 428, 428, 429, 430, 428, 26, 26, 26, 26, 26, 26, 431, 431, 432, 433, - 434, 434, 434, 435, 436, 436, 436, 437, 438, 438, 438, 438, 439, 439, 439, 440, - 439, 439, 441, 439, 439, 439, 439, 439, 442, 443, 444, 445, 446, 446, 447, 448, - 446, 449, 446, 449, 450, 450, 450, 450, 451, 451, 451, 451, 26, 26, 26, 26, - 452, 452, 452, 452, 453, 454, 453, 26, 455, 455, 455, 455, 455, 455, 456, 457, - 458, 458, 459, 458, 460, 460, 461, 460, 462, 462, 463, 464, 26, 465, 26, 26, - 466, 466, 466, 466, 466, 466, 466, 466, 466, 467, 26, 26, 26, 26, 26, 26, - 468, 468, 468, 468, 468, 468, 469, 26, 468, 468, 468, 468, 468, 468, 469, 470, - 471, 471, 471, 471, 471, 26, 471, 472, 473, 473, 473, 473, 474, 475, 473, 473, - 474, 476, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 31, 31, 31, 50, - 477, 477, 477, 477, 477, 478, 479, 26, 480, 26, 26, 26, 26, 26, 26, 481, - 482, 482, 482, 482, 482, 26, 483, 483, 483, 483, 483, 484, 26, 26, 485, 485, - 485, 486, 26, 26, 26, 26, 487, 487, 487, 488, 26, 26, 489, 489, 490, 26, - 491, 491, 491, 491, 491, 491, 491, 491, 491, 492, 493, 491, 491, 491, 492, 494, - 495, 495, 495, 495, 495, 495, 495, 495, 496, 497, 498, 498, 498, 499, 498, 500, - 501, 501, 501, 501, 501, 501, 502, 501, 501, 26, 503, 503, 503, 503, 504, 26, - 505, 505, 505, 505, 505, 505, 505, 505, 505, 505, 505, 505, 506, 137, 507, 26, - 508, 508, 509, 508, 508, 508, 508, 508, 510, 26, 26, 26, 26, 26, 26, 26, - 511, 512, 513, 514, 513, 515, 516, 516, 516, 516, 516, 516, 516, 517, 516, 518, - 519, 520, 521, 522, 522, 523, 524, 525, 520, 526, 527, 528, 529, 530, 530, 26, - 531, 532, 531, 531, 531, 531, 533, 531, 534, 535, 533, 536, 537, 26, 26, 26, - 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 539, 540, 26, 26, 26, - 541, 541, 541, 541, 541, 541, 541, 541, 541, 26, 541, 542, 26, 26, 26, 26, - 543, 543, 543, 543, 543, 543, 544, 543, 543, 543, 543, 544, 26, 26, 26, 26, - 545, 545, 545, 545, 545, 545, 545, 545, 546, 26, 545, 547, 198, 548, 26, 26, - 549, 549, 549, 549, 549, 549, 549, 550, 549, 550, 164, 164, 551, 26, 26, 26, - 552, 552, 552, 553, 552, 554, 552, 552, 555, 26, 26, 26, 26, 26, 26, 26, - 556, 556, 556, 556, 556, 556, 556, 557, 26, 26, 26, 26, 558, 558, 558, 558, - 558, 558, 558, 558, 558, 558, 559, 560, 561, 562, 563, 564, 564, 564, 565, 566, - 561, 26, 564, 567, 26, 26, 26, 26, 26, 26, 26, 26, 568, 569, 568, 568, - 568, 568, 568, 569, 570, 26, 26, 26, 571, 571, 571, 571, 571, 571, 571, 571, - 571, 26, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 573, 26, 178, 178, - 574, 574, 574, 574, 574, 574, 574, 575, 53, 576, 26, 26, 26, 26, 26, 26, - 577, 577, 577, 577, 578, 26, 577, 578, 579, 580, 579, 579, 579, 579, 581, 579, - 582, 26, 579, 579, 579, 583, 584, 584, 584, 584, 585, 584, 584, 586, 587, 26, - 588, 589, 590, 590, 590, 590, 588, 591, 590, 26, 590, 592, 593, 594, 595, 595, - 595, 596, 597, 598, 595, 599, 26, 26, 26, 26, 26, 26, 600, 600, 600, 601, - 602, 602, 603, 602, 602, 602, 602, 604, 602, 602, 602, 605, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 606, 26, 108, 108, 108, 108, 108, 108, 607, 608, - 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 610, 26, 26, 26, 26, - 609, 609, 609, 609, 609, 611, 612, 26, 613, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 615, 26, - 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 617, 26, 616, 616, 616, 616, - 616, 616, 616, 616, 616, 616, 616, 618, 619, 619, 619, 619, 619, 619, 619, 619, - 620, 26, 26, 26, 26, 26, 26, 26, 621, 621, 621, 621, 621, 621, 621, 622, - 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 623, - 624, 624, 624, 625, 624, 626, 627, 627, 627, 627, 627, 627, 627, 627, 627, 628, - 627, 629, 630, 630, 630, 631, 631, 26, 632, 632, 632, 632, 632, 632, 632, 632, - 633, 26, 632, 634, 634, 632, 632, 635, 632, 632, 26, 26, 26, 26, 26, 26, - 636, 636, 636, 636, 636, 636, 636, 637, 638, 638, 638, 638, 638, 638, 638, 638, - 638, 638, 638, 639, 26, 26, 26, 26, 640, 640, 640, 640, 640, 640, 640, 640, - 640, 641, 640, 640, 640, 640, 640, 640, 640, 642, 640, 640, 26, 26, 26, 26, - 26, 26, 26, 26, 643, 26, 345, 26, 644, 644, 644, 644, 644, 644, 644, 644, - 644, 644, 644, 644, 644, 644, 644, 26, 645, 645, 645, 645, 645, 645, 645, 645, - 645, 645, 646, 26, 26, 26, 26, 647, 644, 648, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 649, 650, 651, 286, 286, 286, 286, 286, 286, 286, - 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 652, 26, 653, 26, - 26, 26, 654, 26, 655, 26, 656, 656, 656, 656, 656, 656, 656, 656, 656, 656, - 656, 656, 656, 656, 656, 656, 656, 657, 658, 658, 658, 658, 658, 658, 658, 658, - 658, 658, 658, 658, 658, 659, 658, 660, 658, 661, 658, 662, 359, 26, 26, 26, - 0, 0, 0, 0, 0, 0, 0, 265, 0, 0, 0, 0, 0, 0, 359, 26, - 9, 9, 9, 9, 9, 663, 9, 9, 221, 26, 0, 0, 0, 0, 0, 0, - 359, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 276, 26, - 0, 0, 0, 0, 257, 362, 0, 0, 0, 0, 0, 0, 664, 665, 0, 666, - 667, 668, 0, 0, 0, 669, 0, 0, 0, 0, 0, 0, 0, 266, 26, 26, - 246, 26, 26, 26, 26, 26, 26, 26, 0, 0, 359, 26, 0, 0, 359, 26, - 0, 0, 257, 26, 0, 0, 0, 259, 0, 0, 254, 0, 0, 0, 0, 0, - 0, 0, 0, 254, 670, 671, 0, 672, 673, 0, 0, 0, 0, 0, 0, 0, - 269, 674, 254, 254, 0, 0, 0, 675, 676, 677, 678, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 276, 0, 0, 0, 0, 268, 0, 0, 0, 0, 0, 0, - 679, 679, 679, 679, 679, 679, 679, 679, 679, 680, 26, 681, 682, 679, 26, 26, - 2, 2, 2, 346, 683, 419, 26, 26, 684, 270, 270, 685, 686, 687, 18, 18, - 18, 18, 18, 18, 18, 688, 26, 26, 26, 689, 26, 26, 26, 26, 26, 26, - 690, 690, 690, 690, 690, 691, 690, 692, 690, 693, 26, 26, 26, 26, 26, 26, - 26, 26, 694, 694, 694, 695, 26, 26, 696, 696, 696, 696, 696, 696, 696, 697, - 26, 26, 698, 698, 698, 698, 698, 699, 26, 26, 700, 700, 700, 700, 700, 701, - 26, 26, 26, 26, 172, 702, 170, 172, 703, 703, 703, 703, 703, 703, 703, 703, - 704, 703, 705, 26, 26, 26, 26, 26, 706, 706, 706, 706, 706, 706, 706, 706, - 706, 707, 706, 708, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 362, 0, - 0, 0, 0, 0, 0, 0, 376, 26, 362, 0, 0, 0, 0, 0, 0, 276, - 709, 31, 31, 31, 710, 711, 712, 713, 714, 715, 710, 716, 710, 712, 712, 717, - 31, 718, 31, 719, 720, 718, 31, 719, 26, 26, 26, 26, 26, 26, 721, 26, - 0, 0, 0, 0, 0, 359, 0, 0, 0, 0, 359, 26, 0, 257, 362, 0, - 362, 0, 362, 0, 0, 0, 276, 26, 0, 0, 0, 0, 0, 276, 26, 26, - 26, 26, 26, 26, 722, 0, 0, 0, 723, 26, 0, 0, 0, 0, 0, 359, - 0, 259, 265, 26, 276, 26, 26, 26, 0, 0, 0, 724, 0, 376, 0, 376, - 0, 0, 0, 0, 0, 0, 257, 725, 0, 0, 0, 265, 0, 359, 259, 26, - 0, 359, 0, 0, 0, 0, 0, 0, 0, 26, 0, 265, 0, 0, 0, 0, - 0, 26, 0, 0, 0, 276, 0, 359, 265, 26, 26, 26, 26, 26, 26, 26, - 0, 0, 359, 26, 0, 276, 0, 376, 0, 726, 0, 0, 0, 0, 0, 0, - 257, 722, 0, 727, 0, 265, 0, 259, 0, 0, 358, 0, 0, 0, 0, 0, - 277, 277, 277, 277, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 345, - 277, 277, 277, 280, 277, 277, 277, 277, 277, 277, 277, 277, 345, 26, 277, 277, - 277, 277, 277, 277, 728, 26, 277, 277, 277, 277, 277, 280, 26, 26, 26, 26, - 277, 729, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 26, 26, - 730, 26, 26, 26, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 0, 0, + 216, 219, 216, 219, 216, 220, 9, 9, 9, 9, 9, 221, 9, 222, 26, 26, + 223, 223, 223, 223, 223, 223, 223, 223, 223, 224, 223, 223, 223, 223, 223, 223, + 225, 225, 225, 225, 225, 225, 225, 225, 226, 226, 226, 226, 226, 226, 227, 228, + 229, 229, 229, 229, 229, 229, 229, 230, 229, 231, 232, 232, 232, 232, 232, 232, + 18, 233, 165, 165, 165, 165, 165, 234, 225, 26, 235, 9, 236, 237, 238, 239, + 2, 2, 2, 2, 240, 241, 2, 2, 2, 2, 2, 242, 243, 244, 2, 245, + 2, 2, 2, 2, 2, 2, 2, 246, 9, 9, 9, 9, 9, 9, 9, 9, + 14, 14, 247, 247, 14, 14, 14, 14, 247, 247, 14, 248, 14, 14, 14, 247, + 14, 14, 14, 14, 14, 14, 249, 14, 249, 14, 250, 251, 14, 14, 252, 253, + 0, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 256, 257, + 0, 258, 2, 259, 0, 0, 0, 0, 260, 26, 9, 9, 9, 9, 261, 26, + 0, 0, 0, 0, 262, 263, 4, 0, 0, 264, 0, 0, 2, 2, 2, 2, + 2, 265, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 260, 26, 26, 0, 266, 26, 26, 0, 0, 0, 0, + 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 268, 0, + 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 2, 2, 2, 2, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 270, 271, + 165, 165, 165, 165, 166, 167, 272, 272, 272, 272, 272, 272, 272, 273, 274, 273, + 170, 170, 172, 26, 172, 172, 172, 172, 172, 172, 172, 172, 18, 18, 18, 18, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, + 276, 276, 276, 277, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 278, 26, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 26, 26, 26, 0, 0, + 280, 0, 0, 0, 281, 282, 0, 283, 284, 285, 285, 285, 285, 285, 285, 285, + 285, 285, 286, 287, 288, 289, 289, 289, 289, 289, 289, 289, 289, 289, 289, 290, + 291, 292, 292, 292, 292, 292, 293, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 294, 0, 0, 292, 292, 292, 292, 0, 0, 0, 0, 275, 295, 289, 289, + 169, 169, 169, 294, 0, 0, 0, 0, 0, 0, 0, 0, 169, 169, 169, 296, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 289, 289, 289, 289, 289, 297, + 289, 289, 289, 289, 289, 289, 289, 289, 289, 289, 289, 0, 0, 0, 0, 0, + 276, 276, 276, 276, 276, 276, 276, 276, 0, 0, 0, 0, 0, 0, 0, 0, + 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, + 298, 299, 298, 298, 298, 298, 298, 298, 300, 26, 301, 301, 301, 301, 301, 301, + 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, + 302, 302, 302, 302, 302, 303, 26, 26, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 26, + 0, 0, 0, 0, 305, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 306, 2, 2, 2, 2, 2, 2, 2, 2, 2, 259, 26, 26, 307, 2, + 308, 308, 308, 308, 308, 309, 0, 260, 310, 310, 310, 310, 310, 310, 310, 26, + 311, 311, 311, 311, 311, 311, 311, 311, 312, 313, 311, 314, 52, 52, 52, 52, + 315, 315, 315, 315, 315, 316, 317, 317, 317, 317, 318, 319, 169, 169, 169, 320, + 321, 321, 321, 321, 321, 321, 321, 321, 321, 322, 321, 323, 164, 164, 164, 324, + 325, 325, 325, 325, 325, 325, 326, 26, 325, 327, 325, 328, 164, 164, 164, 164, + 329, 329, 329, 329, 329, 329, 329, 329, 330, 26, 26, 331, 332, 332, 333, 26, + 334, 334, 334, 26, 172, 172, 2, 2, 2, 2, 2, 335, 336, 337, 176, 176, + 176, 176, 176, 176, 176, 176, 176, 176, 332, 332, 332, 332, 332, 338, 332, 339, + 169, 169, 169, 169, 340, 26, 169, 169, 294, 341, 169, 169, 169, 169, 169, 340, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 342, 26, 26, 26, 26, + 343, 26, 344, 345, 25, 25, 346, 347, 348, 25, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 349, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 26, 26, 26, 26, 31, 31, + 9, 9, 0, 260, 9, 350, 0, 0, 0, 0, 351, 0, 258, 352, 353, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 354, + 355, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3, 356, 289, 288, 289, + 289, 289, 289, 357, 169, 169, 169, 294, 358, 358, 358, 359, 258, 258, 26, 360, + 361, 362, 361, 361, 363, 361, 361, 364, 361, 365, 361, 365, 26, 26, 26, 26, + 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 366, + 367, 0, 0, 0, 0, 0, 368, 0, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 253, 0, 369, 370, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 371, + 372, 372, 372, 373, 374, 374, 374, 374, 374, 374, 375, 26, 376, 0, 0, 352, + 377, 377, 377, 377, 378, 379, 380, 380, 380, 381, 382, 382, 382, 382, 382, 383, + 384, 384, 384, 385, 386, 386, 386, 386, 387, 386, 388, 26, 26, 26, 26, 26, + 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 390, 390, 390, 390, 390, 390, + 391, 391, 391, 392, 391, 393, 394, 394, 394, 394, 395, 394, 394, 394, 394, 395, + 396, 396, 396, 396, 396, 26, 397, 397, 397, 397, 397, 397, 398, 399, 400, 401, + 400, 401, 402, 400, 403, 400, 403, 404, 405, 405, 405, 405, 405, 405, 406, 26, + 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, + 407, 407, 407, 407, 407, 407, 408, 26, 407, 407, 409, 26, 407, 26, 26, 26, + 410, 2, 2, 2, 2, 2, 411, 412, 26, 26, 26, 26, 26, 26, 26, 26, + 413, 414, 415, 415, 415, 415, 416, 417, 418, 418, 419, 418, 420, 420, 420, 420, + 421, 421, 421, 422, 423, 421, 26, 26, 26, 26, 26, 26, 424, 424, 425, 426, + 427, 427, 427, 428, 429, 429, 429, 430, 431, 431, 431, 432, 26, 26, 26, 26, + 433, 433, 433, 433, 434, 434, 434, 435, 434, 434, 436, 434, 434, 434, 434, 434, + 437, 438, 439, 440, 441, 441, 442, 443, 441, 444, 441, 444, 445, 445, 445, 445, + 446, 446, 446, 446, 26, 26, 26, 26, 447, 447, 447, 447, 448, 449, 448, 26, + 450, 450, 450, 450, 450, 450, 451, 452, 453, 453, 454, 453, 455, 455, 456, 455, + 457, 457, 458, 459, 26, 460, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 461, 461, 461, 461, 461, 461, 461, 461, 461, 462, 26, 26, 26, 26, 26, 26, + 463, 463, 463, 463, 463, 463, 464, 26, 463, 463, 463, 463, 463, 463, 464, 465, + 466, 466, 466, 466, 466, 26, 466, 467, 468, 468, 468, 468, 469, 470, 468, 468, + 469, 471, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 31, 31, 31, 472, + 473, 473, 473, 473, 473, 474, 475, 26, 476, 26, 31, 477, 26, 26, 26, 476, + 478, 478, 478, 478, 478, 26, 479, 479, 479, 479, 479, 480, 26, 26, 481, 481, + 481, 482, 26, 26, 26, 26, 483, 483, 483, 484, 26, 26, 485, 485, 486, 26, + 487, 487, 487, 487, 487, 487, 487, 487, 487, 488, 489, 487, 487, 487, 488, 490, + 491, 491, 491, 491, 491, 491, 491, 491, 492, 493, 494, 494, 494, 495, 494, 496, + 497, 497, 497, 497, 497, 497, 498, 497, 497, 26, 499, 499, 499, 499, 500, 26, + 501, 501, 501, 501, 501, 501, 501, 501, 501, 501, 501, 501, 502, 137, 503, 26, + 504, 504, 505, 504, 504, 504, 504, 504, 506, 26, 26, 26, 26, 26, 26, 26, + 507, 508, 509, 510, 509, 511, 512, 512, 512, 512, 512, 512, 512, 513, 512, 514, + 515, 516, 517, 518, 518, 519, 520, 521, 516, 522, 523, 524, 525, 526, 526, 26, + 527, 528, 527, 527, 527, 527, 529, 527, 530, 531, 529, 532, 533, 26, 26, 26, + 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 535, 536, 26, 26, 26, + 537, 537, 537, 537, 537, 537, 537, 537, 537, 26, 537, 538, 26, 26, 26, 26, + 539, 539, 539, 539, 539, 539, 540, 539, 539, 539, 539, 540, 26, 26, 26, 26, + 541, 541, 541, 541, 541, 541, 541, 541, 542, 26, 541, 543, 198, 544, 26, 26, + 545, 545, 545, 545, 545, 545, 545, 546, 545, 546, 164, 164, 547, 26, 26, 26, + 548, 548, 548, 549, 548, 550, 548, 548, 551, 26, 26, 26, 26, 26, 26, 26, + 552, 552, 552, 552, 552, 552, 552, 553, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 555, 556, + 557, 558, 559, 560, 560, 560, 561, 562, 557, 26, 560, 563, 26, 26, 26, 26, + 26, 26, 26, 26, 564, 565, 564, 564, 564, 564, 564, 565, 566, 26, 26, 26, + 567, 567, 567, 567, 567, 567, 567, 567, 567, 26, 568, 568, 568, 568, 568, 568, + 568, 568, 568, 568, 569, 26, 178, 178, 570, 570, 570, 570, 570, 570, 570, 571, + 52, 572, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 501, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 573, 573, 573, 573, 574, 26, 573, 574, + 575, 576, 575, 575, 575, 575, 577, 575, 578, 26, 575, 575, 575, 579, 580, 580, + 580, 580, 581, 580, 580, 582, 583, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 584, 585, 586, 586, 586, 586, 584, 587, 586, 26, 586, 588, 589, 590, 591, 591, + 591, 592, 593, 594, 591, 595, 596, 596, 596, 596, 596, 597, 596, 598, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 599, 599, 599, 600, + 601, 601, 602, 601, 601, 601, 601, 603, 601, 601, 601, 604, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 605, 26, 107, 107, 107, 107, 107, 107, 606, 607, + 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, + 608, 608, 608, 609, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 610, 611, 26, + 608, 608, 608, 608, 608, 608, 608, 608, 612, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 613, 613, 613, 613, 613, 613, 613, 613, 613, 613, 613, 613, 614, 26, + 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, + 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 616, 26, 615, 615, 615, 615, + 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 617, + 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, + 618, 618, 618, 618, 618, 618, 618, 618, 619, 26, 26, 26, 26, 26, 26, 26, + 620, 620, 620, 620, 620, 620, 620, 621, 26, 26, 26, 26, 26, 26, 26, 26, + 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, + 304, 304, 304, 304, 304, 304, 304, 622, 623, 623, 623, 624, 623, 625, 626, 626, + 626, 626, 626, 626, 626, 626, 626, 627, 626, 628, 629, 629, 629, 630, 630, 26, + 631, 631, 631, 631, 631, 631, 631, 631, 632, 26, 631, 633, 633, 631, 631, 634, + 631, 631, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 635, 635, 635, 635, 635, 635, 635, 636, + 26, 26, 26, 26, 26, 26, 26, 26, 637, 637, 637, 637, 637, 637, 637, 637, + 637, 637, 637, 638, 639, 639, 639, 640, 639, 639, 641, 26, 26, 26, 26, 26, + 642, 642, 642, 642, 642, 642, 642, 642, 642, 643, 642, 642, 642, 642, 642, 642, + 642, 644, 642, 642, 26, 26, 26, 26, 26, 26, 26, 26, 645, 26, 646, 26, + 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, + 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, + 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 649, 26, 26, 26, 26, 650, + 647, 647, 647, 651, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 652, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 653, 654, + 655, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, + 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, + 285, 285, 285, 285, 656, 26, 657, 26, 26, 26, 658, 26, 659, 26, 660, 660, + 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, + 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 661, + 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, 663, 662, 664, + 662, 665, 662, 666, 352, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 369, + 0, 0, 0, 0, 0, 0, 352, 667, 0, 0, 668, 26, 0, 0, 668, 26, + 9, 9, 9, 9, 9, 221, 9, 9, 669, 26, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 352, 26, 26, 26, 26, 26, 26, 26, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 26, + 0, 0, 0, 0, 258, 355, 0, 0, 0, 0, 0, 0, 670, 671, 0, 672, + 673, 674, 0, 0, 0, 675, 0, 0, 0, 0, 0, 0, 0, 266, 26, 26, + 14, 14, 14, 14, 14, 14, 14, 14, 247, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 352, 26, 0, 0, 352, 26, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 26, 0, 0, 0, 668, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, + 0, 0, 0, 255, 676, 677, 0, 678, 679, 0, 0, 0, 0, 0, 0, 0, + 680, 681, 255, 255, 0, 0, 0, 682, 683, 667, 684, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 268, 0, 0, 0, 0, 0, 0, + 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, + 685, 686, 26, 687, 688, 685, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 2, 2, 2, 343, 689, 412, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 690, 269, 269, 691, 692, 693, 18, 18, 18, 18, 18, 18, 18, 694, 26, 26, + 26, 695, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 696, 696, 696, 696, 696, 697, 696, 698, 696, 699, 26, 26, 26, 26, 26, 26, + 26, 26, 700, 700, 700, 701, 26, 26, 702, 702, 702, 702, 702, 702, 702, 703, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 704, 704, 704, 704, 704, 705, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 706, 706, 706, 706, 706, 707, + 26, 26, 26, 26, 26, 26, 26, 26, 708, 708, 708, 709, 708, 708, 710, 711, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 172, 712, 170, 172, + 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, + 713, 713, 713, 713, 713, 713, 713, 713, 714, 713, 715, 26, 26, 26, 26, 26, + 716, 716, 716, 716, 716, 716, 716, 716, 716, 717, 716, 718, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 355, 0, + 0, 0, 0, 0, 0, 0, 369, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 355, 0, 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, 26, 26, 26, 26, + 719, 31, 31, 31, 720, 721, 722, 723, 724, 725, 720, 726, 720, 722, 722, 727, + 31, 728, 31, 729, 730, 728, 31, 729, 26, 26, 26, 26, 26, 26, 731, 26, + 0, 0, 0, 0, 0, 352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 352, 26, 0, 258, 355, 0, 355, 0, 355, 0, 0, 0, 275, 26, + 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, 26, 26, 732, 0, 0, 0, + 733, 26, 0, 0, 0, 0, 0, 352, 0, 668, 260, 26, 275, 26, 26, 26, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 734, 0, 369, 0, 369, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 260, 0, 352, 668, 26, + 0, 352, 0, 0, 0, 0, 0, 0, 0, 26, 0, 260, 0, 0, 0, 0, + 0, 26, 0, 0, 0, 275, 0, 352, 260, 26, 0, 668, 26, 26, 26, 26, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 275, 0, 369, + 0, 735, 0, 0, 0, 0, 0, 0, 258, 736, 0, 737, 0, 367, 0, 668, + 0, 0, 351, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 266, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 26, 26, 26, 26, + 276, 276, 276, 279, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 276, 276, 276, 276, 279, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 738, 26, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 26, 26, 26, 26, + 276, 276, 276, 279, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 739, 276, 276, 276, 276, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 342, + 740, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0, @@ -2840,8 +2688,7 @@ _hb_ucd_u16[10400] = 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807, 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0, }; -static const int16_t -_hb_ucd_i16[196] = +static const int16_t _hb_ucd_i16[196]= { 0, 0, 0, 0, 1, -1, 0, 0, 2, 0, -2, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0, 0, 16, 0, 0, 0, -16, 0, 0, 1, -1, @@ -2858,47 +2705,42 @@ _hb_ucd_i16[196] = -1, 0, 1, -1, }; -static inline uint_fast8_t -_hb_ucd_gc (unsigned u) +static inline uint8_t _hb_ucd_gc (unsigned u) { - return u<1114110u?_hb_ucd_u8[6472+(((_hb_ucd_u8[816+(((_hb_ucd_u16[((_hb_ucd_u8[272+(((_hb_ucd_u8[u>>1>>3>>4>>4])<<4)+((u>>1>>3>>4)&15u))])<<4)+((u>>1>>3)&15u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2; + return u<1114110 ? _hb_ucd_u8[7920u+((_hb_ucd_u8[2176u+((_hb_ucd_u16[((_hb_ucd_u8[((((((u)>>1))>>3))>>5)])<<5)+((((((u)>>1))>>3))&31)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : 2; } -static inline uint_fast8_t -_hb_ucd_ccc (unsigned u) +static inline uint8_t _hb_ucd_ccc (unsigned u) { - return u<125259u?_hb_ucd_u8[8504+(((_hb_ucd_u8[7936+(((_hb_ucd_u8[7460+(((_hb_ucd_u8[7100+(((_hb_ucd_u8[6854+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0; + return u<125259 ? _hb_ucd_u8[10388u+((_hb_ucd_u8[9284u+((_hb_ucd_u8[8548u+((_hb_ucd_u8[8302u+((((((u)>>2))>>3))>>4)])<<4)+((((((u)>>2))>>3))&15)])<<3)+((((u)>>2))&7)])<<2)+((u)&3)] : 0; } -static inline unsigned -_hb_ucd_b4 (const uint8_t* a, unsigned i) +static inline uint8_t _hb_ucd_b4 (const uint8_t* a, unsigned i) { - return (a[i>>1]>>((i&1u)<<2))&15u; + return (a[i>>1]>>((i&1)<<2))&15; } -static inline int_fast16_t -_hb_ucd_bmg (unsigned u) +static inline int16_t _hb_ucd_bmg (unsigned u) { - return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9252+(((_hb_ucd_u8[9132+(((_hb_ucd_b4(9004+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0; + return u<65380 ? _hb_ucd_i16[((_hb_ucd_u8[11140u+((_hb_ucd_u8[11020u+((_hb_ucd_b4(_hb_ucd_u8+10892u,((((((u)>>2))>>3))>>3)))<<3)+((((((u)>>2))>>3))&7)])<<3)+((((u)>>2))&7)])<<2)+((u)&3)] : 0; } -static inline uint_fast8_t -_hb_ucd_sc (unsigned u) +static inline uint8_t _hb_ucd_sc (unsigned u) { - return u<918000u?_hb_ucd_u8[10486+(((_hb_ucd_u16[3744+(((_hb_ucd_u16[2624+(((_hb_ucd_u8[9588+(u>>3>>3>>4)])<<4)+((u>>3>>3)&15u))])<<3)+((u>>3)&7u))])<<3)+((u)&7u))]:2; + return u<918000 ? _hb_ucd_u8[12662u+((_hb_ucd_u16[3328u+((_hb_ucd_u8[11926u+((_hb_ucd_u8[11476u+((((((u)>>3))>>4))>>4)])<<4)+((((((u)>>3))>>4))&15)])<<4)+((((u)>>3))&15)])<<3)+((u)&7)] : 2; } -static inline uint_fast16_t -_hb_ucd_dm (unsigned u) +static inline uint16_t _hb_ucd_dm (unsigned u) { - return u<195102u?_hb_ucd_u16[6976+(((_hb_ucd_u8[16716+(((_hb_ucd_u8[16334+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0; + return u<195102 ? _hb_ucd_u16[7408u+((_hb_ucd_u8[18972u+((_hb_ucd_u8[18590u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)] : 0; } #elif !defined(HB_NO_UCD_UNASSIGNED) -static const uint8_t -_hb_ucd_u8[17524] = +#include + +static const uint8_t _hb_ucd_u8[14800]= { 0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 6, 5, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 5, 17, 15, 18, 19, 20, 21, 22, 23, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 24, 25, 26, 5, 27, 28, - 5, 29, 30, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 5, 29, 5, 30, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, @@ -2929,23 +2771,23 @@ _hb_ucd_u8[17524] = 17, 17, 17,103, 17, 17,104,100,100,100,100,100,100,100,100,100, 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, 100,105,100,100,100,100,100,100, 17, 17,106,107,100,108,109,110, - 17, 17, 17, 17, 17, 17, 17,111, 17, 17, 17, 17,112,113,100,100, - 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,114, - 17,115,116,100,100,100,100,100,100,100,100,100,117,100,100,100, - 100,100,100,100,100,100,100,100,100,100,100,100,118, 39,119,120, - 121,122,123,124,125,126,127,128, 39, 39,129,100,100,100,100,130, - 131,132,133,100,134,135,100,136,137,138,100,100,139,140,141,100, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,111,112,100,100, + 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,113, + 17,114,115,100,100,100,100,100,100,100,100,100,116,100,100,100, + 100,100,100,100,100,100,100,100,100,100,100,100,117, 39,118,119, + 120,121,122,123,124,125,126,127, 39, 39,128,100,100,100,100,129, + 130,131,132,100,133,134,135,136,137,138,100,100,139,140,141,100, 142,143,144,145, 39, 39,146,147,148, 39,149,150,100,100,100,100, 17, 17, 17, 17, 17, 17,151, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17,152,153, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,154, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,155, 17, 17,156,100, - 100,100,100,100,100,100,100,100, 17, 17,157,100,100,100,100,100, - 17, 17, 17,158, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17,159,100,100,100,100,100,100,100,100,100,100,100,100, - 160,161,100,100,100,100,100,100,100,100,100,100,100,100,100,100, + 17, 17, 17, 17, 17, 17, 17, 17,152, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,153, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,154, 17, 17,155,100, + 100,100,100,100,100,100,100,100, 17, 17,156,100,100,100,100,100, + 17, 17, 17,157, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17,158,100,100,100,100,100,100,100,100,100,100,100, + 159,160,100,100,100,100,100,100,100,100,100,100,100,100,100,100, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,161, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,162, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,163, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2, 7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, @@ -2959,409 +2801,415 @@ _hb_ucd_u8[17524] = 34, 11, 34, 34, 32, 35, 32, 16, 36, 36, 37, 34, 38, 37, 34, 34, 34, 34, 34, 34, 34, 34, 16, 32, 34, 38, 32, 11, 32, 32, 32, 32, 32, 32, 16, 16, 16, 11, 34, 32, 34, 34, 11, 32, 32, 32, 32, 32, - 16, 16, 39, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 41, 41, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, - 40, 40, 42, 41, 41, 41, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, - 43, 43, 43, 43, 43, 43, 43, 43, 32, 32, 42, 32, 44, 45, 16, 10, - 44, 44, 41, 46, 11, 47, 47, 11, 34, 11, 11, 11, 11, 11, 11, 11, - 11, 48, 11, 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 34, - 16, 11, 32, 16, 32, 32, 32, 32, 16, 16, 32, 49, 34, 32, 34, 11, - 32, 50, 43, 43, 51, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16, - 48, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 47, 52, 2, 2, 2, - 16, 16, 16, 16, 53, 54, 55, 56, 57, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 43, 43, 43, 43, 43, 58, 59, 60, 43, 59, 44, 44, 44, 44, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 62, - 36, 63, 64, 44, 44, 44, 44, 44, 65, 65, 65, 8, 9, 66, 2, 67, - 43, 43, 43, 43, 43, 60, 68, 2, 69, 36, 36, 36, 36, 70, 43, 43, - 7, 7, 7, 7, 7, 2, 2, 36, 71, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 72, 43, 43, 43, 73, 50, 43, 43, 74, 75, 76, 43, 43, 36, - 7, 7, 7, 7, 7, 36, 77, 78, 2, 2, 2, 2, 2, 2, 2, 79, - 70, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 80, 62, 36, - 36, 36, 36, 43, 43, 43, 43, 43, 71, 44, 44, 44, 44, 44, 44, 44, - 7, 7, 7, 7, 7, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43, - 43, 43, 40, 21, 2, 81, 57, 20, 36, 36, 36, 43, 43, 75, 43, 43, - 43, 43, 75, 43, 75, 43, 43, 44, 2, 2, 2, 2, 2, 2, 2, 64, - 36, 36, 36, 36, 70, 43, 44, 64, 36, 36, 36, 36, 36, 61, 44, 44, - 36, 36, 36, 36, 82, 36, 36, 61, 65, 44, 44, 57, 43, 43, 43, 43, - 36, 36, 36, 36, 83, 43, 43, 43, 43, 84, 43, 43, 43, 43, 43, 43, - 43, 85, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 85, 71, 86, - 87, 43, 43, 43, 85, 86, 87, 86, 70, 43, 43, 43, 36, 36, 36, 36, - 36, 43, 2, 7, 7, 7, 7, 7, 88, 36, 36, 36, 36, 36, 36, 36, - 70, 86, 62, 36, 36, 36, 61, 62, 61, 62, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 61, 36, 36, 36, 61, 61, 44, 36, 36, 44, 71, 86, - 87, 43, 80, 89, 90, 89, 87, 61, 44, 44, 44, 89, 44, 44, 36, 62, - 36, 43, 44, 7, 7, 7, 7, 7, 36, 20, 27, 27, 27, 56, 63, 80, - 57, 85, 62, 36, 36, 61, 44, 62, 61, 36, 62, 61, 36, 44, 80, 86, - 87, 80, 44, 57, 80, 57, 43, 44, 57, 44, 44, 44, 62, 36, 61, 61, - 44, 44, 44, 7, 7, 7, 7, 7, 43, 36, 70, 64, 44, 44, 44, 44, - 57, 85, 62, 36, 36, 36, 36, 62, 36, 62, 36, 36, 36, 36, 36, 36, - 61, 36, 62, 36, 36, 44, 71, 86, 87, 43, 43, 57, 85, 89, 87, 44, - 61, 44, 44, 44, 44, 44, 44, 44, 66, 44, 44, 44, 62, 43, 43, 43, - 57, 86, 62, 36, 36, 36, 61, 62, 61, 36, 62, 36, 36, 44, 71, 87, - 87, 43, 80, 89, 90, 89, 87, 44, 44, 44, 57, 85, 44, 44, 36, 62, - 78, 27, 27, 27, 44, 44, 44, 44, 44, 71, 62, 36, 36, 61, 44, 36, - 61, 36, 36, 44, 62, 61, 61, 36, 44, 62, 61, 44, 36, 61, 44, 36, - 36, 36, 36, 36, 36, 44, 44, 86, 85, 90, 44, 86, 90, 86, 87, 44, - 61, 44, 44, 89, 44, 44, 44, 44, 27, 91, 67, 67, 56, 92, 44, 44, - 85, 86, 71, 36, 36, 36, 61, 36, 61, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 44, 71, 43, 85, 86, 90, 43, 80, 43, 43, 44, - 44, 44, 57, 80, 36, 61, 62, 44, 44, 44, 44, 93, 27, 27, 27, 91, - 70, 86, 72, 36, 36, 36, 61, 36, 36, 36, 62, 36, 36, 44, 71, 87, - 86, 86, 90, 85, 90, 86, 43, 44, 44, 44, 89, 90, 44, 44, 62, 61, - 62, 94, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36, - 36, 36, 36, 36, 36, 70, 71, 86, 87, 43, 80, 86, 90, 86, 87, 77, - 44, 44, 36, 94, 27, 27, 27, 95, 27, 27, 27, 27, 91, 36, 36, 36, - 57, 86, 62, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 36, 36, 36, - 36, 62, 36, 36, 36, 36, 62, 44, 36, 36, 36, 61, 44, 80, 44, 89, - 86, 43, 80, 80, 86, 86, 86, 86, 44, 86, 64, 44, 44, 44, 44, 44, - 62, 36, 36, 36, 36, 36, 36, 36, 70, 36, 43, 43, 43, 80, 44, 96, - 36, 36, 36, 75, 43, 43, 43, 60, 7, 7, 7, 7, 7, 2, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 62, 61, 61, 36, 36, 61, 36, 36, - 36, 36, 62, 62, 36, 36, 36, 36, 70, 36, 43, 43, 43, 43, 71, 44, - 36, 36, 61, 81, 43, 43, 43, 80, 7, 7, 7, 7, 7, 44, 36, 36, - 77, 67, 2, 2, 2, 2, 2, 2, 2, 97, 97, 67, 43, 67, 67, 67, - 7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 50, 50, 50, 4, 4, 86, - 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, - 57, 43, 43, 43, 43, 43, 43, 85, 43, 43, 60, 43, 36, 36, 70, 43, - 43, 43, 43, 43, 57, 43, 43, 43, 43, 43, 43, 43, 43, 43, 80, 67, - 67, 67, 67, 76, 67, 67, 92, 67, 2, 2, 97, 67, 21, 64, 44, 44, - 36, 36, 36, 36, 36, 94, 87, 43, 85, 43, 43, 43, 87, 85, 87, 71, - 7, 7, 7, 7, 7, 2, 2, 2, 36, 36, 36, 86, 43, 36, 36, 43, - 71, 86, 98, 94, 86, 86, 86, 36, 70, 43, 71, 36, 36, 36, 36, 36, - 36, 85, 87, 85, 86, 86, 87, 94, 7, 7, 7, 7, 7, 86, 87, 67, - 11, 11, 11, 48, 44, 44, 48, 44, 16, 16, 16, 16, 16, 53, 45, 16, - 36, 36, 36, 36, 61, 36, 36, 44, 36, 36, 36, 61, 61, 36, 36, 44, - 61, 36, 36, 44, 36, 36, 36, 61, 61, 36, 36, 44, 36, 36, 36, 36, - 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 57, 43, - 2, 2, 2, 2, 99, 27, 27, 27, 27, 27, 27, 27, 27, 27,100, 44, - 67, 67, 67, 67, 67, 44, 44, 44, 11, 11, 11, 44, 16, 16, 16, 44, - 101, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 77, 72, - 102, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,103,104, 44, - 36, 36, 36, 36, 36, 63, 2,105,106, 36, 36, 36, 61, 44, 44, 44, - 36, 43, 85, 44, 44, 44, 44, 62, 36, 43,107, 64, 44, 44, 44, 44, - 36, 43, 44, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 61, 36, - 61, 43, 44, 44, 44, 44, 44, 44, 36, 36, 43, 87, 43, 43, 43, 86, - 86, 86, 86, 85, 87, 43, 43, 43, 43, 43, 2, 88, 2, 66, 70, 44, - 7, 7, 7, 7, 7, 44, 44, 44, 27, 27, 27, 27, 27, 44, 44, 44, - 2, 2, 2,108, 2, 59, 43, 84, 36, 83, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 61, 44, 44, 44, 36, 36, 70, 71, 36, 36, 36, 36, - 36, 36, 36, 36, 70, 61, 44, 44, 36, 36, 36, 44, 44, 44, 44, 44, - 36, 36, 36, 36, 36, 36, 36, 61, 43, 85, 86, 87, 85, 86, 44, 44, - 86, 85, 86, 86, 87, 43, 44, 44, 92, 44, 2, 7, 7, 7, 7, 7, - 36, 36, 36, 36, 36, 36, 36, 44, 36, 36, 61, 44, 44, 44, 44, 44, - 36, 36, 36, 36, 36, 36, 44, 44, 36, 36, 36, 36, 36, 44, 44, 44, - 7, 7, 7, 7, 7,100, 44, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 36, 36, 36, 70, 85, 87, 44, 2, 36, 36, 94, 85, 43, 43, 43, 80, - 85, 85, 87, 43, 43, 43, 85, 86, 86, 87, 43, 43, 43, 43, 80, 57, - 2, 2, 2, 88, 2, 2, 2, 44, 43, 43, 43, 43, 43, 43, 43,109, - 43, 43, 43, 43, 43, 43, 43, 80, 43, 43, 98, 36, 36, 36, 36, 36, - 36, 36, 85, 43, 43, 85, 85, 86, 86, 85, 98, 36, 36, 36, 61, 2, - 97, 67, 67, 67, 67, 50, 43, 43, 43, 43, 67, 67, 67, 67, 21, 2, - 43, 98, 36, 36, 36, 36, 36, 36, 94, 43, 43, 86, 43, 87, 43, 36, - 36, 36, 36, 85, 43, 86, 87, 87, 43, 86, 44, 44, 44, 44, 2, 2, - 36, 36, 86, 86, 86, 86, 43, 43, 43, 43, 86, 43, 44, 93, 2, 2, - 7, 7, 7, 7, 7, 44, 62, 36, 36, 36, 36, 36, 40, 40, 40, 2, - 16, 16, 16, 16, 34,110, 44, 44, 11, 11, 11, 11, 11, 47, 48, 11, - 2, 2, 2, 2, 44, 44, 44, 44, 43, 60, 43, 43, 43, 43, 43, 43, - 85, 43, 43, 43, 71, 36, 70, 36, 36, 36, 71, 94, 43, 61, 44, 44, - 16, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 45, 16, 16, - 16, 16, 16, 16, 45, 16, 16, 16, 16, 16, 16, 16, 16,111, 40, 40, - 32, 32, 32, 16, 16, 16, 16, 32, 16, 16, 16, 16, 11, 11, 11, 11, - 16, 16, 16, 44, 11, 11, 11, 44, 16, 16, 16, 16, 48, 48, 48, 48, - 16, 16, 16, 16, 16, 16, 16, 44, 16, 16, 16, 16,112,112,112,112, - 16, 16,110, 16, 11, 11,113,114, 41, 16,110, 16, 11, 11,113, 41, - 16, 16, 44, 16, 11, 11,115, 41, 16, 16, 16, 16, 11, 11,116, 41, - 44, 16,110, 16, 11, 11,113,117,118,118,118,118,118,119, 65, 65, - 120,120,120, 2,121,122,121,122, 2, 2, 2, 2,123, 65, 65,124, - 2, 2, 2, 2,125,126, 2,127,128, 2,129,130, 2, 2, 2, 2, - 2, 9,128, 2, 2, 2, 2,131, 65, 65,132, 65, 65, 65, 65, 65, - 133, 44, 27, 27, 27, 8,129,134, 27, 27, 27, 27, 27, 8,129,104, - 40, 40, 40, 40, 40, 40, 81, 44, 20, 20, 20, 20, 20, 20, 20, 20, - 135, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 43, 43,136, 51, - 109, 51,109, 43, 43, 43, 43, 43, 80, 44, 44, 44, 44, 44, 44, 44, - 67,137, 67,138, 67, 34, 11, 16, 11, 32,138, 67, 49, 11, 11, 67, - 67, 67,137,137,137, 11, 11,139, 11, 11, 35, 36, 39, 67, 16, 11, - 8, 8, 49, 16, 16, 26, 67,140, 27, 27, 27, 27, 27, 27, 27, 27, - 105,105,105,105,105,105,105,105,105,141,142,105,143, 67, 44, 44, - 8, 8,144, 67, 67, 8, 67, 67,144, 26, 67,144, 67, 67, 67,144, - 67, 67, 67, 67, 67, 67, 67, 8, 67,144,144, 67, 67, 67, 67, 67, - 67, 67, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 67, 67, 67, 67, 4, 4, 67, 67, 8, 67, 67, 67,145,146, 67, 67, - 67, 67, 67, 67, 67, 67,144, 67, 67, 67, 67, 67, 67, 26, 8, 8, - 8, 8, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 8, 8, - 8, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 92, 44, 44, - 27, 27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, - 67, 67, 67, 26, 67, 67, 67, 67, 26, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 8, 8, 8, 8, 67, 67, 67, 67, 67, 67, 67, 26, - 67, 67, 67, 67, 4, 4, 4, 4, 4, 4, 4, 27, 27, 27, 27, 27, - 27, 27, 67, 67, 67, 67, 67, 67, 8, 8,129,147, 8, 8, 8, 8, - 8, 8, 8, 4, 4, 4, 4, 4, 8,129,148,148,148,148,148,148, - 148,148,148,148,147, 8, 8, 8, 8, 8, 8, 8, 4, 4, 8, 8, - 8, 8, 8, 8, 8, 8, 4, 8, 8, 8,144, 26, 8, 8,144, 67, - 67, 67, 44, 67, 67, 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 67, - 32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 40, 11, - 32, 32,140, 67, 67,138, 34,149, 43, 32, 44, 44, 93, 2, 99, 2, - 16, 16, 16,150, 44, 44,150, 44, 36, 36, 36, 36, 44, 44, 44, 52, - 64, 44, 44, 44, 44, 44, 44, 57, 36, 36, 36, 61, 44, 44, 44, 44, - 36, 36, 36, 61, 36, 36, 36, 61, 2,121,121, 2,125,126,121, 2, - 2, 2, 2, 6, 2,108,121, 2,121, 4, 4, 4, 4, 2, 2, 88, - 2, 2, 2, 2, 2,120, 2, 2,108,151, 2, 2, 2, 2, 2, 2, - 67, 2,152,148,148,148,153, 44, 67, 67, 67, 67, 67, 55, 67, 67, - 67, 67, 44, 44, 44, 44, 44, 44, 67, 67, 67, 44, 44, 44, 44, 44, - 1, 2,154,155, 4, 4, 4, 4, 4, 67, 4, 4, 4, 4,156,157, - 158,105,105,105,105, 43, 43, 86,159, 40, 40, 67,105,160, 63, 67, - 36, 36, 36, 61, 57,161,162, 69, 36, 36, 36, 36, 36, 63, 40, 69, - 44, 44, 62, 36, 36, 36, 36, 36, 67, 27, 27, 67, 67, 67, 67, 67, - 67, 67, 67, 44, 44, 44, 44, 55, 67, 67, 67, 67, 67, 67, 67, 92, - 27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, 27, - 163, 27, 27, 27, 27, 27, 27, 27, 36, 36, 83, 36, 36, 36, 36, 36, - 67, 67, 67, 92, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36,164, 2, - 7, 7, 7, 7, 7, 36, 44, 44, 32, 32, 32, 32, 32, 32, 32, 70, - 51,165, 43, 43, 43, 43, 43, 88, 32, 32, 32, 32, 32, 32, 40, 43, - 36, 36, 36,105,105,105,105,105, 43, 2, 2, 2, 44, 44, 44, 44, - 41, 41, 41,162, 40, 40, 40, 40, 41, 32, 32, 32, 32, 32, 32, 32, - 16, 32, 32, 32, 32, 32, 32, 32, 45, 16, 16, 16, 34, 34, 34, 32, - 32, 32, 32, 32, 42,166, 34, 35, 32, 32, 16, 32, 32, 32, 32, 32, + 16, 16, 36, 16, 16, 16, 16, 16, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 40, 40, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, + 39, 39, 41, 40, 40, 40, 41, 41, 40, 40, 40, 40, 40, 40, 40, 40, + 42, 42, 42, 42, 42, 42, 42, 42, 32, 32, 41, 32, 43, 44, 16, 10, + 43, 43, 40, 45, 11, 46, 46, 11, 34, 11, 11, 11, 11, 11, 11, 11, + 11, 47, 11, 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 34, + 16, 11, 32, 16, 32, 32, 32, 32, 16, 16, 32, 48, 34, 32, 34, 11, + 32, 49, 42, 42, 50, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16, + 47, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 46, 51, 2, 2, 2, + 16, 16, 16, 16, 52, 53, 54, 55, 56, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 57, 58, 59, 42, 58, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43, 61, + 36, 62, 63, 43, 43, 43, 43, 43, 64, 64, 64, 8, 9, 65, 2, 66, + 42, 42, 42, 42, 42, 59, 67, 2, 68, 36, 36, 36, 36, 69, 42, 42, + 7, 7, 7, 7, 7, 2, 2, 36, 70, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 71, 42, 42, 42, 72, 49, 42, 42, 73, 74, 75, 42, 42, 36, + 7, 7, 7, 7, 7, 36, 76, 77, 2, 2, 2, 2, 2, 2, 2, 78, + 69, 36, 36, 36, 36, 36, 36, 36, 42, 42, 42, 42, 42, 79, 61, 36, + 36, 36, 36, 42, 42, 42, 42, 42, 70, 43, 43, 43, 43, 43, 43, 43, + 7, 7, 7, 7, 7, 36, 36, 36, 36, 36, 36, 36, 36, 69, 42, 42, + 42, 42, 39, 21, 2, 80, 56, 20, 36, 36, 36, 42, 42, 74, 42, 42, + 42, 42, 74, 42, 74, 42, 42, 43, 2, 2, 2, 2, 2, 2, 2, 63, + 36, 36, 36, 36, 69, 42, 43, 63, 36, 36, 36, 36, 36, 60, 43, 43, + 36, 36, 36, 36, 81, 36, 36, 36, 64, 43, 43, 56, 42, 42, 42, 42, + 36, 36, 36, 36, 82, 42, 42, 42, 42, 83, 42, 42, 42, 42, 42, 42, + 42, 84, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 84, 70, 85, + 86, 42, 42, 42, 84, 85, 86, 85, 69, 42, 42, 42, 36, 36, 36, 36, + 36, 42, 2, 7, 7, 7, 7, 7, 87, 36, 36, 36, 36, 36, 36, 36, + 69, 85, 61, 36, 36, 36, 60, 61, 60, 61, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 60, 36, 36, 36, 60, 60, 43, 36, 36, 43, 70, 85, + 86, 42, 79, 88, 89, 88, 86, 60, 43, 43, 43, 88, 43, 43, 36, 61, + 36, 42, 43, 7, 7, 7, 7, 7, 36, 20, 27, 27, 27, 55, 62, 79, + 56, 84, 61, 36, 36, 60, 43, 61, 60, 36, 61, 60, 36, 43, 79, 85, + 86, 79, 43, 56, 79, 56, 42, 43, 56, 43, 43, 43, 61, 36, 60, 60, + 43, 43, 43, 7, 7, 7, 7, 7, 42, 36, 69, 63, 43, 43, 43, 43, + 56, 84, 61, 36, 36, 36, 36, 61, 36, 61, 36, 36, 36, 36, 36, 36, + 60, 36, 61, 36, 36, 43, 70, 85, 86, 42, 42, 56, 84, 88, 86, 43, + 60, 43, 43, 43, 43, 43, 43, 43, 65, 43, 43, 43, 61, 42, 42, 42, + 56, 85, 61, 36, 36, 36, 60, 61, 60, 36, 61, 36, 36, 43, 70, 86, + 86, 42, 79, 88, 89, 88, 86, 43, 43, 43, 56, 84, 43, 43, 36, 61, + 77, 27, 27, 27, 43, 43, 43, 43, 43, 70, 61, 36, 36, 60, 43, 36, + 60, 36, 36, 43, 61, 60, 60, 36, 43, 61, 60, 43, 36, 60, 43, 36, + 36, 36, 36, 36, 36, 43, 43, 85, 84, 89, 43, 85, 89, 85, 86, 43, + 60, 43, 43, 88, 43, 43, 43, 43, 27, 90, 66, 66, 55, 91, 43, 43, + 84, 85, 70, 36, 36, 36, 60, 36, 60, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 43, 70, 42, 84, 85, 89, 42, 79, 42, 42, 43, + 43, 43, 56, 79, 36, 60, 36, 43, 43, 43, 43, 92, 27, 27, 27, 90, + 69, 85, 71, 36, 36, 36, 60, 36, 36, 36, 61, 36, 36, 43, 70, 86, + 85, 85, 89, 84, 89, 85, 42, 43, 43, 43, 88, 89, 43, 43, 36, 60, + 61, 93, 43, 43, 43, 43, 43, 43, 42, 85, 36, 36, 36, 36, 60, 36, + 36, 36, 36, 36, 36, 69, 70, 85, 86, 42, 79, 85, 89, 85, 86, 76, + 43, 43, 36, 93, 27, 27, 27, 94, 27, 27, 27, 27, 90, 36, 36, 36, + 56, 85, 61, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43, 36, 36, 36, + 36, 61, 36, 36, 36, 36, 61, 43, 36, 36, 36, 60, 43, 79, 43, 88, + 85, 42, 79, 79, 85, 85, 85, 85, 43, 85, 63, 43, 43, 43, 43, 43, + 61, 36, 36, 36, 36, 36, 36, 36, 69, 36, 42, 42, 42, 79, 43, 95, + 36, 36, 36, 74, 42, 42, 42, 59, 7, 7, 7, 7, 7, 2, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 61, 60, 60, 36, 36, 60, 36, 36, + 36, 36, 61, 61, 36, 36, 36, 36, 69, 36, 42, 42, 42, 42, 70, 43, + 36, 36, 60, 80, 42, 42, 42, 79, 7, 7, 7, 7, 7, 43, 36, 36, + 76, 66, 2, 2, 2, 2, 2, 2, 2, 96, 96, 66, 42, 66, 66, 66, + 7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 49, 49, 49, 4, 4, 85, + 36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43, + 56, 42, 42, 42, 42, 42, 42, 84, 42, 42, 59, 42, 36, 36, 69, 42, + 42, 42, 42, 42, 56, 42, 42, 42, 42, 42, 42, 42, 42, 42, 79, 66, + 66, 66, 66, 75, 66, 66, 91, 66, 2, 2, 96, 66, 21, 63, 43, 43, + 36, 36, 36, 36, 36, 93, 86, 42, 84, 42, 42, 42, 86, 84, 86, 70, + 7, 7, 7, 7, 7, 2, 2, 2, 36, 36, 36, 85, 42, 36, 36, 42, + 70, 85, 97, 93, 85, 85, 85, 36, 69, 42, 70, 36, 36, 36, 36, 36, + 36, 84, 86, 84, 85, 85, 86, 93, 7, 7, 7, 7, 7, 85, 86, 66, + 11, 11, 11, 47, 43, 43, 47, 43, 16, 16, 16, 16, 16, 52, 44, 16, + 36, 36, 36, 36, 60, 36, 36, 43, 36, 36, 36, 60, 60, 36, 36, 43, + 60, 36, 36, 43, 36, 36, 36, 60, 60, 36, 36, 43, 36, 36, 36, 36, + 36, 36, 36, 60, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 56, 42, + 2, 2, 2, 2, 98, 27, 27, 27, 27, 27, 27, 27, 27, 27, 99, 43, + 66, 66, 66, 66, 66, 43, 43, 43, 11, 11, 11, 43, 16, 16, 16, 43, + 100, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 76, 71, + 101, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,102,103, 43, + 36, 36, 36, 36, 36, 62, 2,104,105, 36, 36, 36, 60, 43, 43, 43, + 36, 42, 84, 43, 43, 43, 43, 61, 36, 42,106, 63, 43, 43, 43, 43, + 36, 42, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36, 60, 36, + 60, 42, 43, 43, 43, 43, 43, 43, 36, 36, 42, 86, 42, 42, 42, 85, + 85, 85, 85, 84, 86, 42, 42, 42, 42, 42, 2, 87, 2, 65, 69, 43, + 7, 7, 7, 7, 7, 43, 43, 43, 27, 27, 27, 27, 27, 43, 43, 43, + 2, 2, 2,107, 2, 58, 42, 83, 36, 82, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 60, 43, 43, 43, 36, 36, 69, 70, 36, 36, 36, 36, + 36, 36, 36, 36, 69, 60, 43, 43, 36, 36, 36, 43, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 36, 36, 60, 42, 84, 85, 86, 84, 85, 43, 43, + 85, 84, 85, 85, 86, 42, 43, 43, 91, 43, 2, 7, 7, 7, 7, 7, + 36, 36, 36, 36, 36, 36, 36, 43, 36, 36, 60, 43, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 36, 43, 43, 36, 36, 36, 36, 36, 43, 43, 43, + 7, 7, 7, 7, 7, 99, 43, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 36, 36, 36, 69, 84, 86, 43, 2, 36, 36, 93, 84, 42, 42, 42, 79, + 84, 84, 86, 42, 42, 42, 84, 85, 85, 86, 42, 42, 42, 42, 79, 56, + 2, 2, 2, 87, 2, 2, 2, 43, 42, 42, 42, 42, 42, 42, 42,108, + 42, 42, 42, 42, 42, 42, 42, 43, 42, 42, 42, 42, 42, 42, 43, 43, + 42, 42, 97, 36, 36, 36, 36, 36, 36, 36, 84, 42, 42, 84, 84, 85, + 85, 84, 97, 36, 36, 36, 60, 2, 96, 66, 66, 66, 66, 49, 42, 42, + 42, 42, 66, 66, 66, 66, 21, 2, 42, 97, 36, 36, 36, 36, 36, 36, + 93, 42, 42, 85, 42, 86, 42, 36, 36, 36, 36, 84, 42, 85, 86, 86, + 42, 85, 43, 43, 43, 43, 2, 2, 36, 36, 85, 85, 85, 85, 42, 42, + 42, 42, 85, 42, 43, 92, 2, 2, 7, 7, 7, 7, 7, 43, 61, 36, + 36, 36, 36, 36, 39, 39, 39, 2, 16, 16, 16, 16, 34,109, 43, 43, + 11, 11, 11, 11, 11, 46, 47, 11, 2, 2, 2, 2, 43, 43, 43, 43, + 42, 59, 42, 42, 42, 42, 42, 42, 84, 42, 42, 42, 70, 36, 69, 36, + 36, 36, 70, 93, 42, 60, 43, 43, 16, 16, 16, 16, 16, 16, 39, 39, + 39, 39, 39, 39, 39, 44, 16, 16, 16, 16, 16, 16, 44, 16, 16, 16, + 16, 16, 16, 16, 16,110, 39, 39, 32, 32, 32, 16, 16, 16, 16, 32, + 16, 16, 16, 16, 11, 11, 11, 11, 16, 16, 16, 43, 11, 11, 11, 43, + 16, 16, 16, 16, 47, 47, 47, 47, 16, 16, 16, 16, 16, 16, 16, 43, + 16, 16, 16, 16,111,111,111,111, 16, 16,109, 16, 11, 11,112,113, + 40, 16,109, 16, 11, 11,112, 40, 16, 16, 43, 16, 11, 11,114, 40, + 16, 16, 16, 16, 11, 11,115, 40, 43, 16,109, 16, 11, 11,112,116, + 117,117,117,117,117,118, 64, 64,119,119,119, 2,120,121,120,121, + 2, 2, 2, 2,122, 64, 64,123, 2, 2, 2, 2,124,125, 2,126, + 127, 2,128,129, 2, 2, 2, 2, 2, 9,127, 2, 2, 2, 2,130, + 64, 64,131, 64, 64, 64, 64, 64,132, 43, 27, 27, 27, 8,128,133, + 27, 27, 27, 27, 27, 8,128,103, 39, 39, 39, 39, 39, 39, 80, 43, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 43, 43, 43, 43, 43, 43, 43, + 42, 42, 42, 42, 42, 42,134, 50,108, 50,108, 42, 42, 42, 42, 42, + 79, 43, 43, 43, 43, 43, 43, 43, 66,135, 66,136, 66, 34, 11, 16, + 11, 32,136, 66, 48, 11, 11, 66, 66, 66,135,135,135, 11, 11,137, + 11, 11, 35, 36,138, 66, 16, 11, 8, 8, 48, 16, 16, 26, 66,139, + 27, 27, 27, 27, 27, 27, 27, 27,104,104,104,104,104,104,104,104, + 104,140,141,104,142, 66, 43, 43, 8, 8,143, 66, 66, 8, 66, 66, + 143, 26, 66,143, 66, 66, 66,143, 66, 66, 66, 66, 66, 66, 66, 8, + 66,143,143, 66, 66, 66, 66, 66, 66, 66, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 66, 66, 66, 66, 4, 4, 66, 66, + 8, 66, 66, 66,144,145, 66, 66, 66, 66, 66, 66, 66, 66,143, 66, + 66, 66, 66, 66, 66, 26, 8, 8, 8, 8, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 8, 8, 8, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 91, 43, 43, 27, 27, 27, 27, 27, 27, 66, 66, + 66, 66, 66, 66, 66, 27, 27, 27, 66, 66, 66, 26, 66, 66, 66, 66, + 26, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 8, 8, 8, 8, + 66, 66, 66, 66, 66, 66, 66, 26, 66, 66, 66, 66, 4, 4, 4, 4, + 4, 4, 4, 27, 27, 27, 27, 27, 27, 27, 66, 66, 66, 66, 66, 66, + 8, 8,128,146, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, + 8,128,147,147,147,147,147,147,147,147,147,147,146, 8, 8, 8, + 8, 8, 8, 8, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8, + 8, 8,143, 26, 8, 8,143, 66, 66, 66, 43, 66, 66, 66, 66, 66, + 32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 39, 11, + 32, 32,139, 66, 66,136, 34,148, 42, 32, 43, 43, 92, 2, 98, 2, + 16, 16, 16,149, 43, 43,149, 43, 36, 36, 36, 36, 43, 43, 43, 51, + 63, 43, 43, 43, 43, 43, 43, 56, 36, 36, 36, 60, 43, 43, 43, 43, + 36, 36, 36, 60, 36, 36, 36, 60, 2,120,120, 2,124,125,120, 2, + 2, 2, 2, 6, 2,107,120, 2,120, 4, 4, 4, 4, 2, 2, 87, + 2, 2, 2, 2, 2,119, 2, 2,107,150, 2, 2, 2, 2, 2, 2, + 66, 2,151,147,147,147,152, 43, 66, 66, 66, 66, 66, 54, 66, 66, + 66, 66, 43, 43, 43, 43, 43, 43, 66, 66, 66, 43, 43, 43, 43, 43, + 1, 2,153,154, 4, 4, 4, 4, 4, 66, 4, 4, 4, 4,155,156, + 157,104,104,104,104, 42, 42, 85,158, 39, 39, 66,104,159, 62, 66, + 36, 36, 36, 60, 56,160,161, 68, 36, 36, 36, 36, 36, 62, 39, 68, + 43, 43, 61, 36, 36, 36, 36, 36, 66, 27, 27, 66, 66, 66, 66, 66, + 66, 66, 66, 43, 43, 43, 43, 54, 66, 66, 66, 66, 66, 66, 66, 91, + 27, 27, 27, 27, 27, 66, 66, 66, 66, 66, 66, 66, 27, 27, 27, 27, + 162, 27, 27, 27, 27, 27, 27, 27, 36, 36, 82, 36, 36, 36, 36, 36, + 66, 66, 66, 91, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36,163, 2, + 7, 7, 7, 7, 7, 36, 43, 43, 32, 32, 32, 32, 32, 32, 32, 69, + 50,164, 42, 42, 42, 42, 42, 87, 32, 32, 32, 32, 32, 32, 39, 42, + 36, 36, 36,104,104,104,104,104, 42, 2, 2, 2, 43, 43, 43, 43, + 40, 40, 40,161, 39, 39, 39, 39, 40, 32, 32, 32, 32, 32, 32, 32, + 16, 32, 32, 32, 32, 32, 32, 32, 44, 16, 16, 16, 34, 34, 34, 32, + 32, 32, 32, 32, 41,165, 34, 35, 32, 32, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 11, 11, 32, 11, 11, 32, 32, 32, 32, 32, 32, - 32, 32, 11, 11, 34, 34, 32, 44, 32,150,150, 32, 32, 32, 47, 44, - 44, 40,167, 35, 40, 35, 36, 36, 36, 71, 36, 71, 36, 70, 36, 36, - 36, 94, 87, 85, 67, 67, 80, 44, 27, 27, 27, 67,168, 44, 44, 44, - 36, 36, 2, 2, 44, 44, 44, 44, 86, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 86, 86, 86, 86, 86, 86, 86, 86, 43, 44, 44, 44, 44, 2, - 43, 36, 36, 36, 2, 72, 72, 70, 36, 36, 36, 43, 43, 43, 43, 2, - 36, 36, 36, 70, 43, 43, 43, 43, 43, 86, 44, 44, 44, 44, 44, 93, - 36, 70, 86, 43, 43, 86, 43, 86,107, 2, 2, 2, 2, 2, 2, 52, - 7, 7, 7, 7, 7, 44, 44, 2, 36, 36, 70, 69, 36, 36, 36, 36, - 7, 7, 7, 7, 7, 36, 36, 61, 36, 36, 36, 36, 70, 43, 43, 85, - 87, 85, 87, 80, 44, 44, 44, 44, 36, 70, 36, 36, 36, 36, 85, 44, - 7, 7, 7, 7, 7, 44, 2, 2, 69, 36, 36, 77, 67, 94, 85, 36, - 71, 43, 71, 70, 71, 36, 36, 43, 70, 61, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 62, 83, 2, 36, 36, 36, 36, 36, 94, 43, 86, - 2, 83,169, 80, 44, 44, 44, 44, 62, 36, 36, 61, 62, 36, 36, 61, - 62, 36, 36, 61, 44, 44, 44, 44, 16, 16, 16, 16, 16,114, 40, 40, - 16, 16, 16, 16,111, 41, 44, 44, 36, 94, 87, 86, 85,107, 87, 44, - 36, 36, 44, 44, 44, 44, 44, 44, 36, 36, 36, 61, 44, 62, 36, 36, - 170,170,170,170,170,170,170,170,171,171,171,171,171,171,171,171, - 16, 16, 16,110, 44, 44, 44, 44, 44,150, 16, 16, 44, 44, 62, 71, - 36, 36, 36, 36,172, 36, 36, 36, 36, 36, 36, 61, 36, 36, 61, 61, - 36, 62, 61, 36, 36, 36, 36, 36, 36, 41, 41, 41, 41, 41, 41, 41, - 41,117, 44, 44, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36,148, 44, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 44, 44, 44, 55, 36, 36, 36, 36, 36, 36,168, 67, - 2, 2, 2,152,130, 44, 44, 44, 6,173,174,148,148,148,148,148, - 148,148,130,152,130, 2,127,175, 2, 64, 2, 2,156,148,148,130, - 2,176, 8,177, 66, 2, 44, 44, 36, 36, 61, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 61, 79, 93, 2, 3, 2, 4, 5, 6, 2, - 16, 16, 16, 16, 16, 17, 18,129,130, 4, 2, 36, 36, 36, 36, 36, - 69, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 40, - 44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 61, 44, - 20,178, 56,135, 26, 8,144, 92, 44, 44, 44, 44, 79, 65, 67, 44, - 36, 36, 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 61, 36, 62, - 2, 64, 44,179, 27, 27, 27, 27, 27, 27, 44, 55, 67, 67, 67, 67, - 105,105,143, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 27, 67, 92, - 67, 67, 67, 67, 67, 67, 92, 44, 92, 44, 44, 44, 44, 44, 44, 44, - 67, 67, 67, 67, 67, 67, 50, 44,180, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 44, 44, 27, 27, 44, 44, 44, 44, 62, 36, - 155, 36, 36, 36, 36,181, 44, 44, 36, 36, 36, 43, 43, 80, 44, 44, - 36, 36, 36, 36, 36, 36, 36, 93, 36, 36, 44, 44, 36, 36, 36, 36, - 182,105,105, 44, 44, 44, 44, 44, 11, 11, 11, 11, 16, 16, 16, 16, - 11, 11, 44, 44, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 44, 44, - 36, 36, 36, 36, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44, 44, 93, - 11, 11, 11, 11, 11, 47, 11, 11, 11, 47, 11,150, 16, 16, 16, 16, - 16,150, 16, 16, 16, 16, 16, 16, 16,150, 16, 16, 16,150,110, 44, - 40, 40, 40, 52, 40, 40, 40, 40, 81, 40, 40, 40, 40, 81, 44, 44, - 36, 36, 36, 44, 61, 36, 36, 36, 36, 36, 36, 62, 61, 44, 61, 62, - 36, 36, 36, 93, 27, 27, 27, 27, 36, 36, 36, 77,163, 27, 27, 27, - 44, 44, 44,179, 27, 27, 27, 27, 36, 61, 36, 44, 44,179, 27, 27, - 36, 36, 36, 27, 27, 27, 44, 93, 36, 36, 36, 36, 36, 44, 44, 93, - 36, 36, 36, 36, 44, 44, 27, 36, 44, 27, 27, 27, 27, 27, 27, 27, - 70, 43, 57, 80, 44, 44, 43, 43, 36, 36, 62, 36, 62, 36, 36, 36, - 36, 36, 36, 44, 43, 80, 44, 57, 27, 27, 27, 27,100, 44, 44, 44, - 2, 2, 2, 2, 64, 44, 44, 44, 36, 36, 36, 36, 36, 36,183, 30, - 36, 36, 36, 36, 36, 36,183, 27, 36, 36, 36, 36, 78, 36, 36, 36, - 36, 36, 70, 80, 44,179, 27, 27, 2, 2, 2, 64, 44, 44, 44, 44, - 36, 36, 36, 44, 93, 2, 2, 2, 36, 36, 36, 44, 27, 27, 27, 27, - 36, 61, 44, 44, 27, 27, 27, 27, 36, 44, 44, 44, 93, 2, 64, 44, - 44, 44, 44, 44,179, 27, 27, 27, 11, 47, 44, 44, 44, 44, 44, 44, - 16,110, 44, 44, 44, 27, 27, 27, 36, 36, 43, 43, 44, 44, 44, 44, - 7, 7, 7, 7, 7, 36, 36, 69, 11, 11, 11, 44, 57, 43, 43,159, - 16, 16, 16, 44, 44, 44, 44, 8, 27, 27, 27, 27, 27, 27, 27,100, - 36, 36, 36, 36, 36, 57,184, 44, 36, 44, 44, 44, 44, 44, 44, 44, - 44, 36, 61, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 43, 43, - 27, 27, 27, 95, 44, 44, 44, 44,180, 27, 30, 2, 2, 44, 44, 44, - 36, 43, 43, 2, 2, 44, 44, 44, 36, 36,183, 27, 27, 27, 44, 44, - 87, 98, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, - 43, 43, 43, 60, 2, 2, 2, 44, 27, 27, 27, 7, 7, 7, 7, 7, - 71, 70, 71, 44, 44, 44, 44, 57, 86, 87, 43, 85, 87, 60,185, 2, - 2, 80, 44, 44, 44, 44, 79, 44, 43, 71, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 70, 43, 43, 87, 43, 43, 43, 80, 7, 7, 7, 7, 7, - 2, 2, 94, 98, 44, 44, 44, 44, 36, 70, 2, 61, 44, 44, 44, 44, - 36, 94, 86, 43, 43, 43, 43, 85, 98, 36, 63, 2, 59, 43, 60, 87, - 7, 7, 7, 7, 7, 63, 63, 2,179, 27, 27, 27, 27, 27, 27, 27, - 27, 27,100, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 86, 87, - 43, 86, 85, 43, 2, 2, 2, 71, 70, 44, 44, 44, 44, 44, 44, 44, - 36, 36, 36, 61, 61, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 62, - 36, 36, 36, 36, 63, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 70, - 86, 87, 43, 43, 43, 80, 44, 44, 43, 86, 62, 36, 36, 36, 61, 62, - 61, 36, 62, 36, 36, 57, 71, 86, 85, 86, 90, 89, 90, 89, 86, 44, - 61, 44, 44, 89, 44, 44, 62, 36, 36, 86, 44, 43, 43, 43, 80, 44, - 43, 43, 80, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 62, 44, 61, - 36, 36, 36, 62, 86, 87, 43, 43, 80, 90, 89, 89, 86, 90, 86, 85, - 71, 71, 2, 93, 64, 44, 44, 44, 57, 80, 44, 44, 44, 44, 44, 44, - 36, 36, 94, 86, 43, 43, 43, 43, 86, 43, 85, 71, 36, 63, 2, 2, - 7, 7, 7, 7, 7, 2, 93, 71, 86, 87, 43, 43, 85, 85, 86, 87, - 85, 43, 36, 72, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 94, - 86, 43, 43, 44, 86, 86, 43, 87, 60, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 36, 36, 43, 44, 86, 87, 43, 43, 43, 85, 87, 87, - 60, 2, 61, 44, 44, 44, 44, 44, 2, 2, 2, 2, 2, 2, 64, 44, - 36, 36, 36, 36, 36, 70, 87, 86, 43, 43, 43, 87, 63, 44, 44, 44, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 44, 44, 44, 44, - 36, 36, 36, 36, 36, 61, 57, 87, 86, 43, 43, 87, 43, 43, 44, 44, - 7, 7, 7, 7, 7, 27, 2, 97, 43, 43, 43, 43, 87, 60, 44, 44, - 27,100, 44, 44, 44, 44, 44, 62, 36, 36, 36, 61, 62, 44, 36, 36, - 36, 36, 62, 61, 36, 36, 36, 36, 86, 86, 86, 89, 90, 57, 85, 71, - 98, 87, 2, 64, 44, 44, 44, 44, 36, 36, 36, 36, 44, 36, 36, 36, - 94, 86, 43, 43, 44, 43, 86, 86, 71, 72, 90, 44, 44, 44, 44, 44, - 70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 85, 70, 43, 60, - 2, 2, 2, 59, 44, 44, 44, 44, 70, 43, 43, 85, 87, 43, 36, 36, - 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 85, 43, 2, 72, 2, - 2, 64, 44, 44, 44, 44, 44, 44, 2, 2, 2, 2, 2, 44, 44, 44, - 63, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 80, 43, 43, 43, 87, - 63, 2, 2, 44, 44, 44, 44, 44, 2, 36, 36, 36, 36, 36, 36, 36, - 44, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 89, 43, 43, 43, - 85, 43, 87, 80, 44, 44, 44, 44, 36, 36, 36, 61, 36, 62, 36, 36, - 70, 43, 43, 80, 44, 80, 43, 57, 43, 43, 43, 70, 44, 44, 44, 44, - 36, 36, 36, 62, 61, 36, 36, 36, 36, 36, 36, 36, 36, 86, 86, 90, - 43, 89, 87, 87, 61, 44, 44, 44, 36, 70, 85,107, 64, 44, 44, 44, - 43, 94, 36, 36, 36, 36, 36, 36, 36, 36, 86, 43, 43, 80, 44, 86, - 85, 60, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 80, 44, 44, - 27, 27, 91, 67, 67, 67, 56, 20,168, 67, 67, 67, 67, 67, 67, 67, - 67, 44, 44, 44, 44, 44, 44, 93,105,105,105,105,105,105,105,181, - 2, 2, 64, 44, 44, 44, 44, 44, 63, 64, 44, 44, 44, 44, 44, 44, - 65, 65, 65, 65, 65, 65, 65, 65, 71, 36, 36, 70, 43, 43, 43, 43, - 43, 43, 43, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 43, - 43, 43, 43, 43, 43, 86, 87, 43, 43, 43, 60, 44, 44, 44, 44, 44, - 43, 43, 43, 60, 2, 2, 67, 67, 40, 40, 97, 44, 44, 44, 44, 44, - 7, 7, 7, 7, 7,179, 27, 27, 27, 62, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 44, 44, 62, 36, 40, 69, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 83,164, 2, 27, 27, 27, 30, 2, 64, 44, 44, - 36, 36, 36, 36, 36, 61, 44, 57, 94, 86, 86, 86, 86, 86, 86, 86, - 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 44, 44, 44, 57, - 43, 74, 40, 40, 40, 40, 40, 40, 40, 88, 80, 44, 44, 44, 44, 44, - 86, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 62, - 40, 40, 52, 40, 40, 40, 52, 81, 36, 61, 44, 44, 44, 44, 44, 44, - 44, 61, 44, 44, 44, 44, 44, 44, 36, 61, 62, 44, 44, 44, 44, 44, - 44, 44, 36, 36, 44, 44, 44, 44, 36, 36, 36, 36, 36, 44, 50, 60, - 65, 65, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 43, 43, 43, 44, - 43, 43, 43, 80, 44, 44, 44, 44, 67, 67, 67, 92, 55, 67, 67, 67, - 67, 67,186, 87, 43, 67,186, 86, 86,187, 65, 65, 65, 84, 43, 43, - 43, 76, 50, 43, 43, 43, 67, 67, 67, 67, 67, 67, 67, 43, 43, 67, - 67, 43, 76, 44, 44, 44, 44, 44, 27, 27, 44, 44, 44, 44, 44, 44, - 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 16, 16, 16,110, 16, 16, 16, 16, 16, - 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 47, 11, - 44, 47, 48, 47, 48, 11, 47, 11, 11, 11, 11, 16, 16,150,150, 16, - 16, 16,150, 16, 16, 16, 16, 16, 16, 16, 11, 48, 11, 47, 48, 11, - 11, 11, 47, 11, 11, 11, 47, 16, 16, 16, 16, 16, 11, 48, 11, 47, - 11, 11, 47, 47, 44, 11, 11, 11, 47, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, - 16, 16, 16, 44, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, - 11, 11, 31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, - 16, 16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, - 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, - 16, 33, 16, 16, 16, 32, 44, 7, 43, 43, 43, 76, 67, 50, 43, 43, - 43, 43, 43, 43, 43, 43, 76, 67, 67, 67, 50, 67, 67, 67, 67, 67, - 67, 67, 76, 21, 2, 2, 44, 44, 44, 44, 44, 44, 44, 57, 43, 43, - 16, 16, 16, 16, 16, 39, 16, 16, 16, 16, 16, 16, 16, 16, 16,110, - 44, 44,150, 16, 16,110, 44, 44, 43, 43, 43, 80, 43, 43, 43, 43, - 43, 43, 43, 43, 80, 57, 43, 43, 43, 57, 80, 43, 43, 80, 44, 44, - 40, 40, 40, 40, 40, 40, 40, 44, 44, 44, 44, 44, 44, 44, 44, 57, - 43, 43, 43, 74, 40, 40, 40, 44, 7, 7, 7, 7, 7, 44, 44, 77, - 36, 36, 36, 36, 36, 36, 36, 80, 36, 36, 36, 36, 36, 36, 43, 43, - 7, 7, 7, 7, 7, 44, 44, 96, 36, 36, 36, 36, 36, 83, 43, 43, - 188, 7, 7, 7, 7,189, 44, 93, 36, 36, 36, 61, 36, 36, 62, 61, - 36, 36, 61,179, 27, 27, 27, 27, 16, 16, 43, 43, 43, 74, 44, 44, - 27, 27, 27, 27, 27, 27,163, 27,190, 27,100, 44, 44, 44, 44, 44, - 27, 27, 27, 27, 27, 27, 27,163, 27, 27, 27, 27, 27, 27, 27, 44, - 36, 36, 62, 36, 36, 36, 36, 36, 62, 61, 61, 62, 62, 36, 36, 36, - 36, 61, 36, 36, 62, 62, 44, 44, 44, 61, 44, 62, 62, 62, 62, 36, - 62, 61, 61, 62, 62, 62, 62, 62, 62, 61, 61, 62, 36, 61, 36, 36, - 36, 61, 36, 36, 62, 36, 61, 61, 36, 36, 36, 36, 36, 62, 36, 36, - 62, 36, 62, 36, 36, 62, 36, 36, 8, 44, 44, 44, 44, 44, 44, 44, - 67, 67, 67, 67, 67, 67, 44, 44, 55, 67, 67, 67, 67, 67, 67, 67, - 27, 27, 27, 27, 27, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 44, - 44, 44, 44, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44, 44, 44, - 67, 67, 67, 67, 92, 44, 44, 44, 67, 44, 44, 44, 44, 44, 44, 44, - 67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 67, 67, - 67, 67, 67, 92, 44, 55, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, - 67, 67, 67, 67, 67, 44, 44, 55, 67, 67, 67, 92, 44, 44, 44, 67, - 67, 67, 67, 67, 67, 67, 92, 55, 67, 92, 67, 67, 67, 67, 67, 67, - 79, 44, 44, 44, 44, 44, 44, 44,171,171,171,171,171,171,171, 44, - 171,171,171,171,171,171,171, 0, 0, 0, 29, 21, 21, 21, 23, 21, - 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9, - 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0, - 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15, - 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7, - 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12, - 2, 2, 6, 5, 9, 21, 9, 2, 2, 9, 25, 9, 26, 12, 11, 11, - 2, 6, 5, 21, 17, 2, 2, 26, 26, 23, 2, 12, 17, 12, 21, 12, - 12, 21, 7, 2, 2, 7, 7, 21, 21, 2, 1, 1, 21, 23, 26, 26, - 1, 21, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1, 12, 6, 6, 12, - 12, 26, 7, 26, 26, 7, 2, 1, 12, 2, 6, 2, 24, 7, 7, 6, - 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, 2, 10, 10, 2, 15, 26, - 26, 2, 2, 21, 7, 10, 15, 7, 2, 23, 21, 26, 10, 7, 21, 15, - 15, 2, 17, 7, 29, 7, 7, 22, 18, 2, 14, 14, 14, 7, 10, 21, - 17, 21, 11, 12, 5, 2, 5, 6, 8, 8, 8, 24, 5, 24, 2, 24, - 9, 24, 24, 2, 29, 29, 29, 1, 17, 17, 20, 19, 22, 20, 27, 28, - 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, - 1, 2, 15, 6, 18, 6, 23, 2, 12, 11, 9, 26, 26, 9, 26, 5, - 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25, - 18, 22, 5, 12, 2, 5, 22, 21, 21, 22, 18, 17, 26, 6, 7, 14, - 17, 22, 18, 18, 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, 26, 15, - 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, 6, 10, 4, 4, 3, 3, - 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 25, 2, 25, 24, 2, 15, - 12, 15, 14, 2, 21, 14, 7, 15, 12, 17, 21, 1, 26, 10, 10, 1, - 7, 13, 13, 2, 23, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, 15, 0, 16, 0, + 32, 32, 11, 11, 34, 34, 32, 32, 32, 32, 32, 32, 32, 32, 46, 43, + 51, 39,166, 35, 39, 35, 36, 36, 36, 70, 36, 70, 36, 69, 36, 36, + 36, 93, 86, 84, 66, 66, 79, 43, 27, 27, 27, 66,167, 43, 43, 43, + 36, 36, 2, 2, 43, 43, 43, 43, 85, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 85, 85, 85, 85, 85, 85, 85, 85, 42, 43, 43, 43, 43, 2, + 42, 36, 36, 36, 2, 71, 71, 69, 36, 36, 36, 42, 42, 42, 42, 2, + 36, 36, 36, 69, 42, 42, 42, 42, 42, 85, 43, 43, 43, 43, 43, 92, + 36, 69, 85, 42, 42, 85, 42, 85,106, 2, 2, 2, 2, 2, 2, 51, + 7, 7, 7, 7, 7, 43, 43, 2, 36, 36, 69, 68, 36, 36, 36, 36, + 7, 7, 7, 7, 7, 36, 36, 60, 36, 36, 36, 36, 69, 42, 42, 84, + 86, 84, 86, 79, 43, 43, 43, 43, 36, 69, 36, 36, 36, 36, 84, 43, + 7, 7, 7, 7, 7, 43, 2, 2, 68, 36, 36, 76, 66, 93, 84, 36, + 70, 42, 70, 69, 70, 36, 36, 42, 69, 60, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 61, 82, 2, 36, 36, 36, 36, 36, 93, 42, 85, + 2, 82,168, 79, 43, 43, 43, 43, 61, 36, 36, 60, 61, 36, 36, 60, + 61, 36, 36, 60, 43, 43, 43, 43, 16, 16, 16, 16, 16,113, 39, 39, + 16, 16, 16, 16,110, 40, 43, 43, 36, 93, 86, 85, 84,106, 86, 43, + 36, 36, 43, 43, 43, 43, 43, 43, 36, 36, 36, 60, 43, 61, 36, 36, + 169,169,169,169,169,169,169,169,170,170,170,170,170,170,170,170, + 16, 16, 16,109, 43, 43, 43, 43, 43,149, 16, 16, 43, 43, 61, 70, + 36, 36, 36, 36,171, 36, 36, 36, 36, 36, 36, 60, 36, 36, 60, 60, + 36, 61, 60, 36, 36, 36, 36, 36, 36, 40, 40, 40, 40, 40, 40, 40, + 40, 22, 66, 66, 66, 66, 66, 66, 66, 77, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36,147, 66, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 66, 66, 66, 66, 36, 36, 36, 36, 36, 36,167, 66, + 2, 2, 2,151,129, 43, 43, 43, 6,172,173,147,147,147,147,147, + 147,147,129,151,129, 2,126,174, 2, 63, 2, 2,155,147,147,129, + 2,175, 8,176, 65, 2, 43, 43, 36, 36, 60, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 60, 78, 92, 2, 3, 2, 4, 5, 6, 2, + 16, 16, 16, 16, 16, 17, 18,128,129, 4, 2, 36, 36, 36, 36, 36, + 68, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 39, + 43, 36, 36, 36, 43, 36, 36, 36, 43, 36, 36, 36, 43, 36, 60, 43, + 20,177, 55,178, 26, 8,143, 91, 43, 43, 43, 43, 78, 64, 66, 43, + 36, 36, 36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 60, 36, 61, + 2, 63, 43,179, 27, 27, 27, 27, 27, 27, 43, 54, 66, 66, 66, 66, + 104,104,142, 27, 90, 66, 66, 66, 66, 66, 66, 66, 66, 27, 66, 91, + 66, 66, 66, 66, 66, 66, 91, 43, 91, 43, 43, 43, 43, 43, 43, 43, + 66, 66, 66, 66, 66, 66, 49, 43,180, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 43, 43, 27, 27, 43, 43, 43, 43, 61, 36, + 154, 36, 36, 36, 36,181, 43, 43, 36, 36, 36, 42, 42, 79, 43, 43, + 36, 36, 36, 36, 36, 36, 36, 92, 36, 36, 43, 43, 36, 36, 36, 36, + 182,104,104, 43, 43, 43, 43, 43, 11, 11, 11, 11, 16, 16, 16, 16, + 11, 11, 43, 43, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 43, 43, + 36, 36, 36, 36, 43, 43, 43, 43, 36, 36, 43, 43, 43, 43, 43, 92, + 11, 11, 11, 11, 11, 46, 11, 11, 11, 46, 11,149, 16, 16, 16, 16, + 16,149, 16, 16, 16, 16, 16, 16, 16,149, 16, 16, 16,149,109, 43, + 39, 39, 39, 51, 39, 39, 39, 39, 80, 39, 39, 39, 39, 80, 43, 43, + 36, 36, 36, 43, 60, 36, 36, 36, 36, 36, 36, 61, 60, 43, 60, 61, + 36, 36, 36, 92, 27, 27, 27, 27, 36, 36, 36, 76,162, 27, 27, 27, + 43, 43, 43,179, 27, 27, 27, 27, 36, 60, 36, 43, 43,179, 27, 27, + 36, 36, 36, 27, 27, 27, 43, 92, 36, 36, 36, 36, 36, 43, 43, 92, + 36, 36, 36, 36, 43, 43, 27, 36, 43, 27, 27, 27, 27, 27, 27, 27, + 69, 42, 56, 79, 43, 43, 42, 42, 36, 36, 61, 36, 61, 36, 36, 36, + 36, 36, 36, 43, 42, 79, 43, 56, 27, 27, 27, 27, 99, 43, 43, 43, + 2, 2, 2, 2, 63, 43, 43, 43, 36, 36, 36, 36, 36, 36,183, 30, + 36, 36, 36, 36, 36, 36,183, 27, 36, 36, 36, 36, 77, 36, 36, 36, + 36, 36, 69, 79, 43,179, 27, 27, 2, 2, 2, 63, 43, 43, 43, 43, + 36, 36, 36, 43, 92, 2, 2, 2, 36, 36, 36, 43, 27, 27, 27, 27, + 36, 60, 43, 43, 27, 27, 27, 27, 36, 43, 43, 43, 92, 2, 63, 43, + 43, 43, 43, 43,179, 27, 27, 27, 11, 46, 43, 43, 43, 43, 43, 43, + 16,109, 43, 43, 43, 27, 27, 27, 36, 36, 42, 42, 43, 43, 43, 43, + 7, 7, 7, 7, 7, 36, 36, 68, 11, 11, 11, 43, 56, 42, 42,158, + 16, 16, 16, 43, 43, 43, 43, 8, 27, 27, 27, 27, 27, 27, 27, 99, + 36, 36, 36, 36, 36, 56,184, 43, 36, 43, 43, 43, 43, 43, 43, 43, + 43, 36, 82, 36, 43, 43, 43, 43, 96, 66, 66, 66, 91, 43, 43, 43, + 43, 43, 43, 43, 43, 42, 42, 42, 27, 27, 27, 94, 43, 43, 43, 43, + 180, 27, 30, 2, 2, 43, 43, 43, 36, 42, 42, 2, 2, 43, 43, 43, + 36, 36,183, 27, 27, 27, 43, 43, 86, 97, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 42, 42, 42, 42, 42, 42, 42, 59, 2, 2, 2, 43, + 27, 27, 27, 7, 7, 7, 7, 7, 70, 69, 70, 43, 43, 43, 43, 56, + 85, 86, 42, 84, 86, 59,185, 2, 2, 79, 43, 43, 43, 43, 78, 43, + 42, 70, 36, 36, 36, 36, 36, 36, 36, 36, 36, 69, 42, 42, 86, 42, + 42, 42, 79, 7, 7, 7, 7, 7, 2, 2, 93, 97, 43, 43, 43, 43, + 36, 69, 2, 60, 43, 43, 43, 43, 36, 93, 85, 42, 42, 42, 42, 84, + 97, 36, 62, 2, 58, 42, 59, 86, 7, 7, 7, 7, 7, 62, 62, 2, + 179, 27, 27, 27, 27, 27, 27, 27, 27, 27, 99, 43, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 36, 85, 86, 42, 85, 84, 42, 2, 2, 2, 70, + 69, 43, 43, 43, 43, 43, 43, 43, 36, 36, 36, 60, 60, 36, 36, 61, + 36, 36, 36, 36, 36, 36, 36, 61, 36, 36, 36, 36, 62, 43, 43, 43, + 36, 36, 36, 36, 36, 36, 36, 69, 85, 86, 42, 42, 42, 79, 43, 43, + 42, 85, 61, 36, 36, 36, 60, 61, 60, 36, 61, 36, 36, 56, 70, 85, + 84, 85, 89, 88, 89, 88, 85, 43, 60, 43, 43, 88, 43, 43, 61, 36, + 36, 85, 43, 42, 42, 42, 79, 43, 42, 42, 79, 43, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 61, 43, 60, 36, 36, 36, 61, 85, 86, 42, 42, + 79, 89, 88, 88, 85, 89, 85, 84, 70, 70, 2, 92, 63, 43, 43, 43, + 56, 79, 43, 43, 43, 43, 43, 43, 36, 36, 93, 85, 42, 42, 42, 42, + 85, 42, 84, 70, 36, 62, 2, 2, 7, 7, 7, 7, 7, 2, 92, 70, + 85, 86, 42, 42, 84, 84, 85, 86, 84, 42, 36, 71, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 36, 36, 93, 85, 42, 42, 43, 85, 85, 42, 86, + 59, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 36, 42, 43, + 85, 86, 42, 42, 42, 84, 86, 86, 59, 2, 60, 43, 43, 43, 43, 43, + 2, 2, 2, 2, 2, 2, 63, 43, 36, 36, 36, 36, 36, 69, 86, 85, + 42, 42, 42, 86, 62, 43, 43, 43, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 60, 56, 86, + 85, 42, 42, 86, 42, 42, 43, 43, 7, 7, 7, 7, 7, 27, 2, 96, + 42, 42, 42, 42, 86, 59, 43, 43, 27, 99, 43, 43, 43, 43, 43, 61, + 36, 36, 36, 60, 61, 43, 36, 36, 36, 36, 61, 60, 36, 36, 36, 36, + 85, 85, 85, 88, 89, 56, 84, 70, 97, 86, 2, 63, 43, 43, 43, 43, + 36, 36, 36, 36, 43, 36, 36, 36, 93, 85, 42, 42, 43, 42, 85, 85, + 70, 71, 89, 43, 43, 43, 43, 43, 69, 42, 42, 42, 42, 70, 36, 36, + 36, 69, 42, 42, 84, 69, 42, 59, 2, 2, 2, 58, 43, 43, 43, 43, + 69, 42, 42, 84, 86, 42, 36, 36, 36, 36, 36, 36, 36, 42, 42, 42, + 42, 42, 42, 84, 42, 2, 71, 2, 2, 63, 43, 43, 43, 43, 43, 43, + 2, 2, 2, 2, 2, 43, 43, 43, 84, 42, 84, 84, 43, 43, 43, 43, + 62, 43, 43, 43, 43, 43, 43, 43, 42, 42, 42, 79, 42, 42, 42, 86, + 62, 2, 2, 43, 43, 43, 43, 43, 2, 36, 36, 36, 36, 36, 36, 36, + 43, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 88, 42, 42, 42, + 84, 42, 86, 79, 43, 43, 43, 43, 36, 36, 36, 60, 36, 61, 36, 36, + 69, 42, 42, 79, 43, 79, 42, 56, 42, 42, 42, 69, 43, 43, 43, 43, + 36, 36, 36, 61, 60, 36, 36, 36, 36, 36, 36, 36, 36, 85, 85, 89, + 42, 88, 86, 86, 60, 43, 43, 43, 36, 36, 36, 36, 82, 36, 43, 43, + 36, 69, 84,106, 63, 43, 43, 43, 42, 93, 36, 36, 36, 36, 36, 36, + 36, 36, 85, 42, 42, 79, 43, 85, 84, 59, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 79, 43, 43, 27, 27, 90, 66, 66, 66, 55, 20, + 167, 66, 66, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43, 43, 43, 92, + 104,104,104,104,104,104,104,181, 2, 2, 63, 43, 43, 43, 43, 43, + 62, 63, 43, 43, 43, 43, 43, 43, 64, 64, 64, 64, 64, 64, 64, 64, + 70, 36, 36, 69, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 36, 36, 42, 42, 42, 42, 42, 42, 85, 86, 42, + 42, 42, 59, 43, 43, 43, 43, 43, 42, 42, 42, 59, 2, 2, 66, 66, + 39, 39, 96, 43, 43, 43, 43, 43, 7, 7, 7, 7, 7,179, 27, 27, + 27, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 61, 36, + 39, 68, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 82,163, 2, + 27, 27, 27, 30, 2, 63, 43, 43, 11, 11, 11, 11, 46,149, 16, 16, + 16, 16, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 60, 43, 56, + 93, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 43, 43, 43, 56, 42, 73, 39, 39, 39, 39, 39, 39, + 39, 87, 79, 43, 43, 43, 43, 43, 85, 39,104,181, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 61, 36, 60, 43, 43, 43, 43, 43, 43, + 39, 39, 51, 39, 39, 39, 51, 80, 43, 60, 43, 43, 43, 43, 43, 43, + 36, 60, 61, 43, 43, 43, 43, 43, 43, 43, 36, 36, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 43, 49, 59, 64, 64, 43, 43, 43, 43, 43, 43, + 7, 7, 7, 7, 7, 66, 91, 43, 66, 66, 43, 43, 43, 66, 66, 66, + 176, 43, 43, 43, 43, 43, 43, 43, 42, 42, 42, 79, 43, 43, 43, 43, + 66, 66, 66, 91, 54, 66, 66, 66, 66, 66,186, 86, 42, 66,186, 85, + 85,187, 64, 64, 64, 83, 42, 42, 42, 75, 49, 42, 42, 42, 66, 66, + 66, 66, 66, 66, 66, 42, 42, 66, 66, 42, 75, 43, 43, 43, 43, 43, + 27, 27, 43, 43, 43, 43, 43, 43, 11, 11, 11, 11, 11, 16, 16, 16, + 16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 16, + 16, 16,109, 16, 16, 16, 16, 16, 11, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 46, 11, 43, 46, 47, 46, 47, 11, 46, 11, + 11, 11, 11, 16, 16,149,149, 16, 16, 16,149, 16, 16, 16, 16, 16, + 16, 16, 11, 47, 11, 46, 47, 11, 11, 11, 46, 11, 11, 11, 46, 16, + 16, 16, 16, 16, 11, 47, 11, 46, 11, 11, 46, 46, 43, 11, 11, 11, + 46, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 11, 11, + 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 43, 11, 11, 11, 11, + 31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, 16, 16, + 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, 16, 16, + 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, + 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 32, 43, 7, + 42, 42, 42, 75, 66, 49, 42, 42, 42, 42, 42, 42, 42, 42, 75, 66, + 66, 66, 49, 66, 66, 66, 66, 66, 66, 66, 75, 21, 2, 2, 43, 43, + 43, 43, 43, 43, 43, 56, 42, 42, 16, 16, 16, 16, 16,138, 16, 16, + 16, 16, 16, 16, 16, 16, 16,109, 43, 43,149, 16, 16,109, 43, 43, + 42, 42, 42, 79, 42, 42, 42, 42, 42, 42, 42, 42, 79, 56, 42, 42, + 42, 56, 79, 42, 42, 79, 43, 43, 39, 39, 39, 39, 39, 39, 39, 43, + 43, 43, 43, 43, 43, 43, 43, 56, 42, 42, 42, 73, 39, 39, 39, 43, + 7, 7, 7, 7, 7, 43, 43, 76, 36, 36, 36, 36, 36, 36, 36, 79, + 36, 36, 36, 36, 36, 36, 42, 42, 7, 7, 7, 7, 7, 43, 43, 95, + 36, 36, 36, 36, 36, 82, 42, 42,188, 7, 7, 7, 7,189, 43, 92, + 36, 69, 36, 70, 36, 36, 36, 42, 36, 36, 69, 43, 43, 43, 43, 82, + 36, 36, 36, 60, 36, 36, 61, 60, 36, 36, 60,179, 27, 27, 27, 27, + 16, 16, 42, 42, 42, 73, 43, 43, 27, 27, 27, 27, 27, 27,162, 27, + 190, 27, 99, 43, 43, 43, 43, 43, 27, 27, 27, 27, 27, 27, 27,162, + 27, 27, 27, 27, 27, 27, 27, 43, 36, 36, 61, 36, 36, 36, 36, 36, + 61, 60, 60, 61, 61, 36, 36, 36, 36, 60, 36, 36, 61, 61, 43, 43, + 43, 60, 43, 61, 61, 61, 61, 36, 61, 60, 60, 61, 61, 61, 61, 61, + 61, 60, 60, 61, 36, 60, 36, 36, 36, 60, 36, 36, 61, 36, 60, 60, + 36, 36, 36, 36, 36, 61, 36, 36, 61, 36, 61, 36, 36, 61, 36, 36, + 8, 43, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 66, 66, 43, 43, + 54, 66, 66, 66, 66, 66, 66, 66, 27, 27, 27, 27, 27, 27, 90, 66, + 66, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43, 66, 66, 66, 66, 66, + 66, 91, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 91, 43, 43, 43, + 66, 43, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 66, 25, 40, 40, + 66, 66, 66, 66, 91, 43, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43, + 8, 8, 8, 8,176, 43, 43, 43, 66, 66, 66, 66, 66, 91, 43, 66, + 66, 66, 66, 91, 91, 43, 54, 66, 66, 66, 66, 66, 66, 66, 91, 54, + 66, 66, 66, 66, 66, 91, 43, 54, 66, 91, 66, 66, 66, 66, 66, 66, + 7, 7, 7, 7, 7, 91, 43, 43, 78, 43, 43, 43, 43, 43, 43, 43, + 170,170,170,170,170,170,170, 43,170,170,170,170,170,170,170, 0, + 0, 0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13, + 25, 25, 25, 21, 21, 9, 9, 9, 9, 22, 21, 18, 24, 16, 24, 5, + 5, 5, 5, 22, 25, 18, 25, 0, 23, 23, 26, 21, 24, 26, 7, 20, + 25, 1, 26, 24, 26, 25, 15, 15, 24, 15, 7, 19, 15, 21, 9, 25, + 9, 5, 5, 25, 5, 9, 5, 7, 7, 7, 9, 8, 8, 5, 6, 6, + 24, 24, 6, 24, 12, 12, 2, 2, 6, 5, 9, 21, 9, 2, 2, 9, + 25, 9, 26, 12, 11, 11, 2, 6, 5, 21, 17, 2, 2, 26, 26, 23, + 2, 12, 17, 12, 21, 12, 12, 21, 7, 2, 2, 7, 7, 21, 21, 2, + 1, 1, 21, 23, 26, 26, 1, 21, 6, 7, 7, 12, 12, 7, 21, 7, + 12, 1, 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, 2, 1, 12, 2, + 6, 2, 24, 7, 7, 6, 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, + 2, 10, 10, 2, 15, 26, 26, 2, 2, 21, 7, 10, 15, 7, 2, 23, + 21, 26, 10, 7, 21, 15, 15, 2, 17, 7, 29, 7, 7, 22, 18, 2, + 14, 14, 14, 7, 10, 21, 17, 21, 11, 12, 5, 2, 5, 6, 8, 8, + 8, 24, 5, 24, 2, 24, 9, 24, 24, 2, 29, 29, 29, 1, 17, 17, + 20, 19, 22, 20, 27, 28, 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, + 25, 22, 18, 21, 21, 29, 1, 2, 15, 6, 18, 6, 12, 11, 9, 26, + 26, 9, 26, 5, 7, 5, 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, + 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 2, 5, 22, 21, 21, 22, + 18, 17, 26, 6, 7, 14, 17, 22, 18, 18, 26, 14, 17, 6, 14, 6, + 12, 24, 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, + 6, 10, 4, 4, 3, 3, 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, + 25, 2, 25, 24, 23, 2, 2, 15, 12, 15, 14, 2, 21, 14, 7, 15, + 12, 17, 21, 1, 26, 10, 10, 1, 7, 13, 13, 2, 23, 15, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, + 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 0, + 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, + 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, + 0, 0, 0, 36, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 36, 0, 37, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 40, - 0, 0, 0, 0, 0, 0, 41, 42, 43, 0, 44, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 3, 0, - 0, 0, 4, 5, 6, 7, 0, 8, 9, 10, 0, 11, 12, 13, 14, 15, - 16, 17, 16, 18, 16, 19, 16, 19, 16, 19, 0, 19, 16, 20, 16, 19, - 21, 19, 0, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 32, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, - 34, 0, 0, 35, 0, 0, 36, 0, 37, 0, 0, 0, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 0, 0, 47, 0, 0, 0, 48, 0, 0, 0, 49, - 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0, 52, 53, 0, 54, 0, - 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 58, 0, 0, 59, - 60, 61, 62, 63, 0, 0, 64, 65, 0, 0, 0, 66, 0, 0, 0, 0, - 67, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 0, 72, 0, 0, 73, - 0, 0, 0, 0, 0, 0, 0, 0, 74, 75, 0, 0, 0, 0, 76, 77, - 0, 78, 79, 0, 0, 80, 81, 0, 82, 62, 0, 83, 84, 0, 0, 85, - 86, 87, 0, 88, 0, 89, 0, 90, 0, 0, 51, 91, 51, 0, 92, 0, - 93, 0, 0, 0, 81, 0, 0, 0, 94, 95, 0, 96, 97, 98, 99, 0, - 0, 0, 0, 0, 51, 0, 0, 0, 0,100,101, 0, 0, 0, 0, 0, - 0,102, 0, 0, 0, 0, 0, 0,103, 0, 0, 0, 0, 0, 0,104, - 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,106, 0, 0,107, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,108,109, 0, 0,110, 0, 0, - 0, 0, 0, 0,111, 0,112, 0,105, 0, 0, 0, 0, 0,113,114, - 0, 0, 0, 0, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0,117, - 0,118, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, + 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 4, 5, 6, 7, 0, 8, + 9, 10, 0, 11, 12, 13, 14, 15, 16, 17, 16, 18, 16, 19, 16, 19, + 16, 19, 0, 19, 16, 20, 16, 19, 21, 19, 0, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 35, 0, 0, 36, 0, + 37, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 0, 0, 47, + 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 50, + 0, 51, 0, 52, 53, 0, 54, 0, 0, 0, 0, 0, 0, 55, 56, 57, + 0, 0, 0, 0, 58, 0, 0, 59, 60, 61, 62, 63, 0, 0, 64, 65, + 0, 0, 0, 66, 0, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, + 0, 71, 0, 0, 72, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, + 74, 75, 0, 0, 0, 0, 76, 77, 0, 78, 79, 0, 0, 80, 81, 0, + 82, 62, 0, 83, 84, 0, 0, 85, 86, 87, 0, 88, 0, 89, 0, 90, + 0, 0, 51, 91, 51, 0, 92, 0, 93, 0, 0, 0, 81, 0, 0, 0, + 94, 95, 0, 96, 97, 98, 99, 0, 0, 0, 0, 0, 51, 0, 0, 0, + 0,100,101, 0, 0, 0, 0, 0, 0,102, 0, 0, 0, 0, 0, 0, + 103, 0, 0, 0, 0, 0, 0,104,105, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,106, 0, 0,107, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,108,109, 0, 0,110, 0, 0, 0, 0, 0, 0,111, 0,112, 0, + 105, 0, 0, 0, 0, 0,113,114, 0, 0, 0, 0, 0, 0, 0,115, + 0, 0, 0,116, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0,118, + 0,119, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 0, 0, 0, 0, 9, 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, 14, 15, 0, 16, 0, 17, 18, 0, 0, 19, 0, 20, 21, 0, 0, 0, 0, 0, 22, 23, 0, 24, 25, 0, 0, 26, 0, 0, 0, 27, 0, 0, @@ -3371,560 +3219,384 @@ _hb_ucd_u8[17524] = 0, 43, 0, 44, 0, 0, 0, 45, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 48, 49, 0, 0, 0, 0, 50, 0, 0, 0, 51, 0, 52, 0, 53, 0, 0, 0, 0, 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, - 0, 0, 57, 58, 0, 0, 0, 59, 60, 0, 0, 0, 0, 0, 0, 61, - 52, 0, 62, 63, 0, 0, 64, 0, 0, 0, 65, 66, 0, 0, 0, 67, - 0, 68, 69, 70, 71, 72, 1, 73, 0, 74, 75, 76, 0, 0, 77, 78, - 0, 0, 0, 79, 0, 0, 1, 1, 0, 0, 80, 0, 0, 81, 0, 0, - 0, 0, 77, 82, 0, 83, 0, 0, 0, 0, 0, 78, 84, 0, 85, 0, - 52, 0, 1, 78, 0, 0, 86, 0, 0, 87, 0, 0, 0, 0, 0, 88, - 57, 0, 0, 0, 0, 0, 0, 89, 90, 0, 0, 84, 0, 0, 33, 0, - 0, 91, 0, 0, 0, 0, 92, 0, 0, 0, 0, 49, 0, 0, 93, 0, - 0, 0, 0, 94, 95, 0, 0, 96, 0, 0, 97, 0, 0, 0, 98, 0, - 0, 0, 99, 0, 0, 0,100, 0, 0, 0, 0,101,102, 93, 0, 0, - 103, 0, 0, 0, 84, 0, 0,104, 0, 0, 0,105,106, 0, 0,107, - 108, 0, 0, 0, 0, 0, 0,109, 0, 0,110, 0, 0, 0, 0,111, - 33, 0,112,113,114, 57, 0, 0,115, 35, 0, 0,116, 0, 0, 0, - 117, 0, 0, 0, 0, 0, 0,118, 0, 0,119, 0, 0, 0, 0,120, - 88, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 52,121, 0, 0, 0, - 0,122, 0, 0,123, 0, 0, 0, 0,121, 0, 0,124, 0, 0, 0, - 0, 0, 79, 0, 0, 0, 0,125, 0, 0, 0,126, 0, 0, 0,127, - 0,128, 0, 0, 0, 0,129,130,131, 0,132, 0,133, 0, 0, 0, - 134,135,136, 0, 77, 0, 0, 0, 0, 0, 35, 0, 0, 0,137, 0, - 0, 0,138, 0, 0, 0,139, 0, 0,140, 0, 0,141, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 4, - 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, - 19, 1, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, 27, 28, - 29, 30, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, 1, 36, - 37, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, 42, 0, 0, 0, - 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 19, 1, 21, 0, 0, 47, - 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 51, 0, 0, 19, 52, 1, - 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52, 54, 21, 35, 1, - 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 59, - 0, 60, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, 64, 0, - 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 68, 0, - 0, 69, 70, 0, 71, 72, 73, 74, 75, 76, 0, 0, 0, 77, 0, 0, - 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 49, 0, 80, 0, 0, - 0, 62, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, 83, 0, - 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85, 1, 52, 15, 86, - 36, 10, 21, 87, 0, 55, 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, - 0, 0, 88, 0, 0, 89, 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, - 87, 9, 12, 4, 90, 8, 91, 47, 0, 58, 50, 0, 21, 1, 21, 92, - 93, 1, 1, 1, 1, 94, 95, 96, 97, 1, 98, 58, 81, 99,100, 4, - 58, 0, 0, 0, 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, - 0, 0,101,102, 0, 0,103, 0, 0, 1, 1, 50, 0, 0, 0, 38, - 0, 63, 0, 0, 0, 0, 0, 62, 0, 0,104, 68, 61, 0, 0, 0, - 78, 0, 0, 0,105,106, 58, 38, 81, 0, 0, 0, 0, 0, 0,107, - 1, 14, 4, 12, 84, 0, 0, 0, 0, 38, 87, 0, 0, 0, 0,108, - 0, 0,109, 61, 0,110, 0, 0, 0, 1, 0, 0, 0, 0, 49, 50, - 0, 0, 19, 58, 0, 0, 0, 51, 0,111, 14, 52,112, 41, 0, 0, - 62, 0, 0, 61, 0, 0,113, 0, 87, 0, 0, 0, 61, 62, 0, 0, - 62, 0, 89, 0, 0,113, 0, 0, 0, 0,114, 0, 0, 0, 78, 55, - 0, 38, 1, 58, 1, 58, 0, 0, 0, 0, 0, 88, 63, 89, 0, 0, - 115, 0, 0, 0, 55, 0, 0, 0, 0,115, 0, 0, 0, 0, 61, 0, - 0, 0, 0, 79, 0, 61, 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, - 79, 0, 0, 0, 8, 91, 0, 0, 1, 87, 0, 0,116, 0, 0, 0, - 0, 0, 0,117, 0,118,119,120,121, 0,104, 4,122, 49, 23, 0, - 0, 0, 38, 50, 38, 58, 0, 0, 1, 87, 1, 1, 1, 1, 39, 1, - 48,105, 87, 0, 0, 0, 0, 1, 0, 0, 0,123, 0, 0, 0,112, - 4,122, 0, 0, 0, 1,124, 0, 0, 0, 0, 0,230,230,230,230, - 230,232,220,220,220,220,232,216,220,220,220,220,220,202,202,220, - 220,220,220,202,202,220,220,220, 1, 1, 1, 1, 1,220,220,220, - 220,230,230,230,230,240,230,220,220,220,230,230,230,220,220, 0, - 230,230,230,220,220,220,220,230,232,220,220,230,233,234,234,233, - 234,234,233,230, 0, 0, 0,230, 0,220,230,230,230,230,220,230, - 230,230,222,220,230,230,220,220,230,222,228,230, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0, - 230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31, - 32, 33, 34,230,230,220,220,230,220,230,230,220, 35, 0, 0, 0, - 0, 0,230,230,230, 0, 0,230,230, 0,220,230,230,220, 0, 0, - 0, 36, 0, 0,230,220,230,230,220,220,230,220,220,230,220,230, - 220,230,230, 0, 0,220, 0, 0,230,230, 0,230, 0,230,230,230, - 230,230, 0, 0, 0,220,220,220,230,220,220,220,230,230, 0,220, - 27, 28, 29,230, 7, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230, - 230, 0, 0, 0, 0, 0,230, 0, 0, 84, 91, 0, 0, 0, 0, 9, - 9, 0, 0, 0, 0, 0, 9, 0,103,103, 9, 0,107,107,107,107, - 118,118, 9, 0,122,122,122,122,220,220, 0, 0, 0,220, 0,220, - 0,216, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130, - 130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0,220, 0, - 0, 0, 0, 7, 0, 9, 9, 0, 9, 9, 0, 0, 0,230, 0, 0, - 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0,230, 0, 0,220, - 230,220, 0,220,230,230,230, 0, 0, 0, 9, 9, 0, 0, 7, 0, - 230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220,202,230,230,230, - 230,230,232,228,228,220,218,230,233,220,230,220,230,230, 1, 1, - 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, 0, 0,218,228, - 232,222,224,224, 0, 8, 8, 0, 0, 0, 0,220,230, 0,230,230, - 220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0, - 0,230,220, 0, 0, 0,220,220, 0, 0,230,220, 0, 9, 7, 0, - 0, 7, 9, 0, 0, 0, 9, 7, 6, 6, 0, 0, 0, 0, 1, 0, - 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,216, 0, - 220,220,220, 0,232,232,220,230,230,230, 7, 0, 16, 17, 17, 33, - 17, 49, 17, 17, 84, 97,135,145, 26, 17, 17, 17, 17, 17, 17, 17, + 0, 0, 57, 58, 0, 0, 0, 59, 60, 61, 62, 0, 0, 0, 0, 63, + 52, 0, 64, 65, 0, 0, 66, 0, 0, 0, 67, 68, 0, 0, 0, 69, + 0, 70, 71, 72, 73, 74, 1, 75, 0, 76, 77, 78, 0, 0, 79, 80, + 0, 0, 0, 81, 0, 0, 1, 1, 0, 0, 82, 0, 0, 83, 0, 0, + 0, 0, 79, 84, 0, 85, 0, 0, 0, 0, 0, 80, 86, 0, 87, 0, + 52, 0, 1, 80, 0, 0, 88, 0, 0, 89, 0, 0, 0, 0, 0, 90, + 57, 0, 0, 0, 0, 0, 0, 91, 92, 0, 0, 86, 0, 0, 33, 0, + 0, 93, 0, 0, 0, 0, 94, 0, 0, 0, 0, 49, 0, 0, 95, 0, + 0, 0, 0, 96, 97, 0, 0, 98, 0, 0, 99, 0, 0, 0,100, 0, + 0, 0,101, 0, 0, 0,102, 0, 0, 0, 0,103,104, 95, 0, 0, + 105, 0, 0, 0, 86, 0, 0,106, 0, 0, 0,107,108, 0, 0,109, + 110, 0, 0, 0, 0, 0, 0,111, 0, 0,112, 0, 0, 0, 0,113, + 33, 0,114,115,116, 57, 0, 0,117, 35, 0, 0,118, 0, 0, 0, + 119, 0, 0, 0, 0, 0, 0,120, 0, 0,121, 0, 0, 0, 0,122, + 90, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 52,123, 0, 0, 0, + 0,124, 0, 0,125, 0, 0, 0, 0,123, 0, 0,126, 0, 0, 0, + 0, 0, 81, 0, 0, 0, 0,127, 0, 0, 0,128, 0, 0, 0,129, + 0,130, 0, 0, 0, 0,131,132,133, 0,134, 0,135, 0, 0, 0, + 136,137,138, 0, 79, 0, 0, 0, 0, 0, 35, 0, 0, 0,139, 0, + 0, 0,140, 0, 0, 0,141, 0, 0, 0,142,143, 0,144, 0, 0, + 145, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4, + 5, 6, 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17, + 18, 1, 1, 1, 19, 1, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, + 25, 26, 27, 28, 29, 30, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33, + 34, 35, 1, 36, 37, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, + 42, 0, 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 19, 1, + 21, 0, 0, 47, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 51, 0, + 0, 19, 52, 1, 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52, + 54, 21, 35, 1, 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0, + 0, 0, 0, 59, 0, 60, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0, + 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 67, 0, + 0, 0, 68, 0, 0, 69, 70, 0, 71, 72, 73, 74, 75, 76, 0, 0, + 0, 77, 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 49, + 0, 80, 0, 0, 0, 62, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0, + 0, 0, 83, 0, 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85, + 1, 52, 15, 86, 36, 10, 21, 1, 1, 1, 1, 41, 1, 21, 87, 0, + 0, 55, 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0, + 0, 89, 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, 90, 9, 12, 4, + 91, 8, 92, 47, 0, 58, 50, 0, 21, 1, 21, 93, 94, 1, 1, 1, + 1, 95, 96, 97, 98, 1, 99, 58, 81,100,101, 4, 58, 0, 0, 0, + 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, 0, 0,102,103, + 0, 0,104, 0, 0, 1, 1, 50, 0, 0, 0, 38, 0, 63, 0, 0, + 0, 0, 0, 62, 0, 0,105, 68, 61, 0, 0, 0, 78, 0, 0, 0, + 106,107, 58, 38, 81, 0, 0, 0, 0, 0, 0,108, 1, 14, 4, 12, + 84, 0, 0, 0, 0, 38, 90, 0, 0, 0, 0,109, 0, 0,110, 61, + 0,111, 0, 0, 0, 1, 0, 0, 0, 0, 49, 50, 0, 0, 19, 58, + 0, 0,112, 51, 0,112, 14, 52,113, 41, 0, 0, 62, 0, 0, 61, + 0, 0,114, 0, 90, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, + 0,114, 0, 0, 0, 0,115, 0, 0, 0, 78, 55, 0, 38, 1, 58, + 1, 58, 0, 0, 0, 0, 0, 88, 63, 89, 0, 0,116, 0, 0, 0, + 55, 0, 0, 0, 0,116, 0, 0, 0, 0, 61, 0, 0, 0, 0, 79, + 0, 61, 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 79, 0, 0, 0, + 8, 92, 0, 0, 1, 90, 0, 0,117, 0, 0, 0, 0, 0, 0,118, + 0,119,120,121,122, 0,105, 4,123, 49, 23, 0, 0, 0, 38, 50, + 38, 58, 0, 0, 1, 90, 1, 1, 1, 1, 39, 1, 48,106, 90, 0, + 0, 0, 0, 1, 0, 0, 0,124, 0, 0, 0,113, 19, 59, 0, 38, + 0, 81, 0, 0, 4,123, 0, 0, 0, 1,125, 0, 0, 0, 0, 0, + 230,230,230,230,230,232,220,220,220,220,232,216,220,220,220,220, + 220,202,202,220,220,220,220,202,202,220,220,220, 1, 1, 1, 1, + 1,220,220,220,220,230,230,230,230,240,230,220,220,220,230,230, + 230,220,220, 0,230,230,230,220,220,220,220,230,232,220,220,230, + 233,234,234,233,234,234,233,230, 0, 0, 0,230, 0,220,230,230, + 230,230,220,230,230,230,222,220,230,230,220,220,230,222,228,230, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, + 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, + 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,220,230,230,220, + 35, 0, 0, 0, 0, 0,230,230,230, 0, 0,230,230, 0,220,230, + 230,220, 0, 0, 0, 36, 0, 0,230,220,230,230,220,220,230,220, + 220,230,220,230,220,230,230, 0, 0,220, 0, 0,230,230, 0,230, + 0,230,230,230,230,230, 0, 0, 0,220,220,220,230,220,220,220, + 230,230, 0,220, 27, 28, 29,230, 7, 0, 0, 0, 0, 9, 0, 0, + 0,230,220,230,230, 0, 0, 0, 0, 0,230, 0, 0, 84, 91, 0, + 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 9, 0,103,103, 9, 0, + 107,107,107,107,118,118, 9, 0,122,122,122,122,220,220, 0, 0, + 0,220, 0,220, 0,216, 0, 0, 0,129,130, 0,132, 0, 0, 0, + 0, 0,130,130,130,130, 0, 0,130, 0,230,230, 9, 0,230,230, + 0, 0,220, 0, 0, 0, 0, 7, 0, 9, 9, 0, 9, 9, 0, 0, + 0,230, 0, 0, 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0, + 230, 0, 0,220,230,220, 0,220,230,230,230,234, 0, 0, 9, 9, + 0, 0, 7, 0,230,230,230, 0,230, 0, 1, 1, 1, 0, 0, 0, + 230,234,214,220,202,230,230,230,230,230,232,228,228,220,218,230, + 233,220,230,220,230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230, + 220,230, 1, 1, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0, + 0, 0, 0,220,230, 0,230,230,220, 0, 0,230, 0, 0, 26, 0, + 0,220, 0,230,230, 1,220, 0, 0,230,220, 0, 0, 0,220,220, + 0, 0,230,220, 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, 9, 7, + 6, 6, 0, 0, 0, 0, 1, 0, 0,216,216, 1, 1, 1, 0, 0, + 0,226,216,216,216,216,216, 0,220,220,220, 0,232,232,220,230, + 230,230, 7, 0, 16, 17, 17, 33, 17, 49, 17, 17, 84, 97,135,145, + 26, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,177, 0, 1, 2, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 3, 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, 6, 7, 8, 3, - 3, 3, 3, 3, 9, 10, 11, 12, 13, 3, 3, 3, 3, 3, 3, 3, - 3, 14, 3, 15, 3, 3, 3, 3, 3, 3, 16, 17, 18, 19, 20, 21, - 3, 3, 3, 22, 23, 24, 3, 3, 3, 3, 3, 3, 25, 3, 3, 3, - 3, 3, 3, 3, 3, 26, 3, 3, 27, 28, 0, 1, 0, 0, 0, 0, - 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, - 0, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 9, 0, 9, 0, 0, - 0, 0, 0, 0, 0, 10, 11, 12, 13, 0, 0, 14, 15, 16, 6, 0, - 17, 18, 19, 19, 19, 20, 21, 22, 23, 24, 19, 25, 0, 26, 27, 19, - 19, 28, 29, 30, 0, 31, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, - 0, 19, 28, 0, 32, 33, 9, 34, 35, 19, 0, 0, 36, 37, 38, 39, - 40, 19, 0, 41, 42, 43, 44, 31, 0, 1, 45, 42, 0, 0, 0, 0, - 0, 32, 14, 14, 0, 0, 0, 0, 14, 0, 0, 46, 47, 47, 47, 47, - 48, 49, 47, 47, 47, 47, 50, 51, 52, 53, 43, 21, 0, 0, 0, 0, - 0, 0, 0, 54, 6, 55, 0, 14, 19, 1, 0, 0, 0, 0, 56, 57, - 0, 0, 0, 0, 0, 19, 58, 31, 0, 0, 0, 0, 0, 0, 0, 59, - 14, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 60, - 61, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 3, - 0, 4, 5, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 1, 1, 0, - 0, 8, 9, 0, 8, 9, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0, - 0, 0, 13, 0, 0, 0, 0, 14, 15, 16, 17, 0, 0, 0, 1, 0, - 0, 18, 19, 0, 0, 0, 20, 0, 0, 0, 1, 1, 1, 1, 0, 1, - 1, 1, 1, 1, 1, 1, 0, 8, 21, 9, 0, 0, 22, 0, 0, 0, - 0, 1, 0, 23, 24, 25, 0, 0, 26, 0, 0, 0, 8, 21, 27, 0, - 1, 0, 0, 1, 1, 1, 1, 0, 1, 28, 29, 30, 0, 31, 32, 20, - 1, 1, 0, 0, 0, 8, 21, 9, 1, 4, 5, 0, 0, 0, 33, 9, - 0, 1, 1, 1, 0, 8, 21, 21, 21, 21, 34, 1, 35, 21, 21, 21, - 9, 36, 0, 0, 37, 38, 1, 0, 39, 0, 0, 0, 1, 0, 1, 0, - 0, 0, 0, 8, 21, 9, 1, 0, 0, 0, 40, 0, 8, 21, 21, 21, - 21, 21, 21, 21, 21, 9, 0, 1, 1, 1, 1, 8, 21, 21, 21, 9, - 0, 0, 0, 41, 0, 42, 43, 0, 0, 0, 1, 44, 0, 0, 0, 45, - 8, 9, 1, 0, 0, 0, 8, 21, 21, 21, 9, 0, 1, 0, 1, 1, - 8, 21, 21, 9, 0, 4, 5, 8, 9, 1, 0, 0, 0, 1, 2, 3, - 4, 5, 5, 5, 5, 5, 6, 7, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 9, 16, 17, 18, 9, 19, 20, 21, 22, 23, 24, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 25, 26, 27, 5, 28, 29, 5, 30, 31, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 32, 0, 0, 1, - 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 1, 29, 30, 31, - 32, 32, 33, 32, 32, 32, 34, 32, 32, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 46, 46, - 46, 46, 47, 48, 49, 50, 51, 52, 53, 54, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 44, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 95, - 95, 96, 97, 98, 56, 56, 56, 56, 56, 56, 56, 56, 56, 99,100,100, - 100,100,101,100,100,100,100,100,100,100,100,100,100,100,100,100, - 100,102,103,103,104, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,105, - 56, 56, 56, 56, 56, 56,106,106,107,108, 56,109,110,111,112,112, - 112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, - 112,112,112,112,112,113,112,112,112,114,115,116, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,117,118,119, - 120, 56, 56, 56, 56, 56, 56, 56, 56, 56,121, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,122, 32,123,124,125,126, - 127,128,129,130,131,132,133,133,134, 56, 56, 56, 56,135,136,137, - 138, 56,139,140, 56,141,142,143, 56, 56,144,145,146, 56,147,148, - 149, 32, 32, 32,150,151,152, 32,153,154, 56, 56, 56, 56, 44, 44, - 44, 44, 44, 44,155, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44,156,157, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,158, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44,159, 44, 44,160, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 44, 44,161, 56, 56, 56, 56, 56, 44, 44, - 44,162, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44,163, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,164,165, - 0, 1, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, - 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 0, 19, 0, - 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, - 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, - 9, 9, 0, 9, 9, 9, 2, 2, 9, 9, 9, 9, 0, 9, 2, 2, - 2, 2, 9, 0, 9, 0, 9, 9, 9, 2, 9, 2, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 2, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 2, 4, 4, 4, 2, 2, 4, 4, 4, 2, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2, - 2, 2, 2, 2, 2, 2, 14, 14, 14, 2, 2, 2, 2, 14, 14, 14, - 14, 14, 14, 2, 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, - 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 3, - 3, 3, 3, 3, 3, 3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37, 37, 37, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2, 2, 2, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 2, 2, 64, 64, 64, 90, 90, - 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90, - 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 2, 2, 95, 2, 37, 37, 37, 2, 2, 2, 2, 2, 3, 3, - 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, - 0, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, - 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 5, 5, - 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2, - 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, - 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5, - 2, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 2, 2, 2, - 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 5, 5, 2, 5, 5, 5, - 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 11, - 11, 11, 2, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2, - 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, - 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11, - 2, 2, 11, 2, 11, 11, 11, 2, 2, 11, 11, 11, 2, 2, 2, 11, - 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 2, 11, 2, 2, 2, - 2, 2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 10, - 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, - 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, - 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10, 10, - 2, 2, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 2, 2, 10, 2, - 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, - 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 2, 21, - 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, - 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, - 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, 21, 21, 21, 21, - 2, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 2, 2, 2, 2, - 2, 2, 2, 21, 21, 21, 2, 2, 2, 2, 21, 21, 2, 21, 21, 21, - 21, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22, - 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22, - 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, 22, 22, 22, 2, - 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, - 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 23, 23, - 2, 2, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, 2, 2, 2, 2, - 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 23, 2, 2, 23, 23, - 23, 23, 2, 2, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 2, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16, - 2, 2, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 2, 2, 2, 2, - 2, 2, 2, 16, 16, 2, 16, 16, 16, 16, 2, 2, 16, 16, 2, 16, - 16, 16, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, 20, 20, 20, 20, 2, 2, - 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, 20, 20, 2, 36, - 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 2, 2, 2, 36, 36, 36, 36, 36, 36, 36, 36, - 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, 2, - 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, - 2, 2, 2, 2, 36, 36, 2, 2, 36, 36, 36, 2, 2, 2, 2, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 2, 2, 2, 2, 2, 18, - 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18, - 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, - 18, 18, 18, 18, 18, 2, 18, 18, 2, 2, 18, 18, 18, 18, 25, 25, - 25, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25, - 25, 25, 25, 2, 2, 2, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, - 25, 25, 25, 0, 0, 0, 0, 25, 25, 2, 2, 2, 2, 2, 33, 33, - 33, 33, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 2, 8, 2, 2, 2, 2, 2, 8, 2, 2, 8, 8, - 8, 0, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30, - 30, 30, 30, 30, 30, 2, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, - 30, 30, 30, 2, 2, 2, 30, 30, 2, 2, 2, 2, 2, 2, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 2, 2, 28, 28, - 28, 28, 28, 28, 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 2, 2, 2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 0, 0, 0, 35, 35, 35, 2, 2, 2, 2, 2, 2, 2, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 0, 0, 2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 2, 2, 2, 2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 2, 46, 46, 46, 2, 46, 46, 2, 2, 2, 2, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 2, 2, 31, 31, - 2, 2, 2, 2, 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 2, 2, 2, 2, 2, 2, 32, 2, - 2, 2, 2, 2, 2, 2, 32, 32, 32, 2, 2, 2, 2, 2, 28, 28, - 28, 28, 28, 28, 2, 2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 2, 48, 48, 48, 48, 2, 2, 2, 2, 48, 2, - 2, 2, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 2, 2, 52, 52, 52, 52, 52, 2, 2, 2, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 2, 2, 2, 2, 58, 58, - 2, 2, 2, 2, 2, 2, 58, 58, 58, 2, 2, 2, 58, 58, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 2, 2, 54, 54, 91, 91, - 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 2, 91, 91, - 91, 91, 91, 2, 2, 91, 91, 91, 2, 2, 2, 2, 2, 2, 91, 91, - 91, 91, 91, 91, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 2, 62, 62, 76, 76, - 76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 2, 2, 2, 2, 2, 2, 2, 2, 93, 93, 93, 93, 70, 70, - 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 70, 70, 70, 70, - 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 73, 73, 73, 73, 6, 6, - 6, 2, 2, 2, 2, 2, 8, 8, 8, 2, 2, 8, 8, 8, 1, 1, - 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, - 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, - 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, 9, - 19, 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 19, 6, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9, - 9, 9, 9, 9, 2, 2, 2, 9, 2, 9, 2, 9, 2, 9, 9, 9, - 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9, 9, - 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, 2, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 2, 0, 0, 0, 19, 2, 2, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 2, 19, 19, - 19, 19, 19, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, - 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, - 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 19, 0, - 0, 0, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, - 0, 2, 2, 2, 2, 2, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, - 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 56, 56, - 56, 56, 56, 56, 56, 56, 55, 55, 55, 55, 2, 2, 2, 2, 2, 55, - 55, 55, 55, 55, 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 2, 2, - 2, 2, 2, 2, 2, 61, 61, 2, 2, 2, 2, 2, 2, 2, 0, 0, - 0, 0, 0, 0, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 13, 13, - 13, 13, 13, 13, 2, 2, 0, 0, 0, 0, 0, 13, 0, 13, 0, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 13, 13, - 13, 13, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 1, + 17, 17, 17,177, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 5, 3, + 3, 3, 3, 3, 6, 7, 8, 3, 3, 3, 3, 3, 9, 10, 11, 12, + 13, 3, 3, 3, 3, 3, 3, 3, 3, 14, 3, 15, 3, 3, 3, 3, + 3, 3, 16, 17, 18, 19, 20, 21, 3, 3, 3, 22, 23, 24, 3, 3, + 3, 3, 3, 3, 25, 3, 3, 3, 3, 3, 3, 3, 3, 26, 3, 3, + 27, 28, 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 4, 0, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, + 0, 0, 0, 9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, + 13, 0, 0, 14, 15, 16, 6, 0, 17, 18, 19, 19, 19, 20, 21, 22, + 23, 24, 19, 25, 0, 26, 27, 19, 19, 28, 29, 30, 0, 31, 0, 0, + 0, 8, 0, 0, 0, 0, 0, 0, 0, 19, 28, 0, 32, 33, 9, 34, + 35, 19, 0, 0, 36, 37, 38, 39, 40, 19, 0, 41, 42, 43, 44, 31, + 0, 1, 45, 42, 0, 0, 0, 0, 0, 32, 14, 14, 0, 0, 0, 0, + 14, 0, 0, 46, 47, 47, 47, 47, 48, 49, 47, 47, 47, 47, 50, 51, + 52, 53, 43, 21, 0, 0, 0, 0, 0, 0, 0, 54, 6, 55, 0, 14, + 19, 1, 0, 0, 0, 0, 56, 57, 0, 0, 0, 0, 0, 19, 58, 31, + 0, 0, 0, 0, 0, 0, 0, 59, 14, 0, 0, 0, 0, 1, 0, 2, + 0, 0, 0, 3, 0, 0, 0, 60, 61, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 2, 3, 0, 4, 5, 0, 0, 6, 0, 0, + 0, 7, 0, 0, 0, 1, 1, 0, 0, 8, 9, 0, 8, 9, 0, 0, + 0, 0, 8, 9, 10, 11, 12, 0, 0, 0, 13, 0, 0, 0, 0, 14, + 15, 16, 17, 0, 0, 0, 1, 0, 0, 18, 19, 0, 0, 0, 20, 0, + 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 8, + 21, 9, 0, 0, 22, 0, 0, 0, 0, 1, 0, 23, 24, 25, 0, 0, + 26, 0, 0, 0, 8, 21, 27, 0, 1, 0, 0, 1, 1, 1, 1, 0, + 1, 28, 29, 30, 0, 31, 32, 20, 1, 1, 0, 0, 0, 8, 21, 9, + 1, 4, 5, 0, 0, 0, 33, 9, 0, 1, 1, 1, 0, 8, 21, 21, + 21, 21, 34, 1, 35, 21, 21, 21, 9, 36, 0, 0, 37, 38, 1, 0, + 39, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 8, 21, 9, 1, 0, + 0, 0, 40, 0, 8, 21, 21, 21, 21, 21, 21, 21, 21, 9, 0, 1, + 1, 1, 1, 8, 21, 21, 21, 9, 0, 0, 0, 41, 0, 42, 43, 0, + 0, 0, 1, 44, 0, 0, 0, 45, 8, 9, 1, 0, 0, 0, 8, 21, + 21, 21, 9, 0, 1, 0, 1, 1, 8, 21, 21, 9, 0, 4, 5, 8, + 9, 1, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 9, 10, 11, 11, 11, 11, 12, 13, + 13, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 13, 13, 13, + 24, 25, 26, 26, 26, 27, 13, 13, 13, 28, 29, 30, 13, 31, 32, 33, + 34, 35, 36, 37, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 38, 7, 7, 39, 7, 40, 7, 7, + 7, 41, 13, 42, 7, 7, 43, 7, 7, 7, 44, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 45, 0, 0, 1, 2, 2, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 37, + 37, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 2, 2, 53, 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, 59, + 59, 59, 59, 59, 59, 59, 61, 61, 59, 59, 59, 59, 62, 59, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 59, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 78, 69, 69, 69, 69, 79, 79, 79, 79, 79, 79, 79, 79, 79, 80, + 81, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 94, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 69, 69, 96, 97, 98, 99, 99, 99, + 100,101,102,103,104,105,106,107,108,109, 95,110,111,112,113,114, + 115,116,117,117,118,119,120,121,122,123,124,125,126,127,128,129, + 130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145, + 95,146,147,148,149, 95,150,151,152,153,154,155,156,157,158,159, + 160,161, 95,162,163,164,165,165,165,165,165,165,165,166,167,165, + 168, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95,169,170,170,170,170,170,170,170,170,171,170, + 170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, + 170,170,170,170,170,170,170,170,170,170,170,170,170,172,173,173, + 173,173,174, 95, 95, 95, 95, 95,175, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95,176,176,176,176,177,178,179,180, 95, 95, + 181, 95,182,183,184,185,186,186,186,186,186,186,186,186,186,186, + 186,186,186,186,186,186,186,186,186,186,186,186,187,187,187,188, + 189,190, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95,191,192,193,194,195,195,196, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,197,198, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 59,199, + 59, 59, 59,200,201,202, 59,203,204,205,206,207,208, 95,209,210, + 211, 59, 59,212, 59,213,214,214,214,214,214,215, 95, 95, 95, 95, + 95, 95, 95, 95,216, 95,217,218,219, 95, 95,220, 95, 95, 95,221, + 95,222, 95,223, 95,224,225,226,227, 95, 95, 95, 95, 95,228,229, + 230, 95,231,232, 95, 95,233,234, 59,235,236, 95, 59, 59, 59, 59, + 59, 59, 59,237, 59,238,239,240, 59, 59,241,242, 59,243, 95, 95, + 95, 95, 95, 95, 95, 95, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69,244, 69, 69,245, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69,246, 69, 69, 69, 69, 69, 69, 69, 69, 69,247, 69, 69, + 69, 69,248, 95, 95, 95, 69, 69, 69, 69,249, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 69, 69, 69, 69, 69, 69,250, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,251, 95, + 95, 95, 95, 95, 95, 95,252, 95,253,254, 0, 1, 2, 2, 0, 1, + 2, 2, 2, 3, 4, 5, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 0, 19, 0, 19, 0, 0, 0, 0, 0, + 26, 26, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 2, 2, + 9, 9, 9, 9, 0, 9, 2, 2, 2, 2, 9, 0, 9, 0, 9, 9, + 9, 2, 9, 2, 9, 9, 9, 9, 2, 9, 9, 9, 55, 55, 55, 55, + 55, 55, 6, 6, 6, 6, 6, 1, 1, 6, 2, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 2, 2, 2, 2, 14, 14, 2, 2, 2, 3, 3, 3, 3, 3, 0, + 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 1, 1, 1, + 3, 3, 1, 3, 3, 3, 37, 37, 37, 37, 37, 37, 2, 37, 37, 37, + 37, 2, 2, 37, 37, 37, 38, 38, 38, 38, 38, 38, 2, 2, 64, 64, + 64, 64, 64, 64, 64, 2, 2, 64, 64, 64, 90, 90, 90, 90, 90, 90, + 2, 2, 90, 90, 90, 2, 95, 95, 95, 95, 2, 2, 95, 2, 3, 3, + 2, 2, 2, 2, 2, 3, 3, 3, 0, 3, 7, 7, 7, 7, 7, 1, + 1, 1, 1, 7, 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, 2, 5, + 5, 5, 5, 2, 2, 5, 5, 2, 5, 5, 5, 2, 5, 2, 2, 2, + 5, 5, 5, 5, 2, 2, 5, 5, 5, 2, 2, 2, 2, 5, 5, 5, + 2, 5, 2, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2, + 2, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11, + 2, 2, 2, 11, 2, 2, 11, 2, 11, 2, 2, 2, 11, 11, 2, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10, + 2, 2, 10, 2, 2, 2, 2, 2, 10, 10, 2, 21, 21, 21, 21, 21, + 21, 21, 21, 2, 2, 21, 21, 2, 21, 21, 21, 21, 2, 2, 21, 21, + 2, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22, + 22, 2, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, + 2, 22, 22, 2, 2, 2, 22, 22, 22, 22, 23, 23, 23, 23, 23, 2, + 23, 23, 23, 23, 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 2, + 23, 23, 2, 2, 2, 23, 16, 16, 16, 16, 16, 2, 16, 16, 2, 16, + 16, 16, 16, 16, 2, 2, 2, 16, 16, 2, 16, 16, 16, 2, 2, 2, + 16, 16, 20, 20, 20, 20, 20, 2, 20, 20, 2, 2, 20, 20, 2, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, 36, 36, 36, 36, + 2, 36, 2, 36, 2, 2, 2, 2, 36, 2, 2, 2, 2, 36, 36, 2, + 36, 2, 36, 2, 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 2, 2, 2, 2, 0, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18, + 18, 2, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18, 2, 2, 18, 2, + 18, 2, 25, 25, 25, 25, 2, 25, 25, 25, 25, 2, 2, 2, 25, 2, + 25, 25, 25, 0, 0, 0, 0, 25, 25, 2, 33, 33, 33, 33, 8, 8, + 8, 8, 8, 8, 2, 8, 2, 8, 2, 2, 8, 8, 8, 0, 12, 12, + 12, 12, 30, 30, 30, 30, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30, + 30, 2, 2, 30, 30, 30, 30, 2, 2, 2, 29, 29, 29, 29, 29, 29, + 2, 2, 28, 28, 28, 28, 34, 34, 34, 34, 34, 2, 2, 2, 35, 35, + 35, 35, 35, 35, 35, 0, 0, 0, 35, 35, 35, 2, 2, 2, 45, 45, + 45, 45, 45, 45, 2, 2, 2, 2, 2, 45, 44, 44, 44, 44, 44, 0, + 0, 2, 43, 43, 43, 43, 46, 46, 46, 46, 46, 2, 46, 46, 31, 31, + 31, 31, 31, 31, 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32, + 32, 32, 32, 32, 2, 2, 32, 2, 2, 2, 32, 32, 32, 2, 28, 28, + 2, 2, 48, 48, 48, 48, 48, 48, 48, 2, 48, 2, 2, 2, 52, 52, + 52, 52, 52, 52, 2, 2, 52, 2, 2, 2, 58, 58, 58, 58, 58, 58, + 2, 2, 58, 58, 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 2, 2, + 54, 54, 91, 91, 91, 91, 91, 91, 91, 2, 91, 2, 2, 91, 91, 91, + 2, 2, 1, 1, 2, 2, 62, 62, 62, 62, 62, 2, 62, 62, 76, 76, + 76, 76, 93, 93, 93, 93, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, + 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 6, 6, 6, 2, 8, 8, + 8, 2, 2, 8, 8, 8, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, + 0, 0, 0, 1, 0, 0, 1, 1, 0, 2, 19, 19, 9, 9, 9, 9, + 9, 6, 19, 9, 9, 9, 9, 9, 19, 19, 9, 9, 9, 19, 6, 19, + 19, 19, 19, 19, 19, 9, 9, 9, 2, 2, 2, 9, 2, 9, 2, 9, + 9, 9, 1, 1, 0, 0, 0, 2, 0, 0, 0, 19, 2, 2, 0, 0, + 0, 19, 0, 0, 0, 2, 19, 2, 2, 2, 0, 0, 2, 2, 1, 2, + 2, 2, 0, 0, 9, 0, 0, 0, 19, 19, 27, 27, 27, 27, 2, 2, + 0, 0, 56, 56, 56, 56, 2, 55, 55, 55, 61, 61, 61, 61, 2, 2, + 2, 61, 61, 2, 2, 2, 13, 13, 13, 13, 13, 13, 2, 13, 13, 13, + 2, 2, 0, 13, 0, 13, 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, + 12, 12, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 1, 1, 0, 0, 15, 15, 15, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 17, 17, 17, 2, 2, - 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, - 2, 2, 2, 2, 2, 0, 12, 12, 12, 12, 12, 12, 12, 0, 17, 17, - 17, 17, 17, 17, 17, 0, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 86, 86, - 86, 86, 86, 86, 86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 2, 2, 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, - 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 2, 2, 19, 19, 2, 19, 2, 19, 19, 19, 2, 2, - 19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 2, 2, 2, 65, 65, 65, 65, 65, 65, 65, 65, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2, - 2, 2, 2, 2, 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 0, 69, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 74, 12, 12, 12, 12, 12, 2, 2, 2, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 2, 0, 84, 84, - 2, 2, 2, 2, 84, 84, 33, 33, 33, 33, 33, 33, 33, 2, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68, - 68, 68, 68, 68, 2, 2, 68, 68, 2, 2, 68, 68, 68, 68, 92, 92, - 92, 92, 92, 92, 92, 92, 92, 92, 92, 2, 2, 2, 2, 2, 2, 2, - 2, 92, 92, 92, 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 2, 2, 30, 30, 30, 30, 30, 30, 2, 19, 19, - 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 19, 19, 19, 19, - 0, 0, 2, 2, 2, 2, 87, 87, 87, 87, 87, 87, 2, 2, 87, 87, - 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, - 2, 12, 12, 12, 12, 12, 13, 13, 2, 2, 2, 2, 2, 2, 19, 19, - 19, 19, 19, 19, 19, 2, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2, - 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, 14, - 14, 14, 14, 2, 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 3, 3, - 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 0, 0, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, - 2, 2, 2, 2, 2, 3, 1, 1, 1, 1, 1, 1, 6, 6, 0, 0, - 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, - 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 0, 2, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, - 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 12, 12, 12, 12, 2, 2, - 12, 12, 12, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 2, 49, 49, 49, 2, 49, 49, 2, 49, 49, 49, - 49, 49, 49, 49, 2, 2, 49, 49, 49, 2, 2, 2, 2, 2, 0, 0, - 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, - 0, 0, 0, 2, 2, 2, 9, 2, 2, 2, 2, 2, 2, 2, 0, 0, - 0, 0, 0, 1, 2, 2, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 2, 2, 2, 67, 67, 67, 67, 67, 67, 67, 67, 67, 2, - 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 42, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, - 41, 2, 2, 2, 2, 2,118,118,118,118,118,118,118,118,118,118, - 118, 2, 2, 2, 2, 2, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 2, 2, 2, 2, 59, 59, 59, 59, 59, 59, 2, 2, 40, 40, - 40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51, 51, 51, 50, 50, - 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 2, 2, 50, 50, - 2, 2, 2, 2, 2, 2,135,135,135,135,135,135,135,135,135,135, - 135,135, 2, 2, 2, 2,106,106,106,106,106,106,106,106,104,104, - 104,104,104,104,104,104,104,104,104,104, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2,104,161,161,161,161,161,161,161,161,161,161, - 161, 2,161,161,161,161,161,161,161, 2,161,161, 2,161,161,161, - 2,161,161,161,161,161,161,161, 2,161,161, 2, 2, 2,170,170, - 170,170,170,170,170,170,170,170,170,170, 2, 2, 2, 2,110,110, - 110,110,110,110,110,110,110,110,110,110,110,110,110, 2,110,110, - 110,110,110,110, 2, 2, 19, 19, 19, 19, 19, 19, 2, 19, 19, 2, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2, 2, 2, 47, 47, - 47, 47, 47, 47, 2, 2, 47, 2, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 2, 47, 47, 2, - 2, 2, 47, 2, 2, 47, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 2, 81,120,120,120,120,120,120,120,120,116,116, - 116,116,116,116,116,116,116,116,116,116,116,116,116, 2, 2, 2, - 2, 2, 2, 2, 2,116,128,128,128,128,128,128,128,128,128,128, - 128, 2,128,128, 2, 2, 2, 2, 2,128,128,128,128,128, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 2, 2, 2, 66, 72, 72, - 72, 72, 72, 72, 72, 72, 72, 72, 2, 2, 2, 2, 2, 72, 98, 98, - 98, 98, 98, 98, 98, 98, 97, 97, 97, 97, 97, 97, 97, 97, 2, 2, - 2, 2, 97, 97, 97, 97, 2, 2, 97, 97, 97, 97, 97, 97, 57, 57, - 57, 57, 2, 57, 57, 2, 2, 2, 2, 2, 57, 57, 57, 57, 57, 57, - 57, 57, 2, 57, 57, 57, 2, 57, 57, 57, 57, 57, 57, 57, 57, 57, - 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 2, 2, 57, 57, - 57, 2, 2, 2, 2, 57, 57, 2, 2, 2, 2, 2, 2, 2, 88, 88, - 88, 88, 88, 88, 88, 88,117,117,117,117,117,117,117,117,112,112, - 112,112,112,112,112,112,112,112,112,112,112,112,112, 2, 2, 2, - 2,112,112,112,112,112, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 2, 2, 2, 78, 78, 78, 78, 78, 78, 78, 83, 83, - 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 2, 2, 82, 82, - 82, 82, 82, 82, 82, 82, 82, 82, 82, 2, 2, 2, 2, 2,122,122, - 122,122,122,122,122,122,122,122, 2, 2, 2, 2, 2, 2, 2,122, - 122,122,122, 2, 2, 2, 2,122,122,122,122,122,122,122, 89, 89, - 89, 89, 89, 89, 89, 89, 89, 2, 2, 2, 2, 2, 2, 2,130,130, - 130,130,130,130,130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2, - 130,130,130,130,130,130,144,144,144,144,144,144,144,144,144,144, - 2, 2, 2, 2, 2, 2,165,165,165,165,165,165,165,165,165,165, - 165,165,165,165, 2, 2, 2,165,165,165,165,165,165,165, 2, 2, - 2, 2, 2, 2,165,165,156,156,156,156,156,156,156,156,156,156, - 2,156,156,156, 2, 2,156,156, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3,147,147, - 147,147,147,147,147,147,148,148,148,148,148,148,148,148,148,148, - 2, 2, 2, 2, 2, 2,158,158,158,158,158,158,158,158,158,158, - 2, 2, 2, 2, 2, 2,153,153,153,153,153,153,153,153,153,153, - 153,153, 2, 2, 2, 2,149,149,149,149,149,149,149,149,149,149, - 149,149,149,149,149, 2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, - 94, 94, 94, 94, 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 2, 2, - 2, 2, 2, 2, 2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 85, 2, 2,101,101, - 101,101,101,101,101,101,101, 2, 2, 2, 2, 2, 2, 2,101,101, - 2, 2, 2, 2, 2, 2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 2, 96, 96,111,111,111,111,111,111,111,111,111,111, - 111,111,111,111,111, 2,100,100,100,100,100,100,100,100, 2, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,108,108, - 108,108,108,108,108,108,108,108, 2,108,108,108,108,108,108,108, - 2, 2, 2, 2, 2, 2,129,129,129,129,129,129,129, 2,129, 2, - 129,129,129,129, 2,129,129,129,129,129,129,129,129,129,129,129, - 129,129,129,129, 2,129,129,129, 2, 2, 2, 2, 2, 2,109,109, - 109,109,109,109,109,109,109,109,109, 2, 2, 2, 2, 2,109,109, - 2, 2, 2, 2, 2, 2,107,107,107,107, 2,107,107,107,107,107, - 107,107,107, 2, 2,107,107, 2, 2,107,107,107,107,107,107,107, - 107,107,107,107,107,107,107, 2,107,107,107,107,107,107,107, 2, - 107,107, 2,107,107,107,107,107, 2, 1,107,107,107,107,107, 2, - 2,107,107,107, 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2, - 2, 2, 2,107,107,107,107,107,107,107, 2, 2,107,107,107,107, - 107,107,107, 2, 2, 2,171,171,171,171,171,171,171,171,171,171, - 2,171, 2, 2,171, 2,171,171,171,171,171,171, 2,171,171, 2, - 171, 2, 2,171, 2,171,171,171,171, 2,171,171,171,171,171, 2, - 2, 2, 2, 2, 2, 2, 2,171,171, 2, 2, 2, 2, 2,137,137, - 137,137,137,137,137,137,137,137,137,137, 2,137,137,137,137,137, - 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,124,124,124,124, - 2, 2, 2, 2, 2, 2,123,123,123,123,123,123,123,123,123,123, - 123,123,123,123, 2, 2,114,114,114,114,114,114,114,114,114,114, - 114,114,114, 2, 2, 2,114,114, 2, 2, 2, 2, 2, 2, 32, 32, - 32, 32, 32, 2, 2, 2,102,102,102,102,102,102,102,102,102,102, - 2, 2, 2, 2, 2, 2, 33, 33, 33, 33, 2, 2, 2, 2,126,126, - 126,126,126,126,126,126,126,126,126, 2, 2,126,126,126,126,126, - 126,126, 2, 2, 2, 2,126,126,126,126,126,126,126, 2,142,142, - 142,142,142,142,142,142,142,142,142,142, 2, 2, 2, 2,125,125, - 125,125,125,125,125,125,125,125,125, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2,125,154,154,154,154,154,154,154, 2, 2,154, - 2, 2,154,154,154,154,154,154,154,154, 2,154,154, 2,154,154, - 154,154,154,154,154,154,154,154,154,154,154,154, 2,154,154, 2, - 2,154,154,154,154,154,154,154, 2, 2, 2, 2, 2, 2,150,150, - 150,150,150,150,150,150, 2, 2,150,150,150,150,150,150,150,150, - 150,150,150, 2, 2, 2,141,141,141,141,141,141,141,141,140,140, - 140,140,140,140,140,140,140,140,140, 2, 2, 2, 2, 2,121,121, - 121,121,121,121,121,121,121, 2, 2, 2, 2, 2, 2, 2, 7, 7, - 2, 2, 2, 2, 2, 2,169,169,169,169,169,169,169,169,169,169, - 2, 2, 2, 2, 2, 2,133,133,133,133,133,133,133,133,133, 2, - 133,133,133,133,133,133,133,133,133,133,133,133,133, 2,133,133, - 133,133,133,133, 2, 2,133,133,133,133,133, 2, 2, 2,134,134, - 134,134,134,134,134,134, 2, 2,134,134,134,134,134,134, 2,134, - 134,134,134,134,134,134,134,134,134,134,134,134,134, 2,138,138, - 138,138,138,138,138, 2,138,138, 2,138,138,138,138,138,138,138, - 138,138,138,138,138,138, 2, 2,138, 2,138,138, 2,138,138,138, - 2, 2, 2, 2, 2, 2,143,143,143,143,143,143, 2,143,143, 2, - 143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, - 143,143,143,143,143, 2,143,143, 2,143,143,143,143,143,143, 2, - 2, 2, 2, 2, 2, 2,143,143, 2, 2, 2, 2, 2, 2,145,145, - 145,145,145,145,145,145,145, 2, 2, 2, 2, 2, 2, 2,163,163, - 163,163,163,163,163,163,163, 2,163,163,163,163,163,163,163,163, - 163, 2, 2, 2,163,163,163,163,163, 2, 2, 2, 2, 2, 86, 2, - 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 22, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, - 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63, 63, 2, 63, 63, - 63, 63, 63, 2, 2, 2, 63, 63, 63, 63, 2, 2, 2, 2,157,157, - 157,157,157,157,157,157,157,157,157, 2, 2, 2, 2, 2, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 2, 2, 80, 80, - 80, 2, 2, 2, 2, 2,127,127,127,127,127,127,127,127,127,127, - 127,127,127,127,127, 2,166,166,166,166,166,166,166,166,166,166, - 2, 2, 2, 2, 2, 2, 79, 2, 2, 2, 2, 2, 2, 2,115,115, - 115,115,115,115,115,115,115,115,115,115,115,115,115, 2,115,115, - 2, 2, 2, 2,115,115,159,159,159,159,159,159,159,159,159,159, - 159,159,159,159,159, 2,159,159, 2, 2, 2, 2, 2, 2,103,103, - 103,103,103,103,103,103,103,103,103,103,103,103, 2, 2,119,119, - 119,119,119,119,119,119,119,119,119,119,119,119, 2, 2,119,119, - 2,119,119,119,119,119, 2, 2, 2, 2, 2,119,119,119,167,167, - 167,167,167,167,167,167,167,167, 2, 2, 2, 2, 2, 2,146,146, - 146,146,146,146,146,146,146,146,146, 2, 2, 2, 2, 2, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2, 2, 99, 2, 2, - 2, 2, 2, 2, 2, 99,136,139, 13, 13,155, 2, 2, 2,136,136, - 136,136,136,136,136,136,155,155,155,155,155,155,155,155,155,155, - 155,155,155,155, 2, 2, 2, 2, 2, 2, 2, 2, 2,155,136, 2, - 2, 2, 2, 2, 2, 2, 17, 17, 17, 17, 2, 17, 17, 17, 17, 17, - 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 15, 15, 15, 15, 17, 17, - 17, 2, 2, 2, 2, 2, 2, 2, 15, 2, 2, 2, 2, 2, 15, 15, - 15, 2, 2, 17, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17,139,139, - 139,139,139,139,139,139,139,139,139,139, 2, 2, 2, 2,105,105, - 105,105,105,105,105,105,105,105,105, 2, 2, 2, 2, 2,105,105, - 105,105,105, 2, 2, 2,105, 2, 2, 2, 2, 2, 2, 2,105,105, - 2, 2,105,105,105,105, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 2, 2, - 0, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, - 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, - 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, - 0, 0, 0, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0,131,131,131,131,131,131,131,131,131,131, - 131,131, 2, 2, 2, 2, 2, 2, 2,131,131,131,131,131, 2,131, - 131,131,131,131,131,131, 2, 2, 2, 2, 2, 19, 19, 19, 56, 56, - 56, 56, 56, 56, 56, 2, 56, 2, 2, 56, 56, 56, 56, 56, 56, 56, - 2, 56, 56, 2, 56, 56, 56, 56, 56, 2, 2, 2, 2, 2, 6, 6, - 6, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6,151,151, - 151,151,151,151,151,151,151,151,151,151,151, 2, 2, 2,151,151, - 151,151,151,151, 2, 2,151,151, 2, 2, 2, 2,151,151,160,160, - 160,160,160,160,160,160,160,160,160,160,160,160,160, 2,152,152, - 152,152,152,152,152,152,152,152, 2, 2, 2, 2, 2,152,164,164, - 164,164,164,164,164,164,164,164, 2, 2, 2, 2, 2, 2,168,168, - 168,168,168,168,168,168,168,168,168, 2, 2, 2, 2,168, 30, 30, - 30, 30, 2, 30, 30, 2,113,113,113,113,113,113,113,113,113,113, - 113,113,113, 2, 2,113,113,113,113,113,113,113,113, 2,132,132, - 132,132,132,132,132,132,132,132,132,132, 2, 2, 2, 2,132,132, - 2, 2, 2, 2,132,132, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3, - 3, 2, 3, 2, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, - 3, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 2, 3, - 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 3, - 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 3, - 3, 3, 2, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 0, 0, 15, 0, 0, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, - 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 0, 13, 2, - 2, 2, 2, 2, 2, 2, 13, 13, 13, 2, 2, 2, 2, 2, 2, 0, - 2, 2, 2, 2, 2, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 9, 9, 9, 10, 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, + 17, 0, 2, 26, 26, 26, 26, 26, 26, 26, 2, 12, 12, 12, 12, 12, + 12, 2, 12, 12, 12, 0, 39, 39, 39, 39, 39, 2, 2, 2, 39, 39, + 39, 2, 86, 86, 86, 86, 77, 77, 77, 77, 79, 79, 79, 79, 2, 19, + 19, 19, 60, 60, 60, 60, 60, 2, 2, 2, 65, 65, 65, 65, 75, 75, + 75, 75, 75, 75, 2, 2, 2, 2, 75, 75, 69, 69, 69, 69, 69, 69, + 0, 69, 74, 74, 74, 74, 2, 2, 2, 74, 12, 2, 2, 2, 84, 84, + 84, 84, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2, 84, 84, 33, 33, + 33, 2, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68, 2, 2, 92, 92, + 92, 92, 92, 92, 92, 2, 2, 2, 2, 92, 87, 87, 87, 87, 87, 87, + 87, 2, 19, 9, 19, 19, 19, 19, 0, 0, 87, 87, 2, 2, 2, 2, + 2, 12, 19, 19, 19, 2, 2, 2, 2, 4, 14, 2, 14, 2, 14, 14, + 2, 14, 14, 2, 14, 14, 3, 3, 0, 0, 1, 1, 6, 6, 3, 2, + 3, 3, 3, 2, 2, 0, 2, 0, 0, 0, 0, 0, 17, 17, 17, 17, + 0, 0, 2, 2, 12, 12, 49, 49, 49, 49, 2, 49, 49, 49, 49, 49, + 49, 2, 49, 49, 2, 49, 49, 49, 2, 2, 0, 2, 2, 2, 9, 2, + 2, 2, 0, 1, 2, 2, 71, 71, 71, 71, 71, 2, 2, 2, 67, 67, + 67, 67, 67, 2, 2, 2, 42, 42, 42, 42, 2, 42, 42, 42, 41, 41, + 41, 41, 41, 41, 41, 2,118,118,118,118,118,118,118, 2, 53, 53, + 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59, 2, 2, 40, 40, + 40, 40, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 2, 2,135,135, + 135,135,106,106,106,106,104,104,104,104, 2, 2, 2,104,161,161, + 161,161,161,161,161, 2,161,161, 2,161,161, 2, 2, 2,170,170, + 170,170,110,110,110,110,110,110,110, 2,110,110, 2, 2, 19, 19, + 2, 19, 19, 2, 19, 19, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2, + 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, 2, 2, 47, 81, 81, + 81, 81, 81, 81, 2, 81,120,120,120,120,116,116,116,116,116,116, + 116, 2, 2, 2, 2,116,128,128,128,128,128,128,128, 2,128,128, + 2, 2, 2, 2, 2,128, 66, 66, 66, 66, 2, 2, 2, 66, 72, 72, + 72, 72, 72, 72, 2, 2, 2, 2, 2, 72,173,173,173,173,173,173, + 2, 2, 98, 98, 98, 98, 97, 97, 97, 97, 2, 2, 97, 97, 57, 57, + 57, 57, 2, 57, 57, 2, 2, 57, 57, 57, 57, 57, 2, 2, 57, 57, + 57, 2, 2, 2, 2, 57, 57, 2, 2, 2, 88, 88, 88, 88,117,117, + 117,117,112,112,112,112,112,112,112, 2, 2, 2, 2,112, 78, 78, + 78, 78, 78, 78, 2, 2, 2, 78, 78, 78, 83, 83, 83, 83, 83, 83, + 2, 2, 82, 82, 82, 82, 82, 82, 82, 2,122,122,122,122,122,122, + 2, 2, 2,122,122,122,122, 2, 2, 2, 89, 89, 89, 89, 89, 2, + 2, 2,130,130,130,130,130,130,130, 2, 2, 2,130,130,144,144, + 144,144,144,144, 2, 2,165,165,165,165,165,165, 2, 2, 2,165, + 165,165, 2, 2,165,165, 3, 3, 3, 2,156,156,156,156,156,156, + 2,156,156,156, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2,147,147, + 147,147,148,148,148,148,148,148, 2, 2,158,158,158,158,158,158, + 2, 2,153,153,153,153,149,149,149,149,149,149,149, 2, 94, 94, + 94, 94, 94, 94, 2, 2, 2, 2, 94, 94, 2, 2, 2, 94, 85, 85, + 85, 85, 85, 85, 85, 2, 2, 85, 2, 2,101,101,101,101,101, 2, + 2, 2,101,101, 2, 2, 96, 96, 96, 96, 96, 2, 96, 96,111,111, + 111,111,111,111,111, 2,100,100,100,100,108,108,108,108,108,108, + 2,108,108,108, 2, 2,129,129,129,129,129,129,129, 2,129, 2, + 129,129,129,129, 2,129,129,129, 2, 2,109,109,109,109,109,109, + 109, 2,109,109, 2, 2,107,107,107,107, 2,107,107,107,107, 2, + 2,107,107, 2,107,107,107,107, 2, 1,107,107, 2, 2,107, 2, + 2, 2, 2, 2, 2,107, 2, 2,107,107,171,171,171,171,171,171, + 2,171, 2, 2,171, 2,171, 2,171, 2, 2,171, 2,171,171,171, + 171, 2,171, 2, 2, 2, 2,171,171, 2,137,137,137,137, 2,137, + 137,137,137,137, 2, 2,124,124,124,124,124,124, 2, 2,123,123, + 123,123,123,123, 2, 2,114,114,114,114,114, 2, 2, 2,114,114, + 2, 2,102,102,102,102,102,102, 2, 2,126,126,126,126,126,126, + 126, 2, 2,126,126,126,142,142,142,142,125,125,125,125,125,125, + 125, 2, 2, 2, 2,125,154,154,154,154,154,154,154, 2, 2,154, + 2, 2, 2,154,154, 2,154,154, 2,154,154, 2, 2,154,154,154, + 2, 2,150,150,150,150, 2, 2,150,150,150, 2, 2, 2,141,141, + 141,141,140,140,140,140,140,140,140, 2,121,121,121,121,121, 2, + 2, 2, 7, 7, 2, 2,169,169,169,169,169,169, 2, 2,133,133, + 133,133,133, 2,133,133,133,133,133, 2,133,133, 2, 2,133, 2, + 2, 2,134,134,134,134, 2, 2,134,134, 2,134,134,134,134,134, + 134, 2,138,138,138,138,138,138,138, 2,138,138, 2,138, 2, 2, + 138, 2,138,138, 2, 2,143,143,143,143,143,143, 2,143,143, 2, + 143,143,143,143,143, 2,143, 2, 2, 2,143,143, 2, 2,175,175, + 175,175,175,175, 2, 2,145,145,145,145,145, 2, 2, 2,163,163, + 163,163,163, 2,163,163,163,163,163, 2, 2, 2,163,163, 86, 2, + 2, 2, 63, 63, 63, 63, 63, 63, 2, 2, 63, 63, 63, 2, 63, 2, + 2, 2,157,157,157,157,157,157,157, 2, 80, 80, 80, 80, 80, 80, + 2, 2, 80, 80, 80, 2,127,127,127,127,127,127,127, 2,166,166, + 166,166,166,166, 2, 2, 79, 2, 2, 2,115,115,115,115,115,115, + 115, 2,115,115, 2, 2, 2, 2,115,115,159,159,159,159,159,159, + 159, 2,159,159, 2, 2,103,103,103,103,103,103, 2, 2,119,119, + 119,119,119,119, 2, 2,119,119, 2,119, 2,119,119,119,167,167, + 167,167,167,167, 2, 2,146,146,146,146,146,146,146, 2,172,172, + 172,172,172, 2, 2,172, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2, + 2, 99,136,139, 13, 13,155, 2, 2, 2, 13, 13, 13, 2,136,136, + 136,136,155,155,155,155,155,155, 2, 2, 2, 2, 2,155,136,136, + 136, 2, 2, 17, 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 17, 17, + 17, 2, 2, 2, 15, 2, 2, 17, 2, 2,139,139,139,139,105,105, + 105,105,105,105,105, 2,105, 2, 2, 2,105,105, 2, 2, 1, 1, + 1, 2, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 2, 2, + 0, 2, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 2,131,131, + 131,131, 2, 2, 2,131, 2,131,131,131, 56, 56, 56, 2, 56, 2, + 2, 56, 56, 56, 2, 56, 56, 2, 56, 56, 6, 6, 2, 2, 2, 2, + 2, 6,151,151,151,151,151, 2, 2, 2,151,151, 2, 2, 2, 2, + 151,151,160,160,160,160,160,160,160, 2,152,152,152,152,152,152, + 2, 2, 2, 2, 2,152,164,164,164,164,164,164, 2, 2,168,168, + 168,168,168,168,168, 2, 2, 2, 2,168,174,174,174,174,174,174, + 174, 2,174,174, 2, 2, 2, 2,174,174, 2, 30, 30, 2,113,113, + 113,113,113, 2, 2,113,113,113,113, 2,132,132,132,132,132,132, + 2, 2, 2, 2,132,132, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2, + 2, 3, 2, 3, 2, 3, 2, 2, 3, 2, 3, 2, 3, 2, 3, 3, + 2, 3, 15, 0, 0, 2, 0, 2, 2, 0, 13, 2, 2, 2, 2, 0, + 2, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, + 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 16, 17, 9, 9, 9, 9, 18, 9, 9, 9, 9, 9, 19, 20, - 21, 9, 22, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 23, 9, 9, 9, 9, 9, 24, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 16, 17, + 9, 9, 9, 9, 18, 9, 9, 9, 9, 9, 19, 20, 21, 9, 22, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 25, 9, + 9, 9, 23, 9, 9, 9, 9, 9, 24, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 25, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, @@ -3933,67 +3605,65 @@ _hb_ucd_u8[17524] = 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, - 29, 30, 0, 0, 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, - 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 26, 27, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, 0, + 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, - 46, 47, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, - 53, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, - 55, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, - 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, - 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, + 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, 0, + 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, + 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, + 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99,100,101,102,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0, - 107, 0, 0, 0,108, 0,109, 0,110, 0,111,112,113, 0,114, 0, - 0, 0,115, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102, + 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, 0, + 108, 0,109, 0,110, 0,111,112,113, 0,114, 0, 0, 0,115, 0, + 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,118,119,120,121, 0,122,123,124, - 125,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,128,129,130,131,132,133,134,135,136,137,138,139, - 140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155, - 156,157, 0, 0, 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,118,119,120,121, 0,122,123,124,125,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 162, 0,163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,164,165, 0, - 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157, 0, 0, + 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0,168,169, 0, 0, - 170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,171, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,172, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,162, 0,163, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,164,165, 0, 0, 0, 0, 0, + 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,173, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,167, 0, 0, 0,168,169, 0, 0,170, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,171, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,174, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,175, 0, 0, 0, 0, 0, + 0, 0,174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,176,177, 0, 0, 0, 0,178, - 179, 0, 0, 0,180,181,182,183,184,185,186,187,188,189,190,191, - 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, - 208,209,210,211,212,213, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 2, 3, 4, + 0, 0, 0, 0, 0,176,177, 0, 0, 0, 0,178,179, 0, 0, 0, + 180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195, + 196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211, + 212,213, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, }; -static const uint16_t -_hb_ucd_u16[9668] = +static const uint16_t _hb_ucd_u16[10904]= { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12, 13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23, @@ -4020,23 +3690,23 @@ _hb_ucd_u16[9668] = 48, 184, 48, 185, 48, 186, 187, 188, 48, 48, 48, 189, 190, 191, 192, 193, 194, 192, 48, 48, 195, 48, 48, 196, 197, 48, 198, 48, 48, 48, 48, 199, 48, 200, 201, 202, 203, 48, 204, 205, 48, 48, 206, 48, 207, 208, 209, 209, - 48, 210, 48, 48, 48, 211, 212, 213, 192, 192, 214, 215, 216, 140, 140, 140, - 217, 48, 48, 218, 219, 160, 220, 221, 222, 48, 223, 64, 48, 48, 224, 225, - 48, 48, 226, 227, 228, 64, 48, 229, 230, 9, 9, 231, 232, 233, 234, 235, - 11, 11, 236, 27, 27, 27, 237, 238, 11, 239, 27, 27, 32, 32, 32, 32, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 240, 13, 13, 13, 13, 13, 13, - 241, 242, 241, 241, 242, 243, 241, 244, 245, 245, 245, 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, 271, 272, 272, 273, 274, 275, 209, 276, 277, 209, 278, - 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, - 280, 209, 281, 209, 209, 209, 209, 282, 209, 283, 279, 284, 209, 285, 286, 209, - 209, 209, 176, 140, 287, 140, 271, 271, 271, 288, 209, 209, 209, 209, 289, 271, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 290, 291, 209, 209, 292, - 209, 209, 209, 209, 209, 209, 293, 209, 209, 209, 209, 209, 209, 209, 209, 209, - 209, 209, 209, 209, 209, 209, 294, 295, 271, 296, 209, 209, 297, 279, 298, 279, + 48, 210, 48, 48, 48, 211, 212, 213, 192, 192, 214, 215, 32, 216, 217, 140, + 218, 48, 48, 219, 220, 160, 221, 222, 223, 48, 224, 64, 48, 48, 225, 226, + 48, 48, 227, 228, 229, 64, 48, 230, 231, 9, 9, 232, 233, 234, 235, 236, + 11, 11, 237, 27, 27, 27, 238, 239, 11, 240, 27, 27, 32, 32, 32, 32, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 241, 13, 13, 13, 13, 13, 13, + 242, 243, 242, 242, 243, 244, 242, 245, 246, 246, 246, 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 273, 274, 275, 276, 209, 277, 278, 209, 279, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 281, 209, 282, 209, 209, 209, 209, 283, 209, 284, 280, 285, 209, 286, 287, 209, + 209, 209, 176, 140, 288, 140, 272, 272, 272, 289, 209, 209, 209, 209, 290, 272, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 291, 292, 209, 209, 293, + 209, 209, 209, 209, 209, 209, 294, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 295, 296, 272, 297, 209, 209, 298, 280, 299, 280, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, - 279, 279, 279, 279, 279, 279, 279, 279, 299, 300, 279, 279, 279, 301, 279, 302, - 209, 209, 209, 279, 303, 209, 209, 304, 209, 305, 209, 209, 209, 209, 209, 209, + 280, 280, 280, 280, 280, 280, 280, 280, 300, 301, 280, 280, 280, 302, 280, 303, + 209, 209, 209, 280, 304, 209, 209, 305, 209, 209, 209, 209, 209, 209, 209, 209, 9, 9, 9, 11, 11, 11, 306, 307, 13, 13, 13, 13, 13, 13, 308, 309, 11, 11, 310, 48, 48, 48, 311, 312, 48, 313, 314, 314, 314, 314, 32, 32, 315, 316, 317, 318, 319, 320, 140, 140, 209, 321, 209, 209, 209, 209, 209, 322, @@ -4046,7 +3716,7 @@ _hb_ucd_u16[9668] = 209, 333, 334, 209, 335, 336, 209, 209, 334, 209, 209, 336, 209, 209, 209, 209, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 209, 209, 209, 209, 48, 337, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 151, 209, 209, 209, 338, 48, 48, 229, + 48, 48, 48, 48, 48, 48, 48, 48, 151, 209, 209, 209, 338, 48, 48, 230, 339, 48, 340, 140, 13, 13, 341, 342, 13, 343, 48, 48, 48, 48, 344, 345, 31, 346, 347, 348, 13, 13, 13, 349, 350, 351, 352, 353, 354, 355, 140, 356, 357, 48, 358, 359, 48, 48, 48, 360, 361, 48, 48, 362, 363, 192, 32, 364, @@ -4062,1560 +3732,407 @@ _hb_ucd_u16[9668] = 32, 404, 32, 405, 406, 407, 408, 409, 48, 48, 48, 48, 48, 48, 48, 410, 411, 2, 3, 4, 5, 412, 413, 414, 48, 415, 48, 200, 416, 417, 418, 419, 420, 48, 172, 421, 204, 204, 140, 140, 48, 48, 48, 48, 48, 48, 48, 71, - 422, 271, 271, 423, 272, 272, 272, 424, 425, 426, 427, 140, 140, 209, 209, 428, + 422, 272, 272, 423, 273, 273, 273, 424, 425, 426, 427, 140, 140, 209, 209, 428, 140, 140, 140, 140, 140, 140, 140, 140, 48, 151, 48, 48, 48, 100, 429, 430, 48, 48, 431, 48, 432, 48, 48, 433, 48, 434, 48, 48, 435, 436, 140, 140, 9, 9, 437, 11, 11, 48, 48, 48, 48, 204, 192, 9, 9, 438, 11, 439, 48, 48, 440, 48, 48, 48, 441, 442, 442, 443, 444, 445, 48, 48, 48, 388, 48, 48, 48, 313, 48, 199, 440, 140, 446, 27, 27, 447, 140, 140, 140, 140, 448, 48, 48, 449, 48, 450, 48, 451, 48, 200, 452, 140, 140, 140, 48, 453, - 48, 454, 48, 455, 140, 140, 140, 140, 48, 48, 48, 456, 271, 457, 271, 271, + 48, 454, 48, 455, 48, 207, 140, 140, 48, 48, 48, 456, 272, 457, 272, 272, 458, 459, 48, 460, 461, 462, 48, 463, 48, 464, 140, 140, 465, 48, 466, 467, 48, 48, 48, 468, 48, 469, 48, 470, 48, 471, 472, 140, 140, 140, 140, 140, 48, 48, 48, 48, 196, 140, 140, 140, 9, 9, 9, 473, 11, 11, 11, 474, 48, 48, 475, 192, 476, 9, 477, 11, 478, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 271, 479, 48, 48, 480, 481, 482, 140, 140, 483, - 48, 464, 484, 48, 62, 485, 140, 48, 486, 140, 140, 48, 487, 140, 48, 313, - 488, 48, 48, 489, 490, 457, 491, 492, 222, 48, 48, 493, 494, 48, 196, 192, - 495, 48, 496, 497, 498, 48, 48, 499, 222, 48, 48, 500, 501, 502, 503, 504, - 48, 97, 505, 506, 507, 140, 140, 140, 508, 509, 510, 48, 48, 511, 512, 192, - 513, 83, 84, 514, 515, 516, 517, 518, 519, 48, 48, 520, 521, 522, 523, 140, - 48, 48, 48, 524, 525, 526, 481, 140, 48, 48, 48, 527, 528, 192, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 529, 530, 531, 532, 140, 140, - 48, 48, 48, 533, 534, 192, 535, 140, 48, 48, 536, 537, 192, 538, 539, 140, - 48, 540, 541, 542, 313, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 48, 505, 543, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 544, - 545, 546, 48, 547, 548, 192, 140, 140, 140, 140, 549, 48, 48, 550, 551, 140, - 552, 48, 48, 553, 554, 555, 48, 48, 556, 557, 558, 48, 48, 48, 48, 196, - 559, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 560, 192, - 84, 48, 529, 561, 562, 148, 175, 563, 48, 564, 565, 566, 140, 140, 140, 140, - 567, 48, 48, 568, 569, 192, 570, 48, 571, 572, 192, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 573, - 574, 115, 48, 575, 576, 577, 140, 140, 140, 140, 140, 100, 271, 578, 579, 580, + 140, 140, 140, 140, 140, 140, 272, 479, 48, 48, 480, 481, 482, 483, 140, 484, + 48, 464, 485, 48, 62, 486, 140, 48, 487, 140, 140, 48, 488, 140, 48, 313, + 489, 48, 48, 490, 491, 457, 492, 493, 223, 48, 48, 494, 495, 48, 196, 192, + 496, 48, 497, 498, 499, 48, 48, 500, 223, 48, 48, 501, 502, 503, 504, 505, + 48, 97, 506, 507, 508, 140, 140, 140, 509, 510, 511, 48, 48, 512, 513, 192, + 514, 83, 84, 515, 516, 517, 518, 519, 520, 48, 48, 521, 522, 523, 524, 140, + 48, 48, 48, 525, 526, 527, 481, 140, 48, 48, 48, 528, 529, 192, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 530, 531, 532, 533, 140, 140, + 48, 48, 48, 534, 535, 192, 536, 140, 48, 48, 537, 538, 192, 539, 540, 140, + 48, 541, 542, 543, 313, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 48, 48, 506, 544, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 545, + 546, 547, 48, 548, 549, 192, 140, 140, 140, 140, 550, 48, 48, 551, 552, 140, + 553, 48, 48, 554, 555, 556, 48, 48, 557, 558, 559, 48, 48, 48, 48, 196, + 560, 140, 140, 140, 140, 140, 561, 140, 140, 140, 140, 140, 48, 48, 562, 192, + 84, 48, 530, 563, 564, 148, 175, 565, 48, 566, 567, 568, 140, 140, 140, 140, + 569, 48, 48, 570, 571, 192, 572, 48, 573, 574, 192, 48, 48, 575, 192, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 576, + 577, 115, 48, 578, 579, 580, 140, 140, 140, 140, 140, 100, 272, 581, 582, 583, 48, 48, 48, 48, 48, 48, 48, 48, 48, 207, 140, 140, 140, 140, 140, 140, - 272, 272, 272, 272, 272, 272, 581, 582, 48, 48, 48, 48, 48, 48, 48, 48, + 273, 273, 273, 273, 273, 273, 584, 585, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 388, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 583, - 48, 48, 48, 584, 585, 586, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 586, + 48, 48, 48, 587, 588, 589, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 71, 48, 48, 48, 48, 313, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 587, 588, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 589, - 48, 48, 48, 590, 591, 592, 593, 594, 48, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 595, 48, 596, 192, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 9, 9, 11, 11, 271, 597, 140, 140, 140, 140, 140, 140, - 48, 48, 48, 48, 598, 599, 600, 600, 601, 602, 140, 140, 140, 140, 603, 604, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 440, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 199, 140, 605, - 196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 606, - 48, 48, 607, 608, 140, 609, 610, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 590, 591, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 592, + 48, 48, 48, 593, 594, 595, 596, 597, 48, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 598, 48, 599, 192, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 9, 9, 11, 11, 272, 600, 9, 601, 11, 602, 140, 140, + 48, 48, 48, 48, 603, 604, 605, 605, 606, 607, 140, 140, 140, 140, 608, 609, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 199, 140, 610, + 48, 200, 140, 140, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 48, 611, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 612, + 48, 48, 611, 613, 140, 614, 615, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 206, - 48, 48, 48, 48, 48, 48, 71, 151, 196, 611, 612, 140, 140, 140, 140, 140, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 192, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 322, 140, 140, 140, 140, - 32, 32, 613, 32, 614, 209, 209, 209, 209, 209, 209, 209, 322, 140, 140, 140, + 48, 48, 48, 48, 48, 48, 71, 151, 196, 616, 617, 140, 140, 140, 140, 140, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 618, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 619, 209, 427, 209, 620, + 32, 32, 216, 32, 621, 209, 209, 209, 209, 209, 209, 209, 322, 140, 140, 140, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 323, - 209, 209, 615, 209, 209, 209, 616, 617, 618, 209, 619, 209, 209, 209, 287, 140, - 209, 209, 209, 209, 620, 140, 140, 140, 140, 140, 140, 140, 271, 621, 271, 621, - 209, 209, 209, 209, 209, 338, 271, 461, 140, 140, 140, 140, 140, 140, 140, 140, - 9, 622, 11, 623, 624, 625, 241, 9, 626, 627, 628, 629, 630, 9, 622, 11, - 631, 632, 11, 633, 634, 635, 636, 9, 637, 11, 9, 622, 11, 623, 624, 11, - 241, 9, 626, 636, 9, 637, 11, 9, 622, 11, 638, 9, 639, 640, 641, 642, - 11, 643, 9, 644, 645, 646, 647, 11, 648, 9, 649, 11, 650, 538, 538, 538, - 32, 32, 32, 651, 32, 32, 652, 653, 654, 655, 45, 140, 140, 140, 140, 140, - 656, 657, 658, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 659, 660, 661, 27, 27, 27, 662, 140, 663, 140, 140, 140, 140, 140, 140, 140, - 48, 48, 151, 664, 665, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 666, 140, 48, 48, 667, 668, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 669, 192, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 587, 670, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 671, 200, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 672, 614, 140, 140, - 9, 9, 626, 11, 673, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 503, 271, 271, 674, 675, 140, 140, 140, 140, - 503, 271, 676, 677, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 678, 48, 679, 680, 681, 682, 683, 684, 685, 206, 686, 206, 140, 140, 140, 687, - 209, 209, 688, 209, 209, 209, 209, 209, 209, 322, 333, 689, 689, 689, 209, 323, - 690, 209, 209, 209, 209, 209, 209, 209, 209, 209, 691, 140, 140, 140, 692, 209, - 693, 209, 209, 688, 694, 695, 323, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 696, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 697, 426, 426, - 209, 209, 209, 209, 209, 209, 209, 698, 209, 209, 209, 209, 209, 176, 688, 427, - 688, 209, 209, 209, 699, 176, 209, 209, 699, 209, 691, 688, 695, 140, 140, 140, - 209, 209, 209, 209, 209, 322, 691, 426, 700, 209, 209, 209, 701, 702, 176, 694, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 703, 209, 209, 209, 209, 209, 192, + 209, 209, 622, 209, 209, 209, 623, 624, 625, 209, 626, 209, 209, 209, 288, 140, + 209, 209, 209, 209, 627, 140, 140, 140, 140, 140, 140, 140, 272, 628, 272, 628, + 209, 209, 209, 209, 209, 338, 272, 461, 140, 140, 140, 140, 140, 140, 140, 140, + 9, 629, 11, 630, 631, 632, 242, 9, 633, 634, 635, 636, 637, 9, 629, 11, + 638, 639, 11, 640, 641, 642, 643, 9, 644, 11, 9, 629, 11, 630, 631, 11, + 242, 9, 633, 643, 9, 644, 11, 9, 629, 11, 645, 9, 646, 647, 648, 649, + 11, 650, 9, 651, 652, 653, 654, 11, 655, 9, 656, 11, 657, 539, 539, 539, + 32, 32, 32, 658, 32, 32, 659, 660, 661, 662, 45, 140, 140, 140, 140, 140, + 663, 664, 665, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 666, 667, 668, 27, 27, 27, 669, 140, 670, 140, 140, 140, 140, 140, 140, 140, + 48, 48, 151, 671, 672, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 673, 140, 48, 48, 674, 675, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 676, 192, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 590, 677, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 200, 678, 679, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 680, 200, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 681, 621, 140, 140, + 9, 9, 633, 11, 682, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 504, 272, 272, 683, 684, 140, 140, 140, 140, + 504, 272, 685, 686, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 687, 48, 688, 689, 690, 691, 692, 693, 694, 206, 695, 206, 140, 140, 140, 696, + 209, 209, 697, 209, 209, 209, 209, 209, 209, 322, 333, 698, 698, 698, 209, 323, + 699, 209, 209, 209, 209, 209, 209, 209, 209, 209, 700, 140, 140, 140, 701, 209, + 702, 209, 209, 697, 703, 704, 323, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 705, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 706, 426, 426, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 176, 697, 427, + 697, 209, 209, 209, 707, 176, 209, 209, 707, 209, 700, 697, 704, 708, 140, 140, + 209, 209, 209, 209, 209, 707, 700, 426, 709, 209, 209, 209, 710, 711, 712, 703, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 713, 209, 209, 209, 209, 209, 714, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 140, 140, - 48, 48, 48, 207, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 481, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 100, 48, 48, 48, 48, 48, 48, 204, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 204, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 48, 48, 71, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 140, 140, 140, 140, 140, - 704, 140, 584, 584, 584, 584, 584, 584, 140, 140, 140, 140, 140, 140, 140, 140, + 48, 48, 48, 48, 48, 48, 48, 207, 140, 140, 140, 140, 140, 140, 140, 140, + 715, 140, 587, 587, 587, 587, 587, 587, 140, 140, 140, 140, 140, 140, 140, 140, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 140, - 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 705, - 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 706, - 0, 0, 1, 1, 0, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 5, 0, 6, 7, 7, 7, 8, 9, 10, 11, 12, - 13, 13, 13, 13, 14, 13, 13, 13, 13, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 23, 23, 26, 23, 27, 28, 29, 23, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 23, 23, 39, 40, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 82, 86, 86, 87, 88, 89, 90, 91, 82, - 92, 92, 92, 92, 92, 93, 94, 95, 96, 96, 96, 96, 96, 96, 96, 96, - 97, 97, 98, 97, 99, 100, 101, 97, 102, 97, 103, 104, 105, 106, 106, 107, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 109, 110, 110, 111, - 112, 113, 114, 115, 116, 116, 117, 118, 119, 120, 120, 121, 120, 122, 108, 123, - 124, 125, 126, 127, 128, 129, 130, 116, 131, 132, 133, 134, 135, 136, 137, 82, - 138, 138, 139, 138, 140, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, - 4, 151, 152, 153, 4, 154, 7, 7, 155, 11, 156, 157, 11, 158, 159, 160, - 161, 0, 0, 162, 163, 0, 164, 165, 0, 166, 167, 4, 168, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 169, 170, 0, 0, 0, 0, 0, - 171, 171, 171, 171, 171, 171, 171, 171, 0, 0, 0, 172, 173, 0, 0, 0, - 174, 174, 174, 4, 175, 175, 175, 176, 93, 177, 178, 179, 180, 181, 181, 13, - 0, 0, 182, 82, 183, 184, 184, 185, 184, 184, 184, 184, 184, 184, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 96, 96, 198, 199, 0, 200, - 201, 0, 0, 202, 0, 0, 203, 204, 194, 194, 205, 0, 0, 0, 0, 0, - 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 0, 0, - 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 207, 206, 208, 209, - 210, 210, 210, 210, 210, 210, 210, 210, 210, 211, 13, 13, 13, 212, 212, 213, - 0, 214, 4, 4, 215, 4, 216, 217, 218, 219, 220, 221, 222, 222, 223, 40, - 224, 225, 226, 227, 228, 228, 229, 230, 231, 232, 233, 92, 234, 234, 235, 236, - 237, 238, 239, 240, 106, 106, 241, 242, 96, 96, 96, 96, 96, 243, 244, 245, - 82, 82, 82, 82, 82, 82, 82, 82, 184, 184, 184, 246, 184, 184, 247, 82, - 248, 249, 250, 23, 23, 23, 251, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 252, 23, 23, 253, 23, 254, 255, 256, 257, 258, 259, 23, 23, 23, 260, - 261, 1, 1, 262, 263, 201, 264, 265, 266, 267, 268, 82, 269, 269, 269, 270, - 271, 272, 11, 11, 273, 274, 187, 275, 82, 82, 82, 82, 276, 277, 278, 279, - 280, 281, 282, 283, 284, 285, 286, 82, 287, 287, 288, 289, 290, 291, 292, 293, - 294, 295, 296, 297, 298, 299, 300, 301, 302, 302, 302, 302, 302, 302, 302, 302, - 302, 303, 304, 305, 306, 307, 82, 82, 308, 309, 310, 311, 312, 313, 82, 314, - 315, 316, 82, 82, 317, 318, 319, 320, 321, 322, 323, 324, 325, 82, 326, 327, - 328, 329, 330, 331, 332, 333, 82, 82, 334, 334, 335, 82, 336, 337, 336, 338, - 339, 340, 341, 342, 343, 82, 82, 82, 82, 82, 82, 344, 345, 346, 347, 348, - 349, 350, 351, 352, 353, 354, 355, 356, 357, 357, 358, 359, 360, 360, 361, 362, - 363, 364, 365, 366, 367, 367, 367, 368, 369, 370, 371, 82, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, 382, 383, 384, 384, 385, 386, 387, 387, 388, 82, - 82, 82, 82, 82, 389, 390, 391, 82, 392, 392, 393, 394, 395, 396, 397, 398, - 399, 400, 401, 82, 82, 82, 82, 82, 402, 403, 82, 82, 82, 404, 404, 405, - 406, 407, 408, 82, 82, 409, 410, 411, 412, 412, 413, 414, 414, 415, 416, 417, - 418, 82, 82, 82, 82, 82, 419, 420, 421, 422, 423, 424, 425, 426, 82, 82, - 427, 428, 429, 430, 431, 432, 82, 82, 82, 82, 82, 82, 82, 82, 82, 433, - 434, 435, 436, 82, 82, 437, 438, 439, 440, 440, 440, 440, 440, 440, 440, 440, - 440, 440, 440, 440, 441, 82, 82, 82, 440, 440, 440, 442, 440, 440, 440, 440, - 440, 440, 443, 82, 82, 82, 82, 82, 82, 82, 82, 82, 444, 445, 445, 446, - 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, 448, 447, 447, 447, 447, 447, - 447, 447, 447, 447, 447, 447, 447, 449, 450, 450, 450, 450, 450, 450, 450, 450, - 450, 450, 451, 82, 82, 82, 82, 82, 452, 453, 82, 82, 82, 82, 82, 82, - 212, 212, 212, 212, 212, 212, 212, 212, 212, 454, 455, 456, 457, 458, 459, 460, - 461, 461, 462, 463, 464, 82, 82, 82, 82, 82, 465, 466, 82, 82, 82, 82, - 82, 82, 467, 467, 468, 82, 82, 82, 469, 469, 470, 469, 471, 82, 82, 472, - 473, 473, 473, 473, 473, 473, 473, 473, 473, 473, 473, 473, 473, 473, 473, 474, - 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 476, 477, - 478, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 479, - 480, 191, 191, 191, 191, 191, 191, 191, 191, 481, 482, 483, 484, 484, 484, 484, - 484, 484, 484, 484, 484, 484, 484, 485, 486, 486, 486, 487, 488, 489, 82, 82, - 0, 0, 0, 0, 0, 0, 0, 490, 0, 0, 0, 0, 0, 491, 82, 82, - 7, 492, 493, 0, 0, 0, 489, 82, 0, 0, 0, 0, 0, 0, 0, 494, - 0, 495, 0, 496, 497, 498, 0, 170, 11, 11, 499, 82, 82, 82, 491, 491, - 0, 0, 500, 501, 82, 82, 82, 82, 0, 0, 502, 0, 503, 504, 505, 0, - 506, 507, 508, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 509, 0, 0, - 0, 0, 0, 0, 0, 0, 510, 0, 511, 511, 511, 511, 511, 511, 511, 511, - 511, 511, 511, 511, 512, 513, 82, 82, 514, 515, 82, 82, 82, 82, 82, 82, - 516, 517, 13, 518, 519, 82, 82, 82, 520, 521, 522, 82, 82, 82, 82, 82, - 82, 82, 82, 82, 523, 524, 525, 526, 82, 82, 82, 82, 82, 82, 527, 528, - 82, 82, 82, 82, 82, 82, 529, 530, 82, 82, 82, 82, 82, 82, 82, 531, - 532, 532, 532, 532, 532, 532, 533, 82, 534, 534, 535, 82, 82, 82, 82, 82, - 82, 82, 82, 536, 0, 537, 82, 82, 261, 182, 82, 82, 82, 82, 82, 82, - 538, 539, 540, 541, 542, 543, 82, 544, 0, 545, 0, 0, 491, 546, 547, 494, - 0, 0, 0, 0, 0, 548, 82, 549, 550, 551, 552, 553, 82, 82, 82, 82, - 0, 0, 0, 0, 0, 0, 554, 555, 0, 0, 0, 556, 0, 0, 490, 557, - 545, 0, 558, 0, 559, 560, 561, 82, 0, 0, 491, 562, 563, 0, 564, 565, - 0, 0, 0, 0, 258, 0, 0, 490, 184, 184, 184, 184, 184, 184, 184, 82, - 184, 247, 184, 184, 184, 184, 184, 184, 566, 184, 184, 184, 184, 184, 184, 184, - 184, 184, 184, 184, 184, 567, 184, 184, 184, 184, 184, 184, 184, 184, 184, 568, - 184, 184, 566, 82, 82, 82, 82, 82, 566, 82, 82, 82, 82, 82, 82, 82, - 184, 184, 569, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 570, 82, 82, - 571, 0, 0, 0, 82, 82, 82, 82, 7, 7, 7, 7, 7, 7, 7, 572, - 0, 0, 0, 0, 1, 2, 2, 3, 0, 4, 0, 4, 2, 2, 5, 2, - 2, 2, 2, 2, 2, 2, 2, 6, 7, 8, 0, 0, 9, 9, 9, 9, - 9, 9, 10, 11, 12, 13, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14, - 16, 17, 14, 14, 18, 18, 18, 18, 19, 18, 18, 18, 18, 18, 20, 21, - 21, 21, 22, 20, 21, 21, 21, 21, 21, 23, 24, 25, 25, 25, 25, 25, - 25, 26, 25, 25, 25, 27, 28, 26, 29, 30, 31, 32, 31, 31, 31, 31, - 33, 34, 35, 31, 31, 31, 36, 31, 31, 31, 31, 29, 37, 38, 37, 37, - 37, 37, 37, 37, 37, 39, 31, 31, 40, 40, 40, 40, 40, 40, 41, 26, - 42, 42, 42, 42, 42, 42, 42, 43, 44, 44, 44, 44, 44, 45, 44, 46, - 47, 47, 47, 48, 37, 49, 31, 31, 31, 50, 51, 31, 52, 31, 31, 31, - 53, 53, 53, 53, 53, 53, 54, 53, 55, 53, 53, 53, 56, 57, 58, 59, - 59, 60, 61, 62, 57, 63, 64, 65, 66, 59, 59, 67, 68, 69, 70, 71, - 71, 72, 73, 74, 69, 75, 76, 77, 78, 71, 79, 26, 80, 81, 82, 83, - 83, 84, 85, 86, 81, 87, 88, 26, 89, 83, 90, 91, 92, 93, 94, 95, - 95, 96, 97, 98, 93, 99, 100, 101, 102, 95, 95, 26, 103, 104, 105, 106, - 107, 104, 108, 109, 104, 105, 110, 26, 111, 108, 108, 112, 113, 114, 115, 113, - 113, 115, 113, 116, 114, 117, 118, 119, 120, 113, 121, 113, 122, 123, 124, 122, - 122, 124, 125, 126, 123, 127, 128, 128, 129, 122, 130, 26, 131, 132, 133, 131, - 131, 131, 131, 131, 132, 133, 134, 131, 135, 131, 131, 131, 136, 137, 138, 139, - 137, 137, 140, 141, 138, 142, 143, 137, 144, 137, 145, 26, 146, 147, 147, 147, - 147, 147, 147, 148, 147, 147, 147, 149, 26, 26, 26, 26, 150, 151, 152, 152, - 153, 152, 152, 154, 155, 156, 152, 157, 158, 158, 158, 158, 158, 159, 158, 158, - 158, 160, 159, 158, 158, 158, 158, 159, 158, 158, 158, 161, 158, 161, 162, 163, - 164, 164, 164, 164, 165, 165, 165, 165, 166, 167, 165, 165, 165, 165, 165, 168, - 169, 169, 169, 169, 170, 170, 170, 170, 170, 171, 172, 171, 170, 171, 170, 170, - 170, 170, 171, 172, 171, 170, 172, 170, 170, 170, 171, 170, 170, 170, 170, 173, - 170, 170, 170, 174, 170, 170, 170, 175, 176, 176, 176, 176, 176, 176, 177, 177, - 178, 178, 178, 178, 179, 179, 179, 180, 181, 181, 181, 181, 181, 182, 181, 183, - 184, 184, 185, 186, 187, 187, 188, 26, 189, 189, 190, 26, 191, 192, 193, 26, - 194, 194, 194, 194, 194, 194, 194, 195, 194, 196, 194, 196, 197, 198, 198, 199, - 198, 198, 198, 198, 198, 198, 198, 200, 198, 201, 178, 178, 178, 178, 202, 26, - 203, 203, 203, 204, 203, 205, 203, 205, 206, 203, 207, 207, 207, 208, 209, 26, - 210, 210, 210, 210, 210, 211, 210, 210, 210, 212, 210, 213, 214, 214, 214, 215, - 216, 216, 216, 216, 216, 216, 216, 217, 216, 216, 216, 218, 216, 219, 216, 219, - 216, 220, 9, 9, 9, 221, 26, 26, 222, 222, 222, 222, 222, 223, 222, 222, - 224, 224, 224, 224, 225, 225, 225, 225, 225, 225, 226, 227, 228, 228, 228, 228, - 228, 228, 228, 229, 228, 230, 231, 231, 231, 231, 231, 231, 18, 232, 165, 165, - 165, 165, 165, 233, 224, 26, 234, 9, 235, 236, 237, 238, 239, 240, 2, 2, - 2, 2, 2, 241, 242, 243, 2, 244, 2, 2, 2, 245, 14, 14, 246, 246, - 246, 246, 14, 247, 14, 14, 14, 246, 14, 14, 248, 14, 248, 14, 249, 250, - 14, 14, 251, 252, 0, 253, 0, 0, 254, 0, 255, 256, 0, 257, 2, 258, - 259, 26, 9, 9, 9, 9, 260, 26, 261, 262, 4, 0, 0, 263, 0, 0, - 2, 264, 0, 0, 0, 265, 26, 26, 0, 266, 26, 26, 267, 267, 267, 267, - 0, 0, 268, 0, 0, 0, 269, 0, 270, 270, 270, 270, 17, 17, 17, 17, - 17, 17, 271, 272, 166, 167, 273, 273, 273, 273, 273, 273, 273, 274, 275, 274, - 170, 170, 172, 26, 172, 172, 172, 172, 0, 0, 0, 276, 277, 277, 277, 278, - 277, 277, 277, 277, 277, 277, 279, 26, 277, 277, 280, 26, 26, 26, 0, 0, - 281, 0, 0, 0, 282, 283, 0, 284, 285, 286, 286, 286, 286, 286, 286, 286, - 286, 286, 287, 288, 289, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 291, - 292, 293, 293, 293, 293, 293, 294, 169, 169, 295, 0, 0, 293, 293, 293, 293, - 276, 296, 290, 290, 169, 169, 169, 295, 169, 169, 169, 297, 0, 0, 290, 290, - 290, 290, 290, 298, 290, 290, 290, 0, 299, 299, 299, 299, 299, 300, 299, 299, - 301, 26, 302, 302, 302, 302, 302, 302, 303, 303, 303, 303, 303, 304, 26, 26, - 305, 305, 305, 305, 305, 305, 305, 26, 306, 2, 2, 2, 2, 307, 2, 2, - 2, 308, 309, 258, 26, 26, 310, 2, 311, 311, 311, 311, 311, 312, 0, 265, - 313, 313, 313, 313, 313, 313, 313, 26, 314, 314, 314, 314, 315, 316, 314, 317, - 318, 318, 318, 318, 318, 319, 320, 320, 320, 320, 321, 322, 169, 169, 169, 323, - 324, 324, 324, 324, 324, 325, 324, 326, 164, 164, 164, 327, 328, 328, 328, 328, - 328, 328, 329, 26, 328, 330, 328, 331, 332, 332, 332, 332, 333, 26, 26, 334, - 335, 335, 336, 26, 337, 337, 337, 26, 172, 172, 2, 2, 2, 2, 2, 338, - 339, 340, 176, 176, 335, 335, 335, 335, 335, 341, 335, 342, 343, 26, 169, 169, - 295, 344, 169, 169, 169, 169, 169, 343, 277, 280, 277, 277, 277, 277, 277, 345, - 346, 26, 347, 348, 25, 25, 349, 350, 351, 25, 31, 31, 352, 26, 353, 31, - 31, 31, 31, 354, 31, 31, 355, 31, 31, 356, 26, 26, 26, 26, 31, 31, - 9, 9, 0, 265, 9, 357, 0, 0, 0, 0, 358, 0, 257, 359, 360, 31, - 31, 31, 31, 361, 362, 0, 0, 0, 363, 290, 289, 290, 290, 290, 290, 364, - 365, 365, 365, 366, 257, 257, 26, 367, 368, 369, 368, 368, 370, 368, 368, 371, - 368, 372, 368, 372, 368, 368, 368, 368, 368, 368, 368, 373, 374, 0, 0, 0, - 0, 0, 375, 0, 14, 252, 0, 376, 377, 26, 26, 26, 0, 0, 0, 378, - 379, 379, 379, 380, 381, 381, 381, 381, 381, 381, 382, 26, 383, 0, 0, 359, - 384, 384, 384, 384, 385, 386, 387, 387, 387, 388, 389, 389, 389, 389, 389, 390, - 391, 391, 391, 392, 393, 393, 393, 393, 394, 393, 395, 26, 396, 396, 396, 396, - 396, 396, 397, 397, 397, 397, 397, 397, 398, 398, 398, 399, 398, 400, 401, 401, - 401, 401, 402, 401, 401, 401, 401, 402, 403, 403, 403, 403, 403, 26, 404, 404, - 404, 404, 404, 404, 405, 406, 407, 408, 407, 408, 409, 407, 410, 407, 410, 411, - 412, 412, 412, 412, 412, 412, 413, 26, 414, 414, 414, 414, 414, 414, 415, 26, - 414, 414, 416, 26, 414, 26, 26, 26, 417, 2, 2, 2, 2, 2, 418, 419, - 420, 421, 422, 422, 422, 422, 423, 424, 425, 425, 426, 425, 427, 427, 427, 427, - 428, 428, 428, 429, 430, 428, 26, 26, 431, 431, 432, 433, 434, 434, 434, 435, - 436, 436, 436, 437, 438, 438, 438, 438, 439, 439, 439, 440, 439, 439, 441, 439, - 439, 439, 439, 439, 442, 443, 444, 445, 446, 446, 447, 448, 446, 449, 446, 449, - 450, 450, 450, 450, 451, 451, 451, 451, 452, 452, 452, 452, 453, 454, 453, 26, - 455, 455, 455, 455, 455, 455, 456, 457, 458, 458, 459, 458, 460, 460, 461, 460, - 462, 462, 463, 464, 26, 465, 26, 26, 466, 466, 466, 466, 466, 467, 26, 26, - 468, 468, 468, 468, 468, 468, 469, 26, 468, 468, 469, 470, 471, 471, 471, 471, - 471, 26, 471, 472, 473, 473, 473, 473, 474, 475, 473, 473, 474, 476, 26, 26, - 31, 31, 31, 50, 477, 477, 477, 477, 477, 478, 479, 26, 480, 26, 26, 26, - 26, 26, 26, 481, 482, 482, 482, 482, 482, 26, 483, 483, 483, 483, 483, 484, - 26, 26, 485, 485, 485, 486, 26, 26, 26, 26, 487, 487, 487, 488, 26, 26, - 489, 489, 490, 26, 491, 491, 491, 491, 491, 492, 493, 491, 491, 491, 492, 494, - 495, 495, 495, 495, 496, 497, 498, 498, 498, 499, 498, 500, 501, 501, 501, 501, - 501, 501, 502, 501, 501, 26, 503, 503, 503, 503, 504, 26, 505, 505, 505, 505, - 506, 137, 507, 26, 508, 508, 509, 508, 508, 508, 508, 508, 510, 26, 26, 26, - 511, 512, 513, 514, 513, 515, 516, 516, 516, 516, 516, 516, 516, 517, 516, 518, - 519, 520, 521, 522, 522, 523, 524, 525, 520, 526, 527, 528, 529, 530, 530, 26, - 531, 532, 531, 531, 531, 531, 533, 531, 534, 535, 533, 536, 537, 26, 26, 26, - 538, 538, 538, 538, 538, 538, 538, 539, 540, 26, 26, 26, 541, 541, 541, 541, - 541, 26, 541, 542, 543, 543, 543, 543, 543, 543, 544, 543, 543, 543, 543, 544, - 545, 545, 545, 545, 546, 26, 545, 547, 198, 548, 26, 26, 549, 549, 549, 549, - 549, 549, 549, 550, 549, 550, 164, 164, 551, 26, 26, 26, 552, 552, 552, 553, - 552, 554, 552, 552, 555, 26, 26, 26, 556, 556, 556, 556, 556, 556, 556, 557, - 558, 558, 558, 558, 558, 558, 559, 560, 561, 562, 563, 564, 564, 564, 565, 566, - 561, 26, 564, 567, 568, 569, 568, 568, 568, 568, 568, 569, 570, 26, 26, 26, - 571, 571, 571, 571, 571, 26, 572, 572, 572, 572, 572, 572, 573, 26, 178, 178, - 574, 574, 574, 574, 574, 574, 574, 575, 53, 576, 26, 26, 577, 577, 577, 577, - 578, 26, 577, 578, 579, 580, 579, 579, 579, 579, 581, 579, 582, 26, 579, 579, - 579, 583, 584, 584, 584, 584, 585, 584, 584, 586, 587, 26, 588, 589, 590, 590, - 590, 590, 588, 591, 590, 26, 590, 592, 593, 594, 595, 595, 595, 596, 597, 598, - 595, 599, 26, 26, 600, 600, 600, 601, 602, 602, 603, 602, 602, 602, 602, 604, - 602, 602, 602, 605, 26, 26, 606, 26, 108, 108, 108, 108, 108, 108, 607, 608, - 609, 609, 609, 609, 609, 609, 609, 610, 609, 611, 612, 26, 613, 26, 26, 26, - 26, 26, 614, 614, 614, 614, 614, 614, 614, 614, 615, 26, 616, 616, 616, 616, - 616, 616, 617, 26, 616, 616, 616, 618, 619, 619, 619, 619, 620, 26, 26, 26, - 621, 621, 621, 621, 621, 621, 621, 622, 305, 305, 305, 623, 624, 624, 624, 625, - 624, 626, 627, 627, 627, 627, 627, 627, 627, 627, 627, 628, 627, 629, 630, 630, - 630, 631, 631, 26, 632, 632, 632, 632, 633, 26, 632, 634, 634, 632, 632, 635, - 632, 632, 26, 26, 636, 636, 636, 636, 636, 636, 636, 637, 638, 638, 638, 638, - 638, 638, 638, 639, 640, 640, 640, 640, 640, 641, 640, 640, 640, 642, 640, 640, - 643, 26, 345, 26, 644, 644, 644, 644, 644, 644, 644, 26, 645, 645, 645, 645, - 645, 645, 646, 26, 26, 26, 26, 647, 644, 648, 26, 26, 26, 26, 649, 650, - 651, 286, 286, 286, 652, 26, 653, 26, 26, 26, 654, 26, 655, 26, 656, 656, - 656, 656, 656, 656, 656, 656, 656, 657, 658, 658, 658, 658, 658, 659, 658, 660, - 658, 661, 658, 662, 359, 26, 26, 26, 0, 0, 0, 265, 0, 0, 359, 26, - 9, 663, 9, 9, 221, 26, 0, 0, 0, 0, 276, 26, 257, 362, 0, 0, - 664, 665, 0, 666, 667, 668, 0, 0, 0, 669, 0, 0, 246, 26, 26, 26, - 0, 0, 257, 26, 0, 0, 0, 259, 0, 0, 254, 0, 0, 0, 0, 254, - 670, 671, 0, 672, 673, 0, 0, 0, 269, 674, 254, 254, 0, 0, 0, 675, - 676, 677, 678, 0, 276, 0, 0, 0, 0, 268, 0, 0, 679, 679, 679, 679, - 679, 680, 26, 681, 682, 679, 26, 26, 2, 2, 2, 346, 683, 419, 26, 26, - 684, 270, 270, 685, 686, 687, 18, 18, 18, 688, 26, 26, 26, 689, 26, 26, - 690, 690, 690, 690, 690, 691, 690, 692, 690, 693, 26, 26, 26, 26, 694, 694, - 694, 695, 26, 26, 696, 696, 696, 696, 696, 696, 696, 697, 26, 26, 698, 698, - 698, 698, 698, 699, 26, 26, 700, 700, 700, 700, 700, 701, 172, 702, 170, 172, - 703, 703, 703, 703, 704, 703, 705, 26, 706, 706, 706, 706, 706, 707, 706, 708, - 26, 26, 362, 0, 0, 0, 376, 26, 709, 31, 31, 31, 710, 711, 712, 713, - 714, 715, 710, 716, 710, 712, 712, 717, 31, 718, 31, 719, 720, 718, 31, 719, - 26, 26, 721, 26, 0, 359, 0, 0, 0, 257, 362, 0, 362, 0, 362, 0, - 0, 276, 26, 26, 722, 0, 0, 0, 723, 26, 0, 0, 0, 0, 0, 359, - 0, 259, 265, 26, 276, 26, 26, 26, 0, 0, 0, 724, 0, 376, 0, 376, - 0, 0, 257, 725, 0, 359, 259, 26, 0, 26, 0, 265, 0, 26, 0, 0, - 0, 276, 0, 359, 265, 26, 26, 26, 0, 276, 0, 376, 0, 726, 0, 0, - 257, 722, 0, 727, 0, 265, 0, 259, 277, 277, 277, 280, 345, 26, 277, 277, - 728, 26, 277, 277, 277, 729, 277, 277, 277, 277, 26, 26, 730, 26, 26, 26, - 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976, - 1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082, - 1086,1110, 0, 0,1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161, - 1187,1188,1189,1193, 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269, - 1273,1298, 0,1303, 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, - 961,1146, 964,1149, 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, - 988,1173, 990,1175, 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191, - 1006,1192,1014,1199,1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025, - 1211,1023,1209, 0, 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0, - 1044,1230,1045,1231,1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252, - 1067,1253,1072,1258,1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271, - 1085,1272,1088,1275,1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120, - 1309,1121,1310, 0,1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1093,1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 949,1134,1010,1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339, - 1366, 0,1320,1347,1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241, - 1416,1417,1415,1424,1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348, - 1322,1349,1338,1365, 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197, - 1051,1237,1052,1238,1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, - 0, 0, 997,1182, 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364, - 1335,1362,1046,1232,1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 8, 9, 0, 10,1425, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0, - 1450, 0,1455,1461,1514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1446,1458, - 1468,1476,1480,1486,1517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1489,1503, - 1494,1500,1508, 0, 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0, - 1536,1532,1539, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, - 0, 0, 0, 0,1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0, - 1558,1554,1561, 0, 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, - 0, 0, 0, 0, 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571, - 1530,1552,1531,1553, 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573, - 1544,1566,1538,1560,1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, - 0, 0, 0, 0, 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, - 0, 0, 0, 0,1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, - 0, 0, 0, 0, 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617, - 1618,1619,1621,1622, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628, - 1629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1625,1626, 0,1627, 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, - 0, 0,1633, 0, 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638, - 1640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1636,1637, 0, 0, 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644, - 1643, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, - 0, 0, 0, 0,1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653, - 1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0, - 1655,1657,1656, 0, 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, - 0,1660, 0, 0, 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0, - 1663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, - 0, 0, 0, 0, 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, - 0, 0, 0, 0, 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, - 0,1669, 0, 0, 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0, - 1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0, - 1679, 0,1680, 0, 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, - 0,1683, 0, 0,1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, - 965,1150, 968,1153, 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170, - 1420,1421, 986,1171, 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185, - 1015,1200,1329,1356,1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213, - 1026,1212,1028,1214,1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224, - 1334,1361,1336,1363,1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249, - 1689,1690,1065,1251,1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259, - 1075,1262,1079,1266,1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393, - 1099,1286,1100,1287,1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295, - 1108,1296,1114,1302,1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, - 0, 0, 0, 0, 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345, - 1693,1695,1371,1375,1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, - 972,1157,1326,1353,1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198, - 1054,1240,1048,1234,1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401, - 1395,1400,1398,1403,1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410, - 1408,1413,1407,1412,1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, - 0, 0, 0, 0,1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719, - 1716,1720,1717,1721,1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735, - 1734,1736, 0, 0,1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755, - 1752,1756,1753,1757,1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774, - 1772,1775,1773,1776,1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783, - 1782,1784, 0, 0,1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, - 0,1792, 0,1793,1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812, - 1809,1813,1810,1814,1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28, - 1507, 29, 0, 0,1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724, - 1725,1726,1727,1728,1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760, - 1761,1762,1763,1764,1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817, - 1818,1819,1820,1821,1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12, - 1432, 0, 26, 0, 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14, - 1441,1826,1827,1828,1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, - 0,1831,1832,1833,1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17, - 1453,1313, 11, 3, 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18, - 1464, 4, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,1836, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,1837,1839,1838, 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0, - 1842, 0, 0, 0, 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, - 0, 0, 0, 0, 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,1849, 936, 938,1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, - 0, 0, 0, 0,1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1867,1868,1869,1870,1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872, - 1873,1874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1877, 0,1878, 0,1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0, - 1885, 0,1886, 0,1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, - 0, 0, 0, 0,1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0, - 1900,1901, 0, 0, 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, - 0, 0,1902, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1904, 0,1905, 0,1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0, - 1912, 0,1913, 0,1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, - 0, 0, 0, 0,1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0, - 1927,1928, 0, 0, 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, - 0, 0,1933, 0, 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, - 241, 336, 524, 601, 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, - 180, 416, 482, 662, 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, - 740, 116, 146, 168, 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, - 553, 588, 642, 758, 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, - 412, 445, 457, 585, 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, - 411, 704, 105, 259, 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, - 228, 529, 650, 697, 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, - 624, 700, 750, 170, 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, - 420, 730, 287, 330, 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, - 154, 163, 198, 473, 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, - 314, 499, 506, 603, 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, - 260, 265, 373, 411, 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, - 502, 516, 537, 583, 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, - 771, 155, 190, 269, 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, - 452, 191, 480, 510, 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, - 707, 111, 636, 156, 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, - 128, 210, 0, 0, 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, - 783, 576, 604, 0, 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, - 795, 808, 741, 773, 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, - 270, 317, 327, 329, 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, - 545, 547, 546, 548, 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, - 620, 625, 625, 651, 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, - 869, 623, 0, 0, 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, - 227, 231, 240, 243, 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, - 341, 357, 360, 362, 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, - 477, 535, 485, 490, 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, - 565, 569, 574, 586, 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, - 705, 704, 702, 706, 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, - 790, 802, 825, 848, 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,1586, 0,1605, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603, - 1934,1935,1574,1575,1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589, - 1591, 0,1592, 0,1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582, - 1578,1590,1597, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1937, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0, - 1939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1940, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,1941,1942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1943, - 1944, 0, 0, 0, 0, 0, 0,1945, 0,1946, 0, 0, 0, 0, 0, 0, - 0, 0,1947, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1950, 0,1949,1951, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1953, - 1952, 0,1954, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1955,1956, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1957, 0, 0, 0, - 0, 0, 0, 0, 0,1958,1961,1959,1965,1960,1962,1964,1963, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1967,1966,1968, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,1969,1970,1971,1972,1973,1974,1975, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1976, - 1977,1978,1980,1979,1981, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, - 34, 830, 130, 131, 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, - 924, 151, 152, 37, 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, - 176, 177, 178, 179, 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, - 196, 192, 194, 195, 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, - 213, 219, 214, 216, 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, - 237, 238, 239, 244, 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, - 838, 257, 258, 259, 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, - 274, 842, 277, 276, 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, - 290, 291, 293, 934, 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, - 306, 309, 310, 312, 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, - 333, 331, 332, 334, 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, - 354, 359, 850, 361, 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, - 386, 378, 53, 381, 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, - 392, 856, 54, 399, 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, - 859, 415, 56, 417, 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, - 429, 431, 427, 433, 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, - 453, 865, 447, 460, 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, - 475, 868, 478, 870, 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, - 61, 61, 504, 505, 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, - 877, 878, 63, 64, 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, - 68, 884, 536, 538, 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, - 888, 889, 889, 567, 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, - 587, 74, 590, 592, 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, - 900, 609, 901, 611, 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, - 622, 731, 80, 627, 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, - 635, 641, 646, 651, 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, - 657, 908, 82, 83, 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, - 672, 673, 675, 85, 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, - 914, 88, 89, 696, 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, - 723, 832, 725, 728, 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, - 761, 921, 762, 90, 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, - 94, 927, 787, 787, 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, - 806, 97, 98, 807, 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, - 821, 935, 0, 0, -}; -static const int16_t -_hb_ucd_i16[92] = -{ - 0, 0, 1, -1, 2, 0, -2, 0, 0, 2, 0, -2, 0, 16, 0, -16, - 0, 1, -1, 0, 3, 3, 3, -3, -3, -3, 0, 2016, 0, 2527, 1923, 1914, - 1918, 0, 2250, 0, 0, 138, 0, 7, -7, 0, -1, 1, 1824, 0, 2104, 0, - 2108, 2106, 0, 2106, 1316, 0, -1, -138, 8, 8, 8, 0, 7, 7, -8, -8, - -8, -7,-1316, 1, -1, 3, -3, 1, 0,-1914,-1918, 0, 0,-1923,-1824, 0, - 0,-2016,-2104, 0, 0,-2106,-2108,-2106,-2250, 0,-2527, 0, -}; - -static inline uint_fast8_t -_hb_ucd_gc (unsigned u) -{ - return u<1114110u?_hb_ucd_u8[6472+(((_hb_ucd_u8[816+(((_hb_ucd_u16[((_hb_ucd_u8[272+(((_hb_ucd_u8[u>>1>>3>>4>>4])<<4)+((u>>1>>3>>4)&15u))])<<4)+((u>>1>>3)&15u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2; -} -static inline uint_fast8_t -_hb_ucd_ccc (unsigned u) -{ - return u<125259u?_hb_ucd_u8[8504+(((_hb_ucd_u8[7936+(((_hb_ucd_u8[7460+(((_hb_ucd_u8[7100+(((_hb_ucd_u8[6854+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0; -} -static inline unsigned -_hb_ucd_b4 (const uint8_t* a, unsigned i) -{ - return (a[i>>1]>>((i&1u)<<2))&15u; -} -static inline int_fast16_t -_hb_ucd_bmg (unsigned u) -{ - return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9396+(((_hb_ucd_u8[9164+(((_hb_ucd_u8[9068+(((_hb_ucd_b4(9004+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0; -} -static inline uint_fast8_t -_hb_ucd_sc (unsigned u) -{ - return u<918000u?_hb_ucd_u8[10398+(((_hb_ucd_u16[3952+(((_hb_ucd_u16[2624+(((_hb_ucd_u8[9870+(((_hb_ucd_u8[9644+(u>>3>>2>>3>>4)])<<4)+((u>>3>>2>>3)&15u))])<<3)+((u>>3>>2)&7u))])<<2)+((u>>3)&3u))])<<3)+((u)&7u))]:2; -} -static inline uint_fast16_t -_hb_ucd_dm (unsigned u) -{ - return u<195102u?_hb_ucd_u16[6244+(((_hb_ucd_u8[16628+(((_hb_ucd_u8[16246+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0; -} - - -#else - -static const uint8_t -_hb_ucd_u8[13730] = -{ - 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 7, 11, 12, 12, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 7, 21, 22, 22, 22, 23, 24, 7, 7, - 7, 25, 22, 22, 22, 26, 27, 28, 22, 29, 30, 31, 32, 33, 34, 35, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 21, 22, 36, - 7, 7, 7, 7, 37, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 38, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 34, 34, 34, 35, 36, 37, 34, 34, 34, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 62, 63, 64, 65, 66, 67, 68, 69, 67, 70, 71, - 67, 67, 62, 72, 62, 62, 73, 67, 74, 75, 76, 77, 78, 67, 67, 67, - 79, 80, 34, 81, 82, 83, 67, 67, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 84, 34, 34, 34, 34, - 85, 34, 34, 34, 34, 34, 34, 34, 34, 86, 34, 34, 87, 88, 89, 90, - 91, 92, 93, 94, 95, 96, 97, 98, 34, 34, 34, 34, 34, 34, 34, 34, - 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, - 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, - 100,100, 34, 34, 34, 34,101,102, 34, 34,103,104,105,106,107,108, - 34, 34,109,110,111,112,113,114,115,116,117,118, 34, 34, 34,119, - 120,121,122,123,124,125,126,127, 34,128,129,130,131,132,133,134, - 135,136,137,138,139,140,141,142,143,144,111,145,146,147,148,111, - 149,150,151,152,153,154,155,156,157,158,159,160,111,161,162,163, - 34, 34, 34, 34, 34, 34, 34, 34,164, 34, 34,111,111,111,111,111, - 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,165, - 34, 34, 34, 34, 34, 34, 34, 34,166, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111, - 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, - 111,111,167,111,111,111,111,111,111,111,111,111,111,111,111,111, - 34, 34, 34, 34,168,169,170, 34,111,111,171,111,172,173,174,175, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111, - 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,119, - 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111, - 111,111,111,111,111,111,111,111, 34,176,111,111,111,111,111,111, - 111,111,111,111,111,111,111,111, 67,177, 67, 67, 67, 67,178, 67, - 67, 67,179,180,181,131, 65,111,182,183,184,185,186,187,188,189, - 67, 67, 67, 67,190,191,111,111,111,111,111,111,111,111,192,111, - 193,194,195,111,111,196,111,111,111,197,111,198,111,111,111, 34, - 34,199,200,111,111,111,111,111,131,201,202,111, 34,203,111,111, - 67, 67,204, 67, 67,111, 67,205, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67,177,111,111,111,111,111,111,111,111, - 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,111, - 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111, - 206,111,194,194,111,111,111,111,111,111,111,111,111,111,111,111, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2, - 7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 17, 18, 19, 1, 20, 20, 21, 22, 23, 24, 25, - 26, 27, 15, 2, 28, 29, 27, 30, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 31, 11, 11, 11, 32, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 33, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 34, 34, 34, 34, 34, 34, 34, 34, 16, 32, 32, 32, - 32, 32, 32, 32, 11, 34, 34, 16, 34, 32, 32, 11, 34, 11, 16, 11, - 11, 34, 32, 11, 32, 16, 11, 34, 32, 32, 32, 11, 34, 16, 32, 11, - 34, 11, 34, 34, 32, 35, 32, 16, 36, 36, 37, 34, 38, 37, 34, 34, - 34, 34, 34, 34, 34, 34, 16, 32, 34, 38, 32, 11, 32, 32, 32, 32, - 32, 32, 16, 16, 16, 11, 34, 32, 34, 34, 11, 32, 32, 32, 32, 32, - 16, 16, 39, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 41, 41, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, - 40, 40, 42, 41, 41, 41, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, - 43, 43, 43, 43, 43, 43, 43, 43, 32, 32, 42, 32, 16, 44, 16, 10, - 41, 41, 41, 45, 11, 11, 11, 11, 34, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 34, - 16, 11, 32, 16, 32, 32, 32, 32, 16, 16, 32, 46, 34, 32, 34, 11, - 32, 47, 43, 43, 48, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16, - 11, 11, 11, 11, 49, 2, 2, 2, 16, 16, 16, 16, 50, 51, 52, 53, - 54, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 55, - 56, 57, 43, 56, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 58, 2, 2, 2, 2, 2, 2, 59, 59, 59, 8, 9, 60, 2, 61, - 43, 43, 43, 43, 43, 57, 62, 2, 63, 36, 36, 36, 36, 64, 43, 43, - 7, 7, 7, 7, 7, 2, 2, 36, 65, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 66, 43, 43, 43, 67, 47, 43, 43, 68, 69, 70, 43, 43, 36, - 7, 7, 7, 7, 7, 36, 71, 72, 2, 2, 2, 2, 2, 2, 2, 73, - 64, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 65, 36, - 36, 36, 36, 43, 43, 43, 43, 43, 7, 7, 7, 7, 7, 36, 36, 36, - 36, 36, 36, 36, 36, 64, 43, 43, 43, 43, 40, 21, 2, 40, 69, 20, - 36, 36, 36, 43, 43, 69, 43, 43, 43, 43, 69, 43, 69, 43, 43, 43, - 2, 2, 2, 2, 2, 2, 2, 2, 36, 36, 36, 36, 64, 43, 43, 2, - 36, 36, 36, 36, 74, 36, 36, 36, 59, 59, 59, 75, 43, 43, 43, 43, - 36, 36, 36, 36, 76, 43, 43, 43, 43, 75, 43, 43, 43, 43, 43, 43, - 43, 77, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 77, 65, 78, - 79, 43, 43, 43, 77, 78, 79, 78, 64, 43, 43, 43, 36, 36, 36, 36, - 36, 43, 2, 7, 7, 7, 7, 7, 80, 36, 36, 36, 36, 36, 36, 36, - 64, 78, 81, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 65, 78, - 79, 43, 43, 77, 78, 78, 79, 36, 36, 36, 36, 82, 78, 78, 36, 36, - 36, 43, 43, 7, 7, 7, 7, 7, 36, 20, 27, 27, 27, 53, 58, 43, - 43, 77, 81, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 78, - 79, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 65, 36, 36, 36, - 36, 36, 36, 7, 7, 7, 7, 7, 43, 36, 64, 2, 2, 2, 2, 2, - 79, 43, 43, 43, 77, 78, 79, 43, 60, 20, 20, 20, 83, 43, 43, 43, - 43, 78, 81, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 65, 79, - 79, 43, 43, 77, 78, 78, 79, 43, 43, 43, 43, 77, 78, 78, 36, 36, - 72, 27, 27, 27, 27, 27, 27, 27, 43, 65, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 78, 77, 78, 78, 78, 78, 78, 79, 43, - 36, 36, 36, 82, 78, 78, 78, 78, 78, 78, 78, 7, 7, 7, 7, 7, - 27, 84, 61, 61, 53, 61, 61, 61, 77, 78, 65, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 65, 43, 77, 78, 78, 43, 43, 43, 43, 43, - 43, 43, 43, 43, 36, 36, 36, 36, 7, 7, 7, 85, 27, 27, 27, 84, - 64, 78, 66, 36, 36, 36, 36, 36, 78, 78, 78, 77, 78, 78, 43, 43, - 43, 43, 77, 78, 78, 78, 81, 36, 86, 82, 78, 78, 78, 78, 78, 78, - 43, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 65, 78, - 79, 43, 43, 78, 78, 78, 79, 71, 61, 61, 36, 82, 27, 27, 27, 87, - 27, 27, 27, 27, 84, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 77, - 78, 43, 43, 43, 78, 78, 78, 78, 7, 78, 2, 2, 2, 2, 2, 2, - 64, 36, 43, 43, 43, 43, 43, 88, 36, 36, 36, 69, 43, 43, 43, 57, - 7, 7, 7, 7, 7, 2, 2, 2, 64, 36, 43, 43, 43, 43, 65, 36, - 36, 36, 36, 40, 43, 43, 43, 43, 7, 7, 7, 7, 7, 7, 36, 36, - 71, 61, 2, 2, 2, 2, 2, 2, 2, 89, 89, 61, 43, 61, 61, 61, - 7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 47, 47, 47, 4, 4, 78, - 64, 43, 43, 43, 43, 43, 43, 77, 43, 43, 57, 43, 36, 36, 64, 43, - 43, 43, 43, 43, 43, 43, 43, 61, 61, 61, 61, 70, 61, 61, 61, 61, - 2, 2, 89, 61, 21, 2, 2, 2, 36, 36, 36, 36, 36, 82, 79, 43, - 77, 43, 43, 43, 79, 77, 79, 65, 36, 36, 36, 78, 43, 36, 36, 43, - 65, 78, 81, 82, 78, 78, 78, 36, 64, 43, 65, 36, 36, 36, 36, 36, - 36, 77, 79, 77, 78, 78, 79, 82, 7, 7, 7, 7, 7, 78, 79, 61, - 16, 16, 16, 16, 16, 50, 44, 16, 36, 36, 36, 36, 36, 36, 64, 43, - 2, 2, 2, 2, 90, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, - 61, 61, 61, 61, 61, 61, 61, 61, 11, 11, 11, 11, 16, 16, 16, 16, - 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 71, 66, - 92, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 93, 94, 94, - 36, 36, 36, 36, 36, 58, 2, 95, 96, 36, 36, 36, 36, 36, 36, 36, - 36, 43, 77, 78, 78, 78, 78, 81, 36, 43, 97, 2, 2, 2, 2, 2, - 36, 43, 43, 43, 43, 43, 43, 43, 36, 36, 43, 79, 43, 43, 43, 78, - 78, 78, 78, 77, 79, 43, 43, 43, 43, 43, 2, 80, 2, 60, 64, 43, - 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 98, 2, 56, 43, 75, - 36, 76, 36, 36, 36, 36, 36, 36, 36, 36, 64, 65, 36, 36, 36, 36, - 36, 36, 36, 36, 64, 36, 36, 36, 43, 77, 78, 79, 77, 78, 78, 78, - 78, 77, 78, 78, 79, 43, 43, 43, 61, 61, 2, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 27, 27, 61, 36, 36, 36, 64, 77, 79, 43, 2, - 36, 36, 82, 77, 43, 43, 43, 43, 77, 77, 79, 43, 43, 43, 77, 78, - 78, 79, 43, 43, 43, 43, 43, 43, 2, 2, 2, 80, 2, 2, 2, 2, - 43, 43, 43, 43, 43, 43, 43, 99, 43, 43, 81, 36, 36, 36, 36, 36, - 36, 36, 77, 43, 43, 77, 77, 78, 78, 77, 81, 36, 36, 36, 36, 2, - 89, 61, 61, 61, 61, 47, 43, 43, 43, 43, 61, 61, 61, 61, 21, 2, - 43, 81, 36, 36, 36, 36, 36, 36, 82, 43, 43, 78, 43, 79, 43, 36, - 36, 36, 36, 77, 43, 78, 79, 79, 43, 78, 78, 78, 78, 78, 2, 2, - 36, 36, 78, 78, 78, 78, 43, 43, 43, 43, 78, 43, 43, 57, 2, 2, - 7, 7, 7, 7, 7, 7, 86, 36, 36, 36, 36, 36, 40, 40, 40, 2, - 16, 16, 16, 16, 34, 16, 16, 16, 43, 57, 43, 43, 43, 43, 43, 43, - 77, 43, 43, 43, 65, 36, 64, 36, 36, 36, 65, 82, 43, 36, 36, 36, - 16, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 44, 16, 16, - 16, 16, 16, 16, 44, 16, 16, 16, 16, 16, 16, 16, 16,100, 40, 40, - 32, 32, 32, 16, 16, 16, 16, 32, 16, 16, 16, 16, 11, 11, 11, 11, - 16, 16, 16, 16, 34, 11, 11, 11, 16, 16, 16, 16,101,101,101,101, - 16, 16, 16, 16, 11, 11,102,103, 41, 16, 16, 16, 11, 11,102, 41, - 16, 16, 16, 16, 11, 11,104, 41,105,105,105,105,105,106, 59, 59, - 51, 51, 51, 2,107,108,107,108, 2, 2, 2, 2,109, 59, 59,110, - 2, 2, 2, 2,111,112, 2,113,114, 2,115,116, 2, 2, 2, 2, - 2, 9,114, 2, 2, 2, 2,117, 59, 59, 59, 59, 59, 59, 59, 59, - 118, 40, 27, 27, 27, 8,115,119, 27, 27, 27, 27, 27, 8,115, 94, - 20, 20, 20, 20, 20, 20, 20, 20, 43, 43, 43, 43, 43, 43,120, 48, - 99, 48, 99, 43, 43, 43, 43, 43, 61,121, 61,122, 61, 34, 11, 16, - 11, 32,122, 61, 46, 11, 11, 61, 61, 61,121,121,121, 11, 11,123, - 11, 11, 35, 36, 39, 61, 16, 11, 8, 8, 46, 16, 16, 26, 61,124, - 95, 95, 95, 95, 95, 95, 95, 95, 95,125,126, 95,127, 61, 61, 61, - 8, 8,128, 61, 61, 8, 61, 61,128, 26, 61,128, 61, 61, 61,128, - 61, 61, 61, 61, 61, 61, 61, 8, 61,128,128, 61, 61, 61, 61, 61, - 61, 61, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 61, 61, 61, 61, 4, 4, 61, 61, 8, 61, 61, 61,129,130, 61, 61, - 61, 61, 61, 61, 61, 61,128, 61, 61, 61, 61, 61, 61, 26, 8, 8, - 8, 8, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 8, 8, - 8, 61, 61, 61, 61, 61, 61, 61, 27, 27, 27, 27, 27, 27, 61, 61, - 61, 61, 61, 61, 61, 27, 27, 27, 61, 61, 61, 26, 61, 61, 61, 61, - 26, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 8, 8, 8, 8, - 61, 61, 61, 61, 61, 61, 61, 26, 61, 61, 61, 61, 4, 4, 4, 4, - 4, 4, 4, 27, 27, 27, 27, 27, 27, 27, 61, 61, 61, 61, 61, 61, - 8, 8,115,131, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, - 8,115,132,132,132,132,132,132,132,132,132,132,131, 8, 8, 8, - 8, 8, 8, 8, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8, - 8, 8,128, 26, 8, 8,128, 61, 32, 11, 32, 34, 34, 34, 34, 11, - 32, 32, 34, 16, 16, 16, 40, 11, 32, 32,124, 61, 61,122, 34,133, - 43, 32, 16, 16, 50, 2, 90, 2, 36, 36, 36, 36, 36, 36, 36, 76, - 2, 2, 2, 2, 2, 2, 2, 56, 2,107,107, 2,111,112,107, 2, - 2, 2, 2, 6, 2, 98,107, 2,107, 4, 4, 4, 4, 2, 2, 80, - 2, 2, 2, 2, 2, 51, 2, 2, 98,134, 2, 2, 2, 2, 2, 2, - 61, 2,135,132,132,132,136, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 1, 2,137,138, 4, 4, 4, 4, 4, 61, 4, 4, 4, 4,139, 94, - 140, 95, 95, 95, 95, 43, 43, 78,141, 40, 40, 61, 95,142, 58, 61, - 72, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64,143,144, 63, - 36, 36, 36, 36, 36, 58, 40, 63, 61, 27, 27, 61, 61, 61, 61, 61, - 27, 27, 27, 27, 27, 61, 61, 61, 61, 61, 61, 61, 27, 27, 27, 27, - 145, 27, 27, 27, 27, 27, 27, 27, 36, 36, 76, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36,146, 2, 32, 32, 32, 32, 32, 32, 32, 64, - 48,147, 43, 43, 43, 43, 43, 80, 32, 32, 32, 32, 32, 32, 40, 43, - 36, 36, 36, 95, 95, 95, 95, 95, 43, 2, 2, 2, 2, 2, 2, 2, - 41, 41, 41,144, 40, 40, 40, 40, 41, 32, 32, 32, 32, 32, 32, 32, - 16, 32, 32, 32, 32, 32, 32, 32, 44, 16, 16, 16, 34, 34, 34, 32, - 32, 32, 32, 32, 42,148, 34, 35, 32, 32, 16, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 11, 11, 32, 11, 11, 32, 32, 32, 32, 32, 32, - 32, 32, 11, 11, 34, 34, 32, 16, 32, 16, 16, 32, 32, 32, 11, 11, - 11, 40,149, 35, 40, 35, 36, 36, 36, 65, 36, 65, 36, 64, 36, 36, - 36, 82, 79, 77, 61, 61, 43, 43, 27, 27, 27, 61,150, 61, 61, 61, - 36, 36, 2, 2, 2, 2, 2, 2, 78, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 78, 78, 78, 78, 78, 78, 78, 78, 43, 43, 43, 43, 43, 2, - 43, 36, 36, 36, 2, 66, 66, 64, 36, 36, 36, 43, 43, 43, 43, 2, - 36, 36, 36, 64, 43, 43, 43, 43, 43, 78, 78, 78, 78, 78, 78, 97, - 36, 64, 78, 43, 43, 78, 43, 78, 97, 2, 2, 2, 2, 2, 2, 80, - 7, 7, 7, 7, 7, 7, 7, 2, 36, 36, 64, 63, 36, 36, 36, 36, - 36, 36, 36, 36, 64, 43, 43, 77, 79, 77, 79, 43, 43, 43, 43, 43, - 36, 64, 36, 36, 36, 36, 77, 78, 7, 7, 7, 7, 7, 7, 2, 2, - 63, 36, 36, 71, 61, 82, 77, 36, 65, 43, 65, 64, 65, 36, 36, 43, - 36, 36, 36, 36, 36, 36, 76, 2, 36, 36, 36, 36, 36, 82, 43, 78, - 2, 76,151, 43, 43, 43, 43, 43, 16, 16, 16, 16, 16,103, 40, 40, - 16, 16, 16, 16,100, 41, 41, 41, 36, 82, 79, 78, 77, 97, 79, 43, - 152,152,152,152,152,152,152,152,153,153,153,153,153,153,153,153, - 16, 16, 16, 16, 16, 16, 35, 65, 36, 36, 36, 36,154, 36, 36, 36, - 36, 41, 41, 41, 41, 41, 41, 41, 41, 74, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36,132, 36, 36, 36, 36, 36, 36, 36, 71, - 36, 36, 36, 36, 36, 36,150, 61, 2, 2, 2,135,116, 2, 2, 2, - 6,155,156,132,132,132,132,132,132,132,116,135,116, 2,113,157, - 2, 2, 2, 2,139,132,132,116, 2,158, 8, 8, 60, 2, 2, 2, - 36, 36, 36, 36, 36, 36, 36,159, 2, 2, 3, 2, 4, 5, 6, 2, - 16, 16, 16, 16, 16, 17, 18,115,116, 4, 2, 36, 36, 36, 36, 36, - 63, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 40, - 20,160, 53, 20, 26, 8,128, 61, 61, 61, 61, 61,161, 59, 61, 61, - 2, 2, 2, 90, 27, 27, 27, 27, 27, 27, 27, 84, 61, 61, 61, 61, - 95, 95,127, 27, 84, 61, 61, 61, 61, 61, 61, 61, 61, 27, 61, 61, - 61, 61, 61, 61, 61, 61, 47, 43,162,162,162,162,162,162,162,162, - 163, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 87, 36, - 138, 36, 36, 36, 36, 95, 95, 95, 36, 36, 36, 36, 36, 36, 36, 58, - 164, 95, 95, 95, 95, 95, 95, 95, 11, 11, 11, 32, 16, 16, 16, 16, - 36, 36, 36, 58, 27, 27, 27, 27, 36, 36, 36, 71,145, 27, 27, 27, - 36, 36, 36,165, 27, 27, 27, 27, 36, 36, 36, 36, 36,165, 27, 27, - 36, 36, 36, 27, 27, 27, 27, 30, 36, 36, 36, 36, 36, 36, 27, 36, - 64, 43, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 36,165, 30, 36, 36, 36, 36, 36, 36,165, 27, - 36, 36, 36, 36, 72, 36, 36, 36, 36, 36, 64, 43, 43,163, 27, 27, - 36, 36, 36, 36, 58, 2, 2, 2, 36, 36, 36, 36, 27, 27, 27, 27, - 16, 16, 16, 16, 16, 27, 27, 27, 36, 36, 43, 43, 43, 43, 43, 43, - 7, 7, 7, 7, 7, 36, 36, 63, 11, 11, 11, 11,166, 43, 43,141, - 16, 16, 16, 16, 16, 16, 16, 8, 36, 36, 36, 36, 36, 64,167, 51, - 36, 36, 36, 36, 36, 36, 43, 43, 27, 27, 27, 87, 36, 36, 36, 36, - 163, 27, 30, 2, 2, 2, 2, 2, 36, 43, 43, 2, 2, 2, 2, 2, - 36, 36,165, 27, 27, 27, 27, 27, 79, 81, 36, 36, 36, 36, 36, 36, - 43, 43, 43, 57, 2, 2, 2, 2, 2, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 7, 7, 7, 7, 7, 65, 64, 65, 36, 36, 36, 36, 64, - 78, 79, 43, 77, 79, 57, 73, 2, 2, 43, 43, 43, 43, 43, 67, 59, - 36, 36, 36, 64, 43, 43, 79, 43, 43, 43, 43, 7, 7, 7, 7, 7, - 2, 2, 82, 81, 36, 36, 36, 36, 36, 64, 2, 36, 36, 36, 36, 36, - 36, 82, 78, 43, 43, 43, 43, 77, 81, 36, 58, 2, 56, 43, 57, 79, - 7, 7, 7, 7, 7, 58, 58, 2, 90, 27, 27, 27, 27, 27, 27, 27, - 36, 36, 36, 36, 36, 36, 78, 79, 43, 78, 77, 43, 2, 2, 2, 65, - 36, 36, 36, 36, 36, 36, 36, 64, 77, 78, 78, 78, 78, 78, 78, 78, - 36, 36, 36, 82, 78, 78, 81, 36, 36, 78, 78, 43, 43, 43, 43, 43, - 36, 36, 36, 36, 78, 79, 43, 43, 43, 78, 78, 78, 78, 78, 78, 77, - 65, 65, 2, 2, 2, 2, 2, 2, 56, 43, 43, 43, 43, 43, 43, 43, - 36, 36, 82, 78, 43, 43, 43, 43, 78, 43, 77, 65, 36, 58, 2, 2, - 7, 7, 7, 7, 7, 2, 2, 65, 78, 79, 43, 43, 77, 77, 78, 79, - 77, 43, 36, 66, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 82, - 78, 43, 43, 43, 78, 78, 43, 79, 57, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 36, 36, 43, 43, 78, 79, 43, 43, 43, 77, 79, 79, - 57, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 79, 78, - 43, 43, 43, 79, 58, 2, 2, 2, 36, 36, 36, 36, 36, 36, 64, 79, - 78, 43, 43, 79, 43, 43, 43, 43, 7, 7, 7, 7, 7, 27, 2, 89, - 43, 43, 43, 43, 79, 57, 2, 2, 27, 27, 27, 27, 27, 27, 27, 87, - 78, 78, 78, 78, 78, 79, 77, 65, 81, 79, 2, 2, 2, 2, 2, 2, - 82, 78, 43, 43, 43, 43, 78, 78, 65, 66, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 64, 43, 43, 43, 43, 65, 36, 36, - 36, 64, 43, 43, 77, 64, 43, 57, 2, 2, 2, 56, 43, 43, 43, 43, - 64, 43, 43, 77, 79, 43, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, - 43, 43, 43, 77, 43, 2, 66, 2, 58, 2, 2, 2, 2, 2, 2, 2, - 43, 43, 43, 43, 43, 43, 43, 79, 2, 36, 36, 36, 36, 36, 36, 36, - 43, 43, 43, 43, 77, 43, 43, 43, 77, 43, 79, 43, 43, 43, 43, 43, - 43, 43, 43, 64, 43, 43, 43, 43, 36, 36, 36, 36, 36, 78, 78, 78, - 43, 77, 79, 79, 36, 36, 36, 36, 36, 64, 77, 97, 2, 2, 2, 2, - 43, 82, 36, 36, 36, 36, 36, 36, 36, 36, 78, 43, 43, 43, 43, 78, - 77, 57, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 43, 43, 43, - 27, 27, 84, 61, 61, 61, 53, 20,150, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 21, 65, 36, 36, 64, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 78, 79, 43, - 43, 43, 57, 2, 2, 2, 2, 2, 43, 43, 43, 57, 2, 2, 61, 61, - 40, 40, 89, 61, 61, 61, 61, 61, 7, 7, 7, 7, 7,168, 27, 27, - 27, 87, 36, 36, 36, 36, 36, 36, 40, 63, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 76,146, 2, 27, 27, 27, 30, 2, 2, 2, 2, - 82, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 79, - 43, 68, 40, 40, 40, 40, 40, 40, 40, 80, 43, 43, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 36, 47, 57, 61, 61,169, 79, 43, 61,169, 78, - 78,170, 59, 59, 59, 75, 43, 43, 43, 70, 47, 43, 43, 43, 61, 61, - 61, 61, 61, 61, 61, 43, 43, 61, 61, 43, 70, 61, 61, 61, 61, 61, - 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 16, 11, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, - 31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, 16, 16, - 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, 16, 16, - 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, - 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 32, 16, 7, - 43, 43, 43, 70, 61, 47, 43, 43, 43, 43, 43, 43, 43, 43, 70, 61, - 61, 61, 47, 61, 61, 61, 61, 61, 61, 61, 70, 21, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 56, 43, 43, 16, 16, 16, 16, 16, 39, 16, 16, - 43, 43, 43, 68, 40, 40, 40, 40, 7, 7, 7, 7, 7, 7, 7, 71, - 7, 7, 7, 7, 7, 7, 7,171, 36, 36, 36, 36, 36, 76, 43, 43, - 172, 7, 7, 7, 7, 7, 7, 85, 16, 16, 43, 43, 43, 68, 40, 40, - 27, 27, 27, 27, 27, 27,145, 27,173, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 27,145, 27, 27, 27, 27, 27, 27, 84, 61, - 61, 61, 61, 61, 61, 25, 41, 41, 0, 0, 29, 21, 21, 21, 23, 21, - 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9, - 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0, - 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15, - 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7, - 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12, - 6, 5, 9, 21, 25, 9, 26, 12, 11, 11, 9, 6, 5, 21, 17, 17, - 17, 26, 26, 23, 23, 12, 17, 12, 21, 12, 12, 21, 7, 21, 1, 1, - 21, 23, 26, 26, 1, 21, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1, - 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, 21, 1, 24, 7, 1, 12, - 7, 6, 12, 10, 10, 10, 10, 12, 21, 6, 10, 7, 7, 10, 23, 7, - 15, 26, 13, 21, 13, 7, 15, 7, 12, 23, 21, 26, 21, 15, 17, 7, - 29, 7, 7, 22, 18, 18, 14, 14, 14, 7, 10, 21, 17, 21, 11, 12, - 5, 6, 8, 8, 8, 24, 5, 24, 9, 24, 29, 29, 29, 1, 20, 19, - 22, 20, 27, 28, 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22, - 18, 21, 21, 29, 15, 6, 18, 6, 12, 11, 9, 26, 26, 9, 26, 5, - 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25, - 18, 22, 5, 12, 22, 21, 21, 22, 18, 17, 26, 6, 7, 14, 17, 22, - 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, 26, 15, 6, 21, 11, 21, - 24, 9, 6, 9, 23, 26, 6, 10, 4, 4, 3, 3, 7, 25, 17, 16, - 16, 22, 16, 16, 25, 17, 7, 1, 25, 24, 26, 1, 2, 2, 12, 15, - 21, 14, 7, 15, 9, 12, 12, 17, 13, 15, 26, 10, 10, 1, 13, 23, - 7, 13, 23, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, - 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 20, 0, 21, 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 35, 0, 0, 0, 0, 36, 0, 37, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, - 0, 0, 0, 0, 41, 42, 43, 0, 44, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, - 4, 5, 6, 7, 0, 8, 9, 10, 0, 11, 12, 13, 14, 15, 16, 17, - 16, 18, 16, 19, 16, 19, 16, 19, 0, 19, 16, 20, 16, 19, 21, 19, - 0, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, - 0, 35, 0, 0, 36, 0, 37, 0, 0, 0, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 0, 0, 47, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, - 0, 0, 0, 0, 0, 50, 0, 51, 0, 52, 53, 0, 54, 0, 0, 0, - 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 58, 0, 0, 59, 60, 61, - 62, 63, 0, 0, 64, 65, 0, 0, 0, 66, 0, 0, 0, 0, 67, 0, - 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 69, 0, 0, 0, 70, 0, 71, 0, 0, 72, 0, 0, 73, 0, 0, - 0, 0, 0, 0, 0, 0, 74, 75, 0, 0, 0, 0, 76, 77, 0, 78, - 79, 0, 0, 80, 81, 0, 82, 62, 0, 83, 84, 0, 0, 85, 86, 87, - 0, 88, 0, 89, 0, 90, 0, 0, 51, 91, 51, 0, 92, 0, 93, 0, - 0, 0, 81, 0, 0, 0, 94, 95, 0, 96, 97, 98, 99, 0, 0, 0, - 0, 0, 51, 0, 0, 0, 0,100,101, 0, 0, 0, 0, 0, 0,102, - 0, 0, 0, 0, 0, 0,103, 0, 0, 0, 0, 0, 0,104,105, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,106, 0, 0,107, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,108,109, 0, 0,110, 0, 0, 0, 0, - 0, 0,111, 0,112, 0,105, 0, 0, 0, 0, 0,113,114, 0, 0, - 0, 0, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0,117, 0,118, - 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 0, - 0, 0, 0, 9, 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, 14, 15, - 0, 16, 0, 17, 18, 0, 0, 19, 0, 20, 21, 0, 0, 0, 0, 0, - 22, 23, 0, 24, 25, 0, 0, 26, 0, 0, 0, 27, 0, 0, 28, 29, - 30, 31, 0, 0, 0, 32, 33, 34, 0, 0, 33, 0, 0, 35, 33, 0, - 0, 0, 33, 36, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, - 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 43, - 0, 44, 0, 0, 0, 45, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, - 0, 48, 49, 0, 0, 0, 0, 50, 0, 0, 0, 51, 0, 52, 0, 53, - 0, 0, 0, 0, 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 0, - 57, 58, 0, 0, 0, 59, 60, 0, 0, 0, 0, 0, 0, 61, 52, 0, - 62, 63, 0, 0, 64, 0, 0, 0, 65, 66, 0, 0, 0, 67, 0, 68, - 69, 70, 71, 72, 1, 73, 0, 74, 75, 76, 0, 0, 77, 78, 0, 0, - 0, 79, 0, 0, 1, 1, 0, 0, 80, 0, 0, 81, 0, 0, 0, 0, - 77, 82, 0, 83, 0, 0, 0, 0, 0, 78, 84, 0, 85, 0, 52, 0, - 1, 78, 0, 0, 86, 0, 0, 87, 0, 0, 0, 0, 0, 88, 57, 0, - 0, 0, 0, 0, 0, 89, 90, 0, 0, 84, 0, 0, 33, 0, 0, 91, - 0, 0, 0, 0, 92, 0, 0, 0, 0, 49, 0, 0, 93, 0, 0, 0, - 0, 94, 95, 0, 0, 96, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, - 99, 0, 0, 0,100, 0, 0, 0, 0,101,102, 93, 0, 0,103, 0, - 0, 0, 84, 0, 0,104, 0, 0, 0,105,106, 0, 0,107,108, 0, - 0, 0, 0, 0, 0,109, 0, 0,110, 0, 0, 0, 0,111, 33, 0, - 112,113,114, 57, 0, 0,115, 35, 0, 0,116, 0, 0, 0,117, 0, - 0, 0, 0, 0, 0,118, 0, 0,119, 0, 0, 0, 0,120, 88, 0, - 0, 0, 0, 0, 57, 0, 0, 0, 0, 52,121, 0, 0, 0, 0,122, - 0, 0,123, 0, 0, 0, 0,121, 0, 0,124, 0, 0, 0, 0, 0, - 79, 0, 0, 0, 0,125, 0, 0, 0,126, 0, 0, 0,127, 0,128, - 0, 0, 0, 0,129,130,131, 0,132, 0,133, 0, 0, 0,134,135, - 136, 0, 77, 0, 0, 0, 0, 0, 35, 0, 0, 0,137, 0, 0, 0, - 138, 0, 0, 0,139, 0, 0,140, 0, 0,141, 0, 0, 0, 0, 0, - 0, 0, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 4, 4, 8, - 9, 10, 1, 11, 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, 19, 1, - 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, 27, 28, 29, 30, - 0, 0, 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, 1, 36, 37, 0, - 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, 42, 0, 0, 0, 43, 36, - 44, 45, 21, 45, 46, 0, 0, 0, 19, 1, 21, 0, 0, 47, 0, 38, - 48, 1, 1, 49, 49, 50, 0, 0, 51, 0, 0, 19, 52, 1, 0, 0, - 38, 14, 4, 1, 1, 1, 53, 21, 43, 52, 54, 21, 35, 1, 0, 0, - 0, 55, 0, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 59, 0, 60, - 0, 0, 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, 64, 0, 0, 0, - 65, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 69, - 70, 0, 71, 72, 73, 74, 75, 76, 0, 0, 0, 77, 0, 0, 0, 78, - 79, 0, 0, 0, 0, 47, 0, 0, 0, 49, 0, 80, 0, 0, 0, 62, - 0, 0, 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, 83, 0, 0, 19, - 84, 0, 62, 0, 0, 0, 0, 49, 1, 85, 1, 52, 15, 86, 36, 10, - 21, 87, 0, 55, 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, - 88, 0, 0, 89, 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, 87, 9, - 12, 4, 90, 8, 91, 47, 0, 58, 50, 0, 21, 1, 21, 92, 93, 1, - 1, 1, 1, 94, 95, 96, 97, 1, 98, 58, 81, 99,100, 4, 58, 0, - 0, 0, 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, 0, 0, - 101,102, 0, 0,103, 0, 0, 1, 1, 50, 0, 0, 0, 38, 0, 63, - 0, 0, 0, 0, 0, 62, 0, 0,104, 68, 61, 0, 0, 0, 78, 0, - 0, 0,105,106, 58, 38, 81, 0, 0, 0, 0, 0, 0,107, 1, 14, - 4, 12, 84, 0, 0, 0, 0, 38, 87, 0, 0, 0, 0,108, 0, 0, - 109, 61, 0,110, 0, 0, 0, 1, 0, 0, 0, 0, 49, 50, 0, 0, - 19, 58, 0, 0, 0, 51, 0,111, 14, 52,112, 41, 0, 0, 62, 0, - 0, 61, 0, 0,113, 0, 87, 0, 0, 0, 61, 62, 0, 0, 62, 0, - 89, 0, 0,113, 0, 0, 0, 0,114, 0, 0, 0, 78, 55, 0, 38, - 1, 58, 1, 58, 0, 0, 0, 0, 0, 88, 63, 89, 0, 0,115, 0, - 0, 0, 55, 0, 0, 0, 0,115, 0, 0, 0, 0, 61, 0, 0, 0, - 0, 79, 0, 61, 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 79, 0, - 0, 0, 8, 91, 0, 0, 1, 87, 0, 0,116, 0, 0, 0, 0, 0, - 0,117, 0,118,119,120,121, 0,104, 4,122, 49, 23, 0, 0, 0, - 38, 50, 38, 58, 0, 0, 1, 87, 1, 1, 1, 1, 39, 1, 48,105, - 87, 0, 0, 0, 0, 1, 0, 0, 0,123, 0, 0, 0,112, 4,122, - 0, 0, 0, 1,124, 0, 0, 0, 0, 0,230,230,230,230,230,232, - 220,220,220,220,232,216,220,220,220,220,220,202,202,220,220,220, - 220,202,202,220,220,220, 1, 1, 1, 1, 1,220,220,220,220,230, - 230,230,230,240,230,220,220,220,230,230,230,220,220, 0,230,230, - 230,220,220,220,220,230,232,220,220,230,233,234,234,233,234,234, - 233,230, 0, 0, 0,230, 0,220,230,230,230,230,220,230,230,230, - 222,220,230,230,220,220,230,222,228,230, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0,230,220, - 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, - 34,230,230,220,220,230,220,230,230,220, 35, 0, 0, 0, 0, 0, - 230,230,230, 0, 0,230,230, 0,220,230,230,220, 0, 0, 0, 36, - 0, 0,230,220,230,230,220,220,230,220,220,230,220,230,220,230, - 230, 0, 0,220, 0, 0,230,230, 0,230, 0,230,230,230,230,230, - 0, 0, 0,220,220,220,230,220,220,220,230,230, 0,220, 27, 28, - 29,230, 7, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230,230, 0, - 0, 0, 0, 0,230, 0, 0, 84, 91, 0, 0, 0, 0, 9, 9, 0, - 0, 0, 0, 0, 9, 0,103,103, 9, 0,107,107,107,107,118,118, - 9, 0,122,122,122,122,220,220, 0, 0, 0,220, 0,220, 0,216, - 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130,130,130, - 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0,220, 0, 0, 0, - 0, 7, 0, 9, 9, 0, 9, 9, 0, 0, 0,230, 0, 0, 0,228, - 0, 0, 0,222,230,220,220, 0, 0, 0,230, 0, 0,220,230,220, - 0,220,230,230,230, 0, 0, 0, 9, 9, 0, 0, 7, 0,230, 0, - 1, 1, 1, 0, 0, 0,230,234,214,220,202,230,230,230,230,230, - 232,228,228,220,218,230,233,220,230,220,230,230, 1, 1, 1, 1, - 1,230, 0, 1, 1,230,220,230, 1, 1, 0, 0,218,228,232,222, - 224,224, 0, 8, 8, 0, 0, 0, 0,220,230, 0,230,230,220, 0, - 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0, 0,230, - 220, 0, 0, 0,220,220, 0, 0,230,220, 0, 9, 7, 0, 0, 7, - 9, 0, 0, 0, 9, 7, 6, 6, 0, 0, 0, 0, 1, 0, 0,216, - 216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,216, 0,220,220, - 220, 0,232,232,220,230,230,230, 7, 0, 16, 17, 17, 33, 17, 49, - 17, 17, 84, 97,135,145, 26, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17,177, 0, 1, 2, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, - 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, 6, 7, 8, 3, 3, 3, - 3, 3, 9, 10, 11, 12, 13, 3, 3, 3, 3, 3, 3, 3, 3, 14, - 3, 15, 3, 3, 3, 3, 3, 3, 16, 17, 18, 19, 20, 21, 3, 3, - 3, 22, 23, 24, 3, 3, 3, 3, 3, 3, 25, 3, 3, 3, 3, 3, - 3, 3, 3, 26, 3, 3, 27, 28, 0, 1, 0, 0, 0, 0, 0, 1, - 0, 2, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4, - 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 6, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 8, 9, 0, 0, 0, 0, 0, 0, 9, 0, 9, 0, 0, 0, 0, - 0, 0, 0, 10, 11, 12, 13, 0, 0, 14, 15, 16, 6, 0, 17, 18, - 19, 19, 19, 20, 21, 22, 23, 24, 19, 25, 0, 26, 27, 19, 19, 28, - 29, 30, 0, 31, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 19, - 28, 0, 32, 33, 9, 34, 35, 19, 0, 0, 36, 37, 38, 39, 40, 19, - 0, 41, 42, 43, 44, 31, 0, 1, 45, 42, 0, 0, 0, 0, 0, 32, - 14, 14, 0, 0, 0, 0, 14, 0, 0, 46, 47, 47, 47, 47, 48, 49, - 47, 47, 47, 47, 50, 51, 52, 53, 43, 21, 0, 0, 0, 0, 0, 0, - 0, 54, 6, 55, 0, 14, 19, 1, 0, 0, 0, 0, 56, 57, 0, 0, - 0, 0, 0, 19, 58, 31, 0, 0, 0, 0, 0, 0, 0, 59, 14, 0, - 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 60, 61, 0, - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 3, 0, 4, - 5, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 1, 1, 0, 0, 8, - 9, 0, 8, 9, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0, 0, 0, - 13, 0, 0, 0, 0, 14, 15, 16, 17, 0, 0, 0, 1, 0, 0, 18, - 19, 0, 0, 0, 20, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, - 1, 1, 1, 1, 0, 8, 21, 9, 0, 0, 22, 0, 0, 0, 0, 1, - 0, 23, 24, 25, 0, 0, 26, 0, 0, 0, 8, 21, 27, 0, 1, 0, - 0, 1, 1, 1, 1, 0, 1, 28, 29, 30, 0, 31, 32, 20, 1, 1, - 0, 0, 0, 8, 21, 9, 1, 4, 5, 0, 0, 0, 33, 9, 0, 1, - 1, 1, 0, 8, 21, 21, 21, 21, 34, 1, 35, 21, 21, 21, 9, 36, - 0, 0, 37, 38, 1, 0, 39, 0, 0, 0, 1, 0, 1, 0, 0, 0, - 0, 8, 21, 9, 1, 0, 0, 0, 40, 0, 8, 21, 21, 21, 21, 21, - 21, 21, 21, 9, 0, 1, 1, 1, 1, 8, 21, 21, 21, 9, 0, 0, - 0, 41, 0, 42, 43, 0, 0, 0, 1, 44, 0, 0, 0, 45, 8, 9, - 1, 0, 0, 0, 8, 21, 21, 21, 9, 0, 1, 0, 1, 1, 8, 21, - 21, 9, 0, 4, 5, 8, 9, 1, 0, 0, 0, 1, 2, 3, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 3, 3, 3, 3, 3, 3, - 3, 15, 3, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 0, 0, 1, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 17, 17, - 18, 17, 19, 20, 21, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 24, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 25, 25, 26, 27, - 28, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 52, 53, 31, - 31, 31, 31, 54, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 56, 57, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 58, 31, 31, 31, - 59, 60, 61, 62, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, - 63, 64, 65, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 66, 67, 68, 31, 31, 31, 31, 69, 31, 31, 31, 31, 31, - 31, 31, 17, 70, 71, 72, 17, 17, 73, 74, 31, 75, 76, 77, 78, 79, - 80, 31, 81, 82, 17, 83, 17, 17, 17, 17, 31, 31, 23, 23, 23, 23, - 23, 23, 23, 84, 31, 31, 31, 31, 23, 84, 31, 31, 23, 23, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 85, 0, 0, 1, - 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, - 4, 4, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10, 11, 11, 12, 11, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 19, 27, - 28, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, - 37, 37, 38, 38, 39, 40, 41, 41, 42, 42, 42, 43, 44, 44, 45, 46, - 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 49, 50, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, 51, - 60, 61, 62, 63, 64, 65, 66, 7, 67, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 7, 4, 4, 4, 4, 77, 77, 77, 77, 78, 79, 80, 81, - 82, 83, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 85, 85, - 0, 0, 0, 0, 86, 87, 88, 88, 89, 90, 48, 91, 0, 0, 92, 92, - 92, 92, 92, 93, 94, 95, 96, 97, 98, 47, 99,100,101,102, 0,103, - 104,105, 0, 0, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 0,106,106,106,106,106,106,106,106,106,106,106,107, - 108,108,108,108,108, 11,109,110,111, 4,112, 4,113,114,115,116, - 117,118,119,120,121,122,123,124,125,126, 50,127, 47, 47, 47, 47, - 47, 47, 47, 47,128,128,128,128,128,128,128,128,128,128,128,128, - 92, 92, 92, 92, 92, 92, 92, 92,129,130, 19, 19, 19, 19, 19, 19, - 131, 19, 19, 19,132,133, 19,134,135,136,137,101,138,138,138,138, - 0, 77,139,140,128,128,141,142,143,144,145,146,147,148,149,150, - 151,152,153,154,155,155,155,155,155,155, 4, 4,156,157,158,159, - 160,161,162,163,164,165,166,167,168,169,170,170,171,171,172,172, - 173,174,174,174, 19, 19,175,176,177,178,179,180,181,181,182,183, - 184,185,186,187,188,188,189,190,191,192,193,193,194,194,195,195, - 128,128,196,196,197,198,199,200,201,201,128,128,202,202,203,203, - 204,204,205,205,206,207,208,209, 28, 28,210,210,211,212,213,213, - 214,215,216,216,128,128,217,217,218,218,219, 34,220,220,220,220, - 220,220,220,220,220,220,220,220,220,220,128,128,128,128,128,128, - 128,128,221,221,222,222,222,222,222,222,222,222,223,223,223,223, - 223,223,223,223,223,223,128,128,128,128,128,128,128,128,128,128, - 224,224,128,128,110,110,110,110,110,110,110,110,110,225,226,227, - 228,228,228,228,128,128,128,128,229,229,128,128,230,230,230,230, - 231,231,231,232,233,233,233,233,233,233,233,233,233,233,233,233, - 234,234,234,234,234,234,234,234,233,233,128,128,128,128,128,128, - 128,128,104,104,235,236,236,236,237,238,239,239,239,239,239,239, - 128,128,128,128,240,240,241, 0,128,128,128,128, 0, 0, 0, 0, - 7,242, 0, 0, 0, 0, 0, 0, 0,243,244, 0, 77, 77, 0, 0, - 0, 0,128,128,245,245,245,245,245,245,245,245,245,245,245,245, - 128,128,128,128,128,128,128,128, 4, 4,128,128,246, 11, 11, 11, - 247,247,128,128,128,128,248,249,128,128,128,128,128,128,250,250, - 128,128,251,251,128,128,128,128,128,128, 48, 48,252,252,252,252, - 253,253,128,128, 0, 0, 0, 0, 0, 0,128,128, 19, 19, 19, 19, - 128,128,128,128,254, 0,128,128, 0, 0, 0, 0, 92, 92,128,128, - 128,128,128,128, 0, 0,128,128, 7, 7, 7, 7, 0, 0, 0, 0, - 1, 2, 1, 2, 0, 0, 3, 3, 4, 5, 4, 5, 4, 4, 4, 4, - 4, 4, 4, 6, 0, 0, 7, 0, 8, 8, 8, 8, 8, 8, 8, 9, - 10, 11, 11, 11, 11, 11, 12, 11, 13, 13, 13, 13, 14, 13, 13, 13, - 13, 13, 13, 15, 16, 16, 16, 16, 16, 17, 18, 18, 18, 18, 18, 18, - 19, 20, 21, 21, 22, 23, 21, 24, 21, 21, 21, 21, 21, 25, 21, 21, - 26, 26, 26, 26, 26, 21, 21, 21, 27, 27, 27, 27, 28, 28, 28, 28, - 29, 29, 29, 29, 30, 30, 26, 21, 21, 21, 31, 21, 32, 32, 32, 32, - 32, 33, 34, 32, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, - 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, - 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 45, 44, 44, 44, 44, - 46, 46, 46, 46, 47, 47, 47, 47, 47, 48, 47, 47, 49, 49, 49, 49, - 49, 49, 50, 50, 50, 50, 50, 51, 52, 52, 52, 52, 53, 53, 53, 53, - 53, 53, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 57, 57, - 57, 57, 58, 57, 59, 59, 60, 61, 62, 62, 63, 63, 64, 64, 64, 64, - 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 55, 67, 67, 67, 67, - 67, 68, 68, 68, 69, 69, 69, 69, 69, 69, 64, 64, 70, 70, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 8, 72, 72, 72, 72, 73, 73, 73, 73, - 74, 74, 74, 74, 75, 75, 75, 75, 75, 76, 76, 76, 13, 50, 50, 50, - 73, 77, 78, 79, 4, 4, 80, 4, 4, 81, 82, 83, 4, 4, 4, 84, - 11, 11, 11, 11, 85, 0, 0, 0, 0, 0, 0, 86, 0, 4, 0, 0, - 0, 8, 8, 8, 0, 0, 87, 88, 89, 0, 4, 4, 6, 0, 0, 0, - 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, 4, 4, 92, 92, 92, 92, - 50, 50, 50, 93, 93, 93, 93, 93, 53, 53, 13, 13, 94, 94, 94, 94, - 94, 94, 94, 0, 95, 0, 96, 97, 98, 99, 99, 99, 99,100,101,102, - 102,102,102,103,104,104,104,105, 52, 0,104,104, 0, 0, 0,102, - 52, 52, 0, 0, 0, 0, 52,106, 0,102,102,107,102,102,102,102, - 102,108, 0, 0,109,109,109,109,109,110,110,110,111,111,111,111, - 13, 13,112,112,112,112,112,112, 0, 0,113, 4,114, 4, 4, 4, - 115,115,115, 0,116,116,116,116,117,117,117,117,117,117, 32, 32, - 118,118,119,120,120,120, 52, 52,121,121,121,121,122,121, 49, 49, - 123,123,123,123,123,123, 49, 49,124,124,124,124,124,124,125,125, - 53, 53, 53, 4, 4,126,127, 54,125,125,125,125,128,128,128,128, - 4,129, 18, 18, 18, 21, 21, 21, 21, 21, 21,130, 8, 0,131, 0, - 0, 0, 0, 21, 21, 21, 21,132, 0, 0, 1, 2, 1, 2,133,101, - 102,134, 52, 52,135,135,135,135, 11, 0, 11, 11, 11, 0, 0,136, - 137,137,138,138,138,138,139, 0,140,140,140,141,141,142,142,142, - 143,143,144,144,144,144,144,144,145,145,145,145,145,146,146,146, - 147,147,147,148,148,148,148,148,149,149,149,150,150,150,150,151, - 151,151,151,151,152,152,152,152,153,153,153,153,154,154,154,154, - 155,155,156,156,157,157,157,157,157,157,158,158,159,159,160,160, - 160,160,160,160,161,161,162,162,162,162,162,162,163,163,163,163, - 163,163,164,164,165,165,165,165,166,166,166,166,167,167,167,167, - 168,168,169,169,170,170,170,170,171,171,171,171,172,172,172,172, - 173,173,173,173,174,174,174,174,175,175,175,175,176, 21, 21, 21, - 177,177,177,178,178,178,178,179,179,179,179,180,180,180,181,181, - 182,182,182,182,183,183,183,183,183,184,184,184,185,185,185,185, - 185,186,186,186,187,187,187,187,187,187,188, 43,189,189,189,189, - 190,190,190,191,191,191,191,191,192,192,192,193,192,192,192,192, - 194,194,194,194,195,195,195,195,196,196,196,196,197,197,197,197, - 198,198,198,198,198,198, 66, 66,199,199,199,199,199, 49, 49, 49, - 200,200,200,200,201,201,201,201,202,202,202,202,203,203,203,203, - 204,204,204,204,205,205,205,205,205,206,206,206,206,206,206, 55, - 207,207,207,207,208,208,208,208,209,209,209,209,209,209,209,210, - 210,210,210,210,211,211,211,211,211,211,212,212,212,212,212,212, - 213,213,213,213,214,214,214,214,110,110,110,110,215,215,215,215, - 216,216,216,216,217,217,217,217,218,218,218,218,219,219,219,219, - 220,220,220,221,221,221,221,221,221,222,222,222,223,223,223,223, - 224,224,224,224,225,225,225,225,226,226,226,226,226,226,227, 94, - 228,228,228,228,229,229,229,229,230, 99, 99, 99, 99, 99, 99, 99, - 99, 99,102,231, 99,232,102,233,233,233,233,233,234,234,234,234, - 234,234, 0, 0, 8, 0, 0, 0, 0, 0,235,236,237, 0,238, 0, - 239,239,239,239, 91, 91, 91, 13,240,240,240,240,241,241,241,241, - 242,242,242,242,243,243,243,243,244,244,244,244,245,245,245,245, - 246,246,246,246,247, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, - 2, 2, 3, 0, 0, 0, 4, 0, 2, 2, 2, 2, 2, 3, 2, 2, - 2, 2, 5, 0, 2, 5, 6, 0, 7, 7, 7, 7, 8, 9, 8, 10, - 8, 11, 8, 8, 8, 8, 8, 8, 12, 13, 13, 13, 14, 14, 14, 14, - 14, 15, 14, 14, 16, 17, 17, 17, 17, 17, 17, 17, 18, 19, 19, 19, - 19, 19, 19, 19, 20, 21, 20, 22, 20, 20, 23, 23, 20, 20, 20, 20, - 22, 20, 24, 7, 7, 25, 20, 20, 26, 20, 20, 20, 20, 20, 20, 21, - 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, - 31, 31, 31, 31, 32, 20, 20, 20, 33, 33, 33, 33, 34, 35, 33, 33, - 33, 36, 33, 33, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, - 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, - 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 47, - 48, 48, 48, 48, 49, 49, 49, 49, 49, 50, 51, 49, 52, 52, 52, 52, - 53, 53, 53, 53, 53, 53, 54, 53, 55, 55, 55, 55, 56, 56, 56, 56, - 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, - 60, 60, 61, 62, 63, 63, 63, 63, 64, 64, 64, 64, 64, 65, 0, 0, - 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 70, 71, 71, - 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, - 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78, - 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 7, 7, 7, - 83, 7, 84, 85, 0, 84, 86, 0, 2, 87, 88, 2, 2, 2, 2, 89, - 90, 87, 91, 2, 2, 2, 92, 2, 2, 2, 2, 93, 0, 0, 0, 86, - 1, 0, 0, 94, 0, 95, 96, 0, 4, 0, 0, 0, 0, 0, 0, 4, - 97, 97, 97, 97, 98, 98, 98, 98, 13, 13, 13, 13, 99, 99, 99, 99, - 100,100,100,100, 0,101, 0, 0,102,100,103,104, 0, 0,100, 0, - 105,106,106,106,106,106,106,106,106,106,107,105,108,109,109,109, - 109,109,109,109,109,109,110,108,111,111,111,111,112, 55, 55, 55, - 55, 55, 55,113,109,109,109,110,109,109, 0, 0,114,114,114,114, - 115,115,115,115,116,116,116,116,117,117,117,117, 96, 2, 2, 2, - 2, 2, 94, 2,118,118,118,118,119,119,119,119,120,120,120,120, - 121,121,121,121,121,121,121,122,123,123,123,123,124,124,124,124, - 124,124,124,125,126,126,126,126,127,127,127,127,128,128,128,128, - 2, 2, 3, 2, 2,129,130, 0,131,131,131,131,132, 17, 17, 18, - 20, 20, 20,133, 7, 7, 7,134, 20, 20, 20, 23, 0,135,109,109, - 109,109,109,136,137,137,137,137, 0, 0, 0,138,139,139,139,139, - 140,140,140,140, 84, 0, 0, 0,141,141,141,141,142,142,142,142, - 143,143,143,143,144,144,144,144,145,145,145,145,146,146,146,146, - 147,147,147,147,148,148,148,148,149,149,149,149,150,150,150,150, - 151,151,151,151,152,152,152,152,153,153,153,153,154,154,154,154, - 155,155,155,155,156,156,156,156,157,157,157,157,158,158,158,158, - 159,159,159,159,160,160,160,160,161,161,161,161,162,162,162,162, - 163,163,163,163,164,164,164,164,165,165,165,165,166,166,166,166, - 167,167,167,167,168,168,168,168,169,169,169,169,170,170,170,170, - 171,171,171,171,172,172,172,172,173,173,173,173,174,174,174,174, - 175,175,175,175,176,176,176,176,177, 20, 20, 20,178,178,178,178, - 179,179,179,179,180,180,180,180,181,181,181,181,182,182,182,182, - 183,183,183,183,184,184,184,184,185,185,185,185,186,186,186,186, - 187,187,187,187,188,188,188,188,189, 45, 45, 45,190,190,190,190, - 191,191,191,191,192,192,192,192,193,193,193,193,193,193,194,193, - 195,195,195,195,196,196,196,196,197,197,197,197,198,198,198,198, - 199,199,199,199,200,200,200,200,201,201,201,201,202,202,202,202, - 203,203,203,203,204,204,204,204,205,205,205,205,206,206,206,206, - 207,207,207,207,208,208,208,208,209,209,209,209,210,210,210,210, - 211,211,211,211,212,212,212,212,213,213,213,213,214,214,214,214, - 215,215,215,215,216,216,216,216,217,217,217,217,218,218,218,218, - 219,219,219,219,220,220,220,220,221,221,221,221,222,222,222,222, - 223,223,223,223,224,224,224,224,225,225,225,225,226,226,226,226, - 227,227,227,227,228,229,229,229,230,230,230,230,229,229,229,229, - 231,106,106,106,232,106,106,106,106,233,109,109,234,234,234,234, - 235,235,235,235, 0,236, 86, 0, 0, 0,236, 7, 82,138, 7, 0, - 0, 0,237, 86,238,238,238,238,239,239,239,239,240,240,240,240, - 241,241,241,241,242,242,242,242,243,243,243,243,244,244,244,244, - 245,245,245,245,246, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 0, 19, 0, 0, 0, - 0, 0, 26, 26, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, - 9, 9, 0, 9, 9, 0, 9, 0, 9, 9, 55, 55, 55, 55, 55, 55, - 6, 6, 6, 6, 6, 1, 1, 6, 6, 4, 4, 4, 4, 4, 4, 4, - 4, 14, 14, 14, 14, 14, 14, 14, 3, 3, 3, 3, 3, 0, 3, 3, - 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 1, 1, 1, 3, 3, - 1, 3, 3, 3, 37, 37, 37, 37, 38, 38, 38, 38, 64, 64, 64, 64, - 90, 90, 90, 90, 95, 95, 95, 95, 3, 3, 0, 3, 7, 7, 7, 7, - 7, 1, 1, 1, 1, 7, 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, - 11, 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21, 22, 22, 22, 22, - 23, 23, 23, 23, 16, 16, 16, 16, 20, 20, 20, 20, 36, 36, 36, 36, - 24, 24, 24, 24, 24, 24, 24, 0, 18, 18, 18, 18, 25, 25, 25, 25, - 25, 0, 0, 0, 0, 25, 25, 25, 33, 33, 33, 33, 8, 8, 8, 8, - 8, 8, 8, 0, 12, 12, 12, 12, 30, 30, 30, 30, 29, 29, 29, 29, - 28, 28, 28, 28, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 0, - 0, 0, 35, 35, 45, 45, 45, 45, 44, 44, 44, 44, 44, 0, 0, 0, - 43, 43, 43, 43, 46, 46, 46, 46, 31, 31, 31, 31, 32, 32, 0, 0, - 32, 0, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 52, 52, 52, 52, - 58, 58, 58, 58, 54, 54, 54, 54, 91, 91, 91, 91, 62, 62, 62, 62, - 76, 76, 76, 76, 93, 93, 93, 93, 70, 70, 70, 70, 73, 73, 73, 73, - 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, - 1, 1, 0, 0, 19, 19, 9, 9, 9, 9, 9, 6, 19, 9, 9, 9, - 9, 9, 19, 19, 9, 9, 9, 19, 6, 19, 19, 19, 19, 19, 19, 9, - 0, 0, 0, 19, 0, 0, 9, 0, 0, 0, 19, 19, 27, 27, 27, 27, - 56, 56, 56, 56, 61, 61, 61, 61, 13, 13, 13, 13, 0, 13, 0, 13, - 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 0, 15, 15, 15, - 15, 15, 15, 15, 15, 1, 1, 0, 0, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 0, 26, 26, 26, 26, 26, 12, 12, 12, 12, 12, 12, 0, - 39, 39, 39, 39, 86, 86, 86, 86, 77, 77, 77, 77, 79, 79, 79, 79, - 60, 60, 60, 60, 65, 65, 65, 65, 75, 75, 75, 75, 69, 69, 69, 69, - 69, 69, 0, 69, 74, 74, 74, 74, 84, 84, 84, 84, 84, 84, 84, 0, - 68, 68, 68, 68, 92, 92, 92, 92, 87, 87, 87, 87, 19, 9, 19, 19, - 19, 19, 0, 0, 2, 2, 2, 2, 19, 19, 19, 4, 3, 3, 0, 0, - 1, 1, 6, 6, 0, 0, 17, 17, 17, 17, 0, 0, 49, 49, 49, 49, - 0, 1, 1, 1, 71, 71, 71, 71, 67, 67, 67, 67, 42, 42, 42, 42, - 41, 41, 41, 41,118,118,118,118, 53, 53, 53, 53, 59, 59, 59, 59, - 40, 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50,135,135,135,135, - 106,106,106,106,104,104,104,104,161,161,161,161,170,170,170,170, - 110,110,110,110, 47, 47, 47, 47, 81, 81, 81, 81,120,120,120,120, - 116,116,116,116,128,128,128,128, 66, 66, 66, 66, 72, 72, 72, 72, - 98, 98, 98, 98, 97, 97, 97, 97, 57, 57, 57, 57, 88, 88, 88, 88, - 117,117,117,117,112,112,112,112, 78, 78, 78, 78, 83, 83, 83, 83, - 82, 82, 82, 82,122,122,122,122, 89, 89, 89, 89,130,130,130,130, - 144,144,144,144,165,165,165,165,156,156,156,156,156,156, 3, 3, - 147,147,147,147,148,148,148,148,158,158,158,158,153,153,153,153, - 149,149,149,149, 94, 94, 94, 94, 85, 85, 85, 85,101,101,101,101, - 96, 96, 96, 96,111,111,111,111,100,100,100,100,100, 36, 36, 36, - 108,108,108,108,129,129,129,129,109,109,109,109,107,107,107,107, - 107,107,107, 1,171,171,171,171,137,137,137,137,124,124,124,124, - 123,123,123,123,114,114,114,114,102,102,102,102,126,126,126,126, - 142,142,142,142,125,125,125,125,154,154,154,154,150,150,150,150, - 141,141,141,141,140,140,140,140,121,121,121,121,169,169,169,169, - 133,133,133,133,134,134,134,134,138,138,138,138,143,143,143,143, - 145,145,145,145,163,163,163,163, 63, 63, 63, 63,157,157,157,157, - 80, 80, 80, 80,127,127,127,127,166,166,166,166,115,115,115,115, - 159,159,159,159,103,103,103,103,119,119,119,119,167,167,167,167, - 146,146,146,146, 99, 99, 99, 99,136,139, 13, 13,155,155,155,155, - 136,136,136,136, 17, 15, 15, 15, 17, 17, 15, 15, 15, 17, 17, 17, - 139,139,139,139,105,105,105,105, 0, 0, 0, 1, 0, 0, 1, 1, - 131,131,131,131,151,151,151,151,160,160,160,160,152,152,152,152, - 164,164,164,164,168,168,168,168,113,113,113,113,132,132,132,132, - 15, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, - 9, 10, 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 16, 17, 9, 9, 9, 9, 18, 9, 9, 9, 9, 9, 19, 20, 21, 9, - 22, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 23, 9, 9, 9, 9, 9, 24, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 25, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, - 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, - 0, 0, 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, - 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, - 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, - 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, - 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, - 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100, - 101,102,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0,107, 0, - 0, 0,108, 0,109, 0,110, 0,111,112,113, 0,114, 0, 0, 0, - 115, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,118,119,120,121, 0,122,123,124,125,126, - 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,128,129,130,131,132,133,134,135,136,137,138,139,140,141, - 142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157, - 0, 0, 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,162, 0, - 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,164,165, 0, 0, 0, - 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,167, 0, 0, 0,168,169, 0, 0,170, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,171, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,172, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,175, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,176,177, 0, 0, 0, 0,178,179, 0, - 0, 0,180,181,182,183,184,185,186,187,188,189,190,191,192,193, - 194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209, - 210,211,212,213, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, - 3, 4, -}; -static const uint16_t -_hb_ucd_u16[5080] = -{ - 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12, - 13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23, - 13, 13, 13, 24, 25, 11, 11, 11, 11, 26, 11, 27, 28, 29, 30, 31, - 32, 32, 32, 32, 32, 32, 32, 33, 34, 35, 36, 11, 37, 38, 13, 39, - 9, 9, 9, 11, 11, 11, 13, 13, 40, 13, 13, 13, 41, 13, 13, 13, - 13, 13, 13, 35, 9, 42, 11, 11, 43, 44, 32, 45, 46, 47, 47, 48, - 49, 50, 47, 47, 51, 32, 52, 53, 47, 47, 47, 47, 47, 54, 55, 56, - 57, 58, 47, 32, 59, 47, 47, 47, 47, 47, 60, 53, 61, 47, 62, 63, - 47, 64, 65, 66, 47, 67, 47, 47, 68, 69, 47, 47, 70, 32, 71, 32, - 72, 47, 47, 73, 74, 75, 76, 77, 78, 47, 47, 79, 80, 81, 82, 83, - 84, 47, 47, 85, 86, 87, 88, 89, 84, 47, 47, 79, 90, 47, 82, 91, - 92, 47, 47, 93, 94, 95, 82, 96, 97, 47, 47, 98, 99, 100, 101, 102, - 103, 47, 47, 104, 105, 106, 82, 107, 108, 47, 47, 93, 109, 110, 82, 111, - 112, 47, 47, 113, 114, 115, 82, 116, 92, 47, 47, 47, 117, 118, 101, 119, - 47, 47, 47, 120, 121, 122, 66, 66, 47, 47, 47, 123, 124, 125, 47, 47, - 126, 127, 128, 129, 47, 47, 47, 130, 131, 32, 32, 132, 133, 134, 66, 66, - 47, 47, 135, 136, 122, 137, 138, 139, 140, 141, 9, 9, 9, 11, 11, 142, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 143, 144, 145, - 47, 146, 9, 9, 9, 9, 9, 147, 148, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 149, 47, 150, 151, 47, 47, 47, 47, 152, 153, - 47, 154, 47, 155, 47, 156, 47, 156, 47, 47, 47, 157, 158, 159, 160, 145, - 161, 160, 47, 47, 162, 47, 47, 47, 163, 47, 164, 47, 47, 47, 47, 47, - 47, 47, 165, 166, 167, 47, 47, 47, 47, 47, 47, 47, 47, 168, 146, 146, - 47, 169, 47, 47, 47, 170, 171, 172, 160, 160, 173, 174, 32, 32, 32, 32, - 175, 47, 47, 176, 177, 122, 178, 179, 180, 47, 181, 61, 47, 47, 182, 183, - 47, 47, 184, 185, 186, 61, 47, 187, 188, 9, 9, 9, 66, 189, 190, 191, - 11, 11, 192, 27, 27, 27, 193, 194, 11, 195, 27, 27, 32, 32, 32, 32, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 196, 13, 13, 13, 13, 13, 13, - 197, 197, 197, 197, 197, 198, 197, 11, 199, 199, 199, 200, 201, 202, 202, 201, - 203, 204, 205, 206, 207, 208, 209, 210, 211, 27, 212, 212, 212, 213, 214, 32, - 215, 216, 217, 218, 219, 145, 220, 220, 221, 222, 223, 146, 224, 225, 146, 226, - 227, 227, 227, 227, 227, 227, 227, 227, 228, 146, 229, 146, 146, 146, 146, 230, - 146, 231, 227, 232, 146, 233, 234, 146, 146, 146, 146, 146, 146, 146, 145, 145, - 145, 235, 146, 146, 146, 146, 236, 145, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 237, 238, 146, 146, 239, 146, 146, 146, 146, 146, 146, 240, 146, - 146, 146, 146, 146, 146, 146, 241, 242, 145, 243, 146, 146, 244, 227, 245, 227, - 246, 247, 227, 227, 227, 248, 227, 249, 146, 146, 146, 227, 250, 146, 146, 146, - 9, 9, 9, 11, 11, 11, 251, 252, 13, 13, 13, 13, 13, 13, 253, 254, - 11, 11, 11, 47, 47, 47, 255, 256, 47, 47, 47, 47, 47, 47, 32, 32, - 257, 258, 259, 260, 261, 262, 263, 263, 264, 265, 266, 267, 268, 47, 47, 47, - 47, 269, 148, 47, 47, 47, 47, 270, 47, 271, 47, 47, 146, 146, 146, 47, - 146, 146, 272, 146, 273, 274, 146, 146, 272, 146, 146, 274, 146, 146, 146, 146, - 47, 47, 47, 47, 146, 146, 146, 146, 47, 275, 47, 47, 47, 47, 47, 47, - 47, 146, 146, 146, 146, 47, 47, 187, 276, 47, 61, 47, 13, 13, 277, 278, - 13, 279, 47, 47, 47, 47, 280, 281, 31, 282, 283, 284, 13, 13, 13, 285, - 286, 287, 288, 289, 290, 291, 9, 292, 293, 47, 294, 295, 47, 47, 47, 296, - 297, 47, 47, 298, 299, 160, 32, 300, 61, 47, 301, 47, 302, 303, 47, 47, - 72, 47, 47, 304, 305, 306, 307, 61, 47, 47, 308, 309, 310, 311, 47, 312, - 47, 47, 47, 313, 58, 314, 315, 316, 47, 47, 47, 11, 11, 317, 318, 11, - 11, 11, 11, 11, 47, 47, 319, 160, 320, 320, 320, 320, 320, 320, 320, 320, - 321, 321, 321, 321, 321, 321, 321, 321, 11, 322, 323, 47, 47, 47, 47, 47, - 47, 47, 47, 324, 31, 325, 47, 47, 47, 47, 47, 326, 146, 47, 47, 47, - 47, 47, 47, 47, 327, 146, 146, 328, 32, 329, 32, 330, 331, 332, 333, 47, - 47, 47, 47, 47, 47, 47, 47, 334, 335, 2, 3, 4, 5, 336, 337, 338, - 47, 339, 47, 47, 47, 47, 340, 341, 342, 145, 145, 343, 220, 220, 220, 344, - 345, 146, 146, 146, 146, 146, 146, 346, 347, 347, 347, 347, 347, 347, 347, 347, - 47, 47, 47, 47, 47, 47, 348, 145, 47, 47, 349, 47, 350, 47, 47, 60, - 47, 351, 47, 47, 47, 352, 220, 220, 9, 9, 147, 11, 11, 47, 47, 47, - 47, 47, 160, 9, 9, 147, 11, 11, 47, 47, 47, 47, 47, 47, 351, 9, - 9, 353, 11, 11, 47, 47, 47, 47, 27, 27, 27, 27, 27, 27, 27, 27, - 47, 47, 47, 47, 47, 354, 47, 355, 47, 47, 356, 145, 145, 145, 47, 357, - 47, 358, 47, 351, 66, 66, 66, 66, 47, 47, 47, 359, 145, 145, 145, 145, - 360, 47, 47, 361, 145, 66, 47, 362, 47, 363, 145, 145, 364, 47, 365, 66, - 47, 47, 47, 366, 47, 367, 47, 367, 47, 366, 144, 145, 145, 145, 145, 145, - 9, 9, 9, 9, 11, 11, 11, 368, 47, 47, 369, 160, 370, 9, 371, 11, - 372, 227, 227, 227, 227, 227, 227, 227, 145, 145, 145, 145, 145, 145, 145, 145, - 47, 47, 373, 47, 47, 47, 47, 374, 47, 363, 375, 47, 60, 376, 66, 47, - 377, 66, 66, 47, 378, 145, 47, 47, 379, 47, 47, 361, 380, 381, 382, 383, - 180, 47, 47, 384, 385, 47, 47, 160, 97, 47, 386, 387, 388, 47, 47, 389, - 180, 47, 47, 390, 391, 392, 393, 145, 47, 47, 394, 395, 360, 32, 32, 32, - 47, 47, 366, 47, 47, 396, 172, 160, 92, 47, 47, 113, 397, 398, 399, 32, - 47, 47, 47, 400, 401, 402, 403, 32, 47, 47, 47, 404, 405, 406, 47, 47, - 47, 47, 47, 407, 408, 160, 160, 160, 47, 47, 409, 410, 411, 412, 32, 32, - 47, 47, 47, 413, 414, 160, 66, 66, 47, 47, 415, 416, 160, 160, 160, 160, - 47, 417, 418, 419, 47, 47, 47, 47, 47, 47, 394, 420, 66, 66, 66, 66, - 9, 9, 9, 9, 11, 11, 128, 421, 47, 47, 47, 422, 423, 160, 160, 160, - 47, 47, 47, 47, 47, 424, 425, 426, 427, 47, 47, 428, 429, 430, 47, 47, - 431, 432, 66, 47, 47, 47, 47, 47, 66, 66, 66, 66, 66, 66, 66, 66, - 47, 47, 47, 47, 47, 47, 433, 160, 47, 47, 409, 434, 433, 128, 145, 435, - 47, 156, 436, 437, 32, 32, 32, 32, 47, 47, 47, 360, 438, 160, 47, 47, - 439, 440, 160, 160, 160, 160, 160, 160, 47, 47, 47, 47, 47, 47, 47, 441, - 442, 47, 47, 443, 444, 445, 32, 32, 47, 47, 47, 47, 145, 446, 447, 448, - 220, 220, 220, 220, 220, 220, 220, 66, 47, 47, 47, 47, 47, 47, 47, 433, - 47, 47, 47, 209, 449, 32, 47, 47, 47, 450, 451, 160, 160, 160, 160, 160, - 47, 47, 47, 47, 47, 47, 306, 47, 47, 47, 47, 47, 160, 47, 47, 452, - 47, 47, 47, 453, 454, 455, 456, 47, 27, 27, 27, 27, 457, 47, 458, 160, - 9, 9, 9, 9, 9, 9, 11, 11, 145, 459, 66, 66, 66, 66, 66, 66, - 47, 47, 47, 47, 396, 460, 426, 426, 461, 462, 27, 27, 27, 27, 463, 426, - 47, 464, 209, 209, 209, 209, 209, 209, 146, 146, 146, 146, 146, 146, 146, 160, - 32, 32, 32, 32, 32, 146, 146, 146, 146, 146, 146, 146, 146, 146, 465, 466, - 467, 146, 468, 146, 146, 146, 146, 146, 146, 146, 146, 146, 469, 146, 146, 146, - 9, 470, 11, 471, 472, 11, 197, 9, 473, 474, 9, 475, 11, 9, 470, 11, - 471, 472, 11, 197, 9, 473, 474, 9, 475, 11, 9, 470, 11, 471, 472, 11, - 197, 9, 473, 474, 9, 475, 11, 9, 470, 11, 197, 9, 476, 477, 478, 479, - 11, 480, 9, 481, 482, 483, 484, 11, 485, 9, 486, 11, 487, 160, 160, 160, - 32, 32, 32, 488, 32, 32, 489, 490, 491, 492, 32, 32, 32, 32, 32, 32, - 493, 11, 11, 11, 11, 11, 11, 11, 32, 32, 32, 27, 27, 27, 27, 27, - 32, 32, 32, 32, 32, 32, 32, 32, 47, 47, 47, 494, 495, 146, 146, 146, - 47, 47, 450, 32, 47, 47, 374, 496, 47, 47, 47, 47, 47, 47, 497, 160, - 47, 47, 47, 47, 47, 47, 450, 498, 47, 47, 47, 47, 356, 32, 32, 32, - 9, 9, 473, 11, 499, 306, 66, 66, 145, 145, 500, 501, 145, 145, 145, 145, - 145, 145, 502, 145, 145, 145, 145, 145, 47, 47, 47, 47, 47, 47, 47, 227, - 503, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 504, - 209, 209, 209, 209, 209, 209, 209, 209, 0, 0, 0, 0, 0, 0, 0, 0, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 716, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 717, + 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 3, 3, 4, 5, 4, 5, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 0, 0, 7, 0, + 8, 8, 8, 8, 8, 8, 8, 9, 10, 11, 12, 11, 11, 11, 13, 11, + 14, 14, 14, 14, 14, 14, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 16, 17, 18, 17, 17, 19, 20, 21, 21, 22, 21, 23, 24, + 25, 26, 27, 27, 28, 29, 27, 30, 27, 27, 27, 27, 27, 31, 27, 27, + 32, 33, 33, 33, 34, 27, 27, 27, 35, 35, 35, 36, 37, 37, 37, 38, + 39, 39, 40, 41, 42, 43, 44, 27, 27, 45, 27, 27, 27, 27, 46, 27, + 47, 47, 47, 47, 47, 48, 49, 47, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 108, 109, 110, 111, 108, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 121, 122, 121, 123, 124, 124, 125, 126, 127, 128, 129, 130, 124, 124, + 131, 131, 131, 131, 132, 131, 133, 134, 131, 132, 131, 135, 135, 136, 124, 124, + 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 138, 138, 139, 138, 138, 140, + 141, 141, 141, 141, 141, 141, 141, 141, 142, 142, 142, 142, 143, 144, 142, 142, + 143, 142, 142, 145, 146, 147, 142, 142, 142, 146, 142, 142, 142, 148, 142, 149, + 142, 150, 151, 151, 151, 151, 151, 152, 153, 153, 153, 153, 153, 153, 153, 153, + 154, 155, 156, 156, 156, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 167, 167, 167, 167, 168, 169, 169, 170, 171, 172, 172, 172, 172, 172, 173, + 172, 172, 174, 153, 153, 153, 153, 175, 176, 177, 178, 178, 179, 180, 181, 182, + 183, 183, 184, 183, 185, 186, 167, 167, 187, 188, 189, 189, 189, 190, 189, 191, + 192, 192, 193, 8, 8, 194, 195, 124, 196, 196, 196, 196, 197, 196, 196, 196, + 198, 198, 198, 198, 199, 199, 199, 200, 201, 201, 201, 202, 203, 204, 204, 204, + 205, 138, 138, 206, 207, 208, 209, 210, 4, 4, 211, 4, 4, 212, 213, 214, + 4, 4, 4, 215, 8, 8, 8, 8, 11, 216, 11, 11, 216, 217, 11, 218, + 11, 11, 11, 219, 219, 220, 11, 221, 222, 0, 0, 0, 0, 0, 223, 224, + 225, 226, 0, 0, 227, 8, 8, 228, 0, 0, 229, 230, 231, 0, 4, 4, + 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 233, 124, 234, 124, 0, 0, 235, 235, 235, 235, 235, 235, 235, 235, + 0, 0, 0, 0, 0, 0, 0, 236, 237, 237, 237, 237, 237, 237, 4, 4, + 238, 238, 238, 238, 238, 238, 238, 239, 138, 138, 139, 240, 240, 240, 241, 242, + 142, 243, 244, 244, 244, 244, 14, 14, 0, 0, 0, 0, 0, 245, 124, 124, + 246, 247, 246, 246, 246, 246, 246, 248, 246, 246, 246, 246, 246, 246, 246, 246, + 246, 246, 246, 246, 246, 249, 124, 0, 250, 0, 251, 252, 253, 254, 254, 254, + 254, 255, 256, 257, 257, 257, 257, 258, 259, 260, 260, 261, 141, 141, 141, 141, + 262, 0, 260, 260, 0, 0, 263, 257, 141, 262, 0, 0, 0, 0, 141, 264, + 0, 0, 0, 0, 0, 257, 257, 265, 257, 257, 257, 257, 257, 266, 0, 0, + 246, 246, 246, 246, 0, 0, 0, 0, 267, 267, 267, 267, 267, 267, 267, 267, + 268, 267, 267, 267, 269, 270, 270, 270, 271, 271, 271, 271, 271, 271, 271, 271, + 271, 271, 272, 124, 14, 14, 14, 14, 14, 14, 273, 273, 273, 273, 273, 274, + 0, 0, 275, 4, 4, 4, 4, 4, 276, 4, 4, 4, 4, 226, 124, 277, + 278, 278, 279, 233, 280, 280, 280, 281, 282, 282, 282, 282, 283, 284, 47, 47, + 285, 285, 286, 287, 287, 288, 141, 289, 290, 290, 290, 290, 291, 292, 137, 293, + 294, 294, 294, 295, 296, 297, 137, 137, 298, 298, 298, 298, 299, 300, 301, 302, + 303, 304, 244, 4, 4, 305, 306, 151, 151, 151, 151, 151, 301, 301, 307, 308, + 141, 141, 309, 141, 310, 141, 141, 311, 124, 124, 124, 124, 124, 124, 124, 124, + 246, 246, 246, 246, 246, 246, 312, 246, 246, 246, 246, 246, 246, 313, 124, 124, + 314, 315, 21, 316, 317, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 318, 27, 27, 27, 27, 27, 27, 27, 27, 27, 124, 124, 27, + 8, 233, 319, 0, 0, 320, 321, 322, 27, 27, 27, 27, 27, 27, 27, 323, + 324, 0, 1, 2, 1, 2, 325, 256, 257, 326, 141, 262, 327, 328, 329, 330, + 331, 332, 333, 334, 335, 335, 124, 124, 332, 332, 332, 332, 332, 332, 332, 336, + 337, 0, 0, 338, 11, 11, 11, 11, 339, 340, 341, 124, 124, 0, 0, 342, + 343, 344, 345, 345, 345, 346, 347, 348, 349, 349, 350, 351, 352, 353, 353, 354, + 355, 356, 357, 357, 358, 359, 124, 124, 360, 360, 360, 360, 360, 361, 361, 361, + 362, 363, 364, 365, 365, 366, 365, 367, 368, 368, 369, 370, 370, 370, 371, 372, + 372, 373, 374, 375, 376, 376, 376, 377, 378, 378, 378, 378, 378, 378, 378, 378, + 378, 378, 378, 379, 378, 380, 381, 124, 382, 4, 4, 383, 124, 124, 124, 124, + 384, 385, 385, 386, 387, 388, 389, 389, 390, 391, 392, 124, 124, 124, 393, 394, + 395, 396, 397, 398, 399, 400, 124, 124, 401, 401, 402, 403, 402, 404, 402, 402, + 405, 406, 407, 408, 409, 409, 410, 410, 411, 411, 124, 124, 412, 412, 413, 414, + 415, 415, 415, 416, 417, 418, 419, 420, 421, 422, 423, 124, 124, 124, 124, 124, + 424, 424, 424, 424, 425, 124, 124, 124, 426, 426, 426, 427, 426, 426, 426, 428, + 429, 429, 430, 431, 432, 432, 433, 432, 434, 124, 124, 124, 124, 124, 124, 124, + 124, 124, 124, 124, 124, 124, 27, 435, 436, 436, 437, 438, 439, 440, 124, 441, + 442, 442, 443, 444, 444, 445, 124, 446, 447, 124, 124, 448, 449, 124, 450, 451, + 452, 452, 452, 452, 453, 454, 452, 455, 456, 456, 456, 456, 457, 458, 459, 460, + 461, 461, 461, 462, 463, 464, 464, 465, 466, 466, 466, 466, 466, 466, 467, 468, + 469, 470, 469, 469, 471, 124, 124, 124, 472, 473, 474, 475, 475, 475, 476, 477, + 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 487, 488, 489, 490, 491, 124, + 492, 492, 492, 492, 492, 493, 494, 124, 495, 495, 495, 495, 496, 497, 124, 124, + 498, 498, 498, 499, 498, 500, 124, 124, 501, 501, 501, 501, 502, 503, 504, 124, + 505, 505, 505, 506, 506, 137, 507, 124, 508, 509, 510, 508, 511, 124, 124, 124, + 512, 512, 512, 513, 124, 124, 124, 124, 124, 124, 514, 514, 514, 514, 514, 515, + 516, 517, 518, 519, 520, 521, 124, 124, 124, 124, 522, 523, 523, 522, 524, 124, + 525, 525, 525, 525, 526, 527, 527, 527, 527, 527, 528, 153, 529, 529, 529, 530, + 531, 124, 124, 124, 124, 124, 532, 124, 124, 124, 124, 124, 533, 533, 534, 535, + 536, 537, 537, 538, 539, 537, 540, 541, 541, 542, 543, 544, 124, 124, 124, 124, + 545, 546, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 555, 556, 557, 124, + 124, 124, 124, 124, 124, 124, 558, 559, 560, 561, 560, 562, 560, 563, 124, 124, + 124, 124, 124, 564, 565, 565, 565, 566, 567, 567, 567, 567, 567, 567, 567, 567, + 567, 568, 124, 124, 124, 124, 124, 124, 567, 567, 567, 567, 567, 567, 569, 570, + 567, 567, 567, 567, 571, 124, 124, 124, 124, 572, 572, 572, 572, 572, 572, 573, + 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 575, 574, 574, + 574, 574, 574, 574, 574, 574, 574, 576, 577, 577, 577, 577, 577, 577, 577, 577, + 577, 577, 577, 577, 578, 124, 124, 124, 579, 579, 579, 580, 124, 124, 124, 124, + 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 581, 582, 583, 584, 585, + 585, 585, 585, 586, 587, 588, 589, 590, 591, 591, 591, 591, 592, 593, 594, 595, + 591, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 596, 596, 596, 597, + 124, 124, 124, 124, 598, 598, 598, 598, 598, 599, 600, 601, 600, 602, 124, 124, + 603, 603, 603, 603, 604, 603, 603, 603, 605, 603, 124, 124, 124, 124, 606, 607, + 608, 608, 608, 608, 608, 608, 608, 608, 609, 609, 609, 609, 609, 609, 609, 609, + 609, 609, 609, 609, 609, 610, 124, 611, 608, 612, 124, 124, 124, 124, 124, 124, + 608, 608, 608, 608, 608, 608, 608, 613, 124, 124, 124, 124, 124, 124, 124, 614, + 615, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 616, 617, 124, 618, 619, 620, 620, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 620, 620, 621, 622, 622, 622, 622, 622, 622, 623, 624, + 625, 626, 627, 124, 124, 124, 124, 124, 0, 0, 0, 0, 0, 0, 0, 340, + 0, 0, 0, 628, 0, 629, 0, 629, 8, 8, 194, 8, 630, 0, 0, 0, + 0, 0, 0, 0, 627, 124, 124, 124, 0, 0, 0, 0, 0, 0, 0, 631, + 0, 0, 632, 0, 0, 0, 633, 634, 635, 0, 636, 0, 0, 0, 234, 124, + 11, 11, 11, 11, 637, 124, 124, 124, 124, 124, 124, 124, 0, 627, 0, 627, + 0, 0, 0, 0, 0, 638, 0, 639, 0, 0, 0, 0, 0, 223, 0, 0, + 0, 640, 641, 642, 643, 0, 0, 0, 644, 645, 0, 646, 647, 648, 0, 0, + 0, 0, 649, 0, 0, 0, 0, 0, 0, 0, 0, 0, 650, 0, 0, 0, + 651, 651, 651, 651, 651, 651, 651, 651, 652, 653, 654, 124, 124, 124, 124, 124, + 4, 655, 656, 124, 124, 124, 124, 124, 657, 658, 659, 14, 14, 14, 660, 124, + 661, 124, 124, 124, 124, 124, 124, 124, 662, 662, 663, 664, 665, 124, 124, 124, + 124, 666, 667, 124, 668, 668, 668, 669, 124, 124, 124, 124, 124, 670, 670, 671, + 124, 124, 124, 124, 124, 672, 672, 673, 124, 124, 124, 124, 674, 675, 674, 676, + 124, 124, 124, 124, 124, 124, 677, 678, 679, 679, 679, 679, 679, 679, 679, 679, + 679, 679, 679, 679, 680, 681, 124, 124, 682, 682, 682, 682, 683, 684, 124, 124, + 124, 124, 124, 124, 124, 124, 124, 324, 0, 0, 0, 685, 124, 124, 124, 124, + 324, 0, 0, 245, 124, 124, 124, 124, 686, 27, 687, 688, 689, 690, 691, 692, + 693, 694, 695, 694, 124, 124, 124, 696, 0, 0, 348, 0, 0, 0, 0, 0, + 0, 627, 225, 324, 324, 324, 0, 631, 0, 0, 245, 124, 124, 124, 697, 0, + 698, 0, 0, 348, 639, 227, 631, 124, 0, 0, 0, 0, 0, 699, 340, 340, + 0, 0, 0, 0, 0, 233, 348, 629, 348, 0, 0, 0, 700, 233, 0, 0, + 700, 0, 245, 348, 227, 639, 124, 124, 0, 0, 0, 0, 0, 700, 245, 340, + 701, 0, 0, 0, 702, 703, 704, 639, 0, 320, 0, 0, 0, 0, 0, 234, + 246, 246, 246, 246, 246, 246, 124, 124, 246, 312, 246, 246, 246, 246, 246, 246, + 246, 246, 312, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 705, 246, + 246, 246, 246, 246, 246, 312, 124, 124, 246, 312, 124, 124, 124, 124, 124, 124, + 246, 246, 246, 246, 706, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 313, + 707, 124, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 1, 2, 2, 2, + 2, 2, 3, 0, 0, 0, 4, 0, 2, 2, 2, 2, 2, 3, 2, 2, + 2, 2, 5, 0, 2, 5, 6, 0, 7, 7, 7, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 8, 8, 8, 8, 16, 8, 8, 8, 17, 18, 18, 18, + 19, 19, 19, 19, 19, 20, 19, 19, 21, 22, 22, 22, 22, 22, 22, 22, + 22, 23, 21, 22, 22, 22, 23, 21, 24, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 12, 12, 25, 25, 26, 27, 25, 28, 12, 12, 29, 30, 29, 31, + 29, 29, 32, 32, 29, 29, 29, 29, 31, 29, 33, 7, 7, 34, 29, 29, + 35, 29, 29, 29, 29, 29, 29, 30, 36, 36, 36, 37, 36, 36, 36, 36, + 36, 36, 38, 39, 40, 40, 40, 40, 41, 12, 12, 12, 42, 42, 42, 42, + 42, 42, 43, 44, 45, 45, 45, 45, 45, 45, 45, 46, 45, 45, 45, 47, + 48, 48, 48, 48, 48, 48, 48, 49, 36, 36, 38, 12, 50, 51, 29, 29, + 52, 29, 29, 29, 53, 53, 53, 53, 54, 55, 53, 53, 53, 56, 53, 53, + 57, 58, 57, 59, 59, 57, 57, 57, 57, 57, 60, 57, 61, 62, 63, 57, + 57, 59, 59, 64, 12, 65, 12, 66, 57, 62, 57, 57, 57, 57, 57, 64, + 67, 67, 68, 69, 70, 71, 71, 71, 71, 71, 72, 71, 72, 73, 74, 72, + 68, 69, 70, 74, 75, 12, 67, 76, 12, 77, 71, 71, 71, 68, 12, 12, + 78, 78, 79, 80, 80, 79, 79, 79, 79, 79, 81, 79, 81, 78, 82, 79, + 79, 80, 80, 82, 83, 12, 12, 12, 79, 84, 79, 79, 82, 12, 78, 79, + 85, 85, 86, 87, 87, 86, 86, 86, 86, 86, 88, 86, 88, 85, 89, 86, + 86, 87, 87, 89, 12, 85, 12, 90, 86, 91, 86, 86, 86, 86, 12, 12, + 92, 93, 94, 92, 95, 96, 97, 95, 98, 99, 94, 92, 100, 100, 96, 92, + 94, 92, 95, 96, 99, 98, 12, 12, 12, 92, 100, 100, 100, 100, 94, 12, + 101, 101, 101, 102, 102, 101, 101, 101, 101, 101, 102, 101, 101, 101, 103, 101, + 101, 102, 102, 103, 12, 104, 105, 103, 101, 106, 101, 101, 12, 107, 101, 101, + 108, 108, 108, 109, 109, 108, 108, 108, 108, 108, 109, 108, 108, 110, 111, 108, + 108, 109, 109, 111, 12, 112, 12, 113, 108, 114, 108, 108, 110, 12, 12, 12, + 115, 115, 115, 116, 116, 115, 115, 115, 115, 115, 115, 115, 115, 116, 116, 115, + 12, 115, 115, 115, 115, 117, 115, 115, 118, 118, 119, 119, 119, 120, 121, 119, + 119, 119, 119, 119, 122, 119, 119, 123, 119, 120, 124, 125, 119, 126, 119, 119, + 12, 121, 119, 119, 121, 127, 12, 12, 128, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 130, 131, 129, 129, 129, 12, 12, 12, 12, 12, 132, 133, 134, 135, + 135, 135, 135, 135, 135, 136, 135, 135, 135, 135, 135, 137, 135, 138, 135, 134, + 135, 135, 137, 135, 139, 139, 139, 139, 139, 139, 140, 139, 139, 139, 139, 141, + 140, 139, 139, 139, 139, 139, 139, 142, 139, 143, 144, 12, 145, 145, 145, 145, + 146, 146, 146, 146, 146, 147, 12, 148, 146, 146, 149, 146, 150, 150, 150, 150, + 151, 151, 151, 151, 151, 151, 152, 153, 151, 154, 152, 153, 152, 153, 151, 154, + 152, 153, 151, 151, 151, 154, 151, 151, 151, 151, 154, 155, 151, 151, 151, 156, + 151, 151, 153, 12, 157, 157, 157, 157, 157, 158, 157, 158, 159, 159, 159, 159, + 160, 160, 160, 160, 160, 160, 160, 161, 162, 162, 162, 162, 162, 162, 163, 164, + 162, 162, 165, 12, 166, 166, 166, 166, 166, 167, 12, 168, 169, 169, 169, 169, + 169, 170, 12, 12, 171, 171, 171, 171, 171, 12, 12, 12, 172, 172, 172, 173, + 173, 12, 12, 12, 174, 174, 174, 174, 174, 174, 174, 175, 174, 174, 175, 12, + 176, 177, 178, 178, 178, 178, 179, 12, 178, 178, 178, 178, 178, 178, 180, 12, + 178, 178, 181, 12, 159, 182, 12, 12, 183, 183, 183, 183, 183, 183, 183, 184, + 183, 183, 183, 12, 185, 183, 183, 183, 186, 186, 186, 186, 186, 186, 186, 187, + 186, 188, 12, 12, 189, 189, 189, 189, 189, 189, 189, 12, 189, 189, 190, 12, + 189, 189, 191, 192, 193, 193, 193, 193, 193, 193, 193, 194, 195, 195, 195, 195, + 195, 195, 195, 196, 195, 195, 195, 197, 195, 195, 198, 12, 195, 195, 195, 198, + 7, 7, 7, 199, 7, 7, 7, 12, 200, 200, 200, 200, 200, 200, 200, 201, + 202, 202, 202, 202, 203, 203, 203, 203, 203, 12, 12, 203, 204, 204, 204, 204, + 204, 204, 205, 204, 204, 204, 206, 207, 208, 208, 208, 208, 19, 19, 209, 12, + 146, 146, 210, 211, 202, 202, 12, 12, 212, 7, 7, 7, 213, 7, 214, 215, + 0, 214, 216, 12, 2, 217, 218, 2, 2, 2, 2, 219, 220, 217, 221, 2, + 2, 2, 222, 2, 2, 2, 2, 223, 8, 224, 8, 224, 8, 8, 225, 225, + 8, 8, 8, 224, 8, 15, 8, 8, 8, 10, 8, 226, 10, 15, 8, 14, + 0, 0, 0, 227, 0, 228, 0, 0, 229, 0, 0, 230, 0, 0, 0, 231, + 2, 2, 2, 232, 233, 12, 12, 12, 234, 12, 12, 12, 0, 235, 236, 0, + 4, 0, 0, 0, 0, 0, 0, 4, 2, 2, 5, 12, 0, 0, 233, 12, + 0, 0, 231, 12, 237, 237, 237, 237, 0, 238, 0, 0, 239, 239, 239, 239, + 18, 18, 18, 18, 18, 12, 240, 18, 241, 241, 241, 241, 241, 241, 12, 242, + 243, 12, 12, 242, 151, 154, 12, 12, 151, 154, 151, 154, 0, 0, 0, 233, + 244, 244, 244, 244, 244, 244, 245, 244, 244, 12, 12, 12, 244, 246, 12, 12, + 0, 247, 0, 0, 248, 244, 249, 250, 0, 0, 244, 0, 251, 252, 252, 252, + 252, 252, 252, 252, 252, 253, 254, 255, 256, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 258, 256, 12, 259, 260, 260, 260, 260, 260, 260, 261, 150, 150, 150, + 150, 150, 150, 262, 0, 233, 12, 131, 150, 150, 150, 263, 257, 257, 257, 258, + 257, 257, 0, 0, 264, 264, 264, 264, 264, 264, 264, 265, 264, 266, 12, 12, + 267, 267, 267, 267, 268, 268, 268, 268, 268, 268, 268, 12, 269, 269, 269, 269, + 269, 269, 12, 12, 236, 2, 2, 2, 2, 2, 230, 2, 270, 2, 2, 2, + 271, 271, 271, 271, 271, 271, 271, 272, 273, 273, 273, 273, 273, 273, 12, 12, + 274, 274, 274, 274, 274, 275, 12, 276, 274, 274, 275, 12, 277, 277, 277, 277, + 277, 277, 277, 278, 279, 279, 279, 279, 279, 12, 12, 280, 150, 150, 150, 281, + 282, 282, 282, 282, 282, 282, 282, 283, 282, 282, 284, 285, 145, 145, 145, 286, + 287, 287, 287, 287, 287, 288, 12, 12, 287, 287, 287, 289, 287, 287, 289, 287, + 290, 290, 290, 290, 291, 12, 12, 12, 12, 12, 292, 290, 293, 293, 293, 293, + 293, 294, 12, 12, 155, 154, 155, 154, 155, 154, 12, 12, 2, 2, 3, 2, + 2, 295, 296, 12, 293, 293, 293, 297, 293, 293, 297, 12, 150, 12, 12, 12, + 150, 262, 298, 150, 150, 150, 150, 12, 244, 244, 244, 246, 244, 244, 246, 12, + 2, 299, 12, 12, 300, 22, 12, 24, 25, 26, 25, 301, 302, 303, 25, 25, + 29, 29, 29, 304, 7, 7, 7, 305, 231, 0, 0, 0, 0, 231, 0, 12, + 29, 306, 29, 29, 29, 29, 29, 307, 308, 0, 0, 0, 0, 309, 257, 257, + 257, 257, 257, 310, 311, 150, 311, 150, 311, 150, 311, 281, 0, 231, 0, 231, + 12, 12, 308, 233, 312, 312, 312, 313, 312, 312, 312, 312, 312, 314, 312, 312, + 312, 312, 314, 315, 312, 312, 312, 316, 312, 312, 314, 12, 231, 131, 0, 0, + 0, 131, 0, 0, 8, 8, 8, 14, 0, 0, 0, 317, 318, 12, 12, 12, + 0, 0, 0, 319, 320, 320, 320, 320, 320, 320, 320, 321, 322, 322, 322, 322, + 323, 12, 12, 12, 214, 0, 0, 0, 0, 0, 0, 12, 324, 324, 324, 324, + 324, 12, 12, 325, 326, 326, 326, 326, 326, 326, 327, 12, 328, 328, 328, 328, + 328, 328, 329, 12, 330, 330, 330, 330, 330, 330, 330, 331, 332, 332, 332, 332, + 332, 12, 332, 332, 332, 333, 12, 12, 334, 334, 334, 334, 335, 335, 335, 335, + 336, 336, 336, 336, 336, 336, 336, 337, 336, 336, 337, 12, 338, 338, 338, 338, + 338, 12, 338, 338, 338, 338, 338, 12, 339, 339, 339, 339, 339, 339, 12, 12, + 340, 340, 340, 340, 340, 12, 12, 341, 342, 342, 343, 342, 343, 344, 342, 342, + 344, 342, 342, 342, 344, 342, 344, 345, 346, 346, 346, 346, 346, 12, 12, 12, + 347, 347, 347, 347, 347, 348, 12, 12, 347, 349, 12, 12, 347, 347, 12, 12, + 2, 350, 2, 2, 351, 2, 299, 12, 352, 353, 354, 352, 352, 352, 352, 352, + 352, 355, 356, 357, 358, 358, 358, 358, 358, 359, 358, 358, 360, 360, 360, 360, + 361, 361, 361, 361, 361, 361, 361, 362, 12, 363, 361, 361, 364, 364, 364, 364, + 365, 366, 367, 364, 368, 368, 368, 368, 368, 368, 368, 369, 370, 370, 370, 370, + 370, 370, 371, 372, 373, 373, 373, 373, 373, 373, 374, 12, 375, 375, 375, 375, + 376, 376, 376, 376, 376, 376, 12, 376, 377, 376, 376, 376, 378, 379, 12, 378, + 378, 380, 380, 378, 378, 378, 378, 378, 378, 381, 382, 383, 378, 378, 384, 12, + 385, 385, 385, 385, 386, 386, 386, 386, 387, 387, 387, 387, 387, 388, 389, 387, + 387, 388, 12, 12, 390, 390, 390, 390, 390, 391, 392, 390, 393, 393, 393, 393, + 393, 394, 393, 393, 395, 395, 395, 395, 396, 12, 395, 395, 397, 397, 397, 397, + 398, 12, 399, 400, 12, 12, 399, 397, 401, 401, 401, 401, 401, 401, 402, 12, + 403, 403, 403, 403, 404, 12, 12, 12, 404, 12, 405, 403, 406, 406, 406, 406, + 406, 406, 12, 12, 406, 406, 407, 12, 408, 408, 408, 408, 408, 409, 410, 408, + 408, 409, 12, 411, 29, 29, 29, 412, 413, 413, 413, 413, 413, 413, 414, 415, + 415, 12, 12, 12, 416, 29, 12, 12, 29, 29, 417, 12, 12, 12, 416, 29, + 418, 418, 418, 418, 418, 418, 12, 12, 419, 419, 419, 419, 419, 419, 420, 12, + 421, 421, 421, 421, 421, 421, 422, 12, 423, 423, 423, 423, 423, 423, 423, 12, + 424, 424, 424, 424, 424, 425, 12, 12, 426, 426, 426, 426, 426, 426, 426, 427, + 428, 426, 426, 426, 426, 427, 12, 429, 430, 430, 430, 430, 431, 12, 12, 432, + 433, 433, 433, 433, 433, 433, 434, 12, 433, 433, 435, 12, 436, 436, 436, 436, + 436, 437, 436, 436, 436, 436, 12, 12, 438, 438, 438, 438, 438, 439, 12, 12, + 440, 440, 440, 440, 118, 119, 119, 119, 119, 127, 12, 12, 441, 441, 441, 441, + 442, 441, 441, 441, 443, 12, 12, 12, 444, 445, 446, 447, 444, 444, 444, 447, + 444, 444, 448, 12, 449, 449, 449, 449, 449, 449, 450, 12, 449, 449, 451, 12, + 452, 453, 452, 454, 454, 452, 452, 452, 452, 452, 455, 452, 455, 453, 456, 452, + 452, 454, 454, 457, 458, 459, 12, 453, 452, 460, 452, 458, 452, 458, 12, 12, + 461, 461, 462, 463, 461, 461, 461, 461, 461, 462, 461, 461, 464, 465, 466, 461, + 461, 462, 467, 12, 468, 12, 12, 12, 469, 469, 469, 469, 469, 469, 469, 470, + 471, 12, 12, 12, 472, 472, 472, 472, 472, 472, 12, 12, 472, 472, 473, 12, + 474, 474, 474, 474, 474, 475, 474, 474, 474, 474, 474, 475, 476, 476, 476, 476, + 476, 477, 12, 12, 476, 476, 478, 12, 178, 178, 178, 180, 479, 479, 479, 479, + 479, 479, 480, 12, 145, 12, 12, 12, 481, 481, 481, 481, 481, 481, 482, 483, + 481, 481, 481, 12, 481, 482, 12, 12, 484, 484, 484, 484, 484, 484, 484, 12, + 485, 485, 485, 485, 486, 12, 12, 487, 488, 489, 490, 488, 488, 491, 488, 488, + 488, 488, 488, 488, 488, 492, 493, 488, 488, 489, 12, 12, 488, 488, 494, 12, + 495, 495, 496, 495, 495, 495, 495, 495, 495, 497, 12, 12, 498, 498, 498, 498, + 498, 498, 12, 12, 499, 499, 499, 499, 500, 12, 12, 12, 501, 501, 501, 501, + 501, 501, 502, 12, 53, 53, 503, 12, 440, 440, 12, 12, 504, 504, 504, 504, + 505, 12, 12, 12, 504, 504, 505, 12, 506, 506, 507, 506, 506, 506, 506, 506, + 506, 508, 506, 506, 506, 509, 12, 12, 506, 506, 506, 510, 511, 511, 511, 511, + 512, 511, 511, 511, 511, 511, 513, 511, 511, 514, 12, 12, 515, 516, 517, 515, + 515, 515, 515, 515, 515, 516, 518, 517, 515, 515, 12, 12, 515, 515, 519, 12, + 520, 521, 522, 520, 520, 520, 520, 520, 520, 520, 520, 523, 521, 520, 524, 12, + 520, 520, 525, 12, 526, 526, 526, 526, 526, 526, 526, 12, 526, 526, 527, 12, + 528, 528, 528, 528, 528, 528, 529, 12, 530, 530, 530, 530, 531, 530, 530, 530, + 530, 530, 532, 533, 530, 530, 532, 12, 534, 12, 12, 12, 100, 100, 100, 100, + 96, 12, 12, 98, 535, 535, 535, 535, 535, 535, 536, 12, 535, 535, 535, 537, + 535, 538, 12, 12, 535, 12, 12, 12, 539, 539, 539, 539, 540, 12, 12, 12, + 541, 541, 541, 541, 541, 542, 12, 12, 541, 541, 543, 12, 544, 544, 544, 544, + 544, 545, 12, 12, 546, 546, 546, 546, 546, 546, 547, 12, 269, 269, 548, 12, + 549, 549, 549, 549, 549, 549, 549, 550, 549, 549, 551, 552, 553, 553, 553, 553, + 553, 553, 553, 554, 553, 553, 555, 12, 556, 556, 556, 556, 556, 556, 556, 557, + 556, 557, 12, 12, 558, 558, 558, 558, 558, 559, 12, 12, 558, 558, 560, 558, + 560, 558, 558, 558, 558, 558, 12, 561, 562, 562, 562, 562, 562, 562, 563, 12, + 564, 564, 564, 564, 564, 564, 565, 12, 566, 566, 566, 566, 566, 566, 567, 566, + 566, 12, 12, 12, 568, 568, 568, 568, 568, 568, 569, 570, 568, 568, 12, 570, + 571, 572, 12, 12, 244, 573, 12, 12, 574, 574, 574, 574, 575, 575, 575, 575, + 575, 576, 12, 12, 12, 12, 12, 577, 574, 574, 574, 578, 578, 12, 12, 12, + 257, 579, 257, 580, 581, 252, 252, 252, 582, 12, 12, 12, 583, 12, 12, 12, + 253, 584, 12, 12, 12, 257, 12, 12, 585, 585, 585, 585, 585, 585, 585, 12, + 586, 586, 586, 586, 586, 586, 587, 12, 586, 586, 586, 588, 586, 586, 588, 12, + 586, 586, 589, 586, 0, 12, 12, 12, 0, 12, 238, 0, 317, 12, 12, 12, + 7, 590, 12, 12, 0, 233, 12, 12, 0, 231, 308, 0, 0, 591, 227, 0, + 0, 0, 591, 7, 212, 592, 7, 0, 0, 0, 593, 227, 8, 224, 12, 12, + 0, 231, 12, 12, 0, 0, 317, 12, 0, 0, 0, 228, 594, 595, 308, 228, + 0, 0, 596, 308, 0, 308, 0, 0, 0, 596, 231, 308, 0, 228, 0, 228, + 0, 0, 596, 231, 0, 597, 238, 0, 228, 0, 0, 0, 0, 233, 0, 0, + 0, 0, 0, 238, 598, 598, 598, 598, 598, 598, 598, 12, 12, 12, 599, 598, + 600, 598, 598, 598, 2, 2, 2, 299, 12, 270, 299, 12, 239, 601, 239, 239, + 239, 239, 602, 239, 603, 604, 601, 12, 19, 19, 19, 605, 12, 12, 12, 606, + 607, 607, 607, 607, 607, 607, 607, 608, 607, 607, 607, 609, 607, 607, 609, 610, + 611, 611, 611, 611, 611, 611, 611, 612, 613, 613, 613, 613, 613, 613, 614, 615, + 616, 616, 616, 616, 616, 616, 617, 12, 618, 618, 618, 618, 618, 618, 619, 620, + 621, 621, 621, 621, 621, 621, 621, 622, 621, 623, 12, 624, 151, 154, 151, 625, + 151, 151, 151, 154, 626, 626, 626, 626, 626, 627, 626, 626, 626, 628, 12, 12, + 629, 629, 629, 629, 629, 629, 629, 12, 629, 629, 630, 631, 0, 317, 12, 12, + 29, 632, 29, 29, 633, 634, 632, 29, 412, 29, 635, 12, 636, 51, 635, 632, + 633, 634, 635, 635, 633, 634, 412, 29, 412, 29, 632, 637, 29, 29, 638, 29, + 29, 29, 29, 12, 632, 632, 638, 29, 50, 12, 12, 12, 12, 238, 0, 0, + 639, 12, 12, 12, 0, 0, 317, 0, 0, 0, 12, 12, 0, 0, 231, 238, + 0, 231, 317, 308, 0, 0, 0, 640, 0, 0, 231, 131, 641, 12, 12, 12, + 244, 244, 573, 12, 642, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0,1124,1125,1126,1127,1131,1133, 0,1147, @@ -5831,8 +4348,7 @@ _hb_ucd_u16[5080] = 96, 929, 802, 804, 806, 97, 98, 807, 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0, }; -static const int16_t -_hb_ucd_i16[92] = +static const int16_t _hb_ucd_i16[92]= { 0, 0, 1, -1, 2, 0, -2, 0, 0, 2, 0, -2, 0, 16, 0, -16, 0, 1, -1, 0, 3, 3, 3, -3, -3, -3, 0, 2016, 0, 2527, 1923, 1914, @@ -5842,40 +4358,1271 @@ _hb_ucd_i16[92] = 0,-2016,-2104, 0, 0,-2106,-2108,-2106,-2250, 0,-2527, 0, }; -static inline uint_fast8_t -_hb_ucd_gc (unsigned u) +static inline uint8_t _hb_ucd_gc (unsigned u) { - return u<1114112u?_hb_ucd_u8[5208+(((_hb_ucd_u8[1168+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2; + return u<1114110 ? _hb_ucd_u8[6560u+((_hb_ucd_u8[816u+((_hb_ucd_u16[((_hb_ucd_u8[272u+((_hb_ucd_u8[((((((((u)>>1))>>3))>>4))>>4)])<<4)+((((((((u)>>1))>>3))>>4))&15)])<<4)+((((((u)>>1))>>3))&15)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : 2; } -static inline uint_fast8_t -_hb_ucd_ccc (unsigned u) +static inline uint8_t _hb_ucd_ccc (unsigned u) { - return u<125259u?_hb_ucd_u8[7206+(((_hb_ucd_u8[6638+(((_hb_ucd_u8[6162+(((_hb_ucd_u8[5802+(((_hb_ucd_u8[5556+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0; + return u<125259 ? _hb_ucd_u8[8620u+((_hb_ucd_u8[8036u+((_hb_ucd_u8[7556u+((_hb_ucd_u8[7188u+((_hb_ucd_u8[6942u+((((((((u)>>2))>>2))>>2))>>3)])<<3)+((((((((u)>>2))>>2))>>2))&7)])<<2)+((((((u)>>2))>>2))&3)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)] : 0; } -static inline unsigned -_hb_ucd_b4 (const uint8_t* a, unsigned i) +static inline uint8_t _hb_ucd_b4 (const uint8_t* a, unsigned i) { - return (a[i>>1]>>((i&1u)<<2))&15u; + return (a[i>>1]>>((i&1)<<2))&15; } -static inline int_fast16_t -_hb_ucd_bmg (unsigned u) +static inline int16_t _hb_ucd_bmg (unsigned u) { - return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[8098+(((_hb_ucd_u8[7866+(((_hb_ucd_u8[7770+(((_hb_ucd_b4(7706+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0; + return u<65380 ? _hb_ucd_i16[((_hb_ucd_u8[9516u+((_hb_ucd_u8[9284u+((_hb_ucd_u8[9188u+((_hb_ucd_b4(_hb_ucd_u8+9124u,((((((((u)>>1))>>2))>>3))>>3)))<<3)+((((((((u)>>1))>>2))>>3))&7)])<<3)+((((((u)>>1))>>2))&7)])<<2)+((((u)>>1))&3)])<<1)+((u)&1)] : 0; } -static inline uint_fast8_t -_hb_ucd_sc (unsigned u) +static inline uint8_t _hb_ucd_sc (unsigned u) { - return u<918016u?_hb_ucd_u8[11464+(((_hb_ucd_u8[10472+(((_hb_ucd_u8[9452+(((_hb_ucd_u8[8764+(((_hb_ucd_u8[8460+(((_hb_ucd_u8[8346+(u>>2>>2>>2>>3>>4)])<<4)+((u>>2>>2>>2>>3)&15u))])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2; + return u<918000 ? _hb_ucd_u8[10950u+((_hb_ucd_u16[4648u+((_hb_ucd_u16[2608u+((_hb_ucd_u8[10214u+((_hb_ucd_u8[9764u+((((((((u)>>2))>>2))>>3))>>4)])<<4)+((((((((u)>>2))>>2))>>3))&15)])<<3)+((((((u)>>2))>>2))&7)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)] : 2; } -static inline uint_fast16_t -_hb_ucd_dm (unsigned u) +static inline uint16_t _hb_ucd_dm (unsigned u) { - return u<195102u?_hb_ucd_u16[1656+(((_hb_ucd_u8[12834+(((_hb_ucd_u8[12452+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0; + return u<195102 ? _hb_ucd_u16[7480u+((_hb_ucd_u8[13904u+((_hb_ucd_u8[13522u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)] : 0; } + +#else + +#include + +static const uint8_t _hb_ucd_u8[13937]= +{ + 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 7, 11, 12, 12, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 7, 21, 22, 22, 22, 23, 24, 7, 7, + 7, 25, 22, 22, 22, 26, 27, 28, 22, 29, 30, 31, 32, 33, 34, 35, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 21, 22, 36, + 7, 7, 7, 7, 7, 7, 37, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 38, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 34, 34, 34, 35, 36, 37, 34, 34, 34, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 62, 63, 64, 65, 66, 67, 68, 69, 67, 70, 71, + 67, 67, 62, 72, 62, 62, 73, 67, 74, 75, 76, 77, 78, 67, 67, 67, + 79, 80, 34, 81, 82, 83, 67, 67, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 84, 34, 34, 34, 34, + 85, 34, 34, 34, 34, 34, 34, 34, 34, 86, 34, 34, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 34, 34, 34, 34, 34, 34, 34, 34, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, + 100,100, 34, 34, 34, 34,101,102, 34, 34,103,104,105,106,107,108, + 34, 34,109,110,111,112,113,114,115,116,117,118, 34, 34, 34,119, + 120,121,122,123,124,125,126,127, 34,128,129,130,131,132,133,134, + 135,136,137,138,139,140,141,142,143,144,111,145,146,147,148,111, + 149,150,151,152,153,154,155,156,157,158,159,160,111,161,162,163, + 34, 34, 34, 34, 34, 34, 34, 34,164, 34, 34,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,165, + 34, 34, 34, 34, 34, 34, 34, 34,166, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 111,111,167,111,111,111,111,111,111,111,111,111,111,111,111,111, + 34, 34, 34, 34,168,169,170, 34,111,111,171,111,172,173,174,175, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,119, + 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111, 34,176,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111, 67,177, 67, 67, 67,178,179, 67, + 67, 67,180,181,182,131, 65,111,183,184,185,186,187,188,189,190, + 67, 67, 67, 67,191,192,111,111,111,111,111,111,111,111,193,111, + 194,195,196,111,111,197,111,111,111,198,111,199,111,200,111, 34, + 34,201,202,111,111,111,111,111,131,203,204,111, 34,205,111,111, + 67, 67,206, 67, 67,111, 67,207, 67, 67, 67, 67, 67, 67, 67, 67, + 67,208, 67, 67, 67, 67, 67,177,111,111,111,111,111,111,111,111, + 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,111, + 34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111, + 209,111,195,195,111,111,111,111,111,111,111,111,111,111,111,111, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2, + 7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 17, 18, 19, 1, 20, 20, 21, 22, 23, 24, 25, + 26, 27, 15, 2, 28, 29, 27, 30, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 31, 11, 11, 11, 32, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 33, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 34, 34, 34, 34, 34, 34, 34, 34, 16, 32, 32, 32, + 32, 32, 32, 32, 11, 34, 34, 16, 34, 32, 32, 11, 34, 11, 16, 11, + 11, 34, 32, 11, 32, 16, 11, 34, 32, 32, 32, 11, 34, 16, 32, 11, + 34, 11, 34, 34, 32, 35, 32, 16, 36, 36, 37, 34, 38, 37, 34, 34, + 34, 34, 34, 34, 34, 34, 16, 32, 34, 38, 32, 11, 32, 32, 32, 32, + 32, 32, 16, 16, 16, 11, 34, 32, 34, 34, 11, 32, 32, 32, 32, 32, + 16, 16, 36, 16, 16, 16, 16, 16, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 40, 40, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, + 39, 39, 41, 40, 40, 40, 41, 41, 40, 40, 40, 40, 40, 40, 40, 40, + 42, 42, 42, 42, 42, 42, 42, 42, 32, 32, 41, 32, 16, 43, 16, 10, + 40, 40, 40, 44, 11, 11, 11, 11, 34, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 34, + 16, 11, 32, 16, 32, 32, 32, 32, 16, 16, 32, 45, 34, 32, 34, 11, + 32, 46, 42, 42, 47, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16, + 11, 11, 11, 11, 48, 2, 2, 2, 16, 16, 16, 16, 49, 50, 51, 52, + 53, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 54, + 55, 56, 42, 55, 42, 42, 42, 42, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 57, 2, 2, 2, 2, 2, 2, 58, 58, 58, 8, 9, 59, 2, 60, + 42, 42, 42, 42, 42, 56, 61, 2, 62, 36, 36, 36, 36, 63, 42, 42, + 7, 7, 7, 7, 7, 2, 2, 36, 64, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 65, 42, 42, 42, 66, 46, 42, 42, 67, 68, 69, 42, 42, 36, + 7, 7, 7, 7, 7, 36, 70, 71, 2, 2, 2, 2, 2, 2, 2, 72, + 63, 36, 36, 36, 36, 36, 36, 36, 42, 42, 42, 42, 42, 42, 64, 36, + 36, 36, 36, 42, 42, 42, 42, 42, 7, 7, 7, 7, 7, 36, 36, 36, + 36, 36, 36, 36, 36, 63, 42, 42, 42, 42, 39, 21, 2, 39, 68, 20, + 36, 36, 36, 42, 42, 68, 42, 42, 42, 42, 68, 42, 68, 42, 42, 42, + 2, 2, 2, 2, 2, 2, 2, 2, 36, 36, 36, 36, 63, 42, 42, 2, + 36, 36, 36, 36, 73, 36, 36, 36, 58, 58, 58, 74, 42, 42, 42, 42, + 36, 36, 36, 36, 75, 42, 42, 42, 42, 74, 42, 42, 42, 42, 42, 42, + 42, 76, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 76, 64, 77, + 78, 42, 42, 42, 76, 77, 78, 77, 63, 42, 42, 42, 36, 36, 36, 36, + 36, 42, 2, 7, 7, 7, 7, 7, 79, 36, 36, 36, 36, 36, 36, 36, + 63, 77, 80, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 77, + 78, 42, 42, 76, 77, 77, 78, 36, 36, 36, 36, 81, 77, 77, 36, 36, + 36, 42, 42, 7, 7, 7, 7, 7, 36, 20, 27, 27, 27, 52, 57, 42, + 42, 76, 80, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 42, 77, + 78, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 64, 36, 36, 36, + 36, 36, 36, 7, 7, 7, 7, 7, 42, 36, 63, 2, 2, 2, 2, 2, + 78, 42, 42, 42, 76, 77, 78, 42, 59, 20, 20, 20, 82, 42, 42, 42, + 42, 77, 80, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 78, + 78, 42, 42, 76, 77, 77, 78, 42, 42, 42, 42, 76, 77, 77, 36, 36, + 71, 27, 27, 27, 27, 27, 27, 27, 42, 64, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 77, 76, 77, 77, 77, 77, 77, 78, 42, + 36, 36, 36, 81, 77, 77, 77, 77, 77, 77, 77, 7, 7, 7, 7, 7, + 27, 83, 60, 60, 52, 60, 60, 60, 76, 77, 64, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 64, 42, 76, 77, 77, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 36, 36, 36, 36, 7, 7, 7, 84, 27, 27, 27, 83, + 63, 77, 65, 36, 36, 36, 36, 36, 77, 77, 77, 76, 77, 77, 42, 42, + 42, 42, 76, 77, 77, 77, 36, 36, 85, 81, 77, 77, 77, 77, 77, 77, + 42, 77, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 63, 64, 77, + 78, 42, 42, 77, 77, 77, 78, 70, 60, 60, 36, 81, 27, 27, 27, 86, + 27, 27, 27, 27, 83, 36, 36, 36, 36, 36, 36, 36, 36, 42, 42, 76, + 77, 42, 42, 42, 77, 77, 77, 77, 7, 77, 2, 2, 2, 2, 2, 2, + 63, 36, 42, 42, 42, 42, 42, 87, 36, 36, 36, 68, 42, 42, 42, 56, + 7, 7, 7, 7, 7, 2, 2, 2, 63, 36, 42, 42, 42, 42, 64, 36, + 36, 36, 36, 39, 42, 42, 42, 42, 7, 7, 7, 7, 7, 7, 36, 36, + 70, 60, 2, 2, 2, 2, 2, 2, 2, 88, 88, 60, 42, 60, 60, 60, + 7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 46, 46, 46, 4, 4, 77, + 63, 42, 42, 42, 42, 42, 42, 76, 42, 42, 56, 42, 36, 36, 63, 42, + 42, 42, 42, 42, 42, 42, 42, 60, 60, 60, 60, 69, 60, 60, 60, 60, + 2, 2, 88, 60, 21, 2, 2, 2, 36, 36, 36, 36, 36, 81, 78, 42, + 76, 42, 42, 42, 78, 76, 78, 64, 36, 36, 36, 77, 42, 36, 36, 42, + 64, 77, 80, 81, 77, 77, 77, 36, 63, 42, 64, 36, 36, 36, 36, 36, + 36, 76, 78, 76, 77, 77, 78, 81, 7, 7, 7, 7, 7, 77, 78, 60, + 16, 16, 16, 16, 16, 49, 43, 16, 36, 36, 36, 36, 36, 36, 63, 42, + 2, 2, 2, 2, 89, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 60, 60, 60, 60, 60, 60, 60, 60, 11, 11, 11, 11, 16, 16, 16, 16, + 90, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 65, + 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 92, 93, 93, + 36, 36, 36, 36, 36, 57, 2, 94, 95, 36, 36, 36, 36, 36, 36, 36, + 36, 42, 76, 77, 77, 77, 77, 80, 36, 42, 96, 2, 2, 2, 2, 2, + 36, 42, 42, 42, 42, 42, 42, 42, 36, 36, 42, 78, 42, 42, 42, 77, + 77, 77, 77, 76, 78, 42, 42, 42, 42, 42, 2, 79, 2, 59, 63, 42, + 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 97, 2, 55, 42, 74, + 36, 75, 36, 36, 36, 36, 36, 36, 36, 36, 63, 64, 36, 36, 36, 36, + 36, 36, 36, 36, 63, 36, 36, 36, 42, 76, 77, 78, 76, 77, 77, 77, + 77, 76, 77, 77, 78, 42, 42, 42, 60, 60, 2, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 27, 27, 60, 36, 36, 36, 63, 76, 78, 42, 2, + 36, 36, 81, 76, 42, 42, 42, 42, 76, 76, 78, 42, 42, 42, 76, 77, + 77, 78, 42, 42, 42, 42, 42, 42, 2, 2, 2, 79, 2, 2, 2, 2, + 42, 42, 42, 42, 42, 42, 42, 98, 42, 42, 80, 36, 36, 36, 36, 36, + 36, 36, 76, 42, 42, 76, 76, 77, 77, 76, 80, 36, 36, 36, 36, 2, + 88, 60, 60, 60, 60, 46, 42, 42, 42, 42, 60, 60, 60, 60, 21, 2, + 42, 80, 36, 36, 36, 36, 36, 36, 81, 42, 42, 77, 42, 78, 42, 36, + 36, 36, 36, 76, 42, 77, 78, 78, 42, 77, 77, 77, 77, 77, 2, 2, + 36, 36, 77, 77, 77, 77, 42, 42, 42, 42, 77, 42, 42, 56, 2, 2, + 7, 7, 7, 7, 7, 7, 85, 36, 36, 36, 36, 36, 39, 39, 39, 2, + 16, 16, 16, 16, 34, 16, 16, 16, 42, 56, 42, 42, 42, 42, 42, 42, + 76, 42, 42, 42, 64, 36, 63, 36, 36, 36, 64, 81, 42, 36, 36, 36, + 16, 16, 16, 16, 16, 16, 39, 39, 39, 39, 39, 39, 39, 43, 16, 16, + 16, 16, 16, 16, 43, 16, 16, 16, 16, 16, 16, 16, 16, 99, 39, 39, + 32, 32, 32, 16, 16, 16, 16, 32, 16, 16, 16, 16, 11, 11, 11, 11, + 16, 16, 16, 16, 34, 11, 11, 11, 16, 16, 16, 16,100,100,100,100, + 16, 16, 16, 16, 11, 11,101,102, 40, 16, 16, 16, 11, 11,101, 40, + 16, 16, 16, 16, 11, 11,103, 40,104,104,104,104,104,105, 58, 58, + 50, 50, 50, 2,106,107,106,107, 2, 2, 2, 2,108, 58, 58,109, + 2, 2, 2, 2,110,111, 2,112,113, 2,114,115, 2, 2, 2, 2, + 2, 9,113, 2, 2, 2, 2,116, 58, 58, 58, 58, 58, 58, 58, 58, + 117, 39, 27, 27, 27, 8,114,118, 27, 27, 27, 27, 27, 8,114, 93, + 20, 20, 20, 20, 20, 20, 20, 20, 42, 42, 42, 42, 42, 42,119, 47, + 98, 47, 98, 42, 42, 42, 42, 42, 60,120, 60,121, 60, 34, 11, 16, + 11, 32,121, 60, 45, 11, 11, 60, 60, 60,120,120,120, 11, 11,122, + 11, 11, 35, 36,123, 60, 16, 11, 8, 8, 45, 16, 16, 26, 60,124, + 94, 94, 94, 94, 94, 94, 94, 94, 94,125,126, 94,127, 60, 60, 60, + 8, 8,128, 60, 60, 8, 60, 60,128, 26, 60,128, 60, 60, 60,128, + 60, 60, 60, 60, 60, 60, 60, 8, 60,128,128, 60, 60, 60, 60, 60, + 60, 60, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 60, 60, 60, 60, 4, 4, 60, 60, 8, 60, 60, 60,129,130, 60, 60, + 60, 60, 60, 60, 60, 60,128, 60, 60, 60, 60, 60, 60, 26, 8, 8, + 8, 8, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 8, 8, + 8, 60, 60, 60, 60, 60, 60, 60, 27, 27, 27, 27, 27, 27, 60, 60, + 60, 60, 60, 60, 60, 27, 27, 27, 60, 60, 60, 26, 60, 60, 60, 60, + 26, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 8, 8, 8, 8, + 60, 60, 60, 60, 60, 60, 60, 26, 60, 60, 60, 60, 4, 4, 4, 4, + 4, 4, 4, 27, 27, 27, 27, 27, 27, 27, 60, 60, 60, 60, 60, 60, + 8, 8,114,131, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, + 8,114,132,132,132,132,132,132,132,132,132,132,131, 8, 8, 8, + 8, 8, 8, 8, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8, + 8, 8,128, 26, 8, 8,128, 60, 32, 11, 32, 34, 34, 34, 34, 11, + 32, 32, 34, 16, 16, 16, 39, 11, 32, 32,124, 60, 60,121, 34,133, + 42, 32, 16, 16, 49, 2, 89, 2, 36, 36, 36, 36, 36, 36, 36, 75, + 2, 2, 2, 2, 2, 2, 2, 55, 2,106,106, 2,110,111,106, 2, + 2, 2, 2, 6, 2, 97,106, 2,106, 4, 4, 4, 4, 2, 2, 79, + 2, 2, 2, 2, 2, 50, 2, 2, 97,134, 2, 2, 2, 2, 2, 2, + 60, 2,135,132,132,132,136, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 1, 2,137,138, 4, 4, 4, 4, 4, 60, 4, 4, 4, 4,139, 93, + 140, 94, 94, 94, 94, 42, 42, 77,141, 39, 39, 60, 94,142, 57, 60, + 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 63,143,144, 62, + 36, 36, 36, 36, 36, 57, 39, 62, 60, 27, 27, 60, 60, 60, 60, 60, + 27, 27, 27, 27, 27, 60, 60, 60, 60, 60, 60, 60, 27, 27, 27, 27, + 145, 27, 27, 27, 27, 27, 27, 27, 36, 36, 75, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36,146, 2, 32, 32, 32, 32, 32, 32, 32, 63, + 47,147, 42, 42, 42, 42, 42, 79, 32, 32, 32, 32, 32, 32, 39, 42, + 36, 36, 36, 94, 94, 94, 94, 94, 42, 2, 2, 2, 2, 2, 2, 2, + 40, 40, 40,144, 39, 39, 39, 39, 40, 32, 32, 32, 32, 32, 32, 32, + 16, 32, 32, 32, 32, 32, 32, 32, 43, 16, 16, 16, 34, 34, 34, 32, + 32, 32, 32, 32, 41,148, 34, 35, 32, 32, 16, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 11, 11, 32, 11, 11, 32, 32, 32, 32, 32, 32, + 32, 32, 11, 11, 34, 34, 32, 32, 32, 32, 32, 32, 32, 32, 11, 11, + 48, 39,149, 35, 39, 35, 36, 36, 36, 64, 36, 64, 36, 63, 36, 36, + 36, 81, 78, 76, 60, 60, 42, 42, 27, 27, 27, 60,150, 60, 60, 60, + 36, 36, 2, 2, 2, 2, 2, 2, 77, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 77, 77, 77, 77, 77, 77, 77, 77, 42, 42, 42, 42, 42, 2, + 42, 36, 36, 36, 2, 65, 65, 63, 36, 36, 36, 42, 42, 42, 42, 2, + 36, 36, 36, 63, 42, 42, 42, 42, 42, 77, 77, 77, 77, 77, 77, 96, + 36, 63, 77, 42, 42, 77, 42, 77, 96, 2, 2, 2, 2, 2, 2, 79, + 7, 7, 7, 7, 7, 7, 7, 2, 36, 36, 63, 62, 36, 36, 36, 36, + 36, 36, 36, 36, 63, 42, 42, 76, 78, 76, 78, 42, 42, 42, 42, 42, + 36, 63, 36, 36, 36, 36, 76, 77, 7, 7, 7, 7, 7, 7, 2, 2, + 62, 36, 36, 70, 60, 81, 76, 36, 64, 42, 64, 63, 64, 36, 36, 42, + 36, 36, 36, 36, 36, 36, 75, 2, 36, 36, 36, 36, 36, 81, 42, 77, + 2, 75,151, 42, 42, 42, 42, 42, 16, 16, 16, 16, 16,102, 39, 39, + 16, 16, 16, 16, 99, 40, 40, 40, 36, 81, 78, 77, 76, 96, 78, 42, + 152,152,152,152,152,152,152,152,153,153,153,153,153,153,153,153, + 16, 16, 16, 16, 16, 16, 35, 64, 36, 36, 36, 36,154, 36, 36, 36, + 36, 40, 40, 40, 40, 40, 40, 40, 40, 22, 60, 60, 60, 60, 60, 60, + 60, 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,132, + 60, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 60, 60, 60, + 36, 36, 36, 36, 36, 36,150, 60, 2, 2, 2,135,115, 2, 2, 2, + 6,155,156,132,132,132,132,132,132,132,115,135,115, 2,112,157, + 2, 2, 2, 2,139,132,132,115, 2,158, 8, 8, 59, 2, 2, 2, + 36, 36, 36, 36, 36, 36, 36,159, 2, 2, 3, 2, 4, 5, 6, 2, + 16, 16, 16, 16, 16, 17, 18,114,115, 4, 2, 36, 36, 36, 36, 36, + 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 39, + 20,160, 52, 20, 26, 8,128, 60, 60, 60, 60, 60,161, 58, 60, 60, + 2, 2, 2, 89, 27, 27, 27, 27, 27, 27, 27, 83, 60, 60, 60, 60, + 94, 94,127, 27, 83, 60, 60, 60, 60, 60, 60, 60, 60, 27, 60, 60, + 60, 60, 60, 60, 60, 60, 46, 42,162,162,162,162,162,162,162,162, + 163, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 86, 36, + 138, 36, 36, 36, 36, 94, 94, 94, 36, 36, 36, 36, 36, 36, 36, 57, + 164, 94, 94, 94, 94, 94, 94, 94, 11, 11, 11, 32, 16, 16, 16, 16, + 36, 36, 36, 57, 27, 27, 27, 27, 36, 36, 36, 70,145, 27, 27, 27, + 36, 36, 36,165, 27, 27, 27, 27, 36, 36, 36, 36, 36,165, 27, 27, + 36, 36, 36, 27, 27, 27, 27, 30, 36, 36, 36, 36, 36, 36, 27, 36, + 63, 42, 42, 42, 42, 42, 42, 42, 36, 36, 36, 36, 42, 42, 42, 42, + 36, 36, 36, 36, 36, 36,165, 30, 36, 36, 36, 36, 36, 36,165, 27, + 36, 36, 36, 36, 71, 36, 36, 36, 36, 36, 63, 42, 42,163, 27, 27, + 36, 36, 36, 36, 57, 2, 2, 2, 36, 36, 36, 36, 27, 27, 27, 27, + 16, 16, 16, 16, 16, 27, 27, 27, 36, 36, 42, 42, 42, 42, 42, 42, + 7, 7, 7, 7, 7, 36, 36, 62, 11, 11, 11, 11,166, 42, 42,141, + 16, 16, 16, 16, 16, 16, 16, 8, 36, 36, 36, 36, 36, 63,167, 50, + 88, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 42, 42, 42, + 27, 27, 27, 86, 36, 36, 36, 36,163, 27, 30, 2, 2, 2, 2, 2, + 36, 42, 42, 2, 2, 2, 2, 2, 36, 36,165, 27, 27, 27, 27, 27, + 78, 80, 36, 36, 36, 36, 36, 36, 42, 42, 42, 56, 2, 2, 2, 2, + 2, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 7, 7, 7, + 64, 63, 64, 36, 36, 36, 36, 63, 77, 78, 42, 76, 78, 56, 72, 2, + 2, 42, 42, 42, 42, 42, 66, 58, 36, 36, 36, 63, 42, 42, 78, 42, + 42, 42, 42, 7, 7, 7, 7, 7, 2, 2, 81, 80, 36, 36, 36, 36, + 36, 63, 2, 36, 36, 36, 36, 36, 36, 81, 77, 42, 42, 42, 42, 76, + 80, 36, 57, 2, 55, 42, 56, 78, 7, 7, 7, 7, 7, 57, 57, 2, + 89, 27, 27, 27, 27, 27, 27, 27, 36, 36, 36, 36, 36, 36, 77, 78, + 42, 77, 76, 42, 2, 2, 2, 64, 36, 36, 36, 36, 36, 36, 36, 63, + 76, 77, 77, 77, 77, 77, 77, 77, 36, 36, 36, 81, 77, 77, 80, 36, + 36, 77, 77, 42, 42, 42, 42, 42, 36, 36, 36, 36, 77, 78, 42, 42, + 42, 77, 77, 77, 77, 77, 77, 76, 64, 64, 2, 2, 2, 2, 2, 2, + 55, 42, 42, 42, 42, 42, 42, 42, 36, 36, 81, 77, 42, 42, 42, 42, + 77, 42, 76, 64, 36, 57, 2, 2, 7, 7, 7, 7, 7, 2, 2, 64, + 77, 78, 42, 42, 76, 76, 77, 78, 76, 42, 36, 65, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 81, 77, 42, 42, 42, 77, 77, 42, 78, + 56, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 36, 42, 42, + 77, 78, 42, 42, 42, 76, 78, 78, 56, 2, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 63, 78, 77, 42, 42, 42, 78, 57, 2, 2, 2, + 36, 36, 36, 36, 36, 36, 63, 78, 77, 42, 42, 78, 42, 42, 42, 42, + 7, 7, 7, 7, 7, 27, 2, 88, 42, 42, 42, 42, 78, 56, 2, 2, + 27, 27, 27, 27, 27, 27, 27, 86, 77, 77, 77, 77, 77, 78, 76, 64, + 80, 78, 2, 2, 2, 2, 2, 2, 81, 77, 42, 42, 42, 42, 77, 77, + 64, 65, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 63, 42, 42, 42, 42, 64, 36, 36, 36, 63, 42, 42, 76, 63, 42, 56, + 2, 2, 2, 55, 42, 42, 42, 42, 63, 42, 42, 76, 78, 42, 36, 36, + 36, 36, 36, 36, 36, 42, 42, 42, 42, 42, 42, 76, 42, 2, 65, 2, + 76, 42, 76, 76, 77, 77, 77, 77, 57, 2, 2, 2, 2, 2, 2, 2, + 42, 42, 42, 42, 42, 42, 42, 78, 2, 36, 36, 36, 36, 36, 36, 36, + 42, 42, 42, 42, 76, 42, 42, 42, 76, 42, 78, 42, 42, 42, 42, 42, + 42, 42, 42, 63, 42, 42, 42, 42, 36, 36, 36, 36, 36, 77, 77, 77, + 42, 76, 78, 78, 36, 36, 36, 36, 36, 36, 36, 36, 75, 36, 36, 36, + 36, 63, 76, 96, 2, 2, 2, 2, 42, 81, 36, 36, 36, 36, 36, 36, + 36, 36, 77, 42, 42, 42, 42, 77, 76, 56, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 42, 42, 42, 27, 27, 83, 60, 60, 60, 52, 20, + 150, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 21, + 64, 36, 36, 63, 42, 42, 42, 42, 36, 36, 36, 36, 36, 36, 36, 42, + 42, 42, 42, 42, 42, 77, 78, 42, 42, 42, 56, 2, 2, 2, 2, 2, + 42, 42, 42, 56, 2, 2, 60, 60, 39, 39, 88, 60, 60, 60, 60, 60, + 7, 7, 7, 7, 7,168, 27, 27, 27, 86, 36, 36, 36, 36, 36, 36, + 39, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 75,146, 2, + 27, 27, 27, 30, 2, 2, 2, 2, 11, 11, 11, 11, 11, 32, 16, 16, + 81, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 78, + 42, 67, 39, 39, 39, 39, 39, 39, 39, 79, 42, 42, 42, 42, 42, 42, + 77, 39, 94, 94, 94, 94, 94, 94, 36, 36, 36, 36, 36, 36, 46, 56, + 7, 7, 7, 7, 7, 60, 60, 60, 60, 60,169, 78, 42, 60,169, 77, + 77,170, 58, 58, 58, 74, 42, 42, 42, 69, 46, 42, 42, 42, 60, 60, + 60, 60, 60, 60, 60, 42, 42, 60, 60, 42, 69, 60, 60, 60, 60, 60, + 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 16, 11, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, + 31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, 16, 16, + 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, 16, 16, + 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, + 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 32, 16, 7, + 42, 42, 42, 69, 60, 46, 42, 42, 42, 42, 42, 42, 42, 42, 69, 60, + 60, 60, 46, 60, 60, 60, 60, 60, 60, 60, 69, 21, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 55, 42, 42, 16, 16, 16, 16, 16,123, 16, 16, + 42, 42, 42, 67, 39, 39, 39, 39, 7, 7, 7, 7, 7, 7, 7, 70, + 36, 36, 36, 36, 36, 36, 42, 42, 7, 7, 7, 7, 7, 7, 7,171, + 36, 36, 36, 36, 36, 75, 42, 42,172, 7, 7, 7, 7, 7, 7, 84, + 36, 63, 36, 64, 36, 36, 36, 42, 36, 36, 63, 42, 42, 42, 42, 75, + 16, 16, 42, 42, 42, 67, 39, 39, 27, 27, 27, 27, 27, 27,145, 27, + 173, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,145, + 27, 27, 27, 27, 27, 27, 83, 60, 60, 60, 60, 60, 60, 25, 40, 40, + 0, 0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13, + 25, 25, 25, 21, 21, 9, 9, 9, 9, 22, 21, 18, 24, 16, 24, 5, + 5, 5, 5, 22, 25, 18, 25, 0, 23, 23, 26, 21, 24, 26, 7, 20, + 25, 1, 26, 24, 26, 25, 15, 15, 24, 15, 7, 19, 15, 21, 9, 25, + 9, 5, 5, 25, 5, 9, 5, 7, 7, 7, 9, 8, 8, 5, 6, 6, + 24, 24, 6, 24, 12, 12, 6, 5, 9, 21, 25, 9, 26, 12, 11, 11, + 9, 6, 5, 21, 17, 17, 17, 26, 26, 23, 23, 12, 17, 12, 21, 12, + 12, 21, 7, 21, 1, 1, 21, 23, 26, 26, 1, 21, 6, 7, 7, 12, + 12, 7, 21, 7, 12, 1, 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, + 21, 1, 24, 7, 1, 12, 7, 6, 12, 10, 10, 10, 10, 12, 21, 6, + 10, 7, 7, 10, 23, 7, 15, 26, 13, 21, 13, 7, 15, 7, 12, 23, + 21, 26, 21, 15, 17, 7, 29, 7, 7, 22, 18, 18, 14, 14, 14, 7, + 10, 21, 17, 21, 11, 12, 5, 6, 8, 8, 8, 24, 5, 24, 9, 24, + 29, 29, 29, 1, 20, 19, 22, 20, 27, 28, 1, 29, 21, 20, 19, 21, + 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, 15, 6, 18, 6, 12, 11, + 9, 26, 26, 9, 26, 5, 7, 5, 5, 26, 14, 9, 5, 14, 14, 15, + 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 22, 21, 21, 22, + 18, 17, 26, 6, 7, 14, 17, 22, 26, 14, 17, 6, 14, 6, 12, 24, + 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, 6, 10, + 4, 4, 3, 3, 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 7, 1, + 25, 24, 26, 1, 2, 2, 12, 15, 21, 14, 7, 15, 9, 12, 12, 17, + 13, 15, 26, 10, 10, 1, 13, 23, 7, 13, 23, 15, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, + 0, 0, 15, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, + 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, + 0, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, + 0, 36, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, 43, 44, + 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, + 0, 0, 0, 0, 3, 0, 0, 0, 4, 5, 6, 7, 0, 8, 9, 10, + 0, 11, 12, 13, 14, 15, 16, 17, 16, 18, 16, 19, 16, 19, 16, 19, + 0, 19, 16, 20, 16, 19, 21, 19, 0, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, + 0, 0, 0, 0, 0, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 0, + 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 0, 0, 47, 0, 0, + 0, 48, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, + 0, 52, 53, 0, 54, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, + 0, 0, 58, 0, 0, 59, 60, 61, 62, 63, 0, 0, 64, 65, 0, 0, + 0, 66, 0, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, + 0, 0, 72, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 74, 75, + 0, 0, 0, 0, 76, 77, 0, 78, 79, 0, 0, 80, 81, 0, 82, 62, + 0, 83, 84, 0, 0, 85, 86, 87, 0, 88, 0, 89, 0, 90, 0, 0, + 51, 91, 51, 0, 92, 0, 93, 0, 0, 0, 81, 0, 0, 0, 94, 95, + 0, 96, 97, 98, 99, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0,100, + 101, 0, 0, 0, 0, 0, 0,102, 0, 0, 0, 0, 0, 0,103, 0, + 0, 0, 0, 0, 0,104,105, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,106, 0, 0,107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,108, + 109, 0, 0,110, 0, 0, 0, 0, 0, 0,111, 0,112, 0,105, 0, + 0, 0, 0, 0,113,114, 0, 0, 0, 0, 0, 0, 0,115, 0, 0, + 0,116, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0,118, 0,119, + 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 0, + 0, 0, 0, 9, 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, 14, 15, + 0, 16, 0, 17, 18, 0, 0, 19, 0, 20, 21, 0, 0, 0, 0, 0, + 22, 23, 0, 24, 25, 0, 0, 26, 0, 0, 0, 27, 0, 0, 28, 29, + 30, 31, 0, 0, 0, 32, 33, 34, 0, 0, 33, 0, 0, 35, 33, 0, + 0, 0, 33, 36, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, + 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 43, + 0, 44, 0, 0, 0, 45, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, + 0, 48, 49, 0, 0, 0, 0, 50, 0, 0, 0, 51, 0, 52, 0, 53, + 0, 0, 0, 0, 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 0, + 57, 58, 0, 0, 0, 59, 60, 61, 62, 0, 0, 0, 0, 63, 52, 0, + 64, 65, 0, 0, 66, 0, 0, 0, 67, 68, 0, 0, 0, 69, 0, 70, + 71, 72, 73, 74, 1, 75, 0, 76, 77, 78, 0, 0, 79, 80, 0, 0, + 0, 81, 0, 0, 1, 1, 0, 0, 82, 0, 0, 83, 0, 0, 0, 0, + 79, 84, 0, 85, 0, 0, 0, 0, 0, 80, 86, 0, 87, 0, 52, 0, + 1, 80, 0, 0, 88, 0, 0, 89, 0, 0, 0, 0, 0, 90, 57, 0, + 0, 0, 0, 0, 0, 91, 92, 0, 0, 86, 0, 0, 33, 0, 0, 93, + 0, 0, 0, 0, 94, 0, 0, 0, 0, 49, 0, 0, 95, 0, 0, 0, + 0, 96, 97, 0, 0, 98, 0, 0, 99, 0, 0, 0,100, 0, 0, 0, + 101, 0, 0, 0,102, 0, 0, 0, 0,103,104, 95, 0, 0,105, 0, + 0, 0, 86, 0, 0,106, 0, 0, 0,107,108, 0, 0,109,110, 0, + 0, 0, 0, 0, 0,111, 0, 0,112, 0, 0, 0, 0,113, 33, 0, + 114,115,116, 57, 0, 0,117, 35, 0, 0,118, 0, 0, 0,119, 0, + 0, 0, 0, 0, 0,120, 0, 0,121, 0, 0, 0, 0,122, 90, 0, + 0, 0, 0, 0, 57, 0, 0, 0, 0, 52,123, 0, 0, 0, 0,124, + 0, 0,125, 0, 0, 0, 0,123, 0, 0,126, 0, 0, 0, 0, 0, + 81, 0, 0, 0, 0,127, 0, 0, 0,128, 0, 0, 0,129, 0,130, + 0, 0, 0, 0,131,132,133, 0,134, 0,135, 0, 0, 0,136,137, + 138, 0, 79, 0, 0, 0, 0, 0, 35, 0, 0, 0,139, 0, 0, 0, + 140, 0, 0, 0,141, 0, 0, 0,142,143, 0,144, 0, 0,145, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, + 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17, 18, 1, + 1, 1, 19, 1, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, + 27, 28, 29, 30, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, + 1, 36, 37, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, 42, 0, + 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 19, 1, 21, 0, + 0, 47, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 51, 0, 0, 19, + 52, 1, 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52, 54, 21, + 35, 1, 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0, 0, 0, + 0, 59, 0, 60, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, + 64, 0, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, + 68, 0, 0, 69, 70, 0, 71, 72, 73, 74, 75, 76, 0, 0, 0, 77, + 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 49, 0, 80, + 0, 0, 0, 62, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, + 83, 0, 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85, 1, 52, + 15, 86, 36, 10, 21, 1, 1, 1, 1, 41, 1, 21, 87, 0, 0, 55, + 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0, 0, 89, + 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, 90, 9, 12, 4, 91, 8, + 92, 47, 0, 58, 50, 0, 21, 1, 21, 93, 94, 1, 1, 1, 1, 95, + 96, 97, 98, 1, 99, 58, 81,100,101, 4, 58, 0, 0, 0, 0, 0, + 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, 0, 0,102,103, 0, 0, + 104, 0, 0, 1, 1, 50, 0, 0, 0, 38, 0, 63, 0, 0, 0, 0, + 0, 62, 0, 0,105, 68, 61, 0, 0, 0, 78, 0, 0, 0,106,107, + 58, 38, 81, 0, 0, 0, 0, 0, 0,108, 1, 14, 4, 12, 84, 0, + 0, 0, 0, 38, 90, 0, 0, 0, 0,109, 0, 0,110, 61, 0,111, + 0, 0, 0, 1, 0, 0, 0, 0, 49, 50, 0, 0, 19, 58, 0, 0, + 112, 51, 0,112, 14, 52,113, 41, 0, 0, 62, 0, 0, 61, 0, 0, + 114, 0, 90, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, 0,114, + 0, 0, 0, 0,115, 0, 0, 0, 78, 55, 0, 38, 1, 58, 1, 58, + 0, 0, 0, 0, 0, 88, 63, 89, 0, 0,116, 0, 0, 0, 55, 0, + 0, 0, 0,116, 0, 0, 0, 0, 61, 0, 0, 0, 0, 79, 0, 61, + 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 79, 0, 0, 0, 8, 92, + 0, 0, 1, 90, 0, 0,117, 0, 0, 0, 0, 0, 0,118, 0,119, + 120,121,122, 0,105, 4,123, 49, 23, 0, 0, 0, 38, 50, 38, 58, + 0, 0, 1, 90, 1, 1, 1, 1, 39, 1, 48,106, 90, 0, 0, 0, + 0, 1, 0, 0, 0,124, 0, 0, 0,113, 19, 59, 0, 38, 0, 81, + 0, 0, 4,123, 0, 0, 0, 1,125, 0, 0, 0, 0, 0,230,230, + 230,230,230,232,220,220,220,220,232,216,220,220,220,220,220,202, + 202,220,220,220,220,202,202,220,220,220, 1, 1, 1, 1, 1,220, + 220,220,220,230,230,230,230,240,230,220,220,220,230,230,230,220, + 220, 0,230,230,230,220,220,220,220,230,232,220,220,230,233,234, + 234,233,234,234,233,230, 0, 0, 0,230, 0,220,230,230,230,230, + 220,230,230,230,222,220,230,230,220,220,230,222,228,230, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, + 25, 0,230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, + 30, 31, 32, 33, 34,230,230,220,220,230,220,230,230,220, 35, 0, + 0, 0, 0, 0,230,230,230, 0, 0,230,230, 0,220,230,230,220, + 0, 0, 0, 36, 0, 0,230,220,230,230,220,220,230,220,220,230, + 220,230,220,230,230, 0, 0,220, 0, 0,230,230, 0,230, 0,230, + 230,230,230,230, 0, 0, 0,220,220,220,230,220,220,220,230,230, + 0,220, 27, 28, 29,230, 7, 0, 0, 0, 0, 9, 0, 0, 0,230, + 220,230,230, 0, 0, 0, 0, 0,230, 0, 0, 84, 91, 0, 0, 0, + 0, 9, 9, 0, 0, 0, 0, 0, 9, 0,103,103, 9, 0,107,107, + 107,107,118,118, 9, 0,122,122,122,122,220,220, 0, 0, 0,220, + 0,220, 0,216, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0, + 130,130,130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0, + 220, 0, 0, 0, 0, 7, 0, 9, 9, 0, 9, 9, 0, 0, 0,230, + 0, 0, 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0,230, 0, + 0,220,230,220, 0,220,230,230,230,234, 0, 0, 9, 9, 0, 0, + 7, 0,230,230,230, 0,230, 0, 1, 1, 1, 0, 0, 0,230,234, + 214,220,202,230,230,230,230,230,232,228,228,220,218,230,233,220, + 230,220,230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230,220,230, + 1, 1, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0, 0, 0, + 0,220,230, 0,230,230,220, 0, 0,230, 0, 0, 26, 0, 0,220, + 0,230,230, 1,220, 0, 0,230,220, 0, 0, 0,220,220, 0, 0, + 230,220, 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, 9, 7, 6, 6, + 0, 0, 0, 0, 1, 0, 0,216,216, 1, 1, 1, 0, 0, 0,226, + 216,216,216,216,216, 0,220,220,220, 0,232,232,220,230,230,230, + 7, 0, 16, 17, 17, 33, 17, 49, 17, 17, 84, 97,135,145, 26, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17,177, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 5, 3, 3, 3, + 3, 3, 6, 7, 8, 3, 3, 3, 3, 3, 9, 10, 11, 12, 13, 3, + 3, 3, 3, 3, 3, 3, 3, 14, 3, 15, 3, 3, 3, 3, 3, 3, + 16, 17, 18, 19, 20, 21, 3, 3, 3, 22, 23, 24, 3, 3, 3, 3, + 3, 3, 25, 3, 3, 3, 3, 3, 3, 3, 3, 26, 3, 3, 27, 28, + 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, + 0, 3, 0, 0, 0, 0, 0, 4, 0, 5, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, + 0, 9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 0, + 0, 14, 15, 16, 6, 0, 17, 18, 19, 19, 19, 20, 21, 22, 23, 24, + 19, 25, 0, 26, 27, 19, 19, 28, 29, 30, 0, 31, 0, 0, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 19, 28, 0, 32, 33, 9, 34, 35, 19, + 0, 0, 36, 37, 38, 39, 40, 19, 0, 41, 42, 43, 44, 31, 0, 1, + 45, 42, 0, 0, 0, 0, 0, 32, 14, 14, 0, 0, 0, 0, 14, 0, + 0, 46, 47, 47, 47, 47, 48, 49, 47, 47, 47, 47, 50, 51, 52, 53, + 43, 21, 0, 0, 0, 0, 0, 0, 0, 54, 6, 55, 0, 14, 19, 1, + 0, 0, 0, 0, 56, 57, 0, 0, 0, 0, 0, 19, 58, 31, 0, 0, + 0, 0, 0, 0, 0, 59, 14, 0, 0, 0, 0, 1, 0, 2, 0, 0, + 0, 3, 0, 0, 0, 60, 61, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 2, 3, 0, 4, 5, 0, 0, 6, 0, 0, 0, 7, + 0, 0, 0, 1, 1, 0, 0, 8, 9, 0, 8, 9, 0, 0, 0, 0, + 8, 9, 10, 11, 12, 0, 0, 0, 13, 0, 0, 0, 0, 14, 15, 16, + 17, 0, 0, 0, 1, 0, 0, 18, 19, 0, 0, 0, 20, 0, 0, 0, + 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 8, 21, 9, + 0, 0, 22, 0, 0, 0, 0, 1, 0, 23, 24, 25, 0, 0, 26, 0, + 0, 0, 8, 21, 27, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 28, + 29, 30, 0, 31, 32, 20, 1, 1, 0, 0, 0, 8, 21, 9, 1, 4, + 5, 0, 0, 0, 33, 9, 0, 1, 1, 1, 0, 8, 21, 21, 21, 21, + 34, 1, 35, 21, 21, 21, 9, 36, 0, 0, 37, 38, 1, 0, 39, 0, + 0, 0, 1, 0, 1, 0, 0, 0, 0, 8, 21, 9, 1, 0, 0, 0, + 40, 0, 8, 21, 21, 21, 21, 21, 21, 21, 21, 9, 0, 1, 1, 1, + 1, 8, 21, 21, 21, 9, 0, 0, 0, 41, 0, 42, 43, 0, 0, 0, + 1, 44, 0, 0, 0, 45, 8, 9, 1, 0, 0, 0, 8, 21, 21, 21, + 9, 0, 1, 0, 1, 1, 8, 21, 21, 9, 0, 4, 5, 8, 9, 1, + 0, 0, 16, 50, 84,118,136,152,186,187,187,187,187,187,187,187, + 187,187,187,187,187,187,187,187,187,187,187,187,187,187, 12, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, + 13, 13, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 15, 16, 17, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 19, 32, 33, 33, 33, 33, 33, + 34, 19, 19, 19, 19, 19, 19, 35, 19, 36, 37, 38, 38, 38, 38, 38, + 38, 39, 40, 19, 19, 19, 19, 19, 19, 19, 41, 42, 19, 19, 43, 19, + 19, 19, 44, 45, 9, 46, 47, 48, 49, 50, 51, 52, 9, 9, 19, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 53, 19, 19, 53, 19, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 54, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 55, + 0, 0, 1, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 0, + 1, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 32, 33, 33, 33, 34, 35, 35, 35, 35, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 2, 2, 51, 51, 52, + 53, 54, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, + 57, 56, 56, 56, 56, 56, 56, 58, 59, 60, 61, 56, 62, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 56, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 71, 62, 62, 62, 62, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 73, 74, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 32, + 32, 32, 32, 32, 32, 32, 32, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 62, 62, 62, 62, 88, 89, 89, 89, 90, 89, 91, 92, 93, 94, 95, + 95, 96, 97, 87, 98, 99,100,101,102,103,104,105,105,105, 2,106, + 107,108,109,110,111,112,113,114,115,116,117, 89,118,119,120,121, + 122,123,124,125,126,127,128,129,130, 87,131,132,133,134, 87,135, + 136,137,138,139,140,141,142,143,144,145,146, 87,147,148,149,150, + 150,150,150,150,150,150,150,150,150,150, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87,151,152,152,152,152,152,152,152,152,153, + 153,153,153,153, 87, 87, 87, 87, 87,154, 87, 87, 87, 87, 87,155, + 155,155,155,156,157,158,158, 87, 87,159, 87,160,161,162,163,164, + 164,164,164,164,164,164,164,164,164,164,164,164,164,165,165,165, + 165,164,164, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,166,167, + 168,169,170,170,170, 87, 87,171,172, 87, 87, 87, 87, 87, 87, 56, + 56, 56, 56, 56, 56,173, 56, 56, 56,174,175, 51, 56, 56, 87,176, + 176,176,176,176,176, 87, 87, 87, 87, 87, 87, 87, 87, 2, 87,177, + 6,178, 87, 87,179, 87, 87, 87,180, 87,181, 87,182, 87, 33,183, + 183,184, 87, 87, 87, 87, 87, 56, 56, 56, 87, 89, 89, 87, 87, 56, + 56, 56, 56,185, 87, 56, 56, 62, 62, 62, 62, 62, 87, 87, 87, 62, + 87, 87, 87, 87, 87, 87, 87, 56, 87,186,186, 0, 1, 2, 2, 0, + 0, 0, 0, 1, 2, 1, 2, 0, 0, 3, 3, 4, 5, 4, 5, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 0, 0, 7, 0, 8, + 8, 8, 8, 8, 8, 8, 9, 10, 11, 11, 11, 11, 11, 12, 11, 13, + 13, 13, 13, 13, 13, 13, 13, 14, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 15, 16, 16, 16, 16, 16, 17, 18, 18, 18, 18, 18, 18, 19, + 20, 21, 21, 22, 23, 21, 24, 21, 21, 21, 21, 21, 25, 21, 21, 26, + 26, 26, 26, 26, 21, 21, 21, 27, 27, 27, 27, 28, 28, 28, 28, 29, + 29, 29, 29, 30, 30, 26, 21, 21, 21, 21, 21, 21, 21, 31, 21, 32, + 32, 32, 32, 32, 33, 34, 32, 35, 35, 35, 35, 35, 35, 35, 35, 36, + 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 38, + 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 40, + 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 42, + 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, 43, 43, 43, 44, + 44, 44, 45, 44, 44, 44, 44, 46, 46, 46, 46, 46, 46, 46, 46, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 48, 47, 47, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 52, + 52, 52, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 55, 55, 56, + 56, 57, 57, 57, 57, 58, 57, 59, 59, 60, 61, 62, 62, 63, 63, 64, + 64, 64, 64, 64, 64, 64, 64, 65, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 55, 55, 55, 55, 55, 67, 67, 67, 67, 67, 68, 68, 68, 69, + 69, 69, 69, 69, 69, 64, 64, 70, 70, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 8, 8, 8, 8, 8, 72, 72, 72, 72, 72, 72, 72, 72, 73, + 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 75, 76, 76, 76, 13, + 50, 50, 50, 73, 77, 78, 79, 4, 4, 80, 4, 4, 81, 82, 83, 4, + 4, 4, 84, 8, 8, 8, 8, 11, 11, 11, 11, 11, 11, 11, 11, 85, + 0, 0, 0, 0, 0, 0, 86, 0, 4, 0, 0, 0, 8, 8, 8, 0, + 0, 87, 88, 89, 0, 4, 4, 6, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 90, 90, 90, 90, 90, 90, 90, 90, 91, + 91, 91, 91, 91, 91, 4, 4, 92, 92, 92, 92, 92, 92, 92, 92, 50, + 50, 50, 93, 93, 93, 93, 93, 53, 53, 53, 53, 53, 53, 13, 13, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 0, 95, + 0, 96, 97, 98, 99, 99, 99, 99,100,101,102,102,102,102,103,104, + 104,104,105, 52, 52, 52, 52, 52, 0,104,104, 0, 0, 0,102, 52, + 52, 0, 0, 0, 0, 52,106, 0, 0, 0, 0, 0,102,102,107,102, + 102,102,102,102,108, 0, 0, 94, 94, 94, 94, 0, 0, 0, 0,109, + 109,109,109,109,109,109,109,109,109,109,109,109,110,110,110,111, + 111,111,111,111,111,111,111,111,111,111,111, 13, 13, 13, 13, 13, + 13,112,112,112,112,112,112, 0, 0,113, 4, 4, 4, 4, 4,114, + 4, 4, 4, 4, 4, 4, 4,115,115,115, 0,116,116,116,116,117, + 117,117,117,117,117, 32, 32,118,118,119,120,120,120, 52, 52,121, + 121,121,121,122,121, 49, 49,123,123,123,123,123,123, 49, 49,124, + 124,124,124,124,124,125,125, 53, 53, 53, 4, 4,126,127, 54, 54, + 54, 54, 54,125,125,125,125,128,128,128,128,128,128,128,128, 4, + 129, 18, 18, 18, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21,130, 21, 21, 21, 21, 8, 0,131, 0, 0, 0, 0, 21, 21, + 21, 21, 21, 21, 21, 21,132, 0, 0, 1, 2, 1, 2,133,101,102, + 134, 52, 52, 52, 52, 0, 0,135,135,135,135,135,135,135,135, 0, + 0, 0, 0, 11, 11, 11, 11, 11, 0, 11, 11, 11, 0, 0,136,137, + 137,138,138,138,138,139, 0,140,140,140,141,141,142,142,142,143, + 143,144,144,144,144,144,144,145,145,145,145,145,146,146,146,147, + 147,147,148,148,148,148,148,149,149,149,150,150,150,150,151,151, + 151,151,151,152,152,152,152,153,153,153,153,153,153,153,153,154, + 154,154,154,155,155,156,156,157,157,157,157,157,157,158,158,159, + 159,160,160,161,161,161,161,162,162,163,163,163,163,163,163,164, + 164,164,164,164,164,165,165,166,166,166,166,167,167,167,167,168, + 168,168,168,169,169,170,170,171,171,171,171,171,171,171,171,172, + 172,172,172,172,172,172,172,173,173,173,173,173,173,173,173,174, + 174,174,174,175,175,175,175,175,175,175,175,175,175,175,175,176, + 176,176,176,177, 21, 21, 21,178,178,178,179,179,179,179,180,180, + 180,180,181,181,181,182,182,183,183,183,183,183,183,183,183,184, + 184,184,184,184,185,185,185,186,186,186,186,186,187,187,187,188, + 188,188,188,188,188,189, 43,190,190,190,190,190,190,190,190,191, + 191,191,192,192,192,192,192,193,193,193,194,193,193,193,193,195, + 195,195,195,195,195,195,195,196,196,196,196,196,196,196,196,197, + 197,197,197,197,197,197,197,198,198,198,198,198,198,198,198,199, + 199,199,199,199,199, 66, 66,200,200,200,200,200, 49, 49, 49,201, + 201,201,201,201,201,201,201,202,202,202,202,202,202,202,202,203, + 203,203,203,203,203,203,203,204,204,204,204,204,204,204,204,205, + 205,205,205,205,205,205,205,206,206,206,206,206,207,207,207,207, + 207,207, 55,208,208,208,208, 32, 32, 32, 32, 32, 32,188,188,209, + 209,209,209,209,209,209,209,210,210,210,210,210,210,210,211,211, + 211,211,211,211,211,211,211,212,212,212,212,212,212,213,213,213, + 213,213,214,214,214,214,214,215,215,215,215,215,215,215,215,216, + 216,216,216,216,216,216,216,110,110,110,110, 39, 39, 39, 39,217, + 217,217,217,217,217,217,217,218,218,218,218,218,218,218,218,219, + 219,219,219,219,219,219,219,220,220,220,220,220,220,220,220,221, + 221,221,221,221,221,221,221,112,112,112,112,112,112,112,112,112, + 112,112,112,222,222,222,223,223,223,223,223,223,224,224,224,225, + 225,225,225,225,225,225,225,226,226,226,226,226,226,226,226,227, + 227,227,227,227,227,227,227,227,227,228,228,228,228,228,228,229, + 229,229,229,229,229,229,229,229,229,229,229,229,229,230, 94,231, + 231,231,231,231,231,231,231,232,232,232,232,232,232,232,232,102, + 102,102,102,102,102,102,102,233, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99,102,234, 99,235,102,236,236, + 236,236,236,236,236,236,236,237,237,237,237,237,237,237,237,237, + 237, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 0, 0, 0, 0, + 0, 0, 0, 0, 0,238,239,240, 0,241, 0, 0, 0, 0, 0,242, + 242,242,242,242,242,242,242, 91, 91, 91, 13, 13, 13, 13, 13,243, + 243,243,243,243,243,243,243,244,244,244,244,245,245,245,245,246, + 246,246,246,246,246,246,246,247,247,247,247,247,247,247,247,248, + 248,248,248,248,248,248,248,249,249,249,249,249,249,249,249,250, + 250,250,250,250,250,250,250,251, 0, 0, 0, 0, 0, 0, 0, 8, + 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 1, 2, 2, 2, 2, + 2, 3, 0, 0, 0, 4, 0, 2, 2, 2, 2, 2, 3, 2, 2, 2, + 2, 5, 0, 2, 5, 6, 0, 7, 7, 7, 7, 8, 9, 8, 10, 8, + 11, 8, 8, 8, 8, 8, 8, 12, 13, 13, 13, 14, 14, 14, 14, 14, + 15, 14, 14, 16, 17, 17, 17, 17, 17, 17, 17, 18, 19, 19, 19, 19, + 19, 19, 19, 20, 21, 20, 22, 20, 20, 23, 23, 20, 20, 20, 20, 22, + 20, 24, 7, 7, 25, 20, 20, 26, 20, 20, 20, 20, 20, 20, 21, 27, + 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, + 31, 31, 31, 32, 20, 20, 20, 33, 33, 33, 33, 34, 35, 33, 33, 33, + 36, 33, 33, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, + 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, + 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 47, 48, + 48, 48, 48, 49, 49, 49, 49, 49, 50, 51, 49, 52, 52, 52, 52, 53, + 53, 53, 53, 53, 53, 54, 53, 55, 55, 55, 55, 56, 56, 56, 56, 57, + 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 60, + 60, 61, 62, 63, 63, 63, 63, 64, 64, 64, 64, 64, 65, 0, 0, 66, + 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 70, 71, 71, 71, + 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, + 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78, 79, + 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 7, 7, 7, 83, + 7, 84, 85, 0, 84, 86, 0, 2, 87, 88, 2, 2, 2, 2, 89, 90, + 87, 91, 2, 2, 2, 92, 2, 2, 2, 2, 93, 0, 0, 0, 86, 1, + 0, 0, 94, 0, 95, 96, 0, 4, 0, 0, 0, 0, 0, 0, 4, 97, + 97, 97, 97, 98, 98, 98, 98, 13, 13, 13, 13, 99, 99, 99, 99,100, + 100,100,100, 0,101, 0, 0,102,100,103,104, 0, 0,100, 0,105, + 106,106,106,106,106,106,106,106,106,107,105,108,109,109,109,109, + 109,109,109,109,109,110,108,111,111,111,111,112, 55, 55, 55, 55, + 55, 55,113,109,109,109,110,109,109, 0, 0,114,114,114,114,115, + 115,115,115,116,116,116,116,117,117,117,117, 96, 2, 2, 2, 2, + 2, 94, 2,118,118,118,118,119,119,119,119,120,120,120,120,121, + 121,121,121,121,121,121,122,123,123,123,123,124,124,124,124,124, + 124,124,125,126,126,126,126,127,127,127,127,128,128,128,128, 2, + 2, 3, 2, 2,129,130, 0,131,131,131,131,132, 17, 17, 18, 20, + 20, 20,133, 7, 7, 7,134, 20, 20, 20, 23, 0,135,109,109,109, + 109,109,136,137,137,137,137, 0, 0, 0,138,139,139,139,139,140, + 140,140,140, 84, 0, 0, 0,141,141,141,141,142,142,142,142,143, + 143,143,143,144,144,144,144,145,145,145,145,146,146,146,146,147, + 147,147,147,148,148,148,148,149,149,149,149,150,150,150,150,151, + 151,151,151,152,152,152,152,153,153,153,153,154,154,154,154,155, + 155,155,155,156,156,156,156,157,157,157,157,158,158,158,158,159, + 159,159,159,160,160,160,160,161,161,161,161,162,162,162,162,163, + 163,163,163,164,164,164,164,165,165,165,165,166,166,166,166,167, + 167,167,167,168,168,168,168,169,169,169,169,170,170,170,170,171, + 171,171,171,172,172,172,172,173,173,173,173,174,174,174,174,175, + 175,175,175,176,176,176,176,177,177,177,177,178, 20, 20, 20,179, + 179,179,179,180,180,180,180,181,181,181,181,182,182,182,182,183, + 183,183,183,184,184,184,184,185,185,185,185,186,186,186,186,187, + 187,187,187,188,188,188,188,189,189,189,189,190, 45, 45, 45,191, + 191,191,191,192,192,192,192,193,193,193,193,194,194,194,194,194, + 194,195,194,196,196,196,196,197,197,197,197,198,198,198,198,199, + 199,199,199,200,200,200,200,201,201,201,201,202,202,202,202,203, + 203,203,203,204,204,204,204,205,205,205,205,206,206,206,206,207, + 207,207,207,208,208,208,208,209,209,209,209,210,210,210,210,211, + 211,211,211,212,212,212,212,213,213,213,213,214,214,214,214,215, + 215,215,215,216,216,216,216,217,217,217,217,218,218,218,218,219, + 219,219,219,220,220,220,220,221,221,221,221,222,222,222,222,223, + 223,223,223,224,224,224,224,225,225,225,225,226,226,226,226,227, + 227,227,227,228,228,228,228,229,229,229,229,230,230,230,230,231, + 232,232,232,233,233,233,233,232,232,232,232,234,106,106,106,235, + 106,106,106,106,236,109,109,237,237,237,237,238,238,238,238, 0, + 239, 86, 0, 0, 0,239, 7, 82,138, 7, 0, 0, 0,240, 86,241, + 241,241,241,242,242,242,242,243,243,243,243,244,244,244,244,245, + 245,245,245,246,246,246,246,247,247,247,247,248,248,248,248,249, + 249,249,249,250, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 0, 19, 0, 0, 0, 0, + 0, 26, 26, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 9, + 9, 0, 9, 9, 0, 9, 0, 9, 9, 55, 55, 55, 55, 55, 55, 6, + 6, 6, 6, 6, 1, 1, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, + 14, 14, 14, 14, 14, 14, 14, 3, 3, 3, 3, 3, 0, 3, 3, 0, + 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 1, 1, 1, 3, 3, 1, + 3, 3, 3, 37, 37, 37, 37, 38, 38, 38, 38, 64, 64, 64, 64, 90, + 90, 90, 90, 95, 95, 95, 95, 3, 3, 0, 3, 7, 7, 7, 7, 7, + 1, 1, 1, 1, 7, 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, 11, + 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21, 22, 22, 22, 22, 23, + 23, 23, 23, 16, 16, 16, 16, 20, 20, 20, 20, 36, 36, 36, 36, 24, + 24, 24, 24, 24, 24, 24, 0, 18, 18, 18, 18, 25, 25, 25, 25, 25, + 0, 0, 0, 0, 25, 25, 25, 33, 33, 33, 33, 8, 8, 8, 8, 8, + 8, 8, 0, 12, 12, 12, 12, 30, 30, 30, 30, 29, 29, 29, 29, 28, + 28, 28, 28, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 0, 0, + 0, 35, 35, 45, 45, 45, 45, 44, 44, 44, 44, 44, 0, 0, 0, 43, + 43, 43, 43, 46, 46, 46, 46, 31, 31, 31, 31, 32, 32, 0, 0, 32, + 0, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 52, 52, 52, 52, 58, + 58, 58, 58, 54, 54, 54, 54, 91, 91, 91, 91, 62, 62, 62, 62, 76, + 76, 76, 76, 93, 93, 93, 93, 70, 70, 70, 70, 73, 73, 73, 73, 1, + 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, + 1, 0, 0, 19, 19, 9, 9, 9, 9, 9, 6, 19, 9, 9, 9, 9, + 9, 19, 19, 9, 9, 9, 19, 6, 19, 19, 19, 19, 19, 19, 9, 0, + 0, 0, 19, 0, 0, 9, 0, 0, 0, 19, 19, 27, 27, 27, 27, 56, + 56, 56, 56, 61, 61, 61, 61, 13, 13, 13, 13, 0, 13, 0, 13, 0, + 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 0, 15, 15, 15, 15, + 15, 15, 15, 15, 1, 1, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 0, 26, 26, 26, 26, 26, 12, 12, 12, 12, 12, 12, 0, 39, + 39, 39, 39, 86, 86, 86, 86, 77, 77, 77, 77, 79, 79, 79, 79, 60, + 60, 60, 60, 65, 65, 65, 65, 75, 75, 75, 75, 69, 69, 69, 69, 69, + 69, 0, 69, 74, 74, 74, 74, 84, 84, 84, 84, 84, 84, 84, 0, 68, + 68, 68, 68, 92, 92, 92, 92, 87, 87, 87, 87, 19, 9, 19, 19, 19, + 19, 0, 0, 2, 2, 2, 2, 19, 19, 19, 4, 3, 3, 0, 0, 1, + 1, 6, 6, 0, 0, 17, 17, 17, 17, 0, 0, 49, 49, 49, 49, 0, + 1, 1, 1, 71, 71, 71, 71, 67, 67, 67, 67, 42, 42, 42, 42, 41, + 41, 41, 41,118,118,118,118, 53, 53, 53, 53, 59, 59, 59, 59, 40, + 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50,135,135,135,135,106, + 106,106,106,104,104,104,104,161,161,161,161,170,170,170,170,110, + 110,110,110, 47, 47, 47, 47, 81, 81, 81, 81,120,120,120,120,116, + 116,116,116,128,128,128,128, 66, 66, 66, 66, 72, 72, 72, 72,173, + 173,173,173, 98, 98, 98, 98, 97, 97, 97, 97, 57, 57, 57, 57, 88, + 88, 88, 88,117,117,117,117,112,112,112,112, 78, 78, 78, 78, 83, + 83, 83, 83, 82, 82, 82, 82,122,122,122,122, 89, 89, 89, 89,130, + 130,130,130,144,144,144,144,165,165,165,165,156,156,156,156,156, + 156, 3, 3,147,147,147,147,148,148,148,148,158,158,158,158,153, + 153,153,153,149,149,149,149, 94, 94, 94, 94, 85, 85, 85, 85,101, + 101,101,101, 96, 96, 96, 96,111,111,111,111,100,100,100,100,100, + 36, 36, 36,108,108,108,108,129,129,129,129,109,109,109,109,107, + 107,107,107,107,107,107, 1,171,171,171,171,137,137,137,137,124, + 124,124,124,123,123,123,123,114,114,114,114,102,102,102,102,126, + 126,126,126,142,142,142,142,125,125,125,125,154,154,154,154,150, + 150,150,150,141,141,141,141,140,140,140,140,121,121,121,121,169, + 169,169,169,133,133,133,133,134,134,134,134,138,138,138,138,143, + 143,143,143,175,175,175,175,145,145,145,145,163,163,163,163, 63, + 63, 63, 63,157,157,157,157, 80, 80, 80, 80,127,127,127,127,166, + 166,166,166,115,115,115,115,159,159,159,159,103,103,103,103,119, + 119,119,119,167,167,167,167,146,146,146,146,172,172,172,172, 99, + 99, 99, 99,136,139, 13, 13,155,155,155,155,136,136,136,136, 17, + 15, 15, 15, 17, 17, 15, 15, 15, 17, 17, 17,139,139,139,139,105, + 105,105,105, 0, 0, 0, 1, 0, 0, 1, 1,131,131,131,131,151, + 151,151,151,160,160,160,160,152,152,152,152,164,164,164,164,168, + 168,168,168,174,174,174,174,113,113,113,113,132,132,132,132, 15, + 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, + 10, 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 16, + 17, 9, 9, 9, 9, 18, 9, 9, 9, 9, 9, 19, 20, 21, 9, 22, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 23, 9, 9, 9, 9, 9, 24, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 25, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 26, + 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, + 0, 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, + 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, + 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, + 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, + 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, + 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101, + 102,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, + 0,108, 0,109, 0,110, 0,111,112,113, 0,114, 0, 0, 0,115, + 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,118,119,120,121, 0,122,123,124,125,126, 0, + 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142, + 143,144,145,146,147,148,149,150,151,152,153,154,155,156,157, 0, + 0, 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,162, 0,163, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,164,165, 0, 0, 0, 0, + 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,167, 0, 0, 0,168,169, 0, 0,170, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,171, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,172, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,175, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,176,177, 0, 0, 0, 0,178,179, 0, 0, + 0,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194, + 195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210, + 211,212,213, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, + 4, +}; +static const uint16_t _hb_ucd_u16[5104]= +{ + 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12, + 13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23, + 13, 13, 13, 24, 25, 11, 11, 11, 11, 26, 11, 27, 28, 29, 30, 31, + 32, 32, 32, 32, 32, 32, 32, 33, 34, 35, 36, 11, 37, 38, 13, 39, + 9, 9, 9, 11, 11, 11, 13, 13, 40, 13, 13, 13, 41, 13, 13, 13, + 13, 13, 13, 35, 9, 42, 11, 11, 43, 44, 32, 45, 46, 47, 47, 48, + 49, 50, 47, 47, 51, 32, 52, 53, 47, 47, 47, 47, 47, 54, 55, 56, + 57, 58, 47, 32, 59, 47, 47, 47, 47, 47, 60, 53, 61, 47, 62, 63, + 47, 64, 65, 66, 47, 67, 47, 47, 68, 69, 47, 47, 70, 32, 71, 32, + 72, 47, 47, 73, 74, 75, 76, 77, 78, 47, 47, 79, 80, 81, 82, 83, + 84, 47, 47, 85, 86, 87, 88, 89, 84, 47, 47, 79, 90, 47, 82, 91, + 92, 47, 47, 93, 94, 95, 82, 96, 97, 47, 47, 98, 99, 100, 101, 102, + 103, 47, 47, 104, 105, 106, 82, 107, 108, 47, 47, 93, 109, 110, 82, 111, + 112, 47, 47, 113, 114, 115, 82, 116, 92, 47, 47, 47, 117, 118, 101, 119, + 47, 47, 47, 120, 121, 122, 66, 66, 47, 47, 47, 123, 124, 125, 47, 47, + 126, 127, 128, 129, 47, 47, 47, 130, 131, 32, 32, 132, 133, 134, 66, 66, + 47, 47, 135, 136, 122, 137, 138, 139, 140, 141, 9, 9, 9, 11, 11, 142, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 143, 144, 145, + 47, 146, 9, 9, 9, 9, 9, 147, 148, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 149, 47, 150, 151, 47, 47, 47, 47, 152, 153, + 47, 154, 47, 155, 47, 156, 47, 156, 47, 47, 47, 157, 158, 159, 160, 145, + 161, 160, 47, 47, 162, 47, 47, 47, 163, 47, 164, 47, 47, 47, 47, 47, + 47, 47, 165, 166, 167, 47, 47, 47, 47, 47, 47, 47, 47, 168, 146, 146, + 47, 169, 47, 47, 47, 170, 171, 172, 160, 160, 173, 174, 32, 32, 32, 32, + 175, 47, 47, 176, 177, 122, 178, 179, 180, 47, 181, 61, 47, 47, 182, 183, + 47, 47, 184, 185, 186, 61, 47, 187, 188, 9, 9, 9, 66, 189, 190, 191, + 11, 11, 192, 27, 27, 27, 193, 194, 11, 195, 27, 27, 32, 32, 32, 32, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 196, 13, 13, 13, 13, 13, 13, + 197, 197, 197, 197, 197, 198, 197, 11, 199, 199, 199, 200, 201, 202, 202, 201, + 203, 204, 205, 206, 207, 208, 209, 210, 211, 27, 212, 212, 212, 213, 214, 32, + 215, 216, 217, 218, 219, 145, 220, 220, 221, 222, 223, 146, 224, 225, 146, 226, + 227, 227, 227, 227, 227, 227, 227, 227, 228, 146, 229, 146, 146, 146, 146, 230, + 146, 231, 227, 232, 146, 233, 234, 146, 146, 146, 146, 146, 146, 146, 145, 145, + 145, 235, 146, 146, 146, 146, 236, 145, 146, 146, 146, 146, 146, 146, 146, 146, + 146, 146, 146, 237, 238, 146, 146, 239, 146, 146, 146, 146, 146, 146, 240, 146, + 146, 146, 146, 146, 146, 146, 241, 242, 145, 243, 146, 146, 244, 227, 245, 227, + 246, 247, 227, 227, 227, 248, 227, 249, 146, 146, 146, 227, 250, 146, 146, 146, + 9, 9, 9, 11, 11, 11, 251, 252, 13, 13, 13, 13, 13, 13, 253, 254, + 11, 11, 11, 47, 47, 47, 255, 256, 47, 47, 47, 47, 47, 47, 32, 32, + 257, 258, 259, 260, 261, 262, 263, 263, 264, 265, 266, 267, 268, 47, 47, 47, + 47, 269, 148, 47, 47, 47, 47, 270, 47, 271, 47, 47, 146, 146, 146, 47, + 146, 146, 272, 146, 273, 274, 146, 146, 272, 146, 146, 274, 146, 146, 146, 146, + 47, 47, 47, 47, 146, 146, 146, 146, 47, 275, 47, 47, 47, 47, 47, 47, + 47, 146, 146, 146, 146, 47, 47, 187, 276, 47, 61, 47, 13, 13, 277, 278, + 13, 279, 47, 47, 47, 47, 280, 281, 31, 282, 283, 284, 13, 13, 13, 285, + 286, 287, 288, 289, 290, 291, 9, 292, 293, 47, 294, 295, 47, 47, 47, 296, + 297, 47, 47, 298, 299, 160, 32, 300, 61, 47, 301, 47, 302, 303, 47, 47, + 72, 47, 47, 304, 305, 306, 307, 61, 47, 47, 308, 309, 310, 311, 47, 312, + 47, 47, 47, 313, 58, 314, 315, 316, 47, 47, 47, 11, 11, 317, 318, 11, + 11, 11, 11, 11, 47, 47, 319, 160, 320, 320, 320, 320, 320, 320, 320, 320, + 321, 321, 321, 321, 321, 321, 321, 321, 11, 322, 323, 47, 47, 47, 47, 47, + 47, 47, 47, 324, 325, 326, 47, 47, 47, 47, 47, 327, 146, 47, 47, 47, + 47, 328, 47, 47, 329, 146, 146, 330, 32, 331, 32, 332, 333, 334, 335, 47, + 47, 47, 47, 47, 47, 47, 47, 336, 337, 2, 3, 4, 5, 338, 339, 340, + 47, 341, 47, 47, 47, 47, 342, 343, 344, 145, 145, 345, 220, 220, 220, 346, + 347, 146, 146, 146, 146, 146, 146, 348, 349, 349, 349, 349, 349, 349, 349, 349, + 47, 47, 47, 47, 47, 47, 350, 145, 47, 47, 351, 47, 352, 47, 47, 60, + 47, 353, 47, 47, 47, 354, 220, 220, 9, 9, 147, 11, 11, 47, 47, 47, + 47, 47, 160, 9, 9, 147, 11, 11, 47, 47, 47, 47, 47, 47, 353, 9, + 9, 355, 11, 11, 47, 47, 47, 47, 27, 27, 27, 27, 27, 27, 27, 27, + 47, 47, 47, 47, 47, 356, 47, 357, 47, 47, 358, 145, 145, 145, 47, 359, + 47, 360, 47, 353, 47, 47, 47, 47, 47, 47, 47, 361, 145, 145, 145, 145, + 362, 47, 47, 363, 145, 66, 47, 364, 47, 365, 145, 145, 366, 47, 367, 66, + 47, 47, 47, 368, 47, 369, 47, 369, 47, 368, 144, 145, 145, 145, 145, 145, + 9, 9, 9, 9, 11, 11, 11, 370, 47, 47, 371, 160, 372, 9, 373, 11, + 374, 227, 227, 227, 227, 227, 227, 227, 145, 145, 145, 145, 145, 145, 145, 145, + 47, 47, 375, 47, 275, 376, 146, 377, 47, 365, 378, 47, 60, 379, 66, 47, + 380, 66, 66, 47, 381, 145, 47, 47, 382, 47, 47, 363, 383, 384, 385, 386, + 180, 47, 47, 387, 388, 47, 47, 160, 97, 47, 389, 390, 391, 47, 47, 392, + 180, 47, 47, 393, 394, 395, 396, 145, 47, 47, 397, 398, 362, 32, 32, 32, + 47, 47, 368, 47, 47, 399, 172, 160, 92, 47, 47, 113, 400, 401, 402, 32, + 47, 47, 47, 403, 404, 405, 406, 32, 47, 47, 47, 407, 408, 409, 47, 47, + 47, 47, 47, 410, 411, 160, 160, 160, 47, 47, 412, 413, 414, 415, 32, 32, + 47, 47, 47, 416, 417, 160, 66, 66, 47, 47, 418, 419, 160, 160, 160, 160, + 47, 420, 421, 422, 47, 47, 47, 47, 47, 47, 397, 423, 66, 66, 66, 66, + 9, 9, 9, 9, 11, 11, 128, 424, 47, 47, 47, 425, 426, 160, 160, 160, + 47, 47, 47, 47, 47, 427, 428, 429, 430, 47, 47, 431, 432, 433, 47, 47, + 434, 435, 66, 47, 47, 47, 47, 47, 66, 66, 66, 66, 66, 66, 436, 429, + 47, 47, 47, 47, 47, 47, 437, 160, 47, 47, 412, 438, 437, 128, 145, 439, + 47, 156, 440, 441, 32, 32, 32, 32, 47, 47, 47, 362, 442, 160, 47, 47, + 443, 444, 160, 47, 47, 445, 160, 160, 47, 47, 47, 47, 47, 47, 47, 446, + 447, 47, 47, 448, 449, 450, 32, 32, 47, 47, 47, 47, 145, 451, 452, 453, + 220, 220, 220, 220, 220, 220, 220, 66, 47, 47, 47, 47, 47, 47, 47, 437, + 47, 47, 47, 209, 454, 32, 47, 47, 47, 455, 456, 160, 160, 160, 160, 160, + 47, 47, 47, 47, 47, 47, 306, 47, 47, 47, 47, 47, 160, 47, 47, 457, + 47, 47, 47, 458, 459, 460, 461, 47, 27, 27, 27, 27, 462, 47, 463, 160, + 9, 9, 9, 9, 9, 9, 11, 11, 145, 464, 9, 465, 11, 11, 11, 11, + 47, 47, 47, 47, 399, 466, 429, 429, 467, 468, 27, 27, 27, 27, 469, 470, + 47, 471, 209, 209, 209, 209, 209, 209, 146, 146, 146, 146, 146, 146, 146, 472, + 146, 146, 146, 146, 146, 146, 146, 227, 32, 32, 32, 32, 32, 146, 146, 146, + 146, 146, 146, 146, 146, 146, 473, 474, 475, 146, 476, 146, 146, 146, 146, 146, + 146, 146, 146, 146, 477, 146, 146, 146, 9, 478, 11, 479, 480, 11, 197, 9, + 481, 482, 9, 483, 11, 9, 478, 11, 479, 480, 11, 197, 9, 481, 482, 9, + 483, 11, 9, 478, 11, 479, 480, 11, 197, 9, 481, 482, 9, 483, 11, 9, + 478, 11, 197, 9, 484, 485, 486, 487, 11, 488, 9, 489, 490, 491, 492, 11, + 493, 9, 494, 11, 495, 160, 160, 160, 32, 32, 32, 496, 32, 32, 497, 498, + 499, 500, 32, 32, 32, 32, 32, 32, 501, 11, 11, 11, 11, 11, 11, 11, + 32, 32, 32, 27, 27, 27, 27, 27, 32, 32, 32, 32, 32, 32, 32, 32, + 47, 47, 47, 502, 503, 146, 146, 146, 47, 47, 455, 32, 47, 47, 504, 505, + 47, 47, 47, 47, 47, 47, 506, 160, 47, 47, 47, 47, 47, 47, 455, 507, + 47, 47, 47, 47, 47, 47, 508, 509, 47, 47, 47, 47, 358, 32, 32, 32, + 9, 9, 481, 11, 510, 306, 66, 66, 145, 145, 511, 512, 145, 145, 145, 145, + 145, 145, 513, 145, 145, 145, 145, 145, 47, 47, 47, 47, 47, 47, 47, 227, + 514, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 515, + 146, 146, 146, 146, 146, 227, 227, 227, 209, 209, 209, 209, 209, 209, 209, 209, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008, + 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0, + 1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193, + 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303, + 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149, + 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175, + 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199, + 1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0, + 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231, + 1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258, + 1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275, + 1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0, + 1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093, + 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 949,1134,1010, + 1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347, + 1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424, + 1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365, + 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238, + 1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182, + 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232, + 1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 9, 0, 10,1425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461, + 1514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1446,1458,1468,1476,1480,1486, + 1517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1489,1503,1494,1500,1508, 0, + 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0, + 1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0, + 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553, + 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560, + 1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0, + 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0, + 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627, + 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0, + 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0, + 1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0, + 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0, + 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0, + 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0, + 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0, + 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0, + 1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153, + 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171, + 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356, + 1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214, + 1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363, + 1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251, + 1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266, + 1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287, + 1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302, + 1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0, + 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375, + 1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353, + 1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234, + 1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403, + 1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412, + 1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0, + 1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721, + 1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0, + 1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757, + 1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776, + 1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0, + 1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793, + 1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814, + 1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0, + 1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728, + 1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764, + 1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821, + 1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0, + 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828, + 1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833, + 1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3, + 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0, + 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838, + 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0, + 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0, + 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938, + 1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0, + 1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870, + 1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0, + 1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0, + 1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0, + 1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0, + 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0, + 1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0, + 1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0, + 1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0, + 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0, + 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601, + 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662, + 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168, + 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758, + 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585, + 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259, + 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697, + 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170, + 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330, + 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473, + 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603, + 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411, + 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583, + 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269, + 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510, + 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156, + 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0, + 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0, + 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773, + 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329, + 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548, + 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651, + 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0, + 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243, + 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362, + 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490, + 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586, + 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706, + 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848, + 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575, + 1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0, + 1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0,1939, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1940, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1943,1944, 0, 0, 0, + 0, 0, 0,1945, 0,1946, 0, 0, 0, 0, 0, 0, 0, 0,1947, 0, + 0,1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1950, 0,1949,1951, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1953,1952, 0,1954, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1955,1956, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1957, 0, 0, 0, 0, 0, 0, 0, + 0,1958,1961,1959,1965,1960,1962,1964,1963, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1967,1966,1968, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1969,1970, + 1971,1972,1973,1974,1975, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1976,1977,1978,1980,1979, + 1981, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131, + 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37, + 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179, + 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195, + 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216, + 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244, + 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259, + 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276, + 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934, + 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312, + 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334, + 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361, + 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381, + 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399, + 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417, + 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433, + 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460, + 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870, + 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505, + 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64, + 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538, + 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567, + 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592, + 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611, + 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627, + 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651, + 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83, + 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85, + 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696, + 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728, + 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90, + 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787, + 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807, + 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0, +}; +static const int16_t _hb_ucd_i16[92]= +{ + 0, 0, 1, -1, 2, 0, -2, 0, 0, 2, 0, -2, 0, 16, 0, -16, + 0, 1, -1, 0, 3, 3, 3, -3, -3, -3, 0, 2016, 0, 2527, 1923, 1914, + 1918, 0, 2250, 0, 0, 138, 0, 7, -7, 0, -1, 1, 1824, 0, 2104, 0, + 2108, 2106, 0, 2106, 1316, 0, -1, -138, 8, 8, 8, 0, 7, 7, -8, -8, + -8, -7,-1316, 1, -1, 3, -3, 1, 0,-1914,-1918, 0, 0,-1923,-1824, 0, + 0,-2016,-2104, 0, 0,-2106,-2108,-2106,-2250, 0,-2527, 0, +}; + +static inline uint8_t _hb_ucd_gc (unsigned u) +{ + return u<1114112 ? _hb_ucd_u8[5296u+((_hb_ucd_u8[1168u+((_hb_ucd_u16[((_hb_ucd_u8[544u+((_hb_ucd_u8[((((((((u)>>1))>>3))>>3))>>4)])<<4)+((((((((u)>>1))>>3))>>3))&15)])<<3)+((((((u)>>1))>>3))&7)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : 2; +} +static inline uint8_t _hb_ucd_ccc (unsigned u) +{ + return u<125259 ? _hb_ucd_u8[7322u+((_hb_ucd_u8[6738u+((_hb_ucd_u8[6258u+((_hb_ucd_u8[5890u+((_hb_ucd_u8[5644u+((((((((u)>>2))>>2))>>2))>>3)])<<3)+((((((((u)>>2))>>2))>>2))&7)])<<2)+((((((u)>>2))>>2))&3)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)] : 0; +} +static inline uint8_t _hb_ucd_b4 (const uint8_t* a, unsigned i) +{ + return (a[i>>1]>>((i&1)<<2))&15; +} +static inline int16_t _hb_ucd_bmg (unsigned u) +{ + return u<65380 ? _hb_ucd_i16[((_hb_ucd_u8[8218u+((_hb_ucd_u8[7986u+((_hb_ucd_u8[7890u+((_hb_ucd_b4(_hb_ucd_u8+7826u,((((((((u)>>1))>>2))>>3))>>3)))<<3)+((((((((u)>>1))>>2))>>3))&7)])<<3)+((((((u)>>1))>>2))&7)])<<2)+((((u)>>1))&3)])<<1)+((u)&1)] : 0; +} +static inline uint8_t _hb_ucd_sc (unsigned u) +{ + return u<918016 ? _hb_ucd_u8[11655u+((_hb_ucd_u8[10647u+((_hb_ucd_u8[9151u+((_hb_ucd_u8[8703u+((_hb_ucd_u8[8495u+((_hb_ucd_b4(_hb_ucd_u8+8466u,((((((((((u)>>2))>>2))>>3))>>3))>>4)))<<4)+((((((((((u)>>2))>>2))>>3))>>3))&15)])<<3)+((((((((u)>>2))>>2))>>3))&7)])<<3)+((((((u)>>2))>>2))&7)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)] : 2; +} +static inline uint16_t _hb_ucd_dm (unsigned u) +{ + return u<195102 ? _hb_ucd_u16[1680u+((_hb_ucd_u8[13041u+((_hb_ucd_u8[12659u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)] : 0; +} + + #endif - #endif /* HB_UCD_TABLE_HH */ /* == End of generated table == */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-unicode-emoji-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-unicode-emoji-table.hh index 4bc8d64c28f..711dd9b6571 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-unicode-emoji-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-unicode-emoji-table.hh @@ -7,13 +7,13 @@ * on file with this header: * * # emoji-data.txt - * # Date: 2024-05-01, 21:25:24 GMT - * # © 2024 Unicode®, Inc. + * # Date: 2025-07-25, 17:54:31 GMT + * # © 2025 Unicode®, Inc. * # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. * # For terms of use and license, see https://www.unicode.org/terms_of_use.html * # * # Emoji Data for UTS #51 - * # Used with Emoji Version 16.0 and subsequent minor revisions (if any) + * # Version: 17.0 * # * # For documentation and usage, see https://www.unicode.org/reports/tr51 */ @@ -23,54 +23,62 @@ #include "hb-unicode.hh" -static const uint8_t -_hb_emoji_u8[464] = +#include + +static const uint8_t _hb_emoji_u8[624]= { 16, 17, 17, 17, 50, 20, 21, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,118,152, - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 0, 3, 4, 0, 0, 5, 6, 0, 7, 0, 8, 9, 10, 11, 12, - 0, 0, 13, 0, 0, 0, 14, 0, 15, 0, 0, 0, 0, 16, 0, 0, - 17, 17, 18, 19, 20, 17, 17, 21, 17, 17, 22, 17, 23, 17, 24, 25, - 26, 27, 28, 17, 17, 17, 0, 0, 17, 17, 17, 17, 17, 17, 17, 29, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 4, 0, 0, - 5, 6, 0, 0, 7, 8, 0, 0, 8, 0, 9, 10, 0, 0, 11, 0, - 0, 12, 13, 14, 15, 16, 16, 16, 17, 16, 16, 16, 18, 19, 20, 21, - 22, 23, 0, 0, 0, 24, 0, 0, 25, 0, 26, 0, 0, 27, 0, 0, - 28, 0, 0, 0, 16, 16, 16, 16, 29, 9, 0, 30, 31, 32, 16, 33, - 34, 35, 36, 16, 16, 16, 16, 37, 16, 38, 39, 16, 16, 16, 40, 0, - 0, 0, 0, 41, 0, 0, 42, 16, 43, 0, 44, 0, 45, 46, 16, 16, - 47, 48, 49, 16, 16, 16, 16, 38, 0, 0, 0, 0, 0, 66, 0, 0, - 0, 0, 0, 16, 0, 2, 0, 0, 4, 0, 0, 2, 0, 0,240, 3, - 0, 6, 0, 0, 0, 0, 0, 12, 0, 1, 0, 0, 0,128, 0, 0, - 0,254, 15, 7, 4, 0, 0, 0, 0, 12, 64, 0, 1, 0, 0, 0, - 0, 0, 0,120,191,255,247,255,255,255,255,255, 63, 0,255,255, - 63,255, 87, 32, 2, 1, 24, 0,144, 80,184, 0,248, 0, 0, 0, - 0, 0,224, 0, 2, 0, 1,128, 0, 0, 48, 0,224, 0, 0, 24, - 0, 0, 33, 0, 0, 0, 1, 32, 0, 0,128, 2, 0,224, 0, 0, - 0,240, 3,192, 0, 64,254, 7, 0,224,255,255, 63, 0, 0, 0, - 254,255, 0, 4, 0,128,252,247, 0,254,255,255,255,255,255, 7, - 255,255,255, 63,192,255,255,255,255,255, 0, 0, 0, 0,240,255, - 0, 0,224,255, 0,240, 0, 0, 0,255, 0,252, 0,255, 0, 0, - 0,192,255,255, 0,240,255,255,255,255,255,247,191,255,255,255, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 3, 0, 0, 4, 0, 5, 0, 0, 0, 0, 0, 6, 0, 0, 7, + 0, 0, 0, 8, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0, + 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 19, 20, 0, 0, + 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, + 23, 0, 24, 25, 0, 26, 27, 28, 29, 30, 31, 31, 32, 31, 33, 34, + 31, 31, 31, 35, 36, 37, 38, 39, 31, 40, 31, 41, 0, 0, 0, 42, + 43, 44, 45, 46, 47, 48, 31, 31, 0, 49, 31, 31, 0, 0, 0, 0, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 36, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 16, 0, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 0, 0, 2, 0, 0,240, 3, 0, 6, 0, 0, + 0, 0, 0, 12, 0, 1, 0, 0, 0,128, 0, 0, 0,254, 15, 7, + 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 64, 0, + 1, 0, 0, 0, 0, 0, 0,120, 31, 64, 50, 33, 77,196, 0, 7, + 5,255, 15,128,105, 1, 0,200, 0, 0,252, 26,131, 12, 3, 96, + 48,193, 26, 0, 0, 6,191, 39, 36,191, 84, 32, 2, 1, 24, 0, + 144, 80,184, 0, 24, 0, 0, 0, 0, 0,224, 0, 2, 0, 1,128, + 0, 0, 0, 0, 0, 0, 48, 0,224, 0, 0, 24, 0, 0, 0, 0, + 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, + 0, 0,128, 2, 0, 0, 0, 0, 16, 0, 0, 0, 0,240, 0, 0, + 0, 0,240,255, 0,128, 1, 0, 1,128, 1, 0, 0, 0,192,255, + 0, 0, 0, 0, 0, 0, 3,192, 0, 64,254, 7, 0,192,255,255, + 255,255,255,255, 63, 0, 0, 0,254,255, 0, 4, 0,128,252,247, + 0,254,255,255,192,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,243,255,255,255,255,255,207,206,255,255,255,255, + 255,255,255,255,255,255,185, 7,255,255,255,255,255,255,255,191, + 255,255,255,255,255,255,255, 63, 0,126,255,255,255,128,249, 7, + 128, 60, 97, 0, 48, 1, 6, 16, 28, 0, 14,112, 10,129, 8,252, + 255,255, 0, 0, 0, 0, 0, 0, 63,248,231,255, 63,250,249,255, + 0, 0, 0,252,255,255,255,255, 0,240, 0, 0, 0, 0, 0, 0, + 0,255, 0,252, 0, 0, 0, 0, 0,255, 0, 0, 0,192, 0,240, + 252,255, 0,254,255,255,255,255, 0,240,255,255,255,255,255,247, + 191,255,255,255,255,255,255,255, 0, 0, 0,255, 0,192,255,255, }; -static inline unsigned -_hb_emoji_b4 (const uint8_t* a, unsigned i) +static inline uint8_t _hb_emoji_b4 (const uint8_t* a, unsigned i) { - return (a[i>>1]>>((i&1u)<<2))&15u; + return (a[i>>1]>>((i&1)<<2))&15; } -static inline unsigned -_hb_emoji_b1 (const uint8_t* a, unsigned i) +static inline uint8_t _hb_emoji_b1 (const uint8_t* a, unsigned i) { - return (a[i>>3]>>((i&7u)<<0))&1u; + return (a[i>>3]>>((i&7)<<0))&1; } -static inline uint_fast8_t -_hb_emoji_is_Extended_Pictographic (unsigned u) +static inline uint8_t _hb_emoji_is_Extended_Pictographic (unsigned u) { - return u<131070u?_hb_emoji_b1(264+_hb_emoji_u8,((_hb_emoji_u8[144+(((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>5>>2>>3))<<3)+((u>>5>>2)&7u))])<<2)+((u>>5)&3u))])<<5)+((u)&31u)):0; + return u<131070 ? _hb_emoji_b1(_hb_emoji_u8+224u,((_hb_emoji_u8[64u+((_hb_emoji_b4(_hb_emoji_u8,((((u)>>6))>>4)))<<4)+((((u)>>6))&15)])<<6)+((u)&63)) : 0; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh b/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh index 924105001d7..9e6f89365fe 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh @@ -241,6 +241,57 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE } } + static hb_codepoint_t + vertical_char_for (hb_codepoint_t u) + { + switch (u >> 8) + { + case 0x20: switch (u) { + case 0x2013u: return 0xfe32u; // EN DASH + case 0x2014u: return 0xfe31u; // EM DASH + case 0x2025u: return 0xfe30u; // TWO DOT LEADER + case 0x2026u: return 0xfe19u; // HORIZONTAL ELLIPSIS + } break; + case 0x30: switch (u) { + case 0x3001u: return 0xfe11u; // IDEOGRAPHIC COMMA + case 0x3002u: return 0xfe12u; // IDEOGRAPHIC FULL STOP + case 0x3008u: return 0xfe3fu; // LEFT ANGLE BRACKET + case 0x3009u: return 0xfe40u; // RIGHT ANGLE BRACKET + case 0x300au: return 0xfe3du; // LEFT DOUBLE ANGLE BRACKET + case 0x300bu: return 0xfe3eu; // RIGHT DOUBLE ANGLE BRACKET + case 0x300cu: return 0xfe41u; // LEFT CORNER BRACKET + case 0x300du: return 0xfe42u; // RIGHT CORNER BRACKET + case 0x300eu: return 0xfe43u; // LEFT WHITE CORNER BRACKET + case 0x300fu: return 0xfe44u; // RIGHT WHITE CORNER BRACKET + case 0x3010u: return 0xfe3bu; // LEFT BLACK LENTICULAR BRACKET + case 0x3011u: return 0xfe3cu; // RIGHT BLACK LENTICULAR BRACKET + case 0x3014u: return 0xfe39u; // LEFT TORTOISE SHELL BRACKET + case 0x3015u: return 0xfe3au; // RIGHT TORTOISE SHELL BRACKET + case 0x3016u: return 0xfe17u; // LEFT WHITE LENTICULAR BRACKET + case 0x3017u: return 0xfe18u; // RIGHT WHITE LENTICULAR BRACKET + } break; + case 0xfe: switch (u) { + case 0xfe4fu: return 0xfe34u; // WAVY LOW LINE + } break; + case 0xff: switch (u) { + case 0xff01u: return 0xfe15u; // FULLWIDTH EXCLAMATION MARK + case 0xff08u: return 0xfe35u; // FULLWIDTH LEFT PARENTHESIS + case 0xff09u: return 0xfe36u; // FULLWIDTH RIGHT PARENTHESIS + case 0xff0cu: return 0xfe10u; // FULLWIDTH COMMA + case 0xff1au: return 0xfe13u; // FULLWIDTH COLON + case 0xff1bu: return 0xfe14u; // FULLWIDTH SEMICOLON + case 0xff1fu: return 0xfe16u; // FULLWIDTH QUESTION MARK + case 0xff3bu: return 0xfe47u; // FULLWIDTH LEFT SQUARE BRACKET + case 0xff3du: return 0xfe48u; // FULLWIDTH RIGHT SQUARE BRACKET + case 0xff3fu: return 0xfe33u; // FULLWIDTH LOW LINE + case 0xff5bu: return 0xfe37u; // FULLWIDTH LEFT CURLY BRACKET + case 0xff5du: return 0xfe38u; // FULLWIDTH RIGHT CURLY BRACKET + } break; + } + + return u; + } + struct { #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_func_t name; HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS diff --git a/src/java.desktop/share/native/libharfbuzz/hb-utf.hh b/src/java.desktop/share/native/libharfbuzz/hb-utf.hh index 7fd3bf8828b..3891fb331af 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-utf.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-utf.hh @@ -37,7 +37,7 @@ struct hb_utf8_t typedef uint8_t codepoint_t; static constexpr unsigned max_len = 4; - static const codepoint_t * + static inline const codepoint_t * next (const codepoint_t *text, const codepoint_t *end, hb_codepoint_t *unicode, @@ -106,7 +106,7 @@ struct hb_utf8_t return text; } - static const codepoint_t * + static inline const codepoint_t * prev (const codepoint_t *text, const codepoint_t *start, hb_codepoint_t *unicode, @@ -185,7 +185,7 @@ struct hb_utf16_xe_t typedef TCodepoint codepoint_t; static constexpr unsigned max_len = 2; - static const codepoint_t * + static inline const codepoint_t * next (const codepoint_t *text, const codepoint_t *end, hb_codepoint_t *unicode, @@ -217,7 +217,7 @@ struct hb_utf16_xe_t return text; } - static const codepoint_t * + static inline const codepoint_t * prev (const codepoint_t *text, const codepoint_t *start, hb_codepoint_t *unicode, @@ -294,7 +294,7 @@ struct hb_utf32_xe_t typedef TCodepoint codepoint_t; static constexpr unsigned max_len = 1; - static const TCodepoint * + static inline const TCodepoint * next (const TCodepoint *text, const TCodepoint *end HB_UNUSED, hb_codepoint_t *unicode, @@ -306,7 +306,7 @@ struct hb_utf32_xe_t return text; } - static const TCodepoint * + static inline const TCodepoint * prev (const TCodepoint *text, const TCodepoint *start HB_UNUSED, hb_codepoint_t *unicode, @@ -353,7 +353,7 @@ struct hb_latin1_t typedef uint8_t codepoint_t; static constexpr unsigned max_len = 1; - static const codepoint_t * + static inline const codepoint_t * next (const codepoint_t *text, const codepoint_t *end HB_UNUSED, hb_codepoint_t *unicode, @@ -363,7 +363,7 @@ struct hb_latin1_t return text; } - static const codepoint_t * + static inline const codepoint_t * prev (const codepoint_t *text, const codepoint_t *start HB_UNUSED, hb_codepoint_t *unicode, @@ -405,7 +405,7 @@ struct hb_ascii_t typedef uint8_t codepoint_t; static constexpr unsigned max_len = 1; - static const codepoint_t * + static inline const codepoint_t * next (const codepoint_t *text, const codepoint_t *end HB_UNUSED, hb_codepoint_t *unicode, @@ -417,7 +417,7 @@ struct hb_ascii_t return text; } - static const codepoint_t * + static inline const codepoint_t * prev (const codepoint_t *text, const codepoint_t *start HB_UNUSED, hb_codepoint_t *unicode, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-vector.hh b/src/java.desktop/share/native/libharfbuzz/hb-vector.hh index cd27da96648..b650ca9f066 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-vector.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-vector.hh @@ -32,6 +32,12 @@ #include "hb-meta.hh" #include "hb-null.hh" +// Change to 1 to force inline vector allocs, to see callsite in malloc-stats tool. +#if 0 +#define HB_ALWAYS_INLINE_VECTOR_ALLOCS HB_ALWAYS_INLINE +#else +#define HB_ALWAYS_INLINE_VECTOR_ALLOCS +#endif template @@ -45,6 +51,7 @@ struct hb_vector_t using c_array_t = typename std::conditional, hb_array_t>::type; hb_vector_t () = default; + HB_ALWAYS_INLINE_VECTOR_ALLOCS hb_vector_t (std::initializer_list lst) : hb_vector_t () { alloc (lst.size (), true); @@ -57,18 +64,21 @@ struct hb_vector_t { extend (o); } + HB_ALWAYS_INLINE_VECTOR_ALLOCS hb_vector_t (const hb_vector_t &o) : hb_vector_t () { alloc_exact (o.length); if (unlikely (in_error ())) return; copy_array (o.as_array ()); } + HB_ALWAYS_INLINE_VECTOR_ALLOCS hb_vector_t (array_t o) : hb_vector_t () { alloc_exact (o.length); if (unlikely (in_error ())) return; copy_array (o); } + HB_ALWAYS_INLINE_VECTOR_ALLOCS hb_vector_t (c_array_t o) : hb_vector_t () { alloc_exact (o.length); @@ -84,8 +94,29 @@ struct hb_vector_t } ~hb_vector_t () { fini (); } + template + void + set_storage (Type (&array)[n]) + { set_storage (array, n); } + void + set_storage (hb_array_t array) + { set_storage (array.arrayZ, array.length); } + template + void + set_storage (Type *array, unsigned n) + { + assert (allocated == 0); + assert (length == 0); + + arrayZ = array; + length = n; + } + template + HB_ALWAYS_INLINE_VECTOR_ALLOCS void extend (const Iterable &o) { auto iter = hb_iter (o); @@ -106,12 +137,14 @@ struct hb_vector_t push_has_room (*iter++); } } + HB_ALWAYS_INLINE_VECTOR_ALLOCS void extend (array_t o) { alloc (length + o.length); if (unlikely (in_error ())) return; copy_array (o); } + HB_ALWAYS_INLINE_VECTOR_ALLOCS void extend (c_array_t o) { alloc (length + o.length); @@ -136,10 +169,7 @@ struct hb_vector_t void fini () { - /* We allow a hack to make the vector point to a foreign array - * by the user. In that case length/arrayZ are non-zero but - * allocated is zero. Don't free anything. */ - if (allocated) + if (is_owned ()) { shrink_vector (0); hb_free (arrayZ); @@ -147,11 +177,13 @@ struct hb_vector_t init (); } - void reset () + HB_ALWAYS_INLINE_VECTOR_ALLOCS + hb_vector_t &reset () { if (unlikely (in_error ())) reset_error (); resize (0); + return *this; } friend void swap (hb_vector_t& a, hb_vector_t& b) noexcept @@ -237,13 +269,16 @@ struct hb_vector_t Type * operator + (unsigned int i) { return arrayZ + i; } const Type * operator + (unsigned int i) const { return arrayZ + i; } + HB_ALWAYS_INLINE_VECTOR_ALLOCS Type *push () { if (unlikely (!resize (length + 1))) return std::addressof (Crap (Type)); return std::addressof (arrayZ[length - 1]); } - template Type *push (Args&&... args) + template + HB_ALWAYS_INLINE_VECTOR_ALLOCS + Type *push (Args&&... args) { if (unlikely ((int) length >= allocated && !alloc (length + 1))) // If push failed to allocate then don't copy v, since this may cause @@ -253,13 +288,20 @@ struct hb_vector_t return push_has_room (std::forward (args)...); } - template Type *push_has_room (Args&&... args) + template + HB_ALWAYS_INLINE_VECTOR_ALLOCS + Type *push_has_room (Args&&... args) { /* Emplace. */ Type *p = std::addressof (arrayZ[length++]); return new (p) Type (std::forward (args)...); } + bool is_owned () const + { + return allocated != 0 && allocated != -1; + } + bool in_error () const { return allocated < 0; } void set_error () { @@ -271,27 +313,40 @@ struct hb_vector_t assert (allocated < 0); allocated = -(allocated + 1); } + void ensure_error () + { + if (!in_error ()) + set_error (); + } - template Type * - realloc_vector (unsigned new_allocated, hb_priority<0>) + _realloc (unsigned new_allocated) { if (!new_allocated) { - hb_free (arrayZ); + if (is_owned ()) + hb_free (arrayZ); return nullptr; } + if (!allocated && arrayZ) + { + /* If we have a non-null arrayZ but allocated is 0, then we are + * reallocating from a foreign array. */ + Type *new_array = (Type *) hb_malloc (new_allocated * sizeof (Type)); + if (unlikely (!new_array)) + return nullptr; + hb_memcpy ((void *) new_array, (const void *) arrayZ, length * sizeof (Type)); + return new_array; + } return (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type)); } - template Type * - realloc_vector (unsigned new_allocated, hb_priority<0>) + _malloc_move (unsigned new_allocated) { if (!new_allocated) { - hb_free (arrayZ); + if (is_owned ()) + hb_free (arrayZ); return nullptr; } Type *new_array = (Type *) hb_malloc (new_allocated * sizeof (Type)); @@ -303,22 +358,33 @@ struct hb_vector_t new_array[i] = std::move (arrayZ[i]); arrayZ[i].~Type (); } - hb_free (arrayZ); + if (is_owned ()) + hb_free (arrayZ); } return new_array; } + + template + Type * + realloc_vector (unsigned new_allocated, hb_priority<0>) + { + return _realloc (new_allocated); + } + template + Type * + realloc_vector (unsigned new_allocated, hb_priority<0>) + { + return _malloc_move (new_allocated); + } /* Specialization for types that can be moved using realloc(). */ template Type * realloc_vector (unsigned new_allocated, hb_priority<1>) { - if (!new_allocated) - { - hb_free (arrayZ); - return nullptr; - } - return (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type)); + return _realloc (new_allocated); } template other) { - assert ((int) (length + other.length) <= allocated); hb_memcpy ((void *) (arrayZ + length), (const void *) other.arrayZ, other.length * item_size); length += other.length; } @@ -362,7 +427,6 @@ struct hb_vector_t void copy_array (hb_array_t other) { - assert ((int) (length + other.length) <= allocated); hb_memcpy ((void *) (arrayZ + length), (const void *) other.arrayZ, other.length * item_size); length += other.length; } @@ -372,7 +436,6 @@ struct hb_vector_t void copy_array (hb_array_t other) { - assert ((int) (length + other.length) <= allocated); for (unsigned i = 0; i < other.length; i++) new (std::addressof (arrayZ[length + i])) Type (other.arrayZ[i]); length += other.length; @@ -385,7 +448,6 @@ struct hb_vector_t void copy_array (hb_array_t other) { - assert ((int) (length + other.length) <= allocated); for (unsigned i = 0; i < other.length; i++) { new (std::addressof (arrayZ[length + i])) Type (); @@ -398,12 +460,12 @@ struct hb_vector_t shrink_vector (unsigned size) { assert (size <= length); - if (!std::is_trivially_destructible::value) + if (!hb_is_trivially_destructible(Type)) { unsigned count = length - size; - Type *p = arrayZ + length - 1; + Type *p = arrayZ + length; while (count--) - p--->~Type (); + (--p)->~Type (); } length = size; } @@ -416,6 +478,7 @@ struct hb_vector_t } /* Allocate for size but don't adjust length. */ + HB_ALWAYS_INLINE_VECTOR_ALLOCS bool alloc (unsigned int size, bool exact=false) { if (unlikely (in_error ())) @@ -471,17 +534,64 @@ struct hb_vector_t return true; } + HB_ALWAYS_INLINE_VECTOR_ALLOCS bool alloc_exact (unsigned int size) { return alloc (size, true); } + HB_ALWAYS_INLINE_VECTOR_ALLOCS void clear () { resize (0); } - bool resize (int size_, bool initialize = true, bool exact = false) + template + HB_ALWAYS_INLINE_VECTOR_ALLOCS + bool allocate_from_pool (allocator_t *allocator, unsigned size, unsigned int initialize = true) + { + if (allocator) + { + assert (!length && !allocated); + arrayZ = (Type *) allocator->alloc (size * sizeof (Type), alignof (Type)); + if (unlikely (!arrayZ)) + { + set_error (); + return false; + } + if (initialize) + grow_vector (size, hb_prioritize); + else + length = size; + return true; + } + return resize_full ((int) size, initialize, true); + } + + template + HB_ALWAYS_INLINE_VECTOR_ALLOCS + bool duplicate_vector_from_pool (allocator_t *allocator, const hb_vector_t &other) + { + if (unlikely (!allocate_from_pool (allocator, other.length, false))) + return false; + length = 0; + copy_array (other.as_array ()); + return true; + } + + template + void shrink_back_to_pool (allocator_t *allocator, int size) + { + unsigned orig_length = length; + + shrink (size, false); + + if (allocator && !is_owned ()) + allocator->discard (arrayZ + length, (orig_length - length) * sizeof (Type)); + } + + HB_ALWAYS_INLINE_VECTOR_ALLOCS + bool resize_full (int size_, bool initialize, bool exact) { unsigned int size = size_ < 0 ? 0u : (unsigned int) size_; if (!alloc (size, exact)) @@ -501,9 +611,20 @@ struct hb_vector_t length = size; return true; } - bool resize_exact (int size_, bool initialize = true) + HB_ALWAYS_INLINE_VECTOR_ALLOCS + bool resize (int size_) { - return resize (size_, initialize, true); + return resize_full (size_, true, false); + } + HB_ALWAYS_INLINE_VECTOR_ALLOCS + bool resize_dirty (int size_) + { + return resize_full (size_, false, false); + } + HB_ALWAYS_INLINE_VECTOR_ALLOCS + bool resize_exact (int size_) + { + return resize_full (size_, true, true); } Type pop () @@ -544,7 +665,7 @@ struct hb_vector_t shrink_vector (size); - if (shrink_memory) + if (is_owned () && shrink_memory) alloc_exact (size); /* To force shrinking memory if needed. */ } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-version.h b/src/java.desktop/share/native/libharfbuzz/hb-version.h index e41286d2d8c..c673d1e3612 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-version.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-version.h @@ -41,26 +41,26 @@ HB_BEGIN_DECLS * * The major component of the library version available at compile-time. */ -#define HB_VERSION_MAJOR 11 +#define HB_VERSION_MAJOR 12 /** * HB_VERSION_MINOR: * * The minor component of the library version available at compile-time. */ -#define HB_VERSION_MINOR 2 +#define HB_VERSION_MINOR 3 /** * HB_VERSION_MICRO: * * The micro component of the library version available at compile-time. */ -#define HB_VERSION_MICRO 0 +#define HB_VERSION_MICRO 2 /** * HB_VERSION_STRING: * * A string literal containing the library version available at compile-time. */ -#define HB_VERSION_STRING "11.2.0" +#define HB_VERSION_STRING "12.3.2" /** * HB_VERSION_ATLEAST: diff --git a/src/java.desktop/share/native/libharfbuzz/hb.hh b/src/java.desktop/share/native/libharfbuzz/hb.hh index 8c430e5770d..7582abaa933 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb.hh @@ -89,7 +89,6 @@ #pragma GCC diagnostic error "-Wstring-conversion" #pragma GCC diagnostic error "-Wswitch-enum" #pragma GCC diagnostic error "-Wtautological-overlap-compare" -#pragma GCC diagnostic error "-Wuninitialized" #pragma GCC diagnostic error "-Wunneeded-internal-declaration" #pragma GCC diagnostic error "-Wunused" #pragma GCC diagnostic error "-Wunused-local-typedefs" @@ -110,11 +109,21 @@ #pragma GCC diagnostic warning "-Wformat-signedness" #pragma GCC diagnostic warning "-Wignored-pragma-optimize" #pragma GCC diagnostic warning "-Wlogical-op" -#pragma GCC diagnostic warning "-Wmaybe-uninitialized" #pragma GCC diagnostic warning "-Wmissing-format-attribute" +#pragma GCC diagnostic warning "-Wpessimizing-move" #pragma GCC diagnostic warning "-Wundef" #pragma GCC diagnostic warning "-Wunsafe-loop-optimizations" #pragma GCC diagnostic warning "-Wunused-but-set-variable" +#ifdef __clang__ +// The following are too buggy on gcc +// https://github.com/harfbuzz/harfbuzz/issues/5589 +// https://github.com/harfbuzz/harfbuzz/pull/5367 +#pragma GCC diagnostic warning "-Wmaybe-uninitialized" +#pragma GCC diagnostic warning "-Wuninitialized" +#else +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#pragma GCC diagnostic ignored "-Wuninitialized" +#endif #endif /* Ignored currently, but should be fixed at some point. */ @@ -136,6 +145,7 @@ #pragma GCC diagnostic ignored "-Wformat-nonliteral" #pragma GCC diagnostic ignored "-Wformat-zero-length" #pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#pragma GCC diagnostic ignored "-Wold-style-cast" #pragma GCC diagnostic ignored "-Wpacked" // Erratic impl in clang #pragma GCC diagnostic ignored "-Wrange-loop-analysis" // https://github.com/harfbuzz/harfbuzz/issues/2834 #pragma GCC diagnostic ignored "-Wstrict-aliasing" @@ -239,6 +249,8 @@ // clang defines it so no need. #ifdef __has_builtin #define hb_has_builtin __has_builtin +#elif defined(_MSC_VER) +#define hb_has_builtin(x) 0 #else #define hb_has_builtin(x) ((defined(__GNUC__) && __GNUC__ >= 5)) #endif @@ -314,6 +326,10 @@ #endif #endif +#ifndef HB_HOT +#define HB_HOT __attribute__((hot)) +#endif + /* * Borrowed from https://bugzilla.mozilla.org/show_bug.cgi?id=1215411 * HB_FALLTHROUGH is an annotation to suppress compiler warnings about switch @@ -553,4 +569,13 @@ extern "C" void hb_free_impl(void *ptr); #include "hb-vector.hh" // Requires: hb-array hb-null #include "hb-object.hh" // Requires: hb-atomic hb-mutex hb-vector + +/* Our src/test-*.cc use hb_assert(), such that it's not compiled out under NDEBUG. + * https://github.com/harfbuzz/harfbuzz/issues/5418 */ +#define hb_always_assert(x) \ + HB_STMT_START { \ + if (!(x)) { fprintf(stderr, "Assertion failed: %s, at %s:%d\n", #x, __FILE__, __LINE__); abort(); } \ + } HB_STMT_END + + #endif /* HB_HH */ From 67079b18afb4454fc849a35dd208ccf0b702339f Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 2 Feb 2026 22:29:15 +0000 Subject: [PATCH 296/328] 8377000: [BACKOUT] JDK-8376126 G1: Convert remaining volatiles in G1ConcurrentMark to Atomic Reviewed-by: kvn --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 70 ++++++++----------- src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 32 ++++----- .../share/gc/g1/g1ConcurrentMark.inline.hpp | 14 ++-- .../share/gc/g1/g1RegionMarkStatsCache.hpp | 2 - 4 files changed, 54 insertions(+), 64 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 4ed0a3065bc..5f096c2b9d7 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -24,7 +24,6 @@ #include "classfile/classLoaderData.hpp" #include "classfile/classLoaderDataGraph.hpp" -#include "cppstdlib/new.hpp" #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1BatchedTask.hpp" #include "gc/g1/g1CardSetMemory.hpp" @@ -520,8 +519,8 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, _max_concurrent_workers(0), _region_mark_stats(NEW_C_HEAP_ARRAY(G1RegionMarkStats, _g1h->max_num_regions(), mtGC)), - _top_at_mark_starts(NEW_C_HEAP_ARRAY(Atomic, _g1h->max_num_regions(), mtGC)), - _top_at_rebuild_starts(NEW_C_HEAP_ARRAY(Atomic, _g1h->max_num_regions(), mtGC)), + _top_at_mark_starts(NEW_C_HEAP_ARRAY(HeapWord*, _g1h->max_num_regions(), mtGC)), + _top_at_rebuild_starts(NEW_C_HEAP_ARRAY(HeapWord*, _g1h->max_num_regions(), mtGC)), _needs_remembered_set_rebuild(false) { assert(G1CGC_lock != nullptr, "CGC_lock must be initialized"); @@ -565,12 +564,6 @@ void G1ConcurrentMark::fully_initialize() { _tasks[i] = new G1CMTask(i, this, task_queue, _region_mark_stats); } - for (uint i = 0; i < _g1h->max_num_regions(); i++) { - ::new (&_region_mark_stats[i]) G1RegionMarkStats{}; - ::new (&_top_at_mark_starts[i]) Atomic{}; - ::new (&_top_at_rebuild_starts[i]) Atomic{}; - } - reset_at_marking_complete(); } @@ -583,7 +576,7 @@ PartialArrayStateManager* G1ConcurrentMark::partial_array_state_manager() const } void G1ConcurrentMark::reset() { - _has_aborted.store_relaxed(false); + _has_aborted = false; reset_marking_for_restart(); @@ -595,7 +588,7 @@ void G1ConcurrentMark::reset() { uint max_num_regions = _g1h->max_num_regions(); for (uint i = 0; i < max_num_regions; i++) { - _top_at_rebuild_starts[i].store_relaxed(nullptr); + _top_at_rebuild_starts[i] = nullptr; _region_mark_stats[i].clear(); } @@ -607,7 +600,7 @@ void G1ConcurrentMark::clear_statistics(G1HeapRegion* r) { for (uint j = 0; j < _max_num_tasks; ++j) { _tasks[j]->clear_mark_stats_cache(region_idx); } - _top_at_rebuild_starts[region_idx].store_relaxed(nullptr); + _top_at_rebuild_starts[region_idx] = nullptr; _region_mark_stats[region_idx].clear(); } @@ -643,7 +636,7 @@ void G1ConcurrentMark::reset_marking_for_restart() { } clear_has_overflown(); - _finger.store_relaxed(_heap.start()); + _finger = _heap.start(); for (uint i = 0; i < _max_num_tasks; ++i) { G1CMTaskQueue* queue = _task_queues->queue(i); @@ -665,14 +658,14 @@ void G1ConcurrentMark::set_concurrency(uint active_tasks) { void G1ConcurrentMark::set_concurrency_and_phase(uint active_tasks, bool concurrent) { set_concurrency(active_tasks); - _concurrent.store_relaxed(concurrent); + _concurrent = concurrent; if (!concurrent) { // At this point we should be in a STW phase, and completed marking. assert_at_safepoint_on_vm_thread(); assert(out_of_regions(), "only way to get here: _finger: " PTR_FORMAT ", _heap_end: " PTR_FORMAT, - p2i(finger()), p2i(_heap.end())); + p2i(_finger), p2i(_heap.end())); } } @@ -703,8 +696,8 @@ void G1ConcurrentMark::reset_at_marking_complete() { } G1ConcurrentMark::~G1ConcurrentMark() { - FREE_C_HEAP_ARRAY(Atomic, _top_at_mark_starts); - FREE_C_HEAP_ARRAY(Atomic, _top_at_rebuild_starts); + FREE_C_HEAP_ARRAY(HeapWord*, _top_at_mark_starts); + FREE_C_HEAP_ARRAY(HeapWord*, _top_at_rebuild_starts); FREE_C_HEAP_ARRAY(G1RegionMarkStats, _region_mark_stats); // The G1ConcurrentMark instance is never freed. ShouldNotReachHere(); @@ -1171,7 +1164,7 @@ void G1ConcurrentMark::concurrent_cycle_start() { } uint G1ConcurrentMark::completed_mark_cycles() const { - return _completed_mark_cycles.load_relaxed(); + return AtomicAccess::load(&_completed_mark_cycles); } void G1ConcurrentMark::concurrent_cycle_end(bool mark_cycle_completed) { @@ -1180,7 +1173,7 @@ void G1ConcurrentMark::concurrent_cycle_end(bool mark_cycle_completed) { _g1h->trace_heap_after_gc(_gc_tracer_cm); if (mark_cycle_completed) { - _completed_mark_cycles.add_then_fetch(1u, memory_order_relaxed); + AtomicAccess::inc(&_completed_mark_cycles, memory_order_relaxed); } if (has_aborted()) { @@ -1194,7 +1187,7 @@ void G1ConcurrentMark::concurrent_cycle_end(bool mark_cycle_completed) { } void G1ConcurrentMark::mark_from_roots() { - _restart_for_overflow.store_relaxed(false); + _restart_for_overflow = false; uint active_workers = calc_active_marking_workers(); @@ -1363,7 +1356,7 @@ void G1ConcurrentMark::remark() { } } else { // We overflowed. Restart concurrent marking. - _restart_for_overflow.store_relaxed(true); + _restart_for_overflow = true; verify_during_pause(G1HeapVerifier::G1VerifyRemark, VerifyLocation::RemarkOverflow); @@ -1792,45 +1785,44 @@ void G1ConcurrentMark::clear_bitmap_for_region(G1HeapRegion* hr) { } G1HeapRegion* G1ConcurrentMark::claim_region(uint worker_id) { - // "Checkpoint" the finger. - HeapWord* local_finger = finger(); + // "checkpoint" the finger + HeapWord* finger = _finger; - while (local_finger < _heap.end()) { - assert(_g1h->is_in_reserved(local_finger), "invariant"); + while (finger < _heap.end()) { + assert(_g1h->is_in_reserved(finger), "invariant"); - G1HeapRegion* curr_region = _g1h->heap_region_containing_or_null(local_finger); + G1HeapRegion* curr_region = _g1h->heap_region_containing_or_null(finger); // Make sure that the reads below do not float before loading curr_region. OrderAccess::loadload(); // Above heap_region_containing may return null as we always scan claim // until the end of the heap. In this case, just jump to the next region. - HeapWord* end = curr_region != nullptr ? curr_region->end() : local_finger + G1HeapRegion::GrainWords; + HeapWord* end = curr_region != nullptr ? curr_region->end() : finger + G1HeapRegion::GrainWords; // Is the gap between reading the finger and doing the CAS too long? - HeapWord* res = _finger.compare_exchange(local_finger, end); - if (res == local_finger && curr_region != nullptr) { - // We succeeded. + HeapWord* res = AtomicAccess::cmpxchg(&_finger, finger, end); + if (res == finger && curr_region != nullptr) { + // we succeeded HeapWord* bottom = curr_region->bottom(); HeapWord* limit = top_at_mark_start(curr_region); log_trace(gc, marking)("Claim region %u bottom " PTR_FORMAT " tams " PTR_FORMAT, curr_region->hrm_index(), p2i(curr_region->bottom()), p2i(top_at_mark_start(curr_region))); - // Notice that _finger == end cannot be guaranteed here since, - // someone else might have moved the finger even further. - assert(finger() >= end, "The finger should have moved forward"); + // notice that _finger == end cannot be guaranteed here since, + // someone else might have moved the finger even further + assert(_finger >= end, "the finger should have moved forward"); if (limit > bottom) { return curr_region; } else { assert(limit == bottom, - "The region limit should be at bottom"); + "the region limit should be at bottom"); // We return null and the caller should try calling // claim_region() again. return nullptr; } } else { - // Read the finger again. - HeapWord* next_finger = finger(); - assert(next_finger > local_finger, "The finger should have moved forward " PTR_FORMAT " " PTR_FORMAT, p2i(local_finger), p2i(next_finger)); - local_finger = next_finger; + assert(_finger > finger, "the finger should have moved forward"); + // read it again + finger = _finger; } } @@ -1970,7 +1962,7 @@ bool G1ConcurrentMark::concurrent_cycle_abort() { void G1ConcurrentMark::abort_marking_threads() { assert(!_root_regions.scan_in_progress(), "still doing root region scan"); - _has_aborted.store_relaxed(true); + _has_aborted = true; _first_overflow_barrier_sync.abort(); _second_overflow_barrier_sync.abort(); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 39d98db9876..3a4cbf1b83e 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -368,7 +368,7 @@ class G1ConcurrentMark : public CHeapObj { // For grey objects G1CMMarkStack _global_mark_stack; // Grey objects behind global finger - Atomic _finger; // The global finger, region aligned, + HeapWord* volatile _finger; // The global finger, region aligned, // always pointing to the end of the // last claimed region @@ -395,19 +395,19 @@ class G1ConcurrentMark : public CHeapObj { WorkerThreadsBarrierSync _second_overflow_barrier_sync; // Number of completed mark cycles. - Atomic _completed_mark_cycles; + volatile uint _completed_mark_cycles; // This is set by any task, when an overflow on the global data // structures is detected - Atomic _has_overflown; + volatile bool _has_overflown; // True: marking is concurrent, false: we're in remark - Atomic _concurrent; + volatile bool _concurrent; // Set at the end of a Full GC so that marking aborts - Atomic _has_aborted; + volatile bool _has_aborted; // Used when remark aborts due to an overflow to indicate that // another concurrent marking phase should start - Atomic _restart_for_overflow; + volatile bool _restart_for_overflow; ConcurrentGCTimer* _gc_timer_cm; @@ -461,8 +461,8 @@ class G1ConcurrentMark : public CHeapObj { void print_and_reset_taskqueue_stats(); - HeapWord* finger() { return _finger.load_relaxed(); } - bool concurrent() { return _concurrent.load_relaxed(); } + HeapWord* finger() { return _finger; } + bool concurrent() { return _concurrent; } uint active_tasks() { return _num_active_tasks; } TaskTerminator* terminator() { return &_terminator; } @@ -487,7 +487,7 @@ class G1ConcurrentMark : public CHeapObj { // to satisfy an allocation without doing a GC. This is fine, because all // objects in those regions will be considered live anyway because of // SATB guarantees (i.e. their TAMS will be equal to bottom). - bool out_of_regions() { return finger() >= _heap.end(); } + bool out_of_regions() { return _finger >= _heap.end(); } // Returns the task with the given id G1CMTask* task(uint id) { @@ -499,10 +499,10 @@ class G1ConcurrentMark : public CHeapObj { // Access / manipulation of the overflow flag which is set to // indicate that the global stack has overflown - bool has_overflown() { return _has_overflown.load_relaxed(); } - void set_has_overflown() { _has_overflown.store_relaxed(true); } - void clear_has_overflown() { _has_overflown.store_relaxed(false); } - bool restart_for_overflow() { return _restart_for_overflow.load_relaxed(); } + bool has_overflown() { return _has_overflown; } + void set_has_overflown() { _has_overflown = true; } + void clear_has_overflown() { _has_overflown = false; } + bool restart_for_overflow() { return _restart_for_overflow; } // Methods to enter the two overflow sync barriers void enter_first_sync_barrier(uint worker_id); @@ -516,12 +516,12 @@ class G1ConcurrentMark : public CHeapObj { G1RegionMarkStats* _region_mark_stats; // Top pointer for each region at the start of marking. Must be valid for all committed // regions. - Atomic* _top_at_mark_starts; + HeapWord* volatile* _top_at_mark_starts; // Top pointer for each region at the start of the rebuild remembered set process // for regions which remembered sets need to be rebuilt. A null for a given region // means that this region does not be scanned during the rebuilding remembered // set phase at all. - Atomic* _top_at_rebuild_starts; + HeapWord* volatile* _top_at_rebuild_starts; // True when Remark pause selected regions for rebuilding. bool _needs_remembered_set_rebuild; public: @@ -679,7 +679,7 @@ public: uint completed_mark_cycles() const; - bool has_aborted() { return _has_aborted.load_relaxed(); } + bool has_aborted() { return _has_aborted; } void print_summary_info(); diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp index 21167d5cae9..2f4824e4cae 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp @@ -194,11 +194,11 @@ inline void G1CMTask::process_array_chunk(objArrayOop obj, size_t start, size_t inline void G1ConcurrentMark::update_top_at_mark_start(G1HeapRegion* r) { uint const region = r->hrm_index(); assert(region < _g1h->max_num_regions(), "Tried to access TAMS for region %u out of bounds", region); - _top_at_mark_starts[region].store_relaxed(r->top()); + _top_at_mark_starts[region] = r->top(); } inline void G1ConcurrentMark::reset_top_at_mark_start(G1HeapRegion* r) { - _top_at_mark_starts[r->hrm_index()].store_relaxed(r->bottom()); + _top_at_mark_starts[r->hrm_index()] = r->bottom(); } inline HeapWord* G1ConcurrentMark::top_at_mark_start(const G1HeapRegion* r) const { @@ -207,7 +207,7 @@ inline HeapWord* G1ConcurrentMark::top_at_mark_start(const G1HeapRegion* r) cons inline HeapWord* G1ConcurrentMark::top_at_mark_start(uint region) const { assert(region < _g1h->max_num_regions(), "Tried to access TARS for region %u out of bounds", region); - return _top_at_mark_starts[region].load_relaxed(); + return _top_at_mark_starts[region]; } inline bool G1ConcurrentMark::obj_allocated_since_mark_start(oop obj) const { @@ -217,7 +217,7 @@ inline bool G1ConcurrentMark::obj_allocated_since_mark_start(oop obj) const { } inline HeapWord* G1ConcurrentMark::top_at_rebuild_start(G1HeapRegion* r) const { - return _top_at_rebuild_starts[r->hrm_index()].load_relaxed(); + return _top_at_rebuild_starts[r->hrm_index()]; } inline void G1ConcurrentMark::update_top_at_rebuild_start(G1HeapRegion* r) { @@ -225,10 +225,10 @@ inline void G1ConcurrentMark::update_top_at_rebuild_start(G1HeapRegion* r) { uint const region = r->hrm_index(); assert(region < _g1h->max_num_regions(), "Tried to access TARS for region %u out of bounds", region); - assert(top_at_rebuild_start(r) == nullptr, + assert(_top_at_rebuild_starts[region] == nullptr, "TARS for region %u has already been set to " PTR_FORMAT " should be null", - region, p2i(top_at_rebuild_start(r))); - _top_at_rebuild_starts[region].store_relaxed(r->top()); + region, p2i(_top_at_rebuild_starts[region])); + _top_at_rebuild_starts[region] = r->top(); } inline void G1CMTask::update_liveness(oop const obj, const size_t obj_size) { diff --git a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.hpp b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.hpp index b8f13f4553d..4dcdd33846e 100644 --- a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.hpp +++ b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.hpp @@ -44,8 +44,6 @@ struct G1RegionMarkStats { Atomic _live_words; Atomic _incoming_refs; - G1RegionMarkStats() : _live_words(0), _incoming_refs(0) { } - // Clear all members. void clear() { _live_words.store_relaxed(0); From 1cb4ef8581b5c5572474a5376baf4fd88c5ffeab Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 2 Feb 2026 22:39:31 +0000 Subject: [PATCH 297/328] 8376855: ASAN reports out-of-range read in strncmp in MethodHandles::is_basic_type_signature Reviewed-by: azafari, jsjolen --- src/hotspot/share/prims/methodHandles.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index c243cae20ab..584f077eddc 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, 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 @@ -557,7 +557,7 @@ bool MethodHandles::is_basic_type_signature(Symbol* sig) { switch (ss.type()) { case T_OBJECT: // only java/lang/Object is valid here - if (strncmp((char*) ss.raw_bytes(), OBJ_SIG, OBJ_SIG_LEN) != 0) + if (strncmp((char*) ss.raw_bytes(), OBJ_SIG, ss.raw_length()) != 0) return false; break; case T_VOID: From caf1338243004e62c8a9e5fc8ba5d5e19f6edba2 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Tue, 3 Feb 2026 02:21:06 +0000 Subject: [PATCH 298/328] 8376700: java/nio/file/DirectoryStream/SecureDS.java fails AtomicMoveNotSupportedException Reviewed-by: bpb --- .../nio/file/DirectoryStream/SecureDS.java | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/test/jdk/java/nio/file/DirectoryStream/SecureDS.java b/test/jdk/java/nio/file/DirectoryStream/SecureDS.java index 21204ba980a..a115d56c52f 100644 --- a/test/jdk/java/nio/file/DirectoryStream/SecureDS.java +++ b/test/jdk/java/nio/file/DirectoryStream/SecureDS.java @@ -21,31 +21,43 @@ * questions. */ -/* @test +/* @test id=tmp * @bug 4313887 6838333 8343020 8357425 * @summary Unit test for java.nio.file.SecureDirectoryStream * @requires (os.family == "linux" | os.family == "mac" | os.family == "aix") * @library .. /test/lib - * @build jdk.test.lib.Platform + * @build jdk.test.lib.Platform jtreg.SkippedException * @run main SecureDS */ +/* @test id=cwd + * @requires (os.family == "linux" | os.family == "mac" | os.family == "aix") + * @library .. /test/lib + * @build jdk.test.lib.Platform jtreg.SkippedException + * @run main SecureDS cwd + */ + import java.nio.file.*; import static java.nio.file.Files.*; import static java.nio.file.StandardOpenOption.*; import static java.nio.file.LinkOption.*; import java.nio.file.attribute.*; -import java.nio.channels.*; import java.io.IOException; import java.util.*; import jdk.test.lib.Platform; +import jtreg.SkippedException; public class SecureDS { static boolean supportsSymbolicLinks; public static void main(String[] args) throws IOException { - Path dir = TestUtil.createTemporaryDirectory(); + Path dir; + if (args.length > 0 && args[0].equals("cwd")) { + dir = TestUtil.createTemporaryDirectory(System.getProperty("user.dir")); + } else { + dir = TestUtil.createTemporaryDirectory(); + } try { DirectoryStream stream = newDirectoryStream(dir); stream.close(); @@ -301,7 +313,17 @@ public class SecureDS { Files.writeString(filepath, TEXT); try (DirectoryStream ds = Files.newDirectoryStream(dir);) { if (ds instanceof SecureDirectoryStream sds) { - sds.move(file, null, file); + try { + sds.move(file, null, file); + } catch (AtomicMoveNotSupportedException e) { + if (Files.getFileStore(cwd).equals(Files.getFileStore(dir))) { + // re-throw if move between same volume + throw e; + } else { + throw new SkippedException( + "java.nio.file.AtomicMoveNotSupportedException"); + } + } if (!TEXT.equals(Files.readString(result))) throw new RuntimeException(result + " content incorrect"); } else { @@ -311,11 +333,10 @@ public class SecureDS { boolean fileDeleted = Files.deleteIfExists(filepath); if (!fileDeleted) Files.deleteIfExists(result); + // clean-up + delete(dir1); + delete(dir2); } - - // clean-up - delete(dir1); - delete(dir2); } // null and ClosedDirectoryStreamException From e21cb8525d91e91f000dc375b250c4acd37314e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20H=C3=BCbner?= Date: Tue, 3 Feb 2026 06:32:50 +0000 Subject: [PATCH 299/328] 8370441: Remove unnecessary/confusing null check in Verifier::verify() Reviewed-by: dholmes, coleenp --- src/hotspot/share/classfile/verifier.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index 38dba1d3d5f..30f147b9ae7 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -190,9 +190,8 @@ bool Verifier::verify(InstanceKlass* klass, bool should_verify_class, TRAPS) { // effect (sic!) for external_name(), but instead of doing that, we opt to // explicitly push the hashcode in here. This is signify the following block // is IMPORTANT: - if (klass->java_mirror() != nullptr) { - klass->java_mirror()->identity_hash(); - } + assert(klass->java_mirror() != nullptr, "must be"); + klass->java_mirror()->identity_hash(); if (!is_eligible_for_verification(klass, should_verify_class)) { return true; From 8e2bd92bacd6503346a48df236959c8a959c9c77 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 3 Feb 2026 08:41:37 +0000 Subject: [PATCH 300/328] 8376970: Shenandoah: Verifier should do basic verification before touching oops Reviewed-by: wkemper, xpeng, kdnilsen --- .../gc/shenandoah/shenandoahVerifier.cpp | 46 ++++++++++++++----- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index 0cc6d4c6ed4..b60f8128d1d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -110,15 +110,15 @@ private: void do_oop_work(T* p) { T o = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); + // Basic verification should happen before we touch anything else. + // For performance reasons, only fully verify non-marked field values. + // We are here when the host object for *p is already marked. + oop obj = CompressedOops::decode_raw_not_null(o); + verify_oop_at_basic(p, obj); + if (is_instance_ref_klass(ShenandoahForwarding::klass(obj))) { obj = ShenandoahForwarding::get_forwardee(obj); } - // Single threaded verification can use faster non-atomic stack and bitmap - // methods. - // - // For performance reasons, only fully verify non-marked field values. - // We are here when the host object for *p is already marked. if (in_generation(obj) && _map->par_mark(obj)) { verify_oop_at(p, obj); _stack->push(ShenandoahVerifierTask(obj)); @@ -131,7 +131,7 @@ private: return _generation->contains(region); } - void verify_oop(oop obj) { + void verify_oop(oop obj, bool basic = false) { // Perform consistency checks with gradually decreasing safety level. This guarantees // that failure report would not try to touch something that was not yet verified to be // safe to process. @@ -174,10 +174,14 @@ private: } } + check(ShenandoahAsserts::_safe_unknown, obj, obj_reg->is_active(), + "Object should be in active region"); + // ------------ obj is safe at this point -------------- - check(ShenandoahAsserts::_safe_oop, obj, obj_reg->is_active(), - "Object should be in active region"); + if (basic) { + return; + } switch (_options._verify_liveness) { case ShenandoahVerifier::_verify_liveness_disable: @@ -331,6 +335,18 @@ public: _interior_loc = nullptr; } + /** + * Verify object with known interior reference, with only basic verification. + * @param p interior reference where the object is referenced from; can be off-heap + * @param obj verified object + */ + template + void verify_oop_at_basic(T* p, oop obj) { + _interior_loc = p; + verify_oop(obj, /* basic = */ true); + _interior_loc = nullptr; + } + /** * Verify object without known interior reference. * Useful when picking up the object at known offset in heap, @@ -1232,7 +1248,9 @@ private: void do_oop_work(T* p) { T o = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); + oop obj = CompressedOops::decode_raw_not_null(o); + ShenandoahAsserts::assert_correct(p, obj, __FILE__, __LINE__); + oop fwd = ShenandoahForwarding::get_forwardee_raw_unchecked(obj); if (obj != fwd) { ShenandoahAsserts::print_failure(ShenandoahAsserts::_safe_all, obj, p, nullptr, @@ -1252,7 +1270,9 @@ private: void do_oop_work(T* p) { T o = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); + oop obj = CompressedOops::decode_raw_not_null(o); + ShenandoahAsserts::assert_correct(p, obj, __FILE__, __LINE__); + ShenandoahHeap* heap = ShenandoahHeap::heap(); if (!heap->marking_context()->is_marked_or_old(obj)) { @@ -1306,7 +1326,9 @@ public: inline void work(T* p) { T o = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); + oop obj = CompressedOops::decode_raw_not_null(o); + ShenandoahAsserts::assert_correct(p, obj, __FILE__, __LINE__); + if (_heap->is_in_young(obj) && !_scanner->is_card_dirty((HeapWord*) p)) { ShenandoahAsserts::print_failure(ShenandoahAsserts::_safe_all, obj, p, nullptr, _message, "clean card, it should be dirty.", __FILE__, __LINE__); From 692444f071cab930d1b92bbfac79f87d0d801aab Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 3 Feb 2026 08:44:23 +0000 Subject: [PATCH 301/328] 8376969: Shenandoah: GC state getters should be inlineable Reviewed-by: wkemper, xpeng, kdnilsen --- src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp | 12 ------------ src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp | 4 ++-- .../share/gc/shenandoah/shenandoahHeap.inline.hpp | 11 +++++++++++ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index ef99bd98c93..ccfc1c036c2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -2719,18 +2719,6 @@ bool ShenandoahRegionIterator::has_next() const { return _index < _heap->num_regions(); } -char ShenandoahHeap::gc_state() const { - return _gc_state.raw_value(); -} - -bool ShenandoahHeap::is_gc_state(GCState state) const { - // If the global gc state has been changed, but hasn't yet been propagated to all threads, then - // the global gc state is the correct value. Once the gc state has been synchronized with all threads, - // _gc_state_changed will be toggled to false and we need to use the thread local state. - return _gc_state_changed ? _gc_state.is_set(state) : ShenandoahThreadLocalData::is_gc_state(state); -} - - ShenandoahLiveData* ShenandoahHeap::get_liveness_cache(uint worker_id) { #ifdef ASSERT assert(_liveness_cache != nullptr, "sanity"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 174001170f4..9240091070b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -353,7 +353,7 @@ private: public: // This returns the raw value of the singular, global gc state. - char gc_state() const; + inline char gc_state() const; // Compares the given state against either the global gc state, or the thread local state. // The global gc state may change on a safepoint and is the correct value to use until @@ -361,7 +361,7 @@ public: // compare against the thread local state). The thread local gc state may also be changed // by a handshake operation, in which case, this function continues using the updated thread // local value. - bool is_gc_state(GCState state) const; + inline bool is_gc_state(GCState state) const; // This copies the global gc state into a thread local variable for all threads. // The thread local gc state is primarily intended to support quick access at barriers. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index 34c279a1495..e35f116b843 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -452,6 +452,17 @@ inline bool ShenandoahHeap::in_collection_set_loc(void* p) const { return collection_set()->is_in_loc(p); } +inline char ShenandoahHeap::gc_state() const { + return _gc_state.raw_value(); +} + +inline bool ShenandoahHeap::is_gc_state(GCState state) const { + // If the global gc state has been changed, but hasn't yet been propagated to all threads, then + // the global gc state is the correct value. Once the gc state has been synchronized with all threads, + // _gc_state_changed will be toggled to false and we need to use the thread local state. + return _gc_state_changed ? _gc_state.is_set(state) : ShenandoahThreadLocalData::is_gc_state(state); +} + inline bool ShenandoahHeap::is_idle() const { return _gc_state_changed ? _gc_state.is_clear() : ShenandoahThreadLocalData::gc_state(Thread::current()) == 0; } From 5fec0f3287a64aa56e04ad7c0222dca49a0992e0 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Tue, 3 Feb 2026 08:58:57 +0000 Subject: [PATCH 302/328] 8376585: bin/update_copyright_year.sh could allow updating a specified list of files Reviewed-by: erikj --- bin/update_copyright_year.sh | 183 ++++++++++++++++++++--------------- 1 file changed, 103 insertions(+), 80 deletions(-) diff --git a/bin/update_copyright_year.sh b/bin/update_copyright_year.sh index fa7989d234b..fcdac6b935f 100644 --- a/bin/update_copyright_year.sh +++ b/bin/update_copyright_year.sh @@ -1,7 +1,7 @@ #!/bin/bash -f # -# Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 2026, 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,9 +23,13 @@ # questions. # -# Script to update the Copyright YEAR range in Mercurial & Git sources. +# Script to update the Copyright YEAR range in Git sources. # (Originally from xdono, Thanks!) +# To update Copyright years for changes in a specific branch, +# you use a command along these lines: +# $ git diff upstream/master... | lsdiff | cut -d '/' -f 2- | bash bin/update_copyright_year.sh -m - + #------------------------------------------------------------ copyright="Copyright" copyright_symbol="(c)" @@ -47,7 +51,7 @@ rm -f -r ${tmp} mkdir -p ${tmp} total=0 -usage="Usage: `basename "$0"` [-c company] [-y year] [-h|f]" +usage="Usage: `basename "$0"` [-c company] [-y year] [-m file] [-h|f]" Help() { # Display Help @@ -65,15 +69,18 @@ Help() echo "-b Specifies the base reference for change set lookup." echo "-f Updates the copyright for all change sets in a given year," echo " as specified by -y. Overrides -b flag." + echo "-m Read the list of modified files from the given file," + echo " use - to read from stdin" echo "-h Print this help." echo } full_year=false base_reference=master +modified_files_origin=""; # Process options -while getopts "b:c:fhy:" option; do +while getopts "b:c:fhm:y:" option; do case $option in b) # supplied base reference base_reference=${OPTARG} @@ -91,6 +98,9 @@ while getopts "b:c:fhy:" option; do y) # supplied company year year=${OPTARG} ;; + m) # modified files will be read from the given origin + modified_files_origin="${OPTARG}" + ;; \?) # illegal option echo "$usage" exit 1 @@ -110,18 +120,10 @@ git status &> /dev/null && git_found=true if [ "$git_found" != "true" ]; then echo "Error: Please execute script from within a JDK git repository." exit 1 -else - echo "Using Git version control system" - vcs_status=(git ls-files -m) - if [ "$full_year" = "true" ]; then - vcs_list_changesets=(git log --no-merges --since="${year}-01-01T00:00:00Z" --until="${year}-12-31T23:59:59Z" --pretty=tformat:"%H") - else - vcs_list_changesets=(git log --no-merges "${base_reference}..HEAD" --since="${year}-01-01T00:00:00Z" --until="${year}-12-31T23:59:59Z" --pretty=tformat:"%H") - fi - vcs_changeset_message=(git log -1 --pretty=tformat:"%B") # followed by ${changeset} - vcs_changeset_files=(git diff-tree --no-commit-id --name-only -r) # followed by ${changeset} fi +echo "Using Git version control system" + # Return true if it makes sense to edit this file saneFileToCheck() { @@ -168,6 +170,25 @@ updateFile() # file echo "${changed}" } +# Update the copyright year on files sent in stdin +updateFiles() # stdin: list of files to update +{ + count=0 + fcount=0 + while read i; do + fcount=`expr ${fcount} '+' 1` + if [ `updateFile "${i}"` = "true" ] ; then + count=`expr ${count} '+' 1` + fi + done + if [ ${count} -gt 0 ] ; then + printf " UPDATED year on %d of %d files.\n" ${count} ${fcount} + total=`expr ${total} '+' ${count}` + else + printf " None of the %d files were changed.\n" ${fcount} + fi +} + # Update the copyright year on all files changed by this changeset updateChangesetFiles() # changeset { @@ -178,18 +199,7 @@ updateChangesetFiles() # changeset | ${awk} -F' ' '{for(i=1;i<=NF;i++)print $i}' \ > ${files} if [ -f "${files}" -a -s "${files}" ] ; then - fcount=`cat ${files}| wc -l` - for i in `cat ${files}` ; do - if [ `updateFile "${i}"` = "true" ] ; then - count=`expr ${count} '+' 1` - fi - done - if [ ${count} -gt 0 ] ; then - printf " UPDATED year on %d of %d files.\n" ${count} ${fcount} - total=`expr ${total} '+' ${count}` - else - printf " None of the %d files were changed.\n" ${fcount} - fi + cat ${files} | updateFiles else printf " ERROR: No files changed in the changeset? Must be a mistake.\n" set -x @@ -204,67 +214,80 @@ updateChangesetFiles() # changeset } # Check if repository is clean +vcs_status=(git ls-files -m) previous=`"${vcs_status[@]}"|wc -l` if [ ${previous} -ne 0 ] ; then echo "WARNING: This repository contains previously edited working set files." echo " ${vcs_status[*]} | wc -l = `"${vcs_status[@]}" | wc -l`" fi -# Get all changesets this year -all_changesets=${tmp}/all_changesets -rm -f ${all_changesets} -"${vcs_list_changesets[@]}" > ${all_changesets} - -# Check changeset to see if it is Copyright only changes, filter changesets -if [ -s ${all_changesets} ] ; then - echo "Changesets made in ${year}: `cat ${all_changesets} | wc -l`" - index=0 - cat ${all_changesets} | while read changeset ; do - index=`expr ${index} '+' 1` - desc=${tmp}/desc.${changeset} - rm -f ${desc} - echo "------------------------------------------------" - "${vcs_changeset_message[@]}" "${changeset}" > ${desc} - printf "%d: %s\n%s\n" ${index} "${changeset}" "`cat ${desc}|head -1`" - if [ "${year}" = "2010" ] ; then - if cat ${desc} | grep -i -F "Added tag" > /dev/null ; then - printf " EXCLUDED tag changeset.\n" - elif cat ${desc} | grep -i -F rebrand > /dev/null ; then - printf " EXCLUDED rebrand changeset.\n" - elif cat ${desc} | grep -i -F copyright > /dev/null ; then - printf " EXCLUDED copyright changeset.\n" - else - updateChangesetFiles ${changeset} - fi - else - if cat ${desc} | grep -i -F "Added tag" > /dev/null ; then - printf " EXCLUDED tag changeset.\n" - elif cat ${desc} | grep -i -F "copyright year" > /dev/null ; then - printf " EXCLUDED copyright year changeset.\n" - else - updateChangesetFiles ${changeset} - fi - fi - rm -f ${desc} - done -fi - -if [ ${total} -gt 0 ] ; then - echo "---------------------------------------------" - echo "Updated the copyright year on a total of ${total} files." - if [ ${previous} -eq 0 ] ; then - echo "This count should match the count of modified files in the repository: ${vcs_status[*]}" - else - echo "WARNING: This repository contained previously edited working set files." - fi - echo " ${vcs_status[*]} | wc -l = `"${vcs_status[@]}" | wc -l`" +if [ "x$modified_files_origin" != "x" ]; then + cat $modified_files_origin | updateFiles else - echo "---------------------------------------------" - echo "No files were changed" - if [ ${previous} -ne 0 ] ; then - echo "WARNING: This repository contained previously edited working set files." - fi - echo " ${vcs_status[*]} | wc -l = `"${vcs_status[@]}" | wc -l`" + # Get all changesets this year + if [ "$full_year" = "true" ]; then + vcs_list_changesets=(git log --no-merges --since="${year}-01-01T00:00:00Z" --until="${year}-12-31T23:59:59Z" --pretty=tformat:"%H") + else + vcs_list_changesets=(git log --no-merges "${base_reference}..HEAD" --since="${year}-01-01T00:00:00Z" --until="${year}-12-31T23:59:59Z" --pretty=tformat:"%H") + fi + vcs_changeset_message=(git log -1 --pretty=tformat:"%B") # followed by ${changeset} + vcs_changeset_files=(git diff-tree --no-commit-id --name-only -r) # followed by ${changeset} + + all_changesets=${tmp}/all_changesets + rm -f ${all_changesets} + "${vcs_list_changesets[@]}" > ${all_changesets} + + # Check changeset to see if it is Copyright only changes, filter changesets + if [ -s ${all_changesets} ] ; then + echo "Changesets made in ${year}: `cat ${all_changesets} | wc -l`" + index=0 + cat ${all_changesets} | while read changeset ; do + index=`expr ${index} '+' 1` + desc=${tmp}/desc.${changeset} + rm -f ${desc} + echo "------------------------------------------------" + "${vcs_changeset_message[@]}" "${changeset}" > ${desc} + printf "%d: %s\n%s\n" ${index} "${changeset}" "`cat ${desc}|head -1`" + if [ "${year}" = "2010" ] ; then + if cat ${desc} | grep -i -F "Added tag" > /dev/null ; then + printf " EXCLUDED tag changeset.\n" + elif cat ${desc} | grep -i -F rebrand > /dev/null ; then + printf " EXCLUDED rebrand changeset.\n" + elif cat ${desc} | grep -i -F copyright > /dev/null ; then + printf " EXCLUDED copyright changeset.\n" + else + updateChangesetFiles ${changeset} + fi + else + if cat ${desc} | grep -i -F "Added tag" > /dev/null ; then + printf " EXCLUDED tag changeset.\n" + elif cat ${desc} | grep -i -F "copyright year" > /dev/null ; then + printf " EXCLUDED copyright year changeset.\n" + else + updateChangesetFiles ${changeset} + fi + fi + rm -f ${desc} + done + fi + + if [ ${total} -gt 0 ] ; then + echo "---------------------------------------------" + echo "Updated the copyright year on a total of ${total} files." + if [ ${previous} -eq 0 ] ; then + echo "This count should match the count of modified files in the repository: ${vcs_status[*]}" + else + echo "WARNING: This repository contained previously edited working set files." + fi + echo " ${vcs_status[*]} | wc -l = `"${vcs_status[@]}" | wc -l`" + else + echo "---------------------------------------------" + echo "No files were changed" + if [ ${previous} -ne 0 ] ; then + echo "WARNING: This repository contained previously edited working set files." + fi + echo " ${vcs_status[*]} | wc -l = `"${vcs_status[@]}" | wc -l`" + fi fi # Cleanup From f43fbf08231a0ecf5c495c807302a851208c0736 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Tue, 3 Feb 2026 09:19:15 +0000 Subject: [PATCH 303/328] 8367332: Replace BlockTree tree logic with an intrusive red-black tree Reviewed-by: jsjolen, stuefe --- .../share/memory/metaspace/blockTree.cpp | 183 +++--------- .../share/memory/metaspace/blockTree.hpp | 263 ++++-------------- .../gtest/metaspace/test_blocktree.cpp | 2 +- 3 files changed, 96 insertions(+), 352 deletions(-) diff --git a/src/hotspot/share/memory/metaspace/blockTree.cpp b/src/hotspot/share/memory/metaspace/blockTree.cpp index 7ad24353c96..bdae317a0b9 100644 --- a/src/hotspot/share/memory/metaspace/blockTree.cpp +++ b/src/hotspot/share/memory/metaspace/blockTree.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2022 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -39,18 +39,14 @@ const size_t BlockTree::MinWordSize; #define NODE_FORMAT \ "@" PTR_FORMAT \ ": canary " INTPTR_FORMAT \ - ", parent " PTR_FORMAT \ - ", left " PTR_FORMAT \ - ", right " PTR_FORMAT \ + ", tree " PTR_FORMAT \ ", next " PTR_FORMAT \ ", size %zu" #define NODE_FORMAT_ARGS(n) \ p2i(n), \ (n)->_canary, \ - p2i((n)->_parent), \ - p2i((n)->_left), \ - p2i((n)->_right), \ + p2i(&(n)->_tree_node), \ p2i((n)->_next), \ (n)->_word_size @@ -74,15 +70,6 @@ const size_t BlockTree::MinWordSize; #define tree_assert_invalid_node(cond, failure_node) \ tree_assert(cond, "Invalid node: " NODE_FORMAT, NODE_FORMAT_ARGS(failure_node)) -// walkinfo keeps a node plus the size corridor it and its children -// are supposed to be in. -struct BlockTree::walkinfo { - BlockTree::Node* n; - int depth; - size_t lim1; // ( - size_t lim2; // ) -}; - // Helper for verify() void BlockTree::verify_node_pointer(const Node* n) const { tree_assert(os::is_readable_pointer(n), @@ -98,80 +85,32 @@ void BlockTree::verify_node_pointer(const Node* n) const { void BlockTree::verify() const { // Traverse the tree and test that all nodes are in the correct order. - MemRangeCounter counter; - if (_root != nullptr) { - ResourceMark rm; - GrowableArray stack; + // Verifies node ordering (n1 < n2 => word_size1 < word_size2), + // node validity, and that the tree is balanced and not ill-formed. + _tree.verify_self([&](const TreeNode* tree_node) { + const Node* n = Node::cast_to_node(tree_node); - walkinfo info; - info.n = _root; - info.lim1 = 0; - info.lim2 = SIZE_MAX; - info.depth = 0; + verify_node_pointer(n); - stack.push(info); + counter.add(n->_word_size); - while (stack.length() > 0) { - info = stack.pop(); - const Node* n = info.n; + tree_assert_invalid_node(n->_word_size >= MinWordSize, n); + tree_assert_invalid_node(n->_word_size <= chunklevel::MAX_CHUNK_WORD_SIZE, n); - verify_node_pointer(n); - - // Assume a (ridiculously large) edge limit to catch cases - // of badly degenerated or circular trees. - tree_assert(info.depth < 10000, "too deep (%d)", info.depth); - counter.add(n->_word_size); - - if (n == _root) { - tree_assert_invalid_node(n->_parent == nullptr, n); - } else { - tree_assert_invalid_node(n->_parent != nullptr, n); - } - - // check size and ordering - tree_assert_invalid_node(n->_word_size >= MinWordSize, n); - tree_assert_invalid_node(n->_word_size <= chunklevel::MAX_CHUNK_WORD_SIZE, n); - tree_assert_invalid_node(n->_word_size > info.lim1, n); - tree_assert_invalid_node(n->_word_size < info.lim2, n); - - // Check children - if (n->_left != nullptr) { - tree_assert_invalid_node(n->_left != n, n); - tree_assert_invalid_node(n->_left->_parent == n, n); - - walkinfo info2; - info2.n = n->_left; - info2.lim1 = info.lim1; - info2.lim2 = n->_word_size; - info2.depth = info.depth + 1; - stack.push(info2); - } - - if (n->_right != nullptr) { - tree_assert_invalid_node(n->_right != n, n); - tree_assert_invalid_node(n->_right->_parent == n, n); - - walkinfo info2; - info2.n = n->_right; - info2.lim1 = n->_word_size; - info2.lim2 = info.lim2; - info2.depth = info.depth + 1; - stack.push(info2); - } - - // If node has same-sized siblings check those too. - const Node* n2 = n->_next; - while (n2 != nullptr) { - verify_node_pointer(n2); - tree_assert_invalid_node(n2 != n, n2); // catch simple circles - tree_assert_invalid_node(n2->_word_size == n->_word_size, n2); - counter.add(n2->_word_size); - n2 = n2->_next; - } + // If node has same-sized siblings check those too. + const Node* n2 = n->_next; + while (n2 != nullptr) { + verify_node_pointer(n2); + tree_assert_invalid_node(n2 != n, n2); // catch simple circles + tree_assert_invalid_node(n2->_word_size == n->_word_size, n2); + counter.add(n2->_word_size); + n2 = n2->_next; } - } + + return true; + }); // At the end, check that counters match // (which also verifies that we visited every node, or at least @@ -189,64 +128,34 @@ void BlockTree::print_tree(outputStream* st) const { // as a quasi list is much clearer to the eye. // We print the tree depth-first, with stacked nodes below normal ones // (normal "real" nodes are marked with a leading '+') - if (_root != nullptr) { + if (is_empty()) { + st->print_cr(""); + return; + } - ResourceMark rm; - GrowableArray stack; + _tree.print_on(st, [&](outputStream *st, const TreeNode *tree_node, int depth) { + const Node* n = Node::cast_to_node(tree_node); - walkinfo info; - info.n = _root; - info.depth = 0; - - stack.push(info); - while (stack.length() > 0) { - info = stack.pop(); - const Node* n = info.n; - - // Print node. - st->print("%4d + ", info.depth); - if (os::is_readable_pointer(n)) { - st->print_cr(NODE_FORMAT, NODE_FORMAT_ARGS(n)); - } else { - st->print_cr("@" PTR_FORMAT ": unreadable (skipping subtree)", p2i(n)); - continue; // don't print this subtree - } - - // Print same-sized-nodes stacked under this node - for (Node* n2 = n->_next; n2 != nullptr; n2 = n2->_next) { - st->print_raw(" "); - if (os::is_readable_pointer(n2)) { - st->print_cr(NODE_FORMAT, NODE_FORMAT_ARGS(n2)); - } else { - st->print_cr("@" PTR_FORMAT ": unreadable (skipping rest of chain).", p2i(n2)); - break; // stop printing this chain. - } - } - - // Handle simple circularities - if (n == n->_right || n == n->_left || n == n->_next) { - st->print_cr("@" PTR_FORMAT ": circularity detected.", p2i(n)); - return; // stop printing - } - - // Handle children. - if (n->_right != nullptr) { - walkinfo info2; - info2.n = n->_right; - info2.depth = info.depth + 1; - stack.push(info2); - } - if (n->_left != nullptr) { - walkinfo info2; - info2.n = n->_left; - info2.depth = info.depth + 1; - stack.push(info2); - } + // Print node. + st->print("%4d + ", depth); + if (os::is_readable_pointer(n)) { + st->print_cr(NODE_FORMAT, NODE_FORMAT_ARGS(n)); + } else { + st->print_cr("@" PTR_FORMAT ": unreadable", p2i(n)); + return; } - } else { - st->print_cr(""); - } + // Print same-sized-nodes stacked under this node + for (Node* n2 = n->_next; n2 != nullptr; n2 = n2->_next) { + st->print_raw(" "); + if (os::is_readable_pointer(n2)) { + st->print_cr(NODE_FORMAT, NODE_FORMAT_ARGS(n2)); + } else { + st->print_cr("@" PTR_FORMAT ": unreadable (skipping rest of chain).", p2i(n2)); + break; // stop printing this chain. + } + } + }); } #endif // ASSERT diff --git a/src/hotspot/share/memory/metaspace/blockTree.hpp b/src/hotspot/share/memory/metaspace/blockTree.hpp index a01f60b166f..e7c1edf9c4f 100644 --- a/src/hotspot/share/memory/metaspace/blockTree.hpp +++ b/src/hotspot/share/memory/metaspace/blockTree.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -32,17 +32,18 @@ #include "memory/metaspace/metablock.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/rbTree.inline.hpp" namespace metaspace { -// BlockTree is a rather simple binary search tree. It is used to -// manage medium to large free memory blocks. +// BlockTree is tree built on an intrusive red-black tree. +// It is used to manage medium to large free memory blocks. // // There is no separation between payload (managed blocks) and nodes: the // memory blocks themselves are the nodes, with the block size being the key. // // We store node pointer information in these blocks when storing them. That -// imposes a minimum size to the managed memory blocks (1 word) +// imposes a minimum size to the managed memory blocks (1 MinWordSize) // // We want to manage many memory blocks of the same size, but we want // to prevent the tree from blowing up and degenerating into a list. Therefore @@ -53,9 +54,9 @@ namespace metaspace { // | 100 | // +-----+ // / \ -// +-----+ -// | 80 | -// +-----+ +// +-----+ +-----+ +// | 80 | | 120 | +// +-----+ +-----+ // / | \ // / +-----+ \ // +-----+ | 80 | +-----+ @@ -65,16 +66,11 @@ namespace metaspace { // | 80 | // +-----+ // -// -// Todo: This tree is unbalanced. It would be a good fit for a red-black tree. -// In order to make this a red-black tree, we need an algorithm which can deal -// with nodes which are their own payload (most red-black tree implementations -// swap payloads of their nodes at some point, see e.g. j.u.TreeSet). -// A good example is the Linux kernel rbtree, which is a clean, easy-to-read -// implementation. class BlockTree: public CHeapObj { + using TreeNode = IntrusiveRBNode; + struct Node { static const intptr_t _canary_value = @@ -86,29 +82,27 @@ class BlockTree: public CHeapObj { // in debug. const intptr_t _canary; - // Normal tree node stuff... - // (Note: all null if this is a stacked node) - Node* _parent; - Node* _left; - Node* _right; + // Tree node for linking blocks in the intrusive tree. + TreeNode _tree_node; // Blocks with the same size are put in a list with this node as head. Node* _next; // Word size of node. Note that size cannot be larger than max metaspace size, - // so this could be very well a 32bit value (in case we ever make this a balancing - // tree and need additional space for weighting information). + // so this could very well be a 32bit value. const size_t _word_size; Node(size_t word_size) : _canary(_canary_value), - _parent(nullptr), - _left(nullptr), - _right(nullptr), + _tree_node{}, _next(nullptr), _word_size(word_size) {} + static Node* cast_to_node(const TreeNode* tree_node) { + return (Node*)((uintptr_t)tree_node - offset_of(Node, _tree_node)); + } + #ifdef ASSERT bool valid() const { return _canary == _canary_value && @@ -118,8 +112,23 @@ class BlockTree: public CHeapObj { #endif }; - // Needed for verify() and print_tree() - struct walkinfo; + struct TreeComparator { + static RBTreeOrdering cmp(const size_t a, const TreeNode* b) { + const size_t node_word_size = Node::cast_to_node(b)->_word_size; + + if (a < node_word_size) { return RBTreeOrdering::LT; } + if (a > node_word_size) { return RBTreeOrdering::GT; } + return RBTreeOrdering::EQ; + } + + static bool less_than(const TreeNode* a, const TreeNode* b) { + const size_t a_word_size = Node::cast_to_node(a)->_word_size; + const size_t b_word_size = Node::cast_to_node(b)->_word_size; + + if (a_word_size < b_word_size) { return true; } + return false; + } + }; #ifdef ASSERT // Run a quick check on a node; upon suspicion dive into a full tree check. @@ -134,7 +143,7 @@ public: private: - Node* _root; + IntrusiveRBTree _tree; MemRangeCounter _counter; @@ -143,7 +152,7 @@ private: assert(head->_word_size == n->_word_size, "sanity"); n->_next = head->_next; head->_next = n; - DEBUG_ONLY(n->_left = n->_right = n->_parent = nullptr;) + DEBUG_ONLY(n->_tree_node = TreeNode()); } // Given a node list starting at head, remove one of the follow up nodes from @@ -157,183 +166,6 @@ private: return n; } - // Given a node c and a node p, wire up c as left child of p. - static void set_left_child(Node* p, Node* c) { - p->_left = c; - if (c != nullptr) { - assert(c->_word_size < p->_word_size, "sanity"); - c->_parent = p; - } - } - - // Given a node c and a node p, wire up c as right child of p. - static void set_right_child(Node* p, Node* c) { - p->_right = c; - if (c != nullptr) { - assert(c->_word_size > p->_word_size, "sanity"); - c->_parent = p; - } - } - - // Given a node n, return its successor in the tree - // (node with the next-larger size). - static Node* successor(Node* n) { - Node* succ = nullptr; - if (n->_right != nullptr) { - // If there is a right child, search the left-most - // child of that child. - succ = n->_right; - while (succ->_left != nullptr) { - succ = succ->_left; - } - } else { - succ = n->_parent; - Node* n2 = n; - // As long as I am the right child of my parent, search upward - while (succ != nullptr && n2 == succ->_right) { - n2 = succ; - succ = succ->_parent; - } - } - return succ; - } - - // Given a node, replace it with a replacement node as a child for its parent. - // If the node is root and has no parent, sets it as root. - void replace_node_in_parent(Node* child, Node* replace) { - Node* parent = child->_parent; - if (parent != nullptr) { - if (parent->_left == child) { // Child is left child - set_left_child(parent, replace); - } else { - set_right_child(parent, replace); - } - } else { - assert(child == _root, "must be root"); - _root = replace; - if (replace != nullptr) { - replace->_parent = nullptr; - } - } - return; - } - - // Given a node n and an insertion point, insert n under insertion point. - void insert(Node* insertion_point, Node* n) { - assert(n->_parent == nullptr, "Sanity"); - for (;;) { - DEBUG_ONLY(check_node(insertion_point);) - if (n->_word_size == insertion_point->_word_size) { - add_to_list(n, insertion_point); // parent stays null in this case. - break; - } else if (n->_word_size > insertion_point->_word_size) { - if (insertion_point->_right == nullptr) { - set_right_child(insertion_point, n); - break; - } else { - insertion_point = insertion_point->_right; - } - } else { - if (insertion_point->_left == nullptr) { - set_left_child(insertion_point, n); - break; - } else { - insertion_point = insertion_point->_left; - } - } - } - } - - // Given a node and a wish size, search this node and all children for - // the node closest (equal or larger sized) to the size s. - Node* find_closest_fit(Node* n, size_t s) { - Node* best_match = nullptr; - while (n != nullptr) { - DEBUG_ONLY(check_node(n);) - if (n->_word_size >= s) { - best_match = n; - if (n->_word_size == s) { - break; // perfect match or max depth reached - } - n = n->_left; - } else { - n = n->_right; - } - } - return best_match; - } - - // Given a wish size, search the whole tree for a - // node closest (equal or larger sized) to the size s. - Node* find_closest_fit(size_t s) { - if (_root != nullptr) { - return find_closest_fit(_root, s); - } - return nullptr; - } - - // Given a node n, remove it from the tree and repair tree. - void remove_node_from_tree(Node* n) { - assert(n->_next == nullptr, "do not delete a node which has a non-empty list"); - - if (n->_left == nullptr && n->_right == nullptr) { - replace_node_in_parent(n, nullptr); - - } else if (n->_left == nullptr && n->_right != nullptr) { - replace_node_in_parent(n, n->_right); - - } else if (n->_left != nullptr && n->_right == nullptr) { - replace_node_in_parent(n, n->_left); - - } else { - // Node has two children. - - // 1) Find direct successor (the next larger node). - Node* succ = successor(n); - - // There has to be a successor since n->right was != null... - assert(succ != nullptr, "must be"); - - // ... and it should not have a left child since successor - // is supposed to be the next larger node, so it must be the mostleft node - // in the sub tree rooted at n->right - assert(succ->_left == nullptr, "must be"); - assert(succ->_word_size > n->_word_size, "sanity"); - - Node* successor_parent = succ->_parent; - Node* successor_right_child = succ->_right; - - // Remove successor from its parent. - if (successor_parent == n) { - - // special case: successor is a direct child of n. Has to be the right child then. - assert(n->_right == succ, "sanity"); - - // Just replace n with this successor. - replace_node_in_parent(n, succ); - - // Take over n's old left child, too. - // We keep the successor's right child. - set_left_child(succ, n->_left); - } else { - // If the successors parent is not n, we are deeper in the tree, - // the successor has to be the left child of its parent. - assert(successor_parent->_left == succ, "sanity"); - - // The right child of the successor (if there was one) replaces - // the successor at its parent's left child. - set_left_child(successor_parent, succ->_right); - - // and the successor replaces n at its parent - replace_node_in_parent(n, succ); - - // and takes over n's old children - set_left_child(succ, n->_left); - set_right_child(succ, n->_right); - } - } - } - #ifdef ASSERT void zap_block(MetaBlock block); // Helper for verify() @@ -342,7 +174,7 @@ private: public: - BlockTree() : _root(nullptr) {} + BlockTree() {} // Add a memory block to the tree. Its content will be overwritten. void add_block(MetaBlock block) { @@ -350,10 +182,12 @@ public: const size_t word_size = block.word_size(); assert(word_size >= MinWordSize, "invalid block size %zu", word_size); Node* n = new(block.base()) Node(word_size); - if (_root == nullptr) { - _root = n; - } else { - insert(_root, n); + IntrusiveRBTree::Cursor cursor = _tree.cursor(word_size); + if (cursor.found()) { + add_to_list(n, Node::cast_to_node(cursor.node())); + } + else { + _tree.insert_at_cursor(&n->_tree_node, cursor); } _counter.add(word_size); } @@ -364,9 +198,10 @@ public: assert(word_size >= MinWordSize, "invalid block size %zu", word_size); MetaBlock result; - Node* n = find_closest_fit(word_size); + TreeNode* tree_node = _tree.closest_ge(word_size); - if (n != nullptr) { + if (tree_node != nullptr) { + Node* n = Node::cast_to_node(tree_node); DEBUG_ONLY(check_node(n);) assert(n->_word_size >= word_size, "sanity"); @@ -377,7 +212,7 @@ public: // node into its place in the tree). n = remove_from_list(n); } else { - remove_node_from_tree(n); + _tree.remove(tree_node); } result = MetaBlock((MetaWord*)n, n->_word_size); @@ -395,7 +230,7 @@ public: // Returns total size, in words, of all elements. size_t total_size() const { return _counter.total_size(); } - bool is_empty() const { return _root == nullptr; } + bool is_empty() const { return _tree.size() == 0; } DEBUG_ONLY(void print_tree(outputStream* st) const;) DEBUG_ONLY(void verify() const;) diff --git a/test/hotspot/gtest/metaspace/test_blocktree.cpp b/test/hotspot/gtest/metaspace/test_blocktree.cpp index 6d1e8d2884d..3bcd79c98ad 100644 --- a/test/hotspot/gtest/metaspace/test_blocktree.cpp +++ b/test/hotspot/gtest/metaspace/test_blocktree.cpp @@ -74,7 +74,7 @@ TEST_VM(metaspace, BlockTree_basic) { MetaWord* p = nullptr; MetaWord arr[10000]; - ASSERT_LE(BlockTree::MinWordSize, (size_t)6); // Sanity check. Adjust if Node is changed. + ASSERT_LE(BlockTree::MinWordSize, (size_t)7); // Sanity check. Adjust if Node is changed. const size_t minws = BlockTree::MinWordSize; From efa16e9e5fb07088ef2e0f2509e40fd97e4141d1 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 3 Feb 2026 09:35:21 +0000 Subject: [PATCH 304/328] 8170896: TEST_BUG: java/rmi/server/Unreferenced/leaseCheckInterval/LeaseCheckInterval.java failed with unreferenced() not invoked after 20.0 seconds Reviewed-by: smarks, msheppar, dfuchs --- .../LeaseCheckInterval.java | 99 ++++++++++--------- .../leaseCheckInterval/SelfTerminator.java | 22 +++-- 2 files changed, 69 insertions(+), 52 deletions(-) diff --git a/test/jdk/java/rmi/server/Unreferenced/leaseCheckInterval/LeaseCheckInterval.java b/test/jdk/java/rmi/server/Unreferenced/leaseCheckInterval/LeaseCheckInterval.java index 3fa349fd671..e7c990ebdbd 100644 --- a/test/jdk/java/rmi/server/Unreferenced/leaseCheckInterval/LeaseCheckInterval.java +++ b/test/jdk/java/rmi/server/Unreferenced/leaseCheckInterval/LeaseCheckInterval.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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,10 +31,9 @@ * may be delayed longer than expected. While this is not a spec violation * (because there are no timeliness guarantees for any of these garbage * collection-related events), the user might expect that an unreferenced() - * invocation for an object whose last client has terminated abnorally + * invocation for an object whose last client has terminated abnormally * should occur on relatively the same time order as the lease value * granted. - * @author Peter Jones * * @library ../../../testlibrary * @modules java.rmi/sun.rmi.registry @@ -47,40 +46,39 @@ import java.rmi.Remote; import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; import java.rmi.server.Unreferenced; +import java.time.Duration; +import java.time.Instant; +import java.util.concurrent.CountDownLatch; public class LeaseCheckInterval implements Remote, Unreferenced { public static final String BINDING = "LeaseCheckInterval"; + // lease expiry time (milliseconds) private static final long LEASE_VALUE = 10000; - private static final long TIMEOUT = 20000; + // the maximum allowed duration between the lease expiration and + // the Unreferenced.unreferenced() callback method to be invoked + private static final Duration EXPECTED_MAX_DURATION = Duration.ofMinutes(1); - private Object lock = new Object(); - private boolean unreferencedInvoked = false; + // will be counted down when Unreferenced.unreferenced() is invoked + private static final CountDownLatch callbackInvocationLatch = new CountDownLatch(1); + @Override public void unreferenced() { - System.err.println("unreferenced() method invoked"); - synchronized (lock) { - unreferencedInvoked = true; - lock.notify(); - } + System.err.println("[" + Instant.now() + "] unreferenced() method invoked"); + callbackInvocationLatch.countDown(); } public static void main(String[] args) throws Exception { - - System.err.println("\nRegression test for bug 4285878\n"); - /* * Set the duration of leases granted to a very small value, so that * we can test if expirations are detected in a roughly comparable * time. */ - System.setProperty("java.rmi.dgc.leaseValue", - String.valueOf(LEASE_VALUE)); - + System.setProperty("java.rmi.dgc.leaseValue", String.valueOf(LEASE_VALUE)); + System.err.println("running test with java.rmi.dgc.leaseValue set to " + LEASE_VALUE); LeaseCheckInterval obj = new LeaseCheckInterval(); JavaVM jvm = null; @@ -90,37 +88,32 @@ public class LeaseCheckInterval implements Remote, Unreferenced { Registry localRegistry = TestLibrary.createRegistryOnEphemeralPort(); int registryPort = TestLibrary.getRegistryPort(localRegistry); - System.err.println("created local registry"); + System.err.println("created local registry on port " + registryPort); localRegistry.bind(BINDING, obj); System.err.println("bound remote object in local registry"); - synchronized (obj.lock) { - System.err.println("starting remote client VM..."); - jvm = new JavaVM("SelfTerminator", "-Drmi.registry.port=" + - registryPort, ""); - jvm.start(); - - System.err.println("waiting for unreferenced() callback..."); - obj.lock.wait(TIMEOUT); - - if (obj.unreferencedInvoked) { - System.err.println("TEST PASSED: " + - "unreferenced() invoked in timely fashion"); - } else { - throw new RuntimeException( - "TEST FAILED: unreferenced() not invoked after " + - ((double) TIMEOUT / 1000.0) + " seconds"); - } - } - - } catch (Exception e) { - if (e instanceof RuntimeException) { - throw (RuntimeException) e; - } else { - throw new RuntimeException( - "TEST FAILED: unexpected exception: " + e.toString()); + System.err.println("starting remote client VM..."); + jvm = new JavaVM("SelfTerminator", "-Drmi.registry.port=" + registryPort, ""); + // launch the self terminating java application which will lookup + // the bound object (thus creating a lease) and then terminate itself (thus + // creating the condition for a lease expiry). + jvm.start(); + final Instant startTime = Instant.now(); + System.err.println("waiting for SelfTerminator process to complete"); + final int exitCode = jvm.waitFor(); + if (exitCode != 0) { + throw new AssertionError("SelfTerminator process exited with" + + " a non-zero exit code: " + exitCode); } + System.err.println("SelfTerminator process completed in " + + Duration.between(startTime, Instant.now()) + + ", now waiting for Unreferenced.unreferenced() callback to be invoked"); + callbackInvocationLatch.await(); + final Instant waitEndedAt = Instant.now(); + final Duration waitDuration = assertWithinExpectedTimeLimit(waitEndedAt, startTime); + System.err.println("TEST PASSED: unreferenced() invoked in timely" + + " fashion (duration=" + waitDuration + ")"); } finally { if (jvm != null) { jvm.destroy(); @@ -135,4 +128,22 @@ public class LeaseCheckInterval implements Remote, Unreferenced { } } } + + /* + * Verifies that the duration between the lease expiration and the callback + * invocation is within the expected limit. Throws an exception if the wait + * duration is larger than expected limit, else returns the actual wait duration. + */ + private static Duration assertWithinExpectedTimeLimit(final Instant waitEndedAt, + final Instant terminationStartedAt) { + + final Duration waitDuration = Duration.between(terminationStartedAt, waitEndedAt); + System.out.println("wait completed in " + waitDuration); + if (waitDuration.compareTo(EXPECTED_MAX_DURATION) > 0) { + throw new RuntimeException("Took unexpectedly long (duration=" + + waitDuration + ") to invoke Unreferenced.unreferenced()," + + " expected max duration=" + EXPECTED_MAX_DURATION); + } + return waitDuration; + } } diff --git a/test/jdk/java/rmi/server/Unreferenced/leaseCheckInterval/SelfTerminator.java b/test/jdk/java/rmi/server/Unreferenced/leaseCheckInterval/SelfTerminator.java index 4875634dbb3..36ebbf05bf1 100644 --- a/test/jdk/java/rmi/server/Unreferenced/leaseCheckInterval/SelfTerminator.java +++ b/test/jdk/java/rmi/server/Unreferenced/leaseCheckInterval/SelfTerminator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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,26 +21,32 @@ * questions. */ -/* - * - */ - import java.rmi.Remote; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; +import java.time.Instant; public class SelfTerminator { - public static void main(String[] args) { + public static void main(String[] args) throws Exception { try { + log("main() invoked"); int registryPort = Integer.parseInt(System.getProperty("rmi.registry.port")); Registry registry = LocateRegistry.getRegistry("", registryPort); Remote stub = registry.lookup(LeaseCheckInterval.BINDING); + log("looked up binding, now terminating the process"); Runtime.getRuntime().halt(0); - } catch (Exception e) { - e.printStackTrace(); + } catch (Throwable t) { + log("failure: " + t); + t.printStackTrace(); + throw t; // propagate any failures and fail the process } } + + private static void log(final String message) { + final Instant now = Instant.now(); + System.err.println("[" + now + "] " + SelfTerminator.class.getName() + " - " + message); + } } From 9c83dff811c038ba8b20a9781ea3ac0f4f95b1b9 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Tue, 3 Feb 2026 09:44:00 +0000 Subject: [PATCH 305/328] 8376284: New test serviceability/sa/TestJhsdbJstackMixedCore.java from JDK-8374482 fails on Linux Alpine Reviewed-by: cjplummer, mbaesken --- .../linux/amd64/LinuxAMD64CFrame.java | 5 +- .../sa/TestJhsdbJstackMixedCore.java | 16 ++- test/lib/jdk/test/lib/SA/SATestUtils.java | 114 +++++++++++++++++- 3 files changed, 130 insertions(+), 5 deletions(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java index 4bf6a0305a3..0ec7f1949bd 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java @@ -113,12 +113,13 @@ public final class LinuxAMD64CFrame extends BasicCFrame { // override base class impl to avoid ELF parsing public ClosestSymbol closestSymbolToPC() { Address symAddr = use1ByteBeforeToLookup ? pc().addOffsetTo(-1) : pc(); + var sym = dbg.lookup(dbg.getAddressValue(symAddr)); // Returns a special symbol if the address is signal handler, // otherwise returns closest symbol generated by LinuxDebugger. return dbg.isSignalTrampoline(symAddr) - ? new ClosestSymbol("", 0) - : dbg.lookup(dbg.getAddressValue(symAddr)); + ? new ClosestSymbol(sym.getName() + " ", 0) + : sym; } public Address pc() { diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java index b8b19c743e9..9fc304d1854 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java @@ -30,9 +30,11 @@ import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.util.CoreUtils; +import jtreg.SkippedException; + /** * @test - * @bug 8374482 + * @bug 8374482 8376284 * @requires (os.family == "linux") & (vm.hasSA) * @requires os.arch == "amd64" * @library /test/lib @@ -59,11 +61,21 @@ public class TestJhsdbJstackMixedCore { System.out.println(out.getStdout()); System.err.println(out.getStderr()); - out.shouldContain(""); + out.shouldContain("__restore_rt "); out.shouldContain("Java_jdk_test_lib_apps_LingeredApp_crash"); } public static void main(String... args) throws Throwable { + // Check whether the symbol of signal trampoline is available. + var libc = SATestUtils.getLibCPath(); + + // SA distinguishes the frame is signal trampoline if the function + // is named "__restore_rt". + // SA cannot unwind problematic frame from it if the symbol not found. + if (!SATestUtils.isSymbolAvailable(libc, "__restore_rt")) { + throw new SkippedException("Signal trampoline (__restore_rt) not found in libc."); + } + LingeredApp app = new LingeredApp(); app.setForceCrash(true); LingeredApp.startApp(app, CoreUtils.getAlwaysPretouchArg(true)); diff --git a/test/lib/jdk/test/lib/SA/SATestUtils.java b/test/lib/jdk/test/lib/SA/SATestUtils.java index 01233b5bf55..63f522b3d62 100644 --- a/test/lib/jdk/test/lib/SA/SATestUtils.java +++ b/test/lib/jdk/test/lib/SA/SATestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,15 @@ import jdk.test.lib.JDKToolLauncher; import jdk.test.lib.Platform; import jtreg.SkippedException; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; @@ -259,4 +266,109 @@ public class SATestUtils { throw new SkippedException("Cannot run this test on OSX if adding privileges is required."); } } + + /** + * Find library file that provides strlen(3), then returns it as libc. + * This method works on Linux only. + * @return path to libc + */ + @SuppressWarnings("restricted") + public static String getLibCPath() { + var linker = Linker.nativeLinker(); + var ptrStrlen = linker.defaultLookup() + .findOrThrow("strlen"); + var strlen = linker.downcallHandle( + ptrStrlen, + FunctionDescriptor.of(linker.canonicalLayouts().get("size_t"), ValueLayout.ADDRESS) + ); + var dladdr = linker.downcallHandle( + linker.defaultLookup().findOrThrow("dladdr"), + FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS, ValueLayout.ADDRESS) + ); + + var structDLInfo = MemoryLayout.structLayout( + ValueLayout.ADDRESS.withName("dli_fname"), + ValueLayout.ADDRESS.withName("dli_fbase"), + ValueLayout.ADDRESS.withName("dli_sname"), + ValueLayout.ADDRESS.withName("dli_saddr") + ).withName("Dl_info"); + var hndDliFname = structDLInfo.varHandle(MemoryLayout.PathElement.groupElement("dli_fname")); + + try(var arena = Arena.ofConfined()){ + var info = arena.allocate(structDLInfo); + int result = (int)dladdr.invoke(ptrStrlen, info); + if (result == 0) { + throw new RuntimeException("dladdr() returns zero"); + } + + var ptrDliFname = (MemorySegment)hndDliFname.get(info, 0); + var libcPathLen = (long)strlen.invoke(ptrDliFname); + return ptrDliFname.reinterpret(libcPathLen + 1) // +1 for NUL + .getString(0); + } catch (Throwable t) { + throw new RuntimeException("getLibCPath() failed due to Throwable.", t); + } + } + + /** + * Find debuginfo file for the library. + * This method will work on Linux only. + * "readelf" has to be available. + * @return null if debuginfo is not available. + */ + public static String getDebugInfo(String lib) { + try { + // Attempt to find debuginfo in /usr/lib/debug + Path debuginfoPath = Path.of("/usr/lib/debug", lib + ".debug"); + boolean exists = Files.exists(debuginfoPath); + if (!exists) { + // Attempt to find debuginfo with build ID + var proc = (new ProcessBuilder("readelf", "-n", lib)).start(); + try (var reader = proc.inputReader()) { + var buildID = reader.lines() + .filter(l -> l.contains("Build ID:")) + .findAny() + .map(l -> l.replace("Build ID:", "").trim()) + .get(); + String dir = buildID.substring(0, 2); + String file = buildID.substring(2); + debuginfoPath = Path.of("/usr/lib/debug/.build_id", dir, file + ".debug"); + exists = Files.exists(debuginfoPath); + } + } + return exists ? debuginfoPath.toString() : null; + } catch (IOException e) { + throw new RuntimeException("getDebugInfo() failed due to IOException.", e); + } + } + + private static boolean isSymbolAvailableInternal(String lib, String symbol) throws IOException { + var proc = (new ProcessBuilder("nm", lib)).start(); + try (var reader = proc.inputReader()) { + return reader.lines() + .anyMatch(l -> l.endsWith(" " + symbol)); + } + } + + /** + * This method will work on Linux only. + * Both "readelf" and "nm" have to be available. + * @return true if given symbol is available in given lib. + */ + public static boolean isSymbolAvailable(String lib, String symbol) { + try { + // Attempt to find symbol from lib + boolean result = isSymbolAvailableInternal(lib, symbol); + if (!result) { + // Attempt to find symbol from debuginfo + String debuginfoPath = getDebugInfo(lib); + if (debuginfoPath != null) { + result = isSymbolAvailableInternal(debuginfoPath, symbol); + } + } + return result; + } catch (IOException e) { + throw new RuntimeException("isSymbolAvailable() failed due to IOException.", e); + } + } } From 88f538f114faf62e5decc48ae624b1c1302db13a Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Tue, 3 Feb 2026 10:46:38 +0000 Subject: [PATCH 306/328] 8376324: [IR Framework] Name methods in a CompileCommand-friendly way Reviewed-by: chagedorn, dfenacci --- .../report/FailureMessageBuilder.java | 5 +- .../tests/TestCompileThreshold.java | 6 +- .../ir_framework/tests/TestIRMatching.java | 326 ++++++++---------- .../ir_framework/tests/TestRunTests.java | 4 +- 4 files changed, 160 insertions(+), 181 deletions(-) diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/report/FailureMessageBuilder.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/report/FailureMessageBuilder.java index 9cbba83e90b..f52c5f8fb5f 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/report/FailureMessageBuilder.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/report/FailureMessageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, 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 @@ -82,7 +82,8 @@ public class FailureMessageBuilder implements MatchResultVisitor { msg.append(System.lineSeparator()); } msg.append(methodIndex).append(") "); - msg.append("Method \"").append(method) + msg.append("Method \"") + .append(method.getDeclaringClass().getTypeName()).append("::").append(method.getName()) .append("\" - [Failed IR rules: ").append(failedIRRules).append("]:") .append(System.lineSeparator()); } diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCompileThreshold.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCompileThreshold.java index 7225c7fff07..793ef1ebe34 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCompileThreshold.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCompileThreshold.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -50,7 +50,7 @@ public class TestCompileThreshold { "-DPreferCommandLineFlags=true"); } catch (IRViolationException e) { Asserts.assertTrue(e.getExceptionInfo().contains("Failed IR Rules (1)"), "exactly one rule failed"); - Asserts.assertTrue(e.getExceptionInfo().contains("testWithCompileThreshold()"), + Asserts.assertTrue(e.getExceptionInfo().contains("testWithCompileThreshold"), "testWithCompileThreshold() failed"); } @@ -59,7 +59,7 @@ public class TestCompileThreshold { "-DTest=testWithoutCompileThreshold"); } catch (IRViolationException e) { Asserts.assertTrue(e.getExceptionInfo().contains("Failed IR Rules (1)"), "exactly one rule failed"); - Asserts.assertTrue(e.getExceptionInfo().contains("testWithoutCompileThreshold()"), + Asserts.assertTrue(e.getExceptionInfo().contains("testWithoutCompileThreshold"), "testWithoutCompileThreshold() failed"); } } diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java index 07a6a03f2a6..b6881fede75 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java @@ -34,6 +34,7 @@ import java.io.PrintStream; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; /* * @test @@ -72,180 +73,180 @@ public class TestIRMatching { runWithArguments(GoodCount.class, "-XX:TLABRefillWasteFraction=50"); runWithArguments(MultipleFailOnGood.class, "-XX:TLABRefillWasteFraction=50"); - runCheck(new String[] {"-XX:TLABRefillWasteFraction=50", "-XX:+UsePerfData", "-XX:+UseTLAB"}, BadFailOnConstraint.create(AndOr1.class, "test1(int)", 1, "CallStaticJava")); - runCheck(new String[] {"-XX:TLABRefillWasteFraction=50", "-XX:-UsePerfData", "-XX:+UseTLAB"}, BadFailOnConstraint.create(AndOr1.class, "test2()", 1, "CallStaticJava")); + runCheck(new String[] {"-XX:TLABRefillWasteFraction=50", "-XX:+UsePerfData", "-XX:+UseTLAB"}, BadFailOnConstraint.create(AndOr1.class, "test1", 1, "CallStaticJava")); + runCheck(new String[] {"-XX:TLABRefillWasteFraction=50", "-XX:-UsePerfData", "-XX:+UseTLAB"}, BadFailOnConstraint.create(AndOr1.class, "test2", 1, "CallStaticJava")); - runCheck(BadFailOnConstraint.create(MultipleFailOnBad.class, "fail1()", 1, 1, "Store"), - BadFailOnConstraint.create(MultipleFailOnBad.class, "fail1()", 1, 3, "Store"), - GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail1()", 1, 2, 4), - GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail2()", 1, 1), - BadFailOnConstraint.create(MultipleFailOnBad.class, "fail2()", 1, 2, "CallStaticJava"), - BadFailOnConstraint.create(MultipleFailOnBad.class, "fail3()", 1, 2, "Store"), - GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail3()", 1, 1, 3), - BadFailOnConstraint.create(MultipleFailOnBad.class, "fail4()", 1, 1, "Store"), - GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail4()", 1, 2, 3), - BadFailOnConstraint.create(MultipleFailOnBad.class, "fail5()", 1, 1, "Store"), - GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail5()", 1, 2, 3), - GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail6()", 1, 1), - BadFailOnConstraint.create(MultipleFailOnBad.class, "fail6()", 1, 2, "MyClass"), - BadFailOnConstraint.create(MultipleFailOnBad.class, "fail6()", 1, 3, "CallStaticJava"), - GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail7()", 1, 1), - BadFailOnConstraint.create(MultipleFailOnBad.class, "fail7()", 1, 2, "MyClass"), - GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail8()", 1, 1), - BadFailOnConstraint.create(MultipleFailOnBad.class, "fail8()", 1, 2, "MyClass"), - BadFailOnConstraint.create(MultipleFailOnBad.class, "fail9()", 1, 1, "Store"), - BadFailOnConstraint.create(MultipleFailOnBad.class, "fail9()", 1, 2, "CallStaticJava"), - BadFailOnConstraint.create(MultipleFailOnBad.class, "fail10()", 1, 1, "Store", "iFld"), - GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail10()", 1, 2, 3) + runCheck(BadFailOnConstraint.create(MultipleFailOnBad.class, "fail1", 1, 1, "Store"), + BadFailOnConstraint.create(MultipleFailOnBad.class, "fail1", 1, 3, "Store"), + GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail1", 1, 2, 4), + GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail2", 1, 1), + BadFailOnConstraint.create(MultipleFailOnBad.class, "fail2", 1, 2, "CallStaticJava"), + BadFailOnConstraint.create(MultipleFailOnBad.class, "fail3", 1, 2, "Store"), + GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail3", 1, 1, 3), + BadFailOnConstraint.create(MultipleFailOnBad.class, "fail4", 1, 1, "Store"), + GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail4", 1, 2, 3), + BadFailOnConstraint.create(MultipleFailOnBad.class, "fail5", 1, 1, "Store"), + GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail5", 1, 2, 3), + GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail6", 1, 1), + BadFailOnConstraint.create(MultipleFailOnBad.class, "fail6", 1, 2, "MyClass"), + BadFailOnConstraint.create(MultipleFailOnBad.class, "fail6", 1, 3, "CallStaticJava"), + GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail7", 1, 1), + BadFailOnConstraint.create(MultipleFailOnBad.class, "fail7", 1, 2, "MyClass"), + GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail8", 1, 1), + BadFailOnConstraint.create(MultipleFailOnBad.class, "fail8", 1, 2, "MyClass"), + BadFailOnConstraint.create(MultipleFailOnBad.class, "fail9", 1, 1, "Store"), + BadFailOnConstraint.create(MultipleFailOnBad.class, "fail9", 1, 2, "CallStaticJava"), + BadFailOnConstraint.create(MultipleFailOnBad.class, "fail10", 1, 1, "Store", "iFld"), + GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail10", 1, 2, 3) ); - runCheck(BadCountsConstraint.create(BadCount.class, "bad1()", 1, 2, "Load"), - GoodCountsConstraint.create(BadCount.class, "bad1()", 2), - GoodCountsConstraint.create(BadCount.class, "bad2()", 1), - BadCountsConstraint.create(BadCount.class, "bad2()", 2, 2, "Store"), - BadCountsConstraint.create(BadCount.class, "bad3()", 1, 2, "Load"), - BadCountsConstraint.create(BadCount.class, "bad3()", 2, 2, "Store") + runCheck(BadCountsConstraint.create(BadCount.class, "bad1", 1, 2, "Load"), + GoodCountsConstraint.create(BadCount.class, "bad1", 2), + GoodCountsConstraint.create(BadCount.class, "bad2", 1), + BadCountsConstraint.create(BadCount.class, "bad2", 2, 2,"Store"), + BadCountsConstraint.create(BadCount.class, "bad3", 1, 2,"Load"), + BadCountsConstraint.create(BadCount.class, "bad3", 2, 2,"Store") ); - runCheck(GoodRuleConstraint.create(Calls.class, "calls()", 1), - BadFailOnConstraint.create(Calls.class, "calls()", 2, 1, "CallStaticJava", "dontInline"), - BadFailOnConstraint.create(Calls.class, "calls()", 2, 2, "CallStaticJava", "dontInline"), - GoodRuleConstraint.create(Calls.class, "calls()", 3) + runCheck(GoodRuleConstraint.create(Calls.class, "calls", 1), + BadFailOnConstraint.create(Calls.class, "calls", 2, 1, "CallStaticJava", "dontInline"), + BadFailOnConstraint.create(Calls.class, "calls", 2, 2, "CallStaticJava", "dontInline"), + GoodRuleConstraint.create(Calls.class, "calls", 3) ); - runCheck(BadFailOnConstraint.create(AllocInstance.class, "allocInstance()", 1), - BadFailOnConstraint.create(AllocInstance.class, "allocInstance()", 2), - GoodFailOnConstraint.create(AllocInstance.class, "allocInstance()", 3), - GoodFailOnConstraint.create(AllocInstance.class, "allocInstance()", 4), - GoodFailOnConstraint.create(AllocInstance.class, "allocInstance()", 5), - BadFailOnConstraint.create(AllocInstance.class, "allocInstance()", 6), - BadFailOnConstraint.create(AllocInstance.class, "allocInstance()", 7), - GoodFailOnConstraint.create(AllocInstance.class, "allocInstance()", 8), - GoodFailOnConstraint.create(AllocInstance.class, "allocInstance()", 9), - GoodFailOnConstraint.create(AllocInstance.class, "allocInstance()", 10) + runCheck(BadFailOnConstraint.create(AllocInstance.class, "allocInstance", 1), + BadFailOnConstraint.create(AllocInstance.class, "allocInstance", 2), + GoodFailOnConstraint.create(AllocInstance.class, "allocInstance", 3), + GoodFailOnConstraint.create(AllocInstance.class, "allocInstance", 4), + GoodFailOnConstraint.create(AllocInstance.class, "allocInstance", 5), + BadFailOnConstraint.create(AllocInstance.class, "allocInstance", 6), + BadFailOnConstraint.create(AllocInstance.class, "allocInstance", 7), + GoodFailOnConstraint.create(AllocInstance.class, "allocInstance", 8), + GoodFailOnConstraint.create(AllocInstance.class, "allocInstance", 9), + GoodFailOnConstraint.create(AllocInstance.class, "allocInstance", 10) ); runCheck( - BadFailOnConstraint.create(AllocInstance.class, "allocNested()", 1), - BadFailOnConstraint.create(AllocInstance.class, "allocNested()", 2), - BadFailOnConstraint.create(AllocInstance.class, "allocNested()", 3) + BadFailOnConstraint.create(AllocInstance.class, "allocNested", 1), + BadFailOnConstraint.create(AllocInstance.class, "allocNested", 2), + BadFailOnConstraint.create(AllocInstance.class, "allocNested", 3) ); - runCheck(BadFailOnConstraint.create(AllocArray.class, "allocArray()", 1), - BadFailOnConstraint.create(AllocArray.class, "allocArray()", 2), - GoodFailOnConstraint.create(AllocArray.class, "allocArray()", 3), - GoodFailOnConstraint.create(AllocArray.class, "allocArray()", 4), - GoodFailOnConstraint.create(AllocArray.class, "allocArray()", 5), - BadFailOnConstraint.create(AllocArray.class, "allocArray()", 6), - BadFailOnConstraint.create(AllocArray.class, "allocArray()", 7), - GoodFailOnConstraint.create(AllocArray.class, "allocArray()", 8), - GoodFailOnConstraint.create(AllocArray.class, "allocArray()", 9), - GoodFailOnConstraint.create(AllocArray.class, "allocArray()", 10) + runCheck(BadFailOnConstraint.create(AllocArray.class, "allocArray", 1), + BadFailOnConstraint.create(AllocArray.class, "allocArray", 2), + GoodFailOnConstraint.create(AllocArray.class, "allocArray", 3), + GoodFailOnConstraint.create(AllocArray.class, "allocArray", 4), + GoodFailOnConstraint.create(AllocArray.class, "allocArray", 5), + BadFailOnConstraint.create(AllocArray.class, "allocArray", 6), + BadFailOnConstraint.create(AllocArray.class, "allocArray", 7), + GoodFailOnConstraint.create(AllocArray.class, "allocArray", 8), + GoodFailOnConstraint.create(AllocArray.class, "allocArray", 9), + GoodFailOnConstraint.create(AllocArray.class, "allocArray", 10) ); - runCheck(BadFailOnConstraint.create(AllocArray.class, "allocMultiArray()", 1), - BadFailOnConstraint.create(AllocArray.class, "allocMultiArray()", 2), - GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray()", 3), - GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray()", 4), - GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray()", 5), - BadFailOnConstraint.create(AllocArray.class, "allocMultiArray()", 6), - BadFailOnConstraint.create(AllocArray.class, "allocMultiArray()", 7), - GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray()", 8), - GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray()", 9), - GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray()", 10) + runCheck(BadFailOnConstraint.create(AllocArray.class, "allocMultiArray", 1), + BadFailOnConstraint.create(AllocArray.class, "allocMultiArray", 2), + GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray", 3), + GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray", 4), + GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray", 5), + BadFailOnConstraint.create(AllocArray.class, "allocMultiArray", 6), + BadFailOnConstraint.create(AllocArray.class, "allocMultiArray", 7), + GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray", 8), + GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray", 9), + GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray", 10) ); - runCheck(GoodRuleConstraint.create(RunTests.class, "good1()", 1), - GoodRuleConstraint.create(RunTests.class, "good1()", 2), - GoodRuleConstraint.create(RunTests.class, "good2()", 1), - GoodRuleConstraint.create(RunTests.class, "good2()", 2), - GoodRuleConstraint.create(RunTests.class, "good3(int)", 1), - BadCountsConstraint.create(RunTests.class, "bad1(int)", 1, 0), - BadFailOnConstraint.create(RunTests.class, "bad1(int)", 2, "Load") + runCheck(GoodRuleConstraint.create(RunTests.class, "good1", 1), + GoodRuleConstraint.create(RunTests.class, "good1", 2), + GoodRuleConstraint.create(RunTests.class, "good2", 1), + GoodRuleConstraint.create(RunTests.class, "good2", 2), + GoodRuleConstraint.create(RunTests.class, "good3", 1), + BadCountsConstraint.create(RunTests.class, "bad1", 1, 0), + BadFailOnConstraint.create(RunTests.class, "bad1", 2, "Load") ); runCheck(new String[] {"-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UseCompressedClassPointers"}, - BadFailOnConstraint.create(Loads.class, "load()", 1, 1, "Load"), - BadFailOnConstraint.create(Loads.class, "load()", 1, 3, "LoadI"), - BadCountsConstraint.create(Loads.class, "load()", 1, 1, 0), - BadCountsConstraint.create(Loads.class, "load()", 1, 2, 1,"Load"), - GoodRuleConstraint.create(Loads.class, "load()", 2), - GoodFailOnConstraint.create(Loads.class, "load()", 3), - BadCountsConstraint.create(Loads.class, "load()", 3, 2, 2,"Store"), - BadFailOnConstraint.create(Loads.class, "load()", 4, 2, "Store"), - BadFailOnConstraint.create(Loads.class, "load()", 5, "Load"), - BadFailOnConstraint.create(Loads.class, "load()", 6, "Load"), - BadFailOnConstraint.create(Loads.class, "load()", 7, "Load"), - GoodRuleConstraint.create(Loads.class, "load()", 8), - GoodRuleConstraint.create(Loads.class, "load()", 9), - GoodRuleConstraint.create(Loads.class, "load()", 10), - BadFailOnConstraint.create(Loads.class, "loadKlass()", 1), - BadCountsConstraint.create(Loads.class, "loadKlass()", 2, 2,"Field") + BadFailOnConstraint.create(Loads.class, "load", 1, 1, "Load"), + BadFailOnConstraint.create(Loads.class, "load", 1, 3, "LoadI"), + BadCountsConstraint.create(Loads.class, "load", 1, 1, 0), + BadCountsConstraint.create(Loads.class, "load", 1, 2, 1,"Load"), + GoodRuleConstraint.create(Loads.class, "load", 2), + GoodFailOnConstraint.create(Loads.class, "load", 3), + BadCountsConstraint.create(Loads.class, "load", 3, 2, 2,"Store"), + BadFailOnConstraint.create(Loads.class, "load", 4, 2, "Store"), + BadFailOnConstraint.create(Loads.class, "load", 5, "Load"), + BadFailOnConstraint.create(Loads.class, "load", 6, "Load"), + BadFailOnConstraint.create(Loads.class, "load", 7, "Load"), + GoodRuleConstraint.create(Loads.class, "load", 8), + GoodRuleConstraint.create(Loads.class, "load", 9), + GoodRuleConstraint.create(Loads.class, "load", 10), + BadFailOnConstraint.create(Loads.class, "loadKlass", 1), + BadCountsConstraint.create(Loads.class, "loadKlass", 2, 2,"Field") ); // Loops - runCheck(BadFailOnConstraint.create(Loops.class, "loop()", 1, "Loop"), - GoodRuleConstraint.create(Loops.class, "loop()", 2), - GoodRuleConstraint.create(Loops.class, "loop()", 3), - GoodRuleConstraint.create(Loops.class, "countedLoop()", 1), - BadFailOnConstraint.create(Loops.class, "countedLoop()", 2, "CountedLoop"), - GoodRuleConstraint.create(Loops.class, "countedLoop()", 3), - BadFailOnConstraint.create(Loops.class, "loopAndCountedLoop()", 1, "Loop"), - BadFailOnConstraint.create(Loops.class, "loopAndCountedLoop()", 2, "CountedLoop"), - GoodRuleConstraint.create(Loops.class, "loopAndCountedLoop()", 3), - GoodRuleConstraint.create(Loops.class, "countedLoopMain()", 1), - BadFailOnConstraint.create(Loops.class, "countedLoopMain()", 2, "CountedLoop"), - BadFailOnConstraint.create(Loops.class, "countedLoopMain()", 3, "CountedLoop", "main"), - GoodRuleConstraint.create(Loops.class, "countedLoopUnrolled()", 1), - GoodRuleConstraint.create(Loops.class, "countedLoopUnrolled()", 2), - GoodRuleConstraint.create(Loops.class, "countedLoopUnrolled()", 3) + runCheck(BadFailOnConstraint.create(Loops.class, "loop", 1, "Loop"), + GoodRuleConstraint.create(Loops.class, "loop", 2), + GoodRuleConstraint.create(Loops.class, "loop", 3), + GoodRuleConstraint.create(Loops.class, "countedLoop", 1), + BadFailOnConstraint.create(Loops.class, "countedLoop", 2, "CountedLoop"), + GoodRuleConstraint.create(Loops.class, "countedLoop", 3), + BadFailOnConstraint.create(Loops.class, "loopAndCountedLoop", 1, "Loop"), + BadFailOnConstraint.create(Loops.class, "loopAndCountedLoop", 2, "CountedLoop"), + GoodRuleConstraint.create(Loops.class, "loopAndCountedLoop", 3), + GoodRuleConstraint.create(Loops.class, "countedLoopMain", 1), + BadFailOnConstraint.create(Loops.class, "countedLoopMain", 2, "CountedLoop"), + BadFailOnConstraint.create(Loops.class, "countedLoopMain", 3, "CountedLoop", "main"), + GoodRuleConstraint.create(Loops.class, "countedLoopUnrolled", 1), + GoodRuleConstraint.create(Loops.class, "countedLoopUnrolled", 2), + GoodRuleConstraint.create(Loops.class, "countedLoopUnrolled", 3) ); // Traps - runCheck(GoodRuleConstraint.create(Traps.class, "noTraps()", 1), - BadFailOnConstraint.create(Traps.class, "noTraps()", 2, "Store", "iFld"), - GoodRuleConstraint.create(Traps.class, "noTraps()", 3), - BadFailOnConstraint.create(Traps.class, "predicateTrap()", 1, "CallStaticJava", "uncommon_trap"), - BadFailOnConstraint.create(Traps.class, "predicateTrap()", 2, "CallStaticJava", "uncommon_trap", "predicate"), - GoodRuleConstraint.create(Traps.class, "predicateTrap()", 3), - GoodRuleConstraint.create(Traps.class, "predicateTrap()", 4), - BadFailOnConstraint.create(Traps.class, "nullCheck()", 1, "CallStaticJava", "uncommon_trap"), - BadFailOnConstraint.create(Traps.class, "nullCheck()", 2, "CallStaticJava", "uncommon_trap", "null_check"), - BadFailOnConstraint.create(Traps.class, "nullCheck()", 3, "uncommon_trap", "class_check"), - GoodRuleConstraint.create(Traps.class, "nullCheck()", 4), - BadFailOnConstraint.create(Traps.class, "nullAssert()", 1, "CallStaticJava", "uncommon_trap"), - BadFailOnConstraint.create(Traps.class, "nullAssert()", 2, "CallStaticJava", "uncommon_trap", "null_assert"), - BadFailOnConstraint.create(Traps.class, "nullAssert()", 3, "CallStaticJava", "uncommon_trap", "null_check"), - GoodRuleConstraint.create(Traps.class, "nullAssert()", 4), - BadFailOnConstraint.create(Traps.class, "unstableIf(boolean)", 1, "CallStaticJava", "uncommon_trap"), - BadFailOnConstraint.create(Traps.class, "unstableIf(boolean)", 2, "CallStaticJava", "uncommon_trap", "unstable_if"), - GoodRuleConstraint.create(Traps.class, "unstableIf(boolean)", 3), - BadFailOnConstraint.create(Traps.class, "classCheck()", 1, "CallStaticJava", "uncommon_trap"), - BadFailOnConstraint.create(Traps.class, "classCheck()", 2, "CallStaticJava", "uncommon_trap", "class_check"), - BadFailOnConstraint.create(Traps.class, "classCheck()", 3, "CallStaticJava", "uncommon_trap", "null_check"), - GoodRuleConstraint.create(Traps.class, "classCheck()", 4), - BadFailOnConstraint.create(Traps.class, "rangeCheck()", 1, "CallStaticJava", "uncommon_trap"), - BadFailOnConstraint.create(Traps.class, "rangeCheck()", 2, "CallStaticJava", "uncommon_trap", "range_check"), - BadFailOnConstraint.create(Traps.class, "rangeCheck()", 3, "CallStaticJava", "uncommon_trap", "null_check"), - GoodRuleConstraint.create(Traps.class, "rangeCheck()", 4), - BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 1, "CallStaticJava", "uncommon_trap"), + runCheck(GoodRuleConstraint.create(Traps.class, "noTraps", 1), + BadFailOnConstraint.create(Traps.class, "noTraps", 2, "Store", "iFld"), + GoodRuleConstraint.create(Traps.class, "noTraps", 3), + BadFailOnConstraint.create(Traps.class, "predicateTrap", 1, "CallStaticJava", "uncommon_trap"), + BadFailOnConstraint.create(Traps.class, "predicateTrap", 2, "CallStaticJava", "uncommon_trap", "predicate"), + GoodRuleConstraint.create(Traps.class, "predicateTrap", 3), + GoodRuleConstraint.create(Traps.class, "predicateTrap", 4), + BadFailOnConstraint.create(Traps.class, "nullCheck", 1, "CallStaticJava", "uncommon_trap"), + BadFailOnConstraint.create(Traps.class, "nullCheck", 2, "CallStaticJava", "uncommon_trap", "null_check"), + BadFailOnConstraint.create(Traps.class, "nullCheck", 3, "uncommon_trap", "class_check"), + GoodRuleConstraint.create(Traps.class, "nullCheck", 4), + BadFailOnConstraint.create(Traps.class, "nullAssert", 1, "CallStaticJava", "uncommon_trap"), + BadFailOnConstraint.create(Traps.class, "nullAssert", 2, "CallStaticJava", "uncommon_trap", "null_assert"), + BadFailOnConstraint.create(Traps.class, "nullAssert", 3, "CallStaticJava", "uncommon_trap", "null_check"), + GoodRuleConstraint.create(Traps.class, "nullAssert", 4), + BadFailOnConstraint.create(Traps.class, "unstableIf", 1, "CallStaticJava", "uncommon_trap"), + BadFailOnConstraint.create(Traps.class, "unstableIf", 2, "CallStaticJava", "uncommon_trap", "unstable_if"), + GoodRuleConstraint.create(Traps.class, "unstableIf", 3), + BadFailOnConstraint.create(Traps.class, "classCheck", 1, "CallStaticJava", "uncommon_trap"), + BadFailOnConstraint.create(Traps.class, "classCheck", 2, "CallStaticJava", "uncommon_trap", "class_check"), + BadFailOnConstraint.create(Traps.class, "classCheck", 3, "CallStaticJava", "uncommon_trap", "null_check"), + GoodRuleConstraint.create(Traps.class, "classCheck", 4), + BadFailOnConstraint.create(Traps.class, "rangeCheck", 1, "CallStaticJava", "uncommon_trap"), + BadFailOnConstraint.create(Traps.class, "rangeCheck", 2, "CallStaticJava", "uncommon_trap", "range_check"), + BadFailOnConstraint.create(Traps.class, "rangeCheck", 3, "CallStaticJava", "uncommon_trap", "null_check"), + GoodRuleConstraint.create(Traps.class, "rangeCheck", 4), + BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining", 1, "CallStaticJava", "uncommon_trap"), WhiteBox.getWhiteBox().isJVMCISupportedByGC() ? - BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 2, "CallStaticJava", "uncommon_trap", "intrinsic_or_type_checked_inlining") - : GoodRuleConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 2), - BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 3, "CallStaticJava", "uncommon_trap", "intrinsic"), - BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 4, "CallStaticJava", "uncommon_trap", "null_check"), - GoodRuleConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 5) + BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining", 2, "CallStaticJava", "uncommon_trap", "intrinsic_or_type_checked_inlining") + : GoodRuleConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining", 2), + BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining", 3, "CallStaticJava", "uncommon_trap", "intrinsic"), + BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining", 4, "CallStaticJava", "uncommon_trap", "null_check"), + GoodRuleConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining", 5) ); runCheck(new String[] {"-XX:+BailoutToInterpreterForThrows"}, - BadFailOnConstraint.create(UnhandledTrap.class, "unhandled()", 1, "CallStaticJava", "uncommon_trap"), - BadFailOnConstraint.create(UnhandledTrap.class, "unhandled()", 2, "CallStaticJava", "uncommon_trap", "unhandled"), - GoodRuleConstraint.create(UnhandledTrap.class, "unhandled()", 3) + BadFailOnConstraint.create(UnhandledTrap.class, "unhandled", 1, "CallStaticJava", "uncommon_trap"), + BadFailOnConstraint.create(UnhandledTrap.class, "unhandled", 2, "CallStaticJava", "uncommon_trap", "unhandled"), + GoodRuleConstraint.create(UnhandledTrap.class, "unhandled", 3) ); - runCheck(BadFailOnConstraint.create(ScopeObj.class, "scopeObject()", 1, "ScObj")); - runCheck(BadFailOnConstraint.create(Membar.class, "membar()", 1, "MemBar")); + runCheck(BadFailOnConstraint.create(ScopeObj.class, "scopeObject", 1, "ScObj")); + runCheck(BadFailOnConstraint.create(Membar.class, "membar", 1, "MemBar")); String cmp; if (Platform.isPPC() || Platform.isX86()) { @@ -255,13 +256,13 @@ public class TestIRMatching { } else { cmp = "cmp"; } - runCheck(BadFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 1, cmp, "Constant"), - BadFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 2, 1,cmp, "Constant", "MyClass"), - BadFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 2, 2,cmp, "Constant", "ir_framework/tests/MyClass"), - GoodFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 3), + runCheck(BadFailOnConstraint.create(CheckCastArray.class, "array", 1, cmp, "Constant"), + BadFailOnConstraint.create(CheckCastArray.class, "array", 2, 1,cmp, "Constant", "MyClass"), + BadFailOnConstraint.create(CheckCastArray.class, "array", 2, 2,cmp, "Constant", "ir_framework/tests/MyClass"), + GoodFailOnConstraint.create(CheckCastArray.class, "array", 3), Platform.isS390x() ? // There is no checkcast_arraycopy stub for C2 on s390 - GoodFailOnConstraint.create(CheckCastArray.class, "arrayCopy(java.lang.Object[],java.lang.Class)", 1) - : BadFailOnConstraint.create(CheckCastArray.class, "arrayCopy(java.lang.Object[],java.lang.Class)", 1, "checkcast_arraycopy") + GoodFailOnConstraint.create(CheckCastArray.class, "arrayCopy", 1) + : BadFailOnConstraint.create(CheckCastArray.class, "arrayCopy", 1, "checkcast_arraycopy") ); try { @@ -1555,28 +1556,15 @@ abstract class Constraint { private final Class klass; protected final int ruleIdx; private final Pattern methodPattern; - private final String classAndMethod; - protected final Pattern irPattern; private final String methodName; protected boolean matched; - Constraint(Class klass, String methodName, int ruleIdx, Pattern irPattern) { - this.klass = klass; - classAndMethod = klass.getSimpleName() + "." + methodName; - this.ruleIdx = ruleIdx; - this.methodPattern = Pattern.compile(Pattern.quote(classAndMethod)); - this.irPattern = irPattern; - this.methodName = methodName; - this.matched = false; - } - // For good constraints only Constraint(Class klass, String methodName, int ruleIdx) { this.klass = klass; - classAndMethod = klass.getSimpleName() + "." + methodName; + String classAndMethod = klass.getSimpleName() + "::" + methodName; this.ruleIdx = ruleIdx; - this.methodPattern = Pattern.compile(Pattern.quote(classAndMethod)); - this.irPattern = null; + this.methodPattern = Pattern.compile("\\b" + Pattern.quote(classAndMethod) + "\\b"); this.methodName = methodName; this.matched = false; } @@ -1677,7 +1665,7 @@ abstract class RegexConstraint extends Constraint { final List matches; RegexConstraint(Class klass, String methodName, String category, boolean isGood, List matches, int ruleIdx, int... regexIndexes) { - super(klass, methodName, ruleIdx, initIRPattern(category, ruleIdx)); + super(klass, methodName, ruleIdx); this.category = category; this.regexIndexes = regexIndexes; if (category.equals("failOn")) { @@ -1706,16 +1694,6 @@ abstract class RegexConstraint extends Constraint { return super.errorPrefix() + " with \"" + category + "\""; } - private static Pattern initIRPattern(String category, int ruleIdx) { - if (category.equals("failOn")) { - return Pattern.compile("rule " + ruleIdx + ":.*\\R.*- failOn: Graph contains forbidden nodes.*\\R" + - ".*Constraint \\d+:.*\\R.*Matched forbidden node.*"); - } else { - return Pattern.compile("rule " + ruleIdx + ":.*\\R.*- counts: Graph contains wrong number of nodes:\\R" + - ".*Constraint \\d+:.*\\R.*Expected.*"); - } - } - @Override protected void checkIRRule(String irRule) { int categoryIndex = irRule.indexOf("- " + category); diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestRunTests.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestRunTests.java index f8d64944ff4..39dae4ae3ad 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestRunTests.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestRunTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -54,7 +54,7 @@ public class TestRunTests { Asserts.fail("Should have thrown exception"); } catch (IRViolationException e) { System.setOut(oldOut); - String[] matches = { "test(int)", "test2(int)", "Failed IR Rules (2)"}; + String[] matches = { "test", "test2", "Failed IR Rules (2)"}; Arrays.stream(matches).forEach(m -> Asserts.assertTrue(e.getExceptionInfo().contains(m))); Asserts.assertEQ(e.getExceptionInfo().split("STANDALONE mode", -1).length - 1, 2); } From a5b4c0795d88db3d02d31fb4740612c6a53f7204 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 3 Feb 2026 11:59:01 +0000 Subject: [PATCH 307/328] 8376889: Enhance JfrRecorder::on_create_vm_3() assert output Reviewed-by: mdoerr, mgronlun, asteiner --- src/hotspot/share/jfr/recorder/jfrRecorder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp index 6a6da0f9b04..061e3feac6f 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, 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 @@ -240,7 +240,7 @@ bool JfrRecorder::on_create_vm_2() { } bool JfrRecorder::on_create_vm_3() { - JVMTI_ONLY( assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE, "invalid init sequence"); ) + JVMTI_ONLY( assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE, "invalid init sequence, phase is %d", (int)JvmtiEnvBase::get_phase()); ) return CDSConfig::is_dumping_archive() || launch_command_line_recordings(JavaThread::current()); } From 69c3e2780c44c6ad2ef0f296e8cfba7796f2213e Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 3 Feb 2026 12:37:33 +0000 Subject: [PATCH 308/328] 8376410: G1: Task queue statistics not reset properly on mark abort Reviewed-by: shade, iwalulya --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 14 ++++++++------ src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 4 +++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 5f096c2b9d7..8f3cafe1f5b 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -639,8 +639,7 @@ void G1ConcurrentMark::reset_marking_for_restart() { _finger = _heap.start(); for (uint i = 0; i < _max_num_tasks; ++i) { - G1CMTaskQueue* queue = _task_queues->queue(i); - queue->set_empty(); + _tasks[i]->reset_for_restart(); } } @@ -1943,11 +1942,7 @@ bool G1ConcurrentMark::concurrent_cycle_abort() { return false; } - // Empty mark stack reset_marking_for_restart(); - for (uint i = 0; i < _max_num_tasks; ++i) { - _tasks[i]->clear_region_fields(); - } abort_marking_threads(); @@ -2118,6 +2113,13 @@ void G1CMTask::reset(G1CMBitMap* mark_bitmap) { _mark_stats_cache.reset(); } +void G1CMTask::reset_for_restart() { + clear_region_fields(); + _task_queue->set_empty(); + TASKQUEUE_STATS_ONLY(_partial_array_splitter.stats()->reset()); + TASKQUEUE_STATS_ONLY(_task_queue->stats.reset()); +} + void G1CMTask::register_partial_array_splitter() { ::new (&_partial_array_splitter) PartialArraySplitter(_cm->partial_array_state_manager(), diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 3a4cbf1b83e..0271e6a4208 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -844,8 +844,10 @@ private: // Apply the closure to the given range of elements in the objArray. inline void process_array_chunk(objArrayOop obj, size_t start, size_t end); public: - // Resets the task; should be called right at the beginning of a marking phase. + // Resets the task completely for a new marking; should be called right at the beginning of a marking phase. void reset(G1CMBitMap* mark_bitmap); + // Minimal reset of the task, making it ready for continuing to mark. + void reset_for_restart(); // Register/unregister Partial Array Splitter Allocator with the PartialArrayStateManager. // This allows us to discard memory arenas used for partial object array states at the end // of a concurrent mark cycle. From 99bc98357dab78bef2cce7a10c98d13d1e5730e3 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 3 Feb 2026 13:37:51 +0000 Subject: [PATCH 309/328] 8377015: ConnectionRefusedMessage::testFinishConnect test fails on AIX with java.net.ConnectException: Connection refused Reviewed-by: alanb, mbaesken --- .../Selector/ConnectionRefusedMessage.java | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/test/jdk/java/nio/channels/Selector/ConnectionRefusedMessage.java b/test/jdk/java/nio/channels/Selector/ConnectionRefusedMessage.java index 5e7b6395a66..04490f63efe 100644 --- a/test/jdk/java/nio/channels/Selector/ConnectionRefusedMessage.java +++ b/test/jdk/java/nio/channels/Selector/ConnectionRefusedMessage.java @@ -69,7 +69,15 @@ class ConnectionRefusedMessage { sc.register(selector, SelectionKey.OP_CONNECT); System.err.println("establishing connection to " + destAddr); - boolean connected = sc.connect(destAddr); + boolean connected; + try { + connected = sc.connect(destAddr); + } catch (ConnectException ce) { + // Connect failed immediately, which is OK. + System.err.println("SocketChannel.connect() threw ConnectException - " + ce); + assertExceptionMessage(ce); + return; // nothing more to test + } // this test checks the exception message of a ConnectException, so it's // OK to skip the test if something unexpectedly accepted the connection assumeFalse(connected, "unexpectedly connected to " + destAddr); @@ -90,17 +98,22 @@ class ConnectionRefusedMessage { // with a return value of false fail("ConnectException was not thrown"); } catch (ConnectException ce) { - System.err.println("got (expected) ConnectException - " + ce); + System.err.println("got (expected) ConnectException from " + + "SocketChannel.finishConnect() - " + ce); // verify exception message - if (!"Connection refused".equals(ce.getMessage())) { - // propagate the original exception - fail("unexpected exception message: " + ce.getMessage(), ce); - } + assertExceptionMessage(ce); } } } } + private static void assertExceptionMessage(final ConnectException ce) { + if (!"Connection refused".equals(ce.getMessage())) { + // propagate the original exception + fail("unexpected exception message: " + ce.getMessage(), ce); + } + } + // Try to find a suitable port to provoke a "Connection Refused" error. private static InetSocketAddress findSuitableRefusedAddress() throws IOException { final InetAddress loopbackAddr = InetAddress.getLoopbackAddress(); From e51ccef9cb415ed31db70971bb439ca3d96c5bce Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Tue, 3 Feb 2026 16:32:21 +0000 Subject: [PATCH 310/328] 8347938: Add Support for the Latest ML-KEM and ML-DSA Private Key Encodings Reviewed-by: mullan, bperez, mpowers --- .../com/sun/crypto/provider/ML_KEM.java | 18 +- .../com/sun/crypto/provider/ML_KEM_Impls.java | 110 +++++-- .../sun/security/pkcs/NamedPKCS8Key.java | 121 ++++++-- .../classes/sun/security/provider/ML_DSA.java | 50 ++- .../sun/security/provider/ML_DSA_Impls.java | 110 +++++-- .../sun/security/provider/NamedKEM.java | 57 ++-- .../security/provider/NamedKeyFactory.java | 175 ++++++----- .../provider/NamedKeyPairGenerator.java | 85 ++++-- .../sun/security/provider/NamedSignature.java | 57 ++-- .../classes/sun/security/util/KeyChoices.java | 289 ++++++++++++++++++ .../sun/security/x509/NamedX509Key.java | 5 +- .../share/conf/security/java.security | 25 ++ .../sun/security/provider/acvp/Launcher.java | 4 + .../security/provider/acvp/ML_DSA_Test.java | 14 +- .../security/provider/acvp/ML_KEM_Test.java | 19 +- .../provider/{ => named}/NamedEdDSA.java | 39 ++- .../{ => named}/NamedKeyFactoryTest.java | 58 ++-- .../security/provider/named/NamedKeys.java | 103 +++++++ .../provider/pqc/PrivateKeyEncodings.java | 227 ++++++++++++++ .../security/provider/pqc/SeedOrExpanded.java | 194 ++++++++++++ test/lib/jdk/test/lib/process/Proc.java | 11 +- .../lib/security/RepositoryFileReader.java | 9 + 22 files changed, 1491 insertions(+), 289 deletions(-) create mode 100644 src/java.base/share/classes/sun/security/util/KeyChoices.java rename test/jdk/sun/security/provider/{ => named}/NamedEdDSA.java (84%) rename test/jdk/sun/security/provider/{ => named}/NamedKeyFactoryTest.java (85%) create mode 100644 test/jdk/sun/security/provider/named/NamedKeys.java create mode 100644 test/jdk/sun/security/provider/pqc/PrivateKeyEncodings.java create mode 100644 test/jdk/sun/security/provider/pqc/SeedOrExpanded.java diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java b/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java index bf6576f4d93..56a119893a7 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java @@ -498,7 +498,7 @@ public final class ML_KEM { /* Main internal algorithms from Section 6 of specification */ - protected ML_KEM_KeyPair generateKemKeyPair(byte[] kem_d, byte[] kem_z) { + protected ML_KEM_KeyPair generateKemKeyPair(byte[] kem_d_z) { MessageDigest mlKemH; try { mlKemH = MessageDigest.getInstance(HASH_H_NAME); @@ -508,7 +508,8 @@ public final class ML_KEM { } //Generate K-PKE keys - var kPkeKeyPair = generateK_PkeKeyPair(kem_d); + //The 1st 32-byte `d` is used in K-PKE key pair generation + var kPkeKeyPair = generateK_PkeKeyPair(kem_d_z); //encaps key = kPke encryption key byte[] encapsKey = kPkeKeyPair.publicKey.keyBytes; @@ -527,7 +528,8 @@ public final class ML_KEM { // This should never happen. throw new RuntimeException(e); } - System.arraycopy(kem_z, 0, decapsKey, + // The 2nd 32-byte `z` is copied into decapsKey + System.arraycopy(kem_d_z, 32, decapsKey, kPkePrivateKey.length + encapsKey.length + 32, 32); return new ML_KEM_KeyPair( @@ -535,6 +537,12 @@ public final class ML_KEM { new ML_KEM_DecapsulationKey(decapsKey)); } + public byte[] privKeyToPubKey(byte[] decapsKey) { + int pkLen = (mlKem_k * ML_KEM_N * 12) / 8 + 32 /* rho */; + int skLen = (mlKem_k * ML_KEM_N * 12) / 8; + return Arrays.copyOfRange(decapsKey, skLen, skLen + pkLen); + } + protected ML_KEM_EncapsulateResult encapsulate( ML_KEM_EncapsulationKey encapsulationKey, byte[] randomMessage) { MessageDigest mlKemH; @@ -648,10 +656,12 @@ public final class ML_KEM { throw new RuntimeException(e); } - mlKemG.update(seed); + // Note: only the 1st 32-byte in the seed is used + mlKemG.update(seed, 0, 32); mlKemG.update((byte)mlKem_k); var rhoSigma = mlKemG.digest(); + mlKemG.reset(); var rho = Arrays.copyOfRange(rhoSigma, 0, 32); var sigma = Arrays.copyOfRange(rhoSigma, 32, 64); Arrays.fill(rhoSigma, (byte)0); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM_Impls.java b/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM_Impls.java index 2ce5b3324e7..117f26e6981 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM_Impls.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM_Impls.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,12 @@ package com.sun.crypto.provider; import sun.security.jca.JCAUtil; +import sun.security.pkcs.NamedPKCS8Key; import sun.security.provider.NamedKEM; import sun.security.provider.NamedKeyFactory; import sun.security.provider.NamedKeyPairGenerator; +import sun.security.util.KeyChoices; +import sun.security.x509.NamedX509Key; import java.security.*; import java.util.Arrays; @@ -37,6 +40,20 @@ import javax.crypto.DecapsulateException; public final class ML_KEM_Impls { + private static final int SEED_LEN = 64; + + public static byte[] seedToExpanded(String pname, byte[] seed) { + return new ML_KEM(pname).generateKemKeyPair(seed) + .decapsulationKey() + .keyBytes(); + } + + public static NamedX509Key privKeyToPubKey(NamedPKCS8Key npk) { + return new NamedX509Key(npk.getAlgorithm(), + npk.getParams().getName(), + new ML_KEM(npk.getParams().getName()).privKeyToPubKey(npk.getExpanded())); + } + public sealed static class KPG extends NamedKeyPairGenerator permits KPG2, KPG3, KPG5 { @@ -50,25 +67,27 @@ public final class ML_KEM_Impls { } @Override - protected byte[][] implGenerateKeyPair(String name, SecureRandom random) { - byte[] seed = new byte[32]; + protected byte[][] implGenerateKeyPair(String pname, SecureRandom random) { + byte[] seed = new byte[SEED_LEN]; var r = random != null ? random : JCAUtil.getDefSecureRandom(); r.nextBytes(seed); - byte[] z = new byte[32]; - r.nextBytes(z); - ML_KEM mlKem = new ML_KEM(name); + ML_KEM mlKem = new ML_KEM(pname); ML_KEM.ML_KEM_KeyPair kp; + kp = mlKem.generateKemKeyPair(seed); + var expanded = kp.decapsulationKey().keyBytes(); + try { - kp = mlKem.generateKemKeyPair(seed, z); + return new byte[][]{ + kp.encapsulationKey().keyBytes(), + KeyChoices.writeToChoice( + KeyChoices.getPreferred("mlkem"), + seed, expanded), + expanded + }; } finally { - Arrays.fill(seed, (byte)0); - Arrays.fill(z, (byte)0); + Arrays.fill(seed, (byte) 0); } - return new byte[][] { - kp.encapsulationKey().keyBytes(), - kp.decapsulationKey().keyBytes() - }; } } @@ -94,8 +113,39 @@ public final class ML_KEM_Impls { public KF() { super("ML-KEM", "ML-KEM-512", "ML-KEM-768", "ML-KEM-1024"); } - public KF(String name) { - super("ML-KEM", name); + public KF(String pname) { + super("ML-KEM", pname); + } + + @Override + protected byte[] implExpand(String pname, byte[] input) + throws InvalidKeyException { + return KeyChoices.choiceToExpanded(pname, SEED_LEN, input, + ML_KEM_Impls::seedToExpanded); + } + + @Override + protected Key engineTranslateKey(Key key) throws InvalidKeyException { + var nk = toNamedKey(key); + if (nk instanceof NamedPKCS8Key npk) { + var type = KeyChoices.getPreferred("mlkem"); + if (KeyChoices.typeOfChoice(npk.getRawBytes()) != type) { + var encoding = KeyChoices.choiceToChoice( + type, + npk.getParams().getName(), + SEED_LEN, npk.getRawBytes(), + ML_KEM_Impls::seedToExpanded); + nk = NamedPKCS8Key.internalCreate( + npk.getAlgorithm(), + npk.getParams().getName(), + encoding, + npk.getExpanded().clone()); + if (npk != key) { // npk is neither input or output + npk.destroy(); + } + } + } + return nk; } } @@ -121,15 +171,15 @@ public final class ML_KEM_Impls { private static final int SEED_SIZE = 32; @Override - protected byte[][] implEncapsulate(String name, byte[] encapsulationKey, + protected byte[][] implEncapsulate(String pname, byte[] encapsulationKey, Object ek, SecureRandom secureRandom) { byte[] randomBytes = new byte[SEED_SIZE]; var r = secureRandom != null ? secureRandom : JCAUtil.getDefSecureRandom(); r.nextBytes(randomBytes); - ML_KEM mlKem = new ML_KEM(name); - ML_KEM.ML_KEM_EncapsulateResult mlKemEncapsulateResult = null; + ML_KEM mlKem = new ML_KEM(pname); + ML_KEM.ML_KEM_EncapsulateResult mlKemEncapsulateResult; try { mlKemEncapsulateResult = mlKem.encapsulate( new ML_KEM.ML_KEM_EncapsulationKey( @@ -145,49 +195,49 @@ public final class ML_KEM_Impls { } @Override - protected byte[] implDecapsulate(String name, byte[] decapsulationKey, + protected byte[] implDecapsulate(String pname, byte[] decapsulationKey, Object dk, byte[] cipherText) throws DecapsulateException { - ML_KEM mlKem = new ML_KEM(name); + ML_KEM mlKem = new ML_KEM(pname); var kpkeCipherText = new ML_KEM.K_PKE_CipherText(cipherText); return mlKem.decapsulate(new ML_KEM.ML_KEM_DecapsulationKey( decapsulationKey), kpkeCipherText); } @Override - protected int implSecretSize(String name) { + protected int implSecretSize(String pname) { return ML_KEM.SECRET_SIZE; } @Override - protected int implEncapsulationSize(String name) { - ML_KEM mlKem = new ML_KEM(name); + protected int implEncapsulationSize(String pname) { + ML_KEM mlKem = new ML_KEM(pname); return mlKem.getEncapsulationSize(); } @Override - protected Object implCheckPublicKey(String name, byte[] pk) + protected Object implCheckPublicKey(String pname, byte[] pk) throws InvalidKeyException { - ML_KEM mlKem = new ML_KEM(name); + ML_KEM mlKem = new ML_KEM(pname); return mlKem.checkPublicKey(pk); } @Override - protected Object implCheckPrivateKey(String name, byte[] sk) + protected Object implCheckPrivateKey(String pname, byte[] sk) throws InvalidKeyException { - ML_KEM mlKem = new ML_KEM(name); + ML_KEM mlKem = new ML_KEM(pname); return mlKem.checkPrivateKey(sk); } public K() { - super("ML-KEM", "ML-KEM-512", "ML-KEM-768", "ML-KEM-1024"); + super("ML-KEM", new KF()); } - public K(String name) { - super("ML-KEM", name); + public K(String pname) { + super("ML-KEM", new KF(pname)); } } diff --git a/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java b/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java index a748433da87..e1beb8b6b9b 100644 --- a/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java +++ b/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java @@ -25,11 +25,8 @@ package sun.security.pkcs; -import sun.security.util.DerInputStream; -import sun.security.util.DerValue; import sun.security.x509.AlgorithmId; -import javax.security.auth.DestroyFailedException; import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; @@ -39,6 +36,7 @@ import java.security.NoSuchAlgorithmException; import java.security.ProviderException; import java.security.spec.NamedParameterSpec; import java.util.Arrays; +import java.util.Objects; /// Represents a private key from an algorithm family that is specialized /// with a named parameter set. @@ -50,6 +48,28 @@ import java.util.Arrays; /// identifier in the PKCS #8 encoding of the key is always a single OID derived /// from the parameter set name. /// +/// Besides the existing [PKCS8Key#privKeyMaterial] field, this class optionally +/// supports an expanded format stored in [#expanded]. While `privKeyMaterial` +/// always represents the format used for encoding, `expanded` is always used +/// in computations. The expanded format must be self-sufficient for +/// cryptographic computations without requiring the encoding format. +/// +/// 1. If only `privKeyMaterial` is present, it's also the expanded format. +/// 2. If both `privKeyMaterial` and `expanded` are available, `privKeyMaterial` +/// is the encoding format, and `expanded` is the expanded format. +/// +/// If the two formats are the same, only `privKeyMaterial` is included, and +/// `expanded` must be `null`. Some implementations might be tempted to put the +/// same value into `privKeyMaterial` and `expanded`. However, problems can +/// arise if they happen to be the same object. To avoid ambiguity, always set +/// `expanded` to `null`. +/// +/// If the `expanded` field is required by the algorithm, it is either +/// [calculated from the PKCS #8 encoding][#NamedPKCS8Key(String, byte\[\], Expander)], +/// or [provided directly][#internalCreate(String, String, byte\[\], byte\[\])]. +/// In the latter case, the caller must ensure the consistency of the `encoded` +/// and `expanded` arguments. For example, seed and expanded key must match. +/// /// @see sun.security.provider.NamedKeyPairGenerator public final class NamedPKCS8Key extends PKCS8Key { @Serial @@ -57,42 +77,64 @@ public final class NamedPKCS8Key extends PKCS8Key { private final String fname; private final transient NamedParameterSpec paramSpec; - private final byte[] rawBytes; + private final transient byte[] expanded; private transient boolean destroyed = false; - /// Ctor from family name, parameter set name, raw key bytes. - /// Key bytes won't be cloned, caller must relinquish ownership - public NamedPKCS8Key(String fname, String pname, byte[] rawBytes) { + /// Creates a `NamedPKCS8Key` from raw components. + /// + /// @param fname family name + /// @param pname parameter set name + /// @param encoded raw key bytes, not null + /// @param expanded expanded key format, can be `null`. + private NamedPKCS8Key(String fname, String pname, byte[] encoded, byte[] expanded) { this.fname = fname; this.paramSpec = new NamedParameterSpec(pname); + this.expanded = expanded; + this.privKeyMaterial = Objects.requireNonNull(encoded); try { this.algid = AlgorithmId.get(pname); } catch (NoSuchAlgorithmException e) { throw new ProviderException(e); } - this.rawBytes = rawBytes; - - DerValue val = new DerValue(DerValue.tag_OctetString, rawBytes); - try { - this.privKeyMaterial = val.toByteArray(); - } finally { - val.clear(); - } } - /// Ctor from family name, and PKCS #8 bytes - public NamedPKCS8Key(String fname, byte[] encoded) throws InvalidKeyException { + /// Creates a `NamedPKCS8Key` from raw components. + /// + /// `encoded` and `expanded` won't be cloned, caller must relinquish + /// ownership. This caller must ensure `encoded` and `expanded` match + /// each other and `encoded` is valid and internally-consistent. + /// + /// @param fname family name + /// @param pname parameter set name + /// @param encoded raw key bytes, not null + /// @param expanded expanded key format, can be `null`. + public static NamedPKCS8Key internalCreate(String fname, String pname, + byte[] encoded, byte[] expanded) { + return new NamedPKCS8Key(fname, pname, encoded, expanded); + } + + /// Creates a `NamedPKCS8Key` from family name and PKCS #8 encoding. + /// + /// @param fname family name + /// @param encoded PKCS #8 encoding. It is copied so caller can modify + /// it after the method call. + /// @param expander a function that is able to calculate the expanded + /// format from the encoding format inside `encoded`. If it recognizes + /// the input already in expanded format, it must return `null`. + /// This argument must be `null` if the algorithm's expanded format + /// is always the same as its encoding format. Whatever the case, the + /// ownership of the result is fully granted to this object. + public NamedPKCS8Key(String fname, byte[] encoded, Expander expander) + throws InvalidKeyException { super(encoded); this.fname = fname; - try { - paramSpec = new NamedParameterSpec(algid.getName()); - if (algid.getEncodedParams() != null) { - throw new InvalidKeyException("algorithm identifier has params"); - } - rawBytes = new DerInputStream(privKeyMaterial).getOctetString(); - } catch (IOException e) { - throw new InvalidKeyException("Cannot parse input", e); + this.expanded = expander == null + ? null + : expander.expand(algid.getName(), this.privKeyMaterial); + paramSpec = new NamedParameterSpec(algid.getName()); + if (algid.getEncodedParams() != null) { + throw new InvalidKeyException("algorithm identifier has params"); } } @@ -104,9 +146,15 @@ public final class NamedPKCS8Key extends PKCS8Key { } /// Returns the reference to the internal key. Caller must not modify - /// the content or keep a reference. + /// the content or pass the reference to untrusted application code. public byte[] getRawBytes() { - return rawBytes; + return privKeyMaterial; + } + + /// Returns the reference to the key in expanded format. Caller must not + /// modify the content or pass the reference to untrusted application code. + public byte[] getExpanded() { + return expanded == null ? privKeyMaterial : expanded; } @Override @@ -127,9 +175,11 @@ public final class NamedPKCS8Key extends PKCS8Key { } @Override - public void destroy() throws DestroyFailedException { - Arrays.fill(rawBytes, (byte)0); + public void destroy() { Arrays.fill(privKeyMaterial, (byte)0); + if (expanded != null) { + Arrays.fill(expanded, (byte)0); + } if (encodedKey != null) { Arrays.fill(encodedKey, (byte)0); } @@ -140,4 +190,17 @@ public final class NamedPKCS8Key extends PKCS8Key { public boolean isDestroyed() { return destroyed; } + + /// Expands from encoding format to expanded format. + @FunctionalInterface + public interface Expander { + /// The expand method + /// + /// @param pname parameter set name + /// @param input input encoding + /// @return the expanded key, `null` if `input` is already in expanded + /// @throws InvalidKeyException if `input` is invalid, for example, + /// wrong encoding, or internal inconsistency + byte[] expand(String pname, byte[] input) throws InvalidKeyException; + } } diff --git a/src/java.base/share/classes/sun/security/provider/ML_DSA.java b/src/java.base/share/classes/sun/security/provider/ML_DSA.java index 6a578427e51..1e27349a5d0 100644 --- a/src/java.base/share/classes/sun/security/provider/ML_DSA.java +++ b/src/java.base/share/classes/sun/security/provider/ML_DSA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -568,6 +568,54 @@ public class ML_DSA { return new ML_DSA_KeyPair(sk, pk); } + private static int[][] deepClone(int[][] array) { + int[][] clone = new int[array.length][]; + for (int i = 0; i < array.length; i++) { + clone[i] = array[i].clone(); + } + return clone; + } + + // This is similar to the generateKeyPairInternal method. Instead of + // generating from a seed, it uses stored fields inside the private key + // to calculate the public key. It performs several checks during the + // calculation to make sure the private key is a valid one. Otherwise, + // an IllegalArgumentException is thrown. + public ML_DSA_PublicKey privKeyToPubKey(ML_DSA_PrivateKey sk) { + // Sample A + int[][][] keygenA = generateA(sk.rho); //A is in NTT domain + + // Compute t and tr + // make a copy of sk.s1 and modify it. Although we can also + // take it out of NTT domain later, it was modified for a while. + var s1 = deepClone(sk.s1); + mlDsaVectorNtt(s1); //s1 now in NTT domain + int[][] As1 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + matrixVectorPointwiseMultiply(As1, keygenA, s1); + + mlDsaVectorInverseNtt(As1); + int[][] t = vectorAddPos(As1, sk.s2); + int[][] t0 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + int[][] t1 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + power2Round(t, t0, t1); + if (!Arrays.deepEquals(t0, sk.t0)) { + throw new IllegalArgumentException("t0 does not patch"); + } + + var crHash = new SHAKE256(TR_LEN); + + ML_DSA_PublicKey pk = new ML_DSA_PublicKey(sk.rho, t1); + byte[] publicKeyBytes = pkEncode(pk); + crHash.update(publicKeyBytes); + byte[] tr = crHash.digest(); + if (!Arrays.equals(tr, sk.tr)) { + throw new IllegalArgumentException("tr does not patch"); + } + + //Encode PK + return new ML_DSA_PublicKey(sk.rho, t1); + } + public ML_DSA_Signature signInternal(byte[] message, byte[] rnd, byte[] skBytes) { //Decode private key and initialize hash function ML_DSA_PrivateKey sk = skDecode(skBytes); diff --git a/src/java.base/share/classes/sun/security/provider/ML_DSA_Impls.java b/src/java.base/share/classes/sun/security/provider/ML_DSA_Impls.java index dffe7c5cdb1..730e253f407 100644 --- a/src/java.base/share/classes/sun/security/provider/ML_DSA_Impls.java +++ b/src/java.base/share/classes/sun/security/provider/ML_DSA_Impls.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,12 +26,35 @@ package sun.security.provider; import sun.security.jca.JCAUtil; +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.util.KeyChoices; +import sun.security.x509.NamedX509Key; + import java.security.*; import java.security.SecureRandom; import java.util.Arrays; public class ML_DSA_Impls { + private static final int SEED_LEN = 32; + + public static byte[] seedToExpanded(String pname, byte[] seed) { + var impl = new ML_DSA(name2int(pname)); + var sk = impl.generateKeyPairInternal(seed).privateKey(); + try { + return impl.skEncode(sk); + } finally { + sk.destroy(); + } + } + + public static NamedX509Key privKeyToPubKey(NamedPKCS8Key npk) { + var dsa = new ML_DSA(name2int(npk.getParams().getName())); + return new NamedX509Key(npk.getAlgorithm(), + npk.getParams().getName(), + dsa.pkEncode(dsa.privKeyToPubKey(dsa.skDecode(npk.getExpanded())))); + } + public enum Version { DRAFT, FINAL } @@ -43,16 +66,16 @@ public class ML_DSA_Impls { // --add-exports java.base/sun.security.provider=ALL-UNNAMED public static Version version = Version.FINAL; - static int name2int(String name) { - if (name.endsWith("44")) { + static int name2int(String pname) { + if (pname.endsWith("44")) { return 2; - } else if (name.endsWith("65")) { + } else if (pname.endsWith("65")) { return 3; - } else if (name.endsWith("87")) { + } else if (pname.endsWith("87")) { return 5; } else { // should not happen - throw new ProviderException("Unknown name " + name); + throw new ProviderException("Unknown name " + pname); } } @@ -69,20 +92,26 @@ public class ML_DSA_Impls { } @Override - protected byte[][] implGenerateKeyPair(String name, SecureRandom sr) { - byte[] seed = new byte[32]; - var r = sr != null ? sr : JCAUtil.getDefSecureRandom(); + protected byte[][] implGenerateKeyPair(String pname, SecureRandom random) { + byte[] seed = new byte[SEED_LEN]; + var r = random != null ? random : JCAUtil.getDefSecureRandom(); r.nextBytes(seed); - ML_DSA mlDsa = new ML_DSA(name2int(name)); + + ML_DSA mlDsa = new ML_DSA(name2int(pname)); ML_DSA.ML_DSA_KeyPair kp = mlDsa.generateKeyPairInternal(seed); + var expanded = mlDsa.skEncode(kp.privateKey()); + try { return new byte[][]{ mlDsa.pkEncode(kp.publicKey()), - mlDsa.skEncode(kp.privateKey()) + KeyChoices.writeToChoice( + KeyChoices.getPreferred("mldsa"), + seed, expanded), + expanded }; } finally { kp.privateKey().destroy(); - Arrays.fill(seed, (byte)0); + Arrays.fill(seed, (byte) 0); } } } @@ -109,8 +138,39 @@ public class ML_DSA_Impls { public KF() { super("ML-DSA", "ML-DSA-44", "ML-DSA-65", "ML-DSA-87"); } - public KF(String name) { - super("ML-DSA", name); + public KF(String pname) { + super("ML-DSA", pname); + } + + @Override + protected byte[] implExpand(String pname, byte[] input) + throws InvalidKeyException { + return KeyChoices.choiceToExpanded(pname, SEED_LEN, input, + ML_DSA_Impls::seedToExpanded); + } + + @Override + protected Key engineTranslateKey(Key key) throws InvalidKeyException { + var nk = toNamedKey(key); + if (nk instanceof NamedPKCS8Key npk) { + var type = KeyChoices.getPreferred("mldsa"); + if (KeyChoices.typeOfChoice(npk.getRawBytes()) != type) { + var encoding = KeyChoices.choiceToChoice( + type, + npk.getParams().getName(), + SEED_LEN, npk.getRawBytes(), + ML_DSA_Impls::seedToExpanded); + nk = NamedPKCS8Key.internalCreate( + npk.getAlgorithm(), + npk.getParams().getName(), + encoding, + npk.getExpanded().clone()); + if (npk != key) { // npk is neither input or output + npk.destroy(); + } + } + } + return nk; } } @@ -134,16 +194,16 @@ public class ML_DSA_Impls { public sealed static class SIG extends NamedSignature permits SIG2, SIG3, SIG5 { public SIG() { - super("ML-DSA", "ML-DSA-44", "ML-DSA-65", "ML-DSA-87"); + super("ML-DSA", new KF()); } - public SIG(String name) { - super("ML-DSA", name); + public SIG(String pname) { + super("ML-DSA", new KF(pname)); } @Override - protected byte[] implSign(String name, byte[] skBytes, + protected byte[] implSign(String pname, byte[] skBytes, Object sk2, byte[] msg, SecureRandom sr) { - var size = name2int(name); + var size = name2int(pname); var r = sr != null ? sr : JCAUtil.getDefSecureRandom(); byte[] rnd = new byte[32]; r.nextBytes(rnd); @@ -160,10 +220,10 @@ public class ML_DSA_Impls { } @Override - protected boolean implVerify(String name, byte[] pkBytes, + protected boolean implVerify(String pname, byte[] pkBytes, Object pk2, byte[] msg, byte[] sigBytes) throws SignatureException { - var size = name2int(name); + var size = name2int(pname); var mlDsa = new ML_DSA(size); if (version == Version.FINAL) { // FIPS 204 Algorithm 3 ML-DSA.Verify prepend {0, len(ctx)} @@ -176,18 +236,18 @@ public class ML_DSA_Impls { } @Override - protected Object implCheckPublicKey(String name, byte[] pk) + protected Object implCheckPublicKey(String pname, byte[] pk) throws InvalidKeyException { - ML_DSA mlDsa = new ML_DSA(name2int(name)); + ML_DSA mlDsa = new ML_DSA(name2int(pname)); return mlDsa.checkPublicKey(pk); } @Override - protected Object implCheckPrivateKey(String name, byte[] sk) + protected Object implCheckPrivateKey(String pname, byte[] sk) throws InvalidKeyException { - ML_DSA mlDsa = new ML_DSA(name2int(name)); + ML_DSA mlDsa = new ML_DSA(name2int(pname)); return mlDsa.checkPrivateKey(sk); } } diff --git a/src/java.base/share/classes/sun/security/provider/NamedKEM.java b/src/java.base/share/classes/sun/security/provider/NamedKEM.java index 2731b3460af..60449396d4d 100644 --- a/src/java.base/share/classes/sun/security/provider/NamedKEM.java +++ b/src/java.base/share/classes/sun/security/provider/NamedKEM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,6 @@ import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.NamedParameterSpec; import java.util.Arrays; -import java.util.Objects; /// A base class for all `KEM` implementations that can be /// configured with a named parameter set. See [NamedKeyPairGenerator] @@ -50,21 +49,19 @@ import java.util.Objects; public abstract class NamedKEM implements KEMSpi { private final String fname; // family name - private final String[] pnames; // allowed parameter set name (at least one) + private final NamedKeyFactory fac; /// Creates a new `NamedKEM` object. /// /// @param fname the family name - /// @param pnames the standard parameter set names, at least one is needed. - protected NamedKEM(String fname, String... pnames) { + /// @param fac the `KeyFactory` used to translate foreign keys and + /// perform key validation + protected NamedKEM(String fname, NamedKeyFactory fac) { if (fname == null) { throw new AssertionError("fname cannot be null"); } - if (pnames == null || pnames.length == 0) { - throw new AssertionError("pnames cannot be null or empty"); - } this.fname = fname; - this.pnames = pnames; + this.fac = fac; } @Override @@ -76,8 +73,7 @@ public abstract class NamedKEM implements KEMSpi { "The " + fname + " algorithm does not take any parameters"); } // translate also check the key - var nk = (NamedX509Key) new NamedKeyFactory(fname, pnames) - .engineTranslateKey(publicKey); + var nk = (NamedX509Key) fac.toNamedKey(publicKey); var pk = nk.getRawBytes(); return getKeyConsumerImpl(this, nk.getParams(), pk, implCheckPublicKey(nk.getParams().getName(), pk), secureRandom); @@ -92,16 +88,15 @@ public abstract class NamedKEM implements KEMSpi { "The " + fname + " algorithm does not take any parameters"); } // translate also check the key - var nk = (NamedPKCS8Key) new NamedKeyFactory(fname, pnames) - .engineTranslateKey(privateKey); - var sk = nk.getRawBytes(); + var nk = (NamedPKCS8Key) fac.toNamedKey(privateKey); + var sk = nk.getExpanded(); return getKeyConsumerImpl(this, nk.getParams(), sk, implCheckPrivateKey(nk.getParams().getName(), sk), null); } // We don't have a flag on whether key is public key or private key. // The correct method should always be called. - private record KeyConsumerImpl(NamedKEM kem, String name, int sslen, + private record KeyConsumerImpl(NamedKEM kem, String pname, int sslen, int clen, byte[] key, Object k2, SecureRandom sr) implements KEMSpi.EncapsulatorSpi, KEMSpi.DecapsulatorSpi { @Override @@ -110,7 +105,7 @@ public abstract class NamedKEM implements KEMSpi { if (encapsulation.length != clen) { throw new DecapsulateException("Invalid key encapsulation message length"); } - var ss = kem.implDecapsulate(name, key, k2, encapsulation); + var ss = kem.implDecapsulate(pname, key, k2, encapsulation); try { return new SecretKeySpec(ss, from, to - from, algorithm); @@ -121,7 +116,7 @@ public abstract class NamedKEM implements KEMSpi { @Override public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm) { - var enc = kem.implEncapsulate(name, key, k2, sr); + var enc = kem.implEncapsulate(pname, key, k2, sr); try { return new KEM.Encapsulated( new SecretKeySpec(enc[1], @@ -146,46 +141,46 @@ public abstract class NamedKEM implements KEMSpi { private static KeyConsumerImpl getKeyConsumerImpl(NamedKEM kem, NamedParameterSpec nps, byte[] key, Object k2, SecureRandom sr) { - String name = nps.getName(); - return new KeyConsumerImpl(kem, name, kem.implSecretSize(name), kem.implEncapsulationSize(name), + String pname = nps.getName(); + return new KeyConsumerImpl(kem, pname, kem.implSecretSize(pname), kem.implEncapsulationSize(pname), key, k2, sr); } /// User-defined encap function. /// - /// @param name parameter name + /// @param pname parameter name /// @param pk public key in raw bytes /// @param pk2 parsed public key, `null` if none. See [#implCheckPublicKey]. /// @param sr SecureRandom object, `null` if not initialized /// @return the key encapsulation message and the shared key (in this order) /// @throws ProviderException if there is an internal error - protected abstract byte[][] implEncapsulate(String name, byte[] pk, Object pk2, SecureRandom sr); + protected abstract byte[][] implEncapsulate(String pname, byte[] pk, Object pk2, SecureRandom sr); /// User-defined decap function. /// - /// @param name parameter name + /// @param pname parameter name /// @param sk private key in raw bytes /// @param sk2 parsed private key, `null` if none. See [#implCheckPrivateKey]. /// @param encap the key encapsulation message /// @return the shared key /// @throws ProviderException if there is an internal error /// @throws DecapsulateException if there is another error - protected abstract byte[] implDecapsulate(String name, byte[] sk, Object sk2, byte[] encap) + protected abstract byte[] implDecapsulate(String pname, byte[] sk, Object sk2, byte[] encap) throws DecapsulateException; /// User-defined function returning shared secret key length. /// - /// @param name parameter name + /// @param pname parameter name /// @return shared secret key length /// @throws ProviderException if there is an internal error - protected abstract int implSecretSize(String name); + protected abstract int implSecretSize(String pname); /// User-defined function returning key encapsulation message length. /// - /// @param name parameter name + /// @param pname parameter name /// @return key encapsulation message length /// @throws ProviderException if there is an internal error - protected abstract int implEncapsulationSize(String name); + protected abstract int implEncapsulationSize(String pname); /// User-defined function to validate a public key. /// @@ -196,11 +191,11 @@ public abstract class NamedKEM implements KEMSpi { /// /// The default implementation returns `null`. /// - /// @param name parameter name + /// @param pname parameter name /// @param pk public key in raw bytes /// @return a parsed key, `null` if none. /// @throws InvalidKeyException if the key is invalid - protected Object implCheckPublicKey(String name, byte[] pk) throws InvalidKeyException { + protected Object implCheckPublicKey(String pname, byte[] pk) throws InvalidKeyException { return null; } @@ -213,11 +208,11 @@ public abstract class NamedKEM implements KEMSpi { /// /// The default implementation returns `null`. /// - /// @param name parameter name + /// @param pname parameter name /// @param sk private key in raw bytes /// @return a parsed key, `null` if none. /// @throws InvalidKeyException if the key is invalid - protected Object implCheckPrivateKey(String name, byte[] sk) throws InvalidKeyException { + protected Object implCheckPrivateKey(String pname, byte[] sk) throws InvalidKeyException { return null; } } diff --git a/src/java.base/share/classes/sun/security/provider/NamedKeyFactory.java b/src/java.base/share/classes/sun/security/provider/NamedKeyFactory.java index 727358dd074..9099f1446ff 100644 --- a/src/java.base/share/classes/sun/security/provider/NamedKeyFactory.java +++ b/src/java.base/share/classes/sun/security/provider/NamedKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,6 @@ import java.security.spec.NamedParameterSpec; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Arrays; -import java.util.Objects; /// A base class for all `KeyFactory` implementations that can be /// configured with a named parameter set. See [NamedKeyPairGenerator] @@ -58,7 +57,7 @@ import java.util.Objects; /// /// When reading from a RAW format, it needs enough info to derive the /// parameter set name. -public class NamedKeyFactory extends KeyFactorySpi { +public abstract class NamedKeyFactory extends KeyFactorySpi { private final String fname; // family name private final String[] pnames; // allowed parameter set name (at least one) @@ -78,92 +77,110 @@ public class NamedKeyFactory extends KeyFactorySpi { this.pnames = pnames; } - private String checkName(String name) throws InvalidKeyException { - for (var pname : pnames) { - if (pname.equalsIgnoreCase(name)) { + private String checkName(String pname) throws InvalidKeyException { + for (var n : pnames) { + if (n.equalsIgnoreCase(pname)) { // return the stored standard name - return pname; + return n; } } - throw new InvalidKeyException("Unsupported parameter set name: " + name); + throw new InvalidKeyException("Unsupported parameter set name: " + pname); } @Override protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException { - if (keySpec instanceof X509EncodedKeySpec xspec) { - try { - return fromX509(xspec.getEncoded()); - } catch (InvalidKeyException e) { - throw new InvalidKeySpecException(e); + return switch (keySpec) { + case X509EncodedKeySpec xspec -> { + try { + yield fromX509(xspec.getEncoded()); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException(e); + } } - } else if (keySpec instanceof RawKeySpec rks) { - if (pnames.length == 1) { - return new NamedX509Key(fname, pnames[0], rks.getKeyArr()); - } else { - throw new InvalidKeySpecException("Parameter set name unavailable"); + case RawKeySpec rks -> { + if (pnames.length == 1) { + yield new NamedX509Key(fname, pnames[0], rks.getKeyArr()); + } else { + throw new InvalidKeySpecException("Parameter set name unavailable"); + } } - } else if (keySpec instanceof EncodedKeySpec espec - && espec.getFormat().equalsIgnoreCase("RAW")) { - if (pnames.length == 1) { - return new NamedX509Key(fname, pnames[0], espec.getEncoded()); - } else { - throw new InvalidKeySpecException("Parameter set name unavailable"); + case EncodedKeySpec espec when espec.getFormat().equalsIgnoreCase("RAW") -> { + if (pnames.length == 1) { + yield new NamedX509Key(fname, pnames[0], espec.getEncoded()); + } else { + throw new InvalidKeySpecException("Parameter set name unavailable"); + } } - } else { - throw new InvalidKeySpecException("Unsupported keyspec: " + keySpec); - } + case null -> throw new InvalidKeySpecException( + "keySpec must not be null"); + default -> + throw new InvalidKeySpecException(keySpec.getClass().getName() + + " not supported."); + }; } @Override protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException { - if (keySpec instanceof PKCS8EncodedKeySpec pspec) { - var bytes = pspec.getEncoded(); - try { - return fromPKCS8(bytes); - } catch (InvalidKeyException e) { - throw new InvalidKeySpecException(e); - } finally { - Arrays.fill(bytes, (byte) 0); - } - } else if (keySpec instanceof RawKeySpec rks) { - if (pnames.length == 1) { - var bytes = rks.getKeyArr(); + return switch (keySpec) { + case PKCS8EncodedKeySpec pspec -> { + var bytes = pspec.getEncoded(); try { - return new NamedPKCS8Key(fname, pnames[0], bytes); + yield fromPKCS8(bytes); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException(e); } finally { Arrays.fill(bytes, (byte) 0); } - } else { - throw new InvalidKeySpecException("Parameter set name unavailable"); } - } else if (keySpec instanceof EncodedKeySpec espec - && espec.getFormat().equalsIgnoreCase("RAW")) { - if (pnames.length == 1) { - var bytes = espec.getEncoded(); - try { - return new NamedPKCS8Key(fname, pnames[0], bytes); - } finally { - Arrays.fill(bytes, (byte) 0); + case RawKeySpec rks -> { + if (pnames.length == 1) { + var raw = rks.getKeyArr(); + try { + yield fromRaw(pnames[0], raw); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException("Invalid key input", e); + } + } else { + throw new InvalidKeySpecException("Parameter set name unavailable"); } - } else { - throw new InvalidKeySpecException("Parameter set name unavailable"); } - } else { - throw new InvalidKeySpecException("Unsupported keyspec: " + keySpec); - } + case EncodedKeySpec espec when espec.getFormat().equalsIgnoreCase("RAW") -> { + if (pnames.length == 1) { + var raw = espec.getEncoded(); + try { + yield fromRaw(pnames[0], raw); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException("Invalid key input", e); + } + } else { + throw new InvalidKeySpecException("Parameter set name unavailable"); + } + } + case null -> throw new InvalidKeySpecException( + "keySpec must not be null"); + default -> + throw new InvalidKeySpecException(keySpec.getClass().getName() + + " not supported."); + }; + } + + private PrivateKey fromRaw(String pname, byte[] raw) + throws InvalidKeyException { + return NamedPKCS8Key.internalCreate( + fname, pname, raw, implExpand(pname, raw)); } private PrivateKey fromPKCS8(byte[] bytes) - throws InvalidKeyException, InvalidKeySpecException { - var k = new NamedPKCS8Key(fname, bytes); + throws InvalidKeyException { + var k = new NamedPKCS8Key(fname, bytes, this::implExpand); checkName(k.getParams().getName()); return k; } private PublicKey fromX509(byte[] bytes) - throws InvalidKeyException, InvalidKeySpecException { + throws InvalidKeyException { var k = new NamedX509Key(fname, bytes); checkName(k.getParams().getName()); return k; @@ -184,7 +201,7 @@ public class NamedKeyFactory extends KeyFactorySpi { protected T engineGetKeySpec(Key key, Class keySpec) throws InvalidKeySpecException { try { - key = engineTranslateKey(key); + key = toNamedKey(key); } catch (InvalidKeyException e) { throw new InvalidKeySpecException(e); } @@ -225,6 +242,12 @@ public class NamedKeyFactory extends KeyFactorySpi { @Override protected Key engineTranslateKey(Key key) throws InvalidKeyException { + // The base toNamedKey only makes sure key is translated into a NamedKey. + // the key material is still the same as the input. + return toNamedKey(key); + } + + protected Key toNamedKey(Key key) throws InvalidKeyException { if (key == null) { throw new InvalidKeyException("Key must not be null"); } @@ -242,27 +265,28 @@ public class NamedKeyFactory extends KeyFactorySpi { } else if (format.equalsIgnoreCase("RAW")) { var kAlg = key.getAlgorithm(); if (key instanceof AsymmetricKey pk) { - String name; + String pname; // Three cases that we can find the parameter set name from a RAW key: // 1. getParams() returns one // 2. getAlgorithm() returns param set name (some provider does this) // 3. getAlgorithm() returns family name but this KF is for param set name if (pk.getParams() instanceof NamedParameterSpec nps) { - name = checkName(nps.getName()); + pname = checkName(nps.getName()); } else { if (kAlg.equalsIgnoreCase(fname)) { if (pnames.length == 1) { - name = pnames[0]; + pname = pnames[0]; } else { throw new InvalidKeyException("No parameter set info"); } } else { - name = checkName(kAlg); + pname = checkName(kAlg); } } + var raw = key.getEncoded(); return key instanceof PrivateKey - ? new NamedPKCS8Key(fname, name, key.getEncoded()) - : new NamedX509Key(fname, name, key.getEncoded()); + ? fromRaw(pname, raw) + : new NamedX509Key(fname, pname, raw); } else { throw new InvalidKeyException("Unsupported key type: " + key.getClass()); } @@ -270,19 +294,26 @@ public class NamedKeyFactory extends KeyFactorySpi { var bytes = key.getEncoded(); try { return fromPKCS8(bytes); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException("Invalid PKCS#8 key", e); } finally { Arrays.fill(bytes, (byte) 0); } } else if (format.equalsIgnoreCase("X.509") && key instanceof PublicKey) { - try { - return fromX509(key.getEncoded()); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException("Invalid X.509 key", e); - } + return fromX509(key.getEncoded()); } else { throw new InvalidKeyException("Unsupported key format: " + key.getFormat()); } } + + /// User-defined function to generate the expanded format of + /// a [NamedPKCS8Key] from its encoding format. + /// + /// This method is called when the key factory is constructing a private + /// key. The ownership of the result is fully granted to the caller. + /// + /// @param pname the parameter set name + /// @param input the encoding, could be any format + /// @return the expanded key, not null + /// @throws InvalidKeyException if `input` is invalid + protected abstract byte[] implExpand(String pname, byte[] input) + throws InvalidKeyException; } diff --git a/src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java b/src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java index 5be2b2b2a08..6b55924b0fe 100644 --- a/src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java +++ b/src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,6 @@ import java.security.ProviderException; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.NamedParameterSpec; -import java.util.Objects; /// A base class for all `KeyPairGenerator` implementations that can be /// configured with a named parameter set. @@ -52,15 +51,21 @@ import java.util.Objects; /// with `getAlgorithm` returning the family name, and `getParams` returning /// the parameter set name as a [NamedParameterSpec] object. /// -/// An implementation must include a zero-argument public constructor that -/// calls `super(fname, pnames)`, where `fname` is the family name of the -/// algorithm and `pnames` are its supported parameter set names. `pnames` -/// must contain at least one element. For an implementation of -/// `NamedKeyPairGenerator`, the first element becomes its default parameter -/// set, i.e. the parameter set to be used in key pair generation unless +/// A `NamedKeyPairGenerator` or `NamedKeyFactory` implementation must include +/// a zero-argument public constructor that calls `super(fname, pnames)`, where +/// `fname` is the family name of the algorithm and `pnames` are its supported +/// parameter set names. `pnames` must contain at least one element. For an +/// implementation of `NamedKeyPairGenerator`, the first element becomes its +/// default parameter set, i.e. the parameter set used by generated keys unless /// [#initialize(AlgorithmParameterSpec, java.security.SecureRandom)] /// is called on a different parameter set. /// +/// A `NamedKEM` or `NamedSignature` implementation must include a zero-argument +/// public constructor that calls `super(fname, factory)`, where `fname` is the +/// family name of the algorithm and `factory` is the `NamedKeyFactory` object +/// that is used to translate foreign keys. `factory` only recognizes +/// parameter sets supported by this implementation. +/// /// An implementation must implement all abstract methods. For all these /// methods, the implementation must relinquish any "ownership" of any input /// and output array argument. Precisely, the implementation must not retain @@ -69,8 +74,8 @@ import java.util.Objects; /// array argument and must not retain any reference to an input array argument /// after the call. /// -/// Also, an implementation must not keep any extra copy of a private key. -/// For key generation, the only copy is the one returned in the +/// Also, an implementation must not keep any extra copy of a private key in +/// any format. For key generation, the only copy is the one returned in the /// [#implGenerateKeyPair] call. For all other methods, it must not make /// a copy of the input private key. A `KEM` implementation also must not /// keep a copy of the shared secret key, no matter if it's an encapsulator @@ -84,6 +89,34 @@ import java.util.Objects; /// (For example, `implSign`) later. An implementation must not retain /// a reference of the parsed key. /// +/// The private key, represented as a byte array when used in `NamedKEM` or +/// `NamedSignature`, is referred to as its expanded format. For some +/// algorithms, this format may differ from the +/// [key material][NamedPKCS8Key#getRawBytes()] inside a PKCS #8 file. For example, +/// [FIPS 204](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf) +/// Table 2 defines the ML-DSA-65 private key as a 4032-byte array, which is +/// used in the ML-DSA.Sign function in Algorithm 2, representing the +/// expanded format. However, in +/// [RFC 9881](https://datatracker.ietf.org/doc/html/rfc9881#name-private-key-format), +/// a private key can be encoded into a CHOICE of three formats, none in the +/// same as the FIPS 204 format. The choices are defined in +/// [sun.security.util.KeyChoices]. A `NamedKeyPairGenerator` implementation +/// should return both the expanded key and a preferred encoding in its +/// [#implGenerateKeyPair] method. +/// +/// A `NamedKeyFactory` must override the `implExpand` method to derive +/// the expanded format from an encoding format, or return `null` if there +/// is no difference. +/// +/// Implementations may support multiple encoding formats. +/// +/// A `NamedKeyFactory` must not modify the encoding when generating a key +/// from a `KeySpec` object, ensuring that when re-encoded, the key retains +/// its original encoding format. +/// +/// A `NamedKeyFactory` can choose a different encoding format when +/// `translateKey` is called. +/// /// When constructing a [NamedX509Key] or [NamedPKCS8Key] object from raw key /// bytes, the key bytes are directly referenced within the object, so the /// caller must not modify them afterward. Similarly, the key's `getRawBytes` @@ -105,9 +138,9 @@ import java.util.Objects; public abstract class NamedKeyPairGenerator extends KeyPairGeneratorSpi { private final String fname; // family name - private final String[] pnames; // allowed parameter set name (at least one) + private final String[] pnames; // allowed parameter set names (at least one) - protected String name; // init as + protected String pname; // parameter set name, if can be determined private SecureRandom secureRandom; /// Creates a new `NamedKeyPairGenerator` object. @@ -126,22 +159,22 @@ public abstract class NamedKeyPairGenerator extends KeyPairGeneratorSpi { this.pnames = pnames; } - private String checkName(String name) throws InvalidAlgorithmParameterException { - for (var pname : pnames) { - if (pname.equalsIgnoreCase(name)) { - // return the stored standard name - return pname; + private String checkName(String pname) throws InvalidAlgorithmParameterException { + for (var n : pnames) { + if (n.equalsIgnoreCase(pname)) { + // return the stored standard pname + return n; } } throw new InvalidAlgorithmParameterException( - "Unsupported parameter set name: " + name); + "Unsupported parameter set name: " + pname); } @Override public void initialize(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { if (params instanceof NamedParameterSpec spec) { - name = checkName(spec.getName()); + pname = checkName(spec.getName()); } else { throw new InvalidAlgorithmParameterException( "Unsupported AlgorithmParameterSpec: " + params); @@ -161,17 +194,21 @@ public abstract class NamedKeyPairGenerator extends KeyPairGeneratorSpi { @Override public KeyPair generateKeyPair() { - String pname = name != null ? name : pnames[0]; - var keys = implGenerateKeyPair(pname, secureRandom); - return new KeyPair(new NamedX509Key(fname, pname, keys[0]), - new NamedPKCS8Key(fname, pname, keys[1])); + String tmpName = pname != null ? pname : pnames[0]; + var keys = implGenerateKeyPair(tmpName, secureRandom); + return new KeyPair(new NamedX509Key(fname, tmpName, keys[0]), + NamedPKCS8Key.internalCreate(fname, tmpName, keys[1], + keys.length == 2 ? null : keys[2])); } /// User-defined key pair generator. /// /// @param pname parameter set name /// @param sr `SecureRandom` object, `null` if not initialized - /// @return public key and private key (in this order) in raw bytes + /// @return the public key, the private key in its encoding format, and + /// the private key in its expanded format (in this order) in + /// raw bytes. If the expanded format of the private key is the + /// same as its encoding format, the 3rd element must be omitted. /// @throws ProviderException if there is an internal error protected abstract byte[][] implGenerateKeyPair(String pname, SecureRandom sr); } diff --git a/src/java.base/share/classes/sun/security/provider/NamedSignature.java b/src/java.base/share/classes/sun/security/provider/NamedSignature.java index 921a39cfc92..07d20828c3c 100644 --- a/src/java.base/share/classes/sun/security/provider/NamedSignature.java +++ b/src/java.base/share/classes/sun/security/provider/NamedSignature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,6 @@ import java.security.SecureRandom; import java.security.SignatureException; import java.security.SignatureSpi; import java.security.spec.AlgorithmParameterSpec; -import java.util.Objects; /// A base class for all `Signature` implementations that can be /// configured with a named parameter set. See [NamedKeyPairGenerator] @@ -50,12 +49,12 @@ import java.util.Objects; public abstract class NamedSignature extends SignatureSpi { private final String fname; // family name - private final String[] pnames; // allowed parameter set name (at least one) + private final NamedKeyFactory fac; private final ByteArrayOutputStream bout = new ByteArrayOutputStream(); // init with... - private String name; + private String pname; private byte[] secKey; private byte[] pubKey; @@ -65,26 +64,23 @@ public abstract class NamedSignature extends SignatureSpi { /// Creates a new `NamedSignature` object. /// /// @param fname the family name - /// @param pnames the standard parameter set names, at least one is needed. - protected NamedSignature(String fname, String... pnames) { + /// @param fac the `KeyFactory` used to translate foreign keys and + /// perform key validation + protected NamedSignature(String fname, NamedKeyFactory fac) { if (fname == null) { throw new AssertionError("fname cannot be null"); } - if (pnames == null || pnames.length == 0) { - throw new AssertionError("pnames cannot be null or empty"); - } this.fname = fname; - this.pnames = pnames; + this.fac = fac; } @Override protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { // translate also check the key - var nk = (NamedX509Key) new NamedKeyFactory(fname, pnames) - .engineTranslateKey(publicKey); - name = nk.getParams().getName(); + var nk = (NamedX509Key) fac.toNamedKey(publicKey); + pname = nk.getParams().getName(); pubKey = nk.getRawBytes(); - pk2 = implCheckPublicKey(name, pubKey); + pk2 = implCheckPublicKey(pname, pubKey); secKey = null; bout.reset(); } @@ -92,11 +88,10 @@ public abstract class NamedSignature extends SignatureSpi { @Override protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { // translate also check the key - var nk = (NamedPKCS8Key) new NamedKeyFactory(fname, pnames) - .engineTranslateKey(privateKey); - name = nk.getParams().getName(); - secKey = nk.getRawBytes(); - sk2 = implCheckPrivateKey(name, secKey); + var nk = (NamedPKCS8Key) fac.toNamedKey(privateKey); + pname = nk.getParams().getName(); + secKey = nk.getExpanded(); + sk2 = implCheckPrivateKey(pname, secKey); pubKey = null; bout.reset(); } @@ -116,7 +111,7 @@ public abstract class NamedSignature extends SignatureSpi { if (secKey != null) { var msg = bout.toByteArray(); bout.reset(); - return implSign(name, secKey, sk2, msg, appRandom); + return implSign(pname, secKey, sk2, msg, appRandom); } else { throw new SignatureException("No private key"); } @@ -127,21 +122,21 @@ public abstract class NamedSignature extends SignatureSpi { if (pubKey != null) { var msg = bout.toByteArray(); bout.reset(); - return implVerify(name, pubKey, pk2, msg, sig); + return implVerify(pname, pubKey, pk2, msg, sig); } else { throw new SignatureException("No public key"); } } @Override - @SuppressWarnings("deprecation") + @Deprecated protected void engineSetParameter(String param, Object value) throws InvalidParameterException { throw new InvalidParameterException("setParameter() not supported"); } @Override - @SuppressWarnings("deprecation") + @Deprecated protected Object engineGetParameter(String param) throws InvalidParameterException { throw new InvalidParameterException("getParameter() not supported"); } @@ -162,7 +157,7 @@ public abstract class NamedSignature extends SignatureSpi { /// User-defined sign function. /// - /// @param name parameter name + /// @param pname parameter name /// @param sk private key in raw bytes /// @param sk2 parsed private key, `null` if none. See [#implCheckPrivateKey]. /// @param msg the message @@ -170,12 +165,12 @@ public abstract class NamedSignature extends SignatureSpi { /// @return the signature /// @throws ProviderException if there is an internal error /// @throws SignatureException if there is another error - protected abstract byte[] implSign(String name, byte[] sk, Object sk2, + protected abstract byte[] implSign(String pname, byte[] sk, Object sk2, byte[] msg, SecureRandom sr) throws SignatureException; /// User-defined verify function. /// - /// @param name parameter name + /// @param pname parameter name /// @param pk public key in raw bytes /// @param pk2 parsed public key, `null` if none. See [#implCheckPublicKey]. /// @param msg the message @@ -183,7 +178,7 @@ public abstract class NamedSignature extends SignatureSpi { /// @return true if verified /// @throws ProviderException if there is an internal error /// @throws SignatureException if there is another error - protected abstract boolean implVerify(String name, byte[] pk, Object pk2, + protected abstract boolean implVerify(String pname, byte[] pk, Object pk2, byte[] msg, byte[] sig) throws SignatureException; /// User-defined function to validate a public key. @@ -195,11 +190,11 @@ public abstract class NamedSignature extends SignatureSpi { /// /// The default implementation returns `null`. /// - /// @param name parameter name + /// @param pname parameter name /// @param pk public key in raw bytes /// @return a parsed key, `null` if none. /// @throws InvalidKeyException if the key is invalid - protected Object implCheckPublicKey(String name, byte[] pk) throws InvalidKeyException { + protected Object implCheckPublicKey(String pname, byte[] pk) throws InvalidKeyException { return null; } @@ -212,11 +207,11 @@ public abstract class NamedSignature extends SignatureSpi { /// /// The default implementation returns `null`. /// - /// @param name parameter name + /// @param pname parameter name /// @param sk private key in raw bytes /// @return a parsed key, `null` if none. /// @throws InvalidKeyException if the key is invalid - protected Object implCheckPrivateKey(String name, byte[] sk) throws InvalidKeyException { + protected Object implCheckPrivateKey(String pname, byte[] sk) throws InvalidKeyException { return null; } } diff --git a/src/java.base/share/classes/sun/security/util/KeyChoices.java b/src/java.base/share/classes/sun/security/util/KeyChoices.java new file mode 100644 index 00000000000..da3c611750e --- /dev/null +++ b/src/java.base/share/classes/sun/security/util/KeyChoices.java @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.util; + +import java.security.*; +import java.util.Arrays; +import java.util.Locale; +import java.util.function.BiFunction; + +/** + * The content of an ML-KEM or ML-DSA private key is defined as a CHOICE + * among three different representations. For example: + *

    + *  ML-KEM-1024-PrivateKey ::= CHOICE {
    + *       seed [0] OCTET STRING (SIZE (64)),
    + *       expandedKey OCTET STRING (SIZE (3168)),
    + *       both SEQUENCE {
    + *           seed OCTET STRING (SIZE (64)),
    + *           expandedKey OCTET STRING (SIZE (3168))
    + *           }
    + *       }
    + * 
    + * This class supports reading, writing, and converting between them. + *

    + * Current code follows draft-ietf-lamps-kyber-certificates-11 and RFC 9881. + */ +public final class KeyChoices { + + public enum Type { SEED, EXPANDED_KEY, BOTH } + + private record Choice(Type type, byte[] seed, byte[] expanded) {} + + /** + * Gets the preferred choice type for an algorithm, defined as an + * overridable security property "jdk..pkcs8.encoding". + * + * @param name "mlkem" or "mldsa". + * @throws IllegalArgumentException if property is invalid value + * @return the type + */ + public static Type getPreferred(String name) { + var prop = SecurityProperties.getOverridableProperty( + "jdk." + name + ".pkcs8.encoding"); + if (prop == null) { + return Type.SEED; + } + return switch (prop.toLowerCase(Locale.ROOT)) { + case "seed" -> Type.SEED; + case "expandedkey" -> Type.EXPANDED_KEY; + case "both" -> Type.BOTH; + default -> throw new IllegalArgumentException("Unknown format: " + prop); + }; + } + + /** + * Writes one of the ML-KEM or ML-DSA private key formats. + *

    + * This method does not check the length of the inputs or whether + * they match each other. The caller must make sure `seed` and/or + * `expanded` are provided if `type` requires any of them. + * + * @param type preferred output choice type + * @param seed the seed, could be null + * @param expanded the expanded key, could be null + * @return one of the choices + */ + public static byte[] writeToChoice(Type type, byte[] seed, byte[] expanded) { + byte[] skOctets; + // Ensures using one-byte len in DER + assert seed == null || seed.length < 128; + // Ensures using two-byte len in DER + assert expanded == null || expanded.length > 256 && expanded.length < 60000; + + return switch (type) { + case SEED -> { + assert seed != null; + skOctets = new byte[seed.length + 2]; + skOctets[0] = (byte)0x80; + skOctets[1] = (byte) seed.length; + System.arraycopy(seed, 0, skOctets, 2, seed.length); + yield skOctets; + } + case EXPANDED_KEY -> { + assert expanded != null; + skOctets = new byte[expanded.length + 4]; + skOctets[0] = 0x04; + writeShortLength(skOctets, 1, expanded.length); + System.arraycopy(expanded, 0, skOctets, 4, expanded.length); + yield skOctets; + } + case BOTH -> { + assert seed != null; + assert expanded != null; + skOctets = new byte[10 + seed.length + expanded.length]; + skOctets[0] = 0x30; + writeShortLength(skOctets, 1, 6 + seed.length + expanded.length); + skOctets[4] = 0x04; + skOctets[5] = (byte)seed.length; + System.arraycopy(seed, 0, skOctets, 6, seed.length); + skOctets[6 + seed.length] = 0x04; + writeShortLength(skOctets, 7 + seed.length, expanded.length); + System.arraycopy(expanded, 0, skOctets, 10 + seed.length, expanded.length); + yield skOctets; + } + }; + } + + /** + * Gets the type of input. + * + * @param input input bytes + * @return the type + * @throws InvalidKeyException if input is invalid + */ + public static Type typeOfChoice(byte[] input) throws InvalidKeyException { + if (input.length < 1) { + throw new InvalidKeyException("Empty key"); + } + return switch (input[0]) { + case (byte) 0x80 -> Type.SEED; + case 0x04 -> Type.EXPANDED_KEY; + case 0x30 -> Type.BOTH; + default -> throw new InvalidKeyException("Wrong tag: " + input[0]); + }; + } + + /** + * Splits one of the ML-KEM or ML-DSA private key formats into + * seed and expandedKey, if exists. + * + * @param seedLen correct seed length + * @param input input bytes + * @return a {@code Choice} object. Byte arrays inside are newly allocated + * @throws InvalidKeyException if input is invalid + */ + private static Choice readFromChoice(int seedLen, byte[] input) + throws InvalidKeyException { + if (input.length < seedLen + 2) { + throw new InvalidKeyException("Too short"); + } + return switch (input[0]) { + case (byte) 0x80 -> { + // 80 SEED_LEN + if (input[1] != seedLen && input.length != seedLen + 2) { + throw new InvalidKeyException("Invalid seed"); + } + yield new Choice(Type.SEED, + Arrays.copyOfRange(input, 2, seedLen + 2), null); + } + case 0x04 -> { + // 04 82 nn nn + if (readShortLength(input, 1) != input.length - 4) { + throw new InvalidKeyException("Invalid expandedKey"); + } + yield new Choice(Type.EXPANDED_KEY, + null, Arrays.copyOfRange(input, 4, input.length)); + } + case 0x30 -> { + // 30 82 mm mm 04 SEED_LEN 04 82 nn nn + if (input.length < 6 + seedLen + 4) { + throw new InvalidKeyException("Too short"); + } + if (readShortLength(input, 1) != input.length - 4 + || input[4] != 0x04 + || input[5] != (byte)seedLen + || input[seedLen + 6] != 0x04 + || readShortLength(input, seedLen + 7) + != input.length - 10 - seedLen) { + throw new InvalidKeyException("Invalid both"); + } + yield new Choice(Type.BOTH, + Arrays.copyOfRange(input, 6, 6 + seedLen), + Arrays.copyOfRange(input, seedLen + 10, input.length)); + } + default -> throw new InvalidKeyException("Wrong tag: " + input[0]); + }; + } + + /** + * Reads from any encoding and write to the specified type. + * + * @param type preferred output choice type + * @param pname parameter set name + * @param seedLen seed length + * @param input the input encoding + * @param expander function to calculate expanded from seed, could be null + * if there is already expanded in input + * @return the preferred encoding + * @throws InvalidKeyException if input is invalid or does not have enough + * information to generate the output + */ + public static byte[] choiceToChoice(Type type, String pname, + int seedLen, byte[] input, + BiFunction expander) + throws InvalidKeyException { + var choice = readFromChoice(seedLen, input); + try { + if (type != Type.EXPANDED_KEY && choice.type == Type.EXPANDED_KEY) { + throw new InvalidKeyException( + "key contains not enough info to translate"); + } + var expanded = (choice.expanded == null && type != Type.SEED) + ? expander.apply(pname, choice.seed) + : choice.expanded; + return writeToChoice(type, choice.seed, expanded); + } finally { + if (choice.seed != null) { + Arrays.fill(choice.seed, (byte) 0); + } + if (choice.expanded != null) { + Arrays.fill(choice.expanded, (byte) 0); + } + } + } + + /** + * Reads from any choice of encoding and return the expanded format. + * + * @param pname parameter set name + * @param seedLen seed length + * @param input input encoding + * @param expander function to calculate expanded from seed, could be null + * if there is already expanded in input + * @return the expanded key + * @throws InvalidKeyException if input is invalid + */ + public static byte[] choiceToExpanded(String pname, + int seedLen, byte[] input, + BiFunction expander) + throws InvalidKeyException { + var choice = readFromChoice(seedLen, input); + if (choice.type == Type.BOTH) { + var calculated = expander.apply(pname, choice.seed); + if (!Arrays.equals(choice.expanded, calculated)) { + throw new InvalidKeyException("seed and expandedKey do not match"); + } + Arrays.fill(calculated, (byte)0); + } + try { + if (choice.expanded != null) { + return choice.expanded; + } + return expander.apply(pname, choice.seed); + } finally { + if (choice.seed != null) { + Arrays.fill(choice.seed, (byte)0); + } + } + } + + // Reads a 2 bytes length from DER encoding + private static int readShortLength(byte[] input, int from) + throws InvalidKeyException { + if (input[from] != (byte)0x82) { + throw new InvalidKeyException("Unexpected length"); + } + return ((input[from + 1] & 0xff) << 8) + (input[from + 2] & 0xff); + } + + // Writes a 2 bytes length to DER encoding + private static void writeShortLength(byte[] input, int from, int value) { + input[from] = (byte)0x82; + input[from + 1] = (byte) (value >> 8); + input[from + 2] = (byte) (value); + } +} diff --git a/src/java.base/share/classes/sun/security/x509/NamedX509Key.java b/src/java.base/share/classes/sun/security/x509/NamedX509Key.java index dc36bd3b9b3..0c3fe2bf121 100644 --- a/src/java.base/share/classes/sun/security/x509/NamedX509Key.java +++ b/src/java.base/share/classes/sun/security/x509/NamedX509Key.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,7 +71,8 @@ public final class NamedX509Key extends X509Key { setKey(new BitArray(rawBytes.length * 8, rawBytes)); } - /// Ctor from family name, and X.509 bytes + /// Ctor from family name, and X.509 bytes. Input byte array + /// is copied. Caller can modify it after the method call. public NamedX509Key(String fname, byte[] encoded) throws InvalidKeyException { this.fname = fname; decode(encoded); diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 9a81ba86268..ef4d7285f51 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -1700,3 +1700,28 @@ jdk.epkcs8.defaultAlgorithm=PBEWithHmacSHA256AndAES_128 # com.sun.security.allowedAIALocations=http://some.company.com/cacert \ # ldap://ldap.company.com/dc=company,dc=com?caCertificate;binary com.sun.security.allowedAIALocations= + +# +# PKCS #8 encoding format for newly created ML-KEM and ML-DSA private keys +# +# draft-ietf-lamps-kyber-certificates-11 and RFC 9881 define three possible formats for a private key: +# a seed (64 bytes for ML-KEM, 32 bytes for ML-DSA), an expanded private key, +# or a sequence containing both. +# +# The following security properties determine the encoding format used when a +# new keypair is generated with a KeyPairGenerator, and the output of the +# translateKey method on an existing key using a ML-KEM or ML-DSA KeyFactory. +# +# Valid values for these properties are "seed", "expandedKey", and "both" +# (case-insensitive). The default is "seed". +# +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# +# Note: These properties are currently used by the SunJCE (for ML-KEM) and SUN +# (for ML-DSA) providers in the JDK Reference implementation. They are not +# guaranteed to be supported by other implementations or third-party security +# providers. +# +#jdk.mlkem.pkcs8.encoding = seed +#jdk.mldsa.pkcs8.encoding = seed diff --git a/test/jdk/sun/security/provider/acvp/Launcher.java b/test/jdk/sun/security/provider/acvp/Launcher.java index 680d1026275..2ee0ff96bd1 100644 --- a/test/jdk/sun/security/provider/acvp/Launcher.java +++ b/test/jdk/sun/security/provider/acvp/Launcher.java @@ -41,6 +41,8 @@ import java.util.zip.ZipFile; * ML_DSA_Impls.version might be modified * @library /test/lib * @modules java.base/sun.security.provider + * java.base/sun.security.util + * java.base/com.sun.crypto.provider * @run main/othervm/timeout=480 Launcher */ @@ -50,6 +52,8 @@ import java.util.zip.ZipFile; * @summary Test verifying the intrinsic implementation. * @library /test/lib * @modules java.base/sun.security.provider + * java.base/sun.security.util + * java.base/com.sun.crypto.provider * @run main/othervm/timeout=480 -Xcomp Launcher */ 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 281bb415305..ac56642b8d7 100644 --- a/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java +++ b/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java @@ -24,6 +24,7 @@ import jdk.test.lib.Asserts; import jdk.test.lib.json.JSONValue; import jdk.test.lib.security.FixedSecureRandom; import sun.security.provider.ML_DSA_Impls; +import sun.security.util.DerOutputStream; import java.security.*; import java.security.spec.EncodedKeySpec; @@ -68,12 +69,13 @@ public class ML_DSA_Test { System.out.println(">> " + pname); for (var c : t.get("tests").asArray()) { System.out.print(c.get("tcId").asString() + " "); - g.initialize(np, new FixedSecureRandom(toByteArray(c.get("seed").asString()))); + var seed = toByteArray(c.get("seed").asString()); + g.initialize(np, new FixedSecureRandom(seed)); var kp = g.generateKeyPair(); var pk = f.getKeySpec(kp.getPublic(), EncodedKeySpec.class).getEncoded(); - var sk = f.getKeySpec(kp.getPrivate(), EncodedKeySpec.class).getEncoded(); Asserts.assertEqualsByteArray(toByteArray(c.get("pk").asString()), pk); - Asserts.assertEqualsByteArray(toByteArray(c.get("sk").asString()), sk); + Asserts.assertEqualsByteArray(toByteArray(c.get("sk").asString()), + ML_DSA_Impls.seedToExpanded(pname, seed)); } System.out.println(); } @@ -106,7 +108,7 @@ public class ML_DSA_Test { var sk = new PrivateKey() { public String getAlgorithm() { return pname; } public String getFormat() { return "RAW"; } - public byte[] getEncoded() { return toByteArray(c.get("sk").asString()); } + public byte[] getEncoded() { return oct(toByteArray(c.get("sk").asString())); } }; var sr = new FixedSecureRandom( det ? new byte[32] : toByteArray(c.get("rnd").asString())); @@ -119,6 +121,10 @@ public class ML_DSA_Test { } } + static byte[] oct(byte[] in) { + return new DerOutputStream().putOctetString(in).toByteArray(); + } + static void sigVerTest(JSONValue kat, Provider p) throws Exception { var s = p == null ? Signature.getInstance("ML-DSA") 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 c46c6a99e6d..35c1ce611da 100644 --- a/test/jdk/sun/security/provider/acvp/ML_KEM_Test.java +++ b/test/jdk/sun/security/provider/acvp/ML_KEM_Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,9 +20,11 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +import com.sun.crypto.provider.ML_KEM_Impls; import jdk.test.lib.Asserts; import jdk.test.lib.json.JSONValue; import jdk.test.lib.security.FixedSecureRandom; +import sun.security.util.DerOutputStream; import javax.crypto.KEM; import java.security.*; @@ -65,13 +67,14 @@ public class ML_KEM_Test { System.out.println(">> " + pname); for (var c : t.get("tests").asArray()) { System.out.print(c.get("tcId").asString() + " "); - g.initialize(np, new FixedSecureRandom( - toByteArray(c.get("d").asString()), toByteArray(c.get("z").asString()))); + var seed = toByteArray(c.get("d").asString() + c.get("z").asString()); + g.initialize(np, new FixedSecureRandom(seed)); var kp = g.generateKeyPair(); var pk = f.getKeySpec(kp.getPublic(), EncodedKeySpec.class).getEncoded(); - var sk = f.getKeySpec(kp.getPrivate(), EncodedKeySpec.class).getEncoded(); Asserts.assertEqualsByteArray(toByteArray(c.get("ek").asString()), pk); - Asserts.assertEqualsByteArray(toByteArray(c.get("dk").asString()), sk); + Asserts.assertEqualsByteArray( + toByteArray(c.get("dk").asString()), + ML_KEM_Impls.seedToExpanded(pname, seed)); } System.out.println(); } @@ -106,7 +109,7 @@ public class ML_KEM_Test { var dk = new PrivateKey() { public String getAlgorithm() { return pname; } public String getFormat() { return "RAW"; } - public byte[] getEncoded() { return toByteArray(t.get("dk").asString()); } + public byte[] getEncoded() { return oct(toByteArray(t.get("dk").asString())); } }; for (var c : t.get("tests").asArray()) { System.out.print(c.get("tcId").asString() + " "); @@ -118,4 +121,8 @@ public class ML_KEM_Test { } } } + + static byte[] oct(byte[] in) { + return new DerOutputStream().putOctetString(in).toByteArray(); + } } diff --git a/test/jdk/sun/security/provider/NamedEdDSA.java b/test/jdk/sun/security/provider/named/NamedEdDSA.java similarity index 84% rename from test/jdk/sun/security/provider/NamedEdDSA.java rename to test/jdk/sun/security/provider/named/NamedEdDSA.java index 4d0e3e9228a..30df8b22b31 100644 --- a/test/jdk/sun/security/provider/NamedEdDSA.java +++ b/test/jdk/sun/security/provider/named/NamedEdDSA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, 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,11 +23,12 @@ /* * @test - * @bug 8340327 + * @bug 8340327 8347938 * @modules java.base/sun.security.ec.ed * java.base/sun.security.ec.point * java.base/sun.security.jca * java.base/sun.security.provider + * java.base/sun.security.util * @library /test/lib */ @@ -40,7 +41,10 @@ import sun.security.jca.JCAUtil; import sun.security.provider.NamedKeyFactory; import sun.security.provider.NamedKeyPairGenerator; import sun.security.provider.NamedSignature; +import sun.security.util.DerOutputStream; +import sun.security.util.DerValue; +import java.io.IOException; import java.security.*; import java.security.spec.EdDSAParameterSpec; import java.security.spec.NamedParameterSpec; @@ -66,11 +70,11 @@ public class NamedEdDSA { public static class EdDSASignature extends NamedSignature { public EdDSASignature() { - super("EdDSA", "Ed25519", "Ed448"); + super("EdDSA", new EdDSAKeyFactory()); } protected EdDSASignature(String pname) { - super("EdDSA", pname); + super("EdDSA", new EdDSAKeyFactory(pname)); } public static class Ed25519 extends EdDSASignature { @@ -86,22 +90,32 @@ public class NamedEdDSA { } @Override - public byte[] implSign(String name, byte[] sk, Object sk2, byte[] msg, SecureRandom sr) throws SignatureException { - return getOps(name).sign(plain, sk, msg); + public byte[] implSign(String pname, byte[] sk, Object sk2, byte[] msg, SecureRandom sr) { + return getOps(pname).sign(plain, sk, msg); } @Override - public boolean implVerify(String name, byte[] pk, Object pk2, byte[] msg, byte[] sig) throws SignatureException { - return getOps(name).verify(plain, (AffinePoint) pk2, pk, msg, sig); + public boolean implVerify(String pname, byte[] pk, Object pk2, byte[] msg, byte[] sig) throws SignatureException { + return getOps(pname).verify(plain, (AffinePoint) pk2, pk, msg, sig); } @Override - public Object implCheckPublicKey(String name, byte[] pk) throws InvalidKeyException { - return getOps(name).decodeAffinePoint(InvalidKeyException::new, pk); + public Object implCheckPublicKey(String pname, byte[] pk) throws InvalidKeyException { + return getOps(pname).decodeAffinePoint(InvalidKeyException::new, pk); } } public static class EdDSAKeyFactory extends NamedKeyFactory { + @Override + protected byte[] implExpand(String pname, byte[] input) + throws InvalidKeyException { + try { + return new DerValue(input).getOctetString(); + } catch (IOException e) { + throw new InvalidKeyException(e); + } + } + public EdDSAKeyFactory() { super("EdDSA", "Ed25519", "Ed448"); } @@ -157,7 +171,10 @@ public class NamedEdDSA { // set the high-order bit of the encoded point byte msb = (byte) (point.isXOdd() ? 0x80 : 0); encodedPoint[encodedPoint.length - 1] |= msb; - return new byte[][] { encodedPoint, sk }; + return new byte[][] { + encodedPoint, + new DerOutputStream().putOctetString(sk).toByteArray(), + sk}; } private static void swap(byte[] arr, int i, int j) { diff --git a/test/jdk/sun/security/provider/NamedKeyFactoryTest.java b/test/jdk/sun/security/provider/named/NamedKeyFactoryTest.java similarity index 85% rename from test/jdk/sun/security/provider/NamedKeyFactoryTest.java rename to test/jdk/sun/security/provider/named/NamedKeyFactoryTest.java index 1ca179bc046..e58809fcb69 100644 --- a/test/jdk/sun/security/provider/NamedKeyFactoryTest.java +++ b/test/jdk/sun/security/provider/named/NamedKeyFactoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8340327 + * @bug 8340327 8347938 * @modules java.base/sun.security.x509 * java.base/sun.security.pkcs * java.base/sun.security.provider @@ -41,10 +41,13 @@ import sun.security.x509.NamedX509Key; import java.security.*; import java.security.spec.*; +import java.util.Arrays; public class NamedKeyFactoryTest { private static final SeededSecureRandom RAND = SeededSecureRandom.one(); + private static final byte[] RAW_SK = RAND.nBytes(16); + private static final byte[] RAW_PK = RAND.nBytes(16); public static void main(String[] args) throws Exception { Security.addProvider(new ProviderImpl()); @@ -78,8 +81,8 @@ public class NamedKeyFactoryTest { g.initialize(new NamedParameterSpec("ShA-256")); checkKeyPair(g.generateKeyPair(), "SHA", "SHA-256"); - var pk = new NamedX509Key("sHa", "ShA-256", RAND.nBytes(2)); - var sk = new NamedPKCS8Key("sHa", "SHa-256", RAND.nBytes(2)); + var pk = new NamedX509Key("sHa", "ShA-256", RAW_PK); + var sk = NamedPKCS8Key.internalCreate("sHa", "SHa-256", RAW_SK, null); checkKey(pk, "sHa", "ShA-256"); checkKey(sk, "sHa", "SHa-256"); @@ -134,25 +137,27 @@ public class NamedKeyFactoryTest { Asserts.assertEquals("RAW", srk2.getFormat()); Asserts.assertEqualsByteArray(srk2.getEncoded(), sk.getRawBytes()); + checkKey(kf2.generatePrivate(srk), "SHA", "SHA-256"); Asserts.assertEqualsByteArray(kf2.generatePrivate(srk).getEncoded(), sk.getEncoded()); Utils.runAndCheckException(() -> kf.generatePrivate(srk), InvalidKeySpecException.class); // no pname + checkKey(kf2.generatePrivate(srk), "SHA", "SHA-256"); Asserts.assertEqualsByteArray(kf2.generatePrivate(srk2).getEncoded(), sk.getEncoded()); Utils.runAndCheckException(() -> kf.generatePrivate(srk2), InvalidKeySpecException.class); // no pname var pk1 = new PublicKey() { public String getAlgorithm() { return "SHA"; } public String getFormat() { return "RAW"; } - public byte[] getEncoded() { return RAND.nBytes(2); } + public byte[] getEncoded() { return RAW_PK; } }; var pk2 = new PublicKey() { public String getAlgorithm() { return "sHA-256"; } public String getFormat() { return "RAW"; } - public byte[] getEncoded() { return RAND.nBytes(2); } + public byte[] getEncoded() { return RAW_PK; } }; var pk3 = new PublicKey() { public String getAlgorithm() { return "SHA"; } public String getFormat() { return "RAW"; } - public byte[] getEncoded() { return RAND.nBytes(2); } + public byte[] getEncoded() { return RAW_PK; } public AlgorithmParameterSpec getParams() { return new NamedParameterSpec("sHA-256"); } }; @@ -167,17 +172,17 @@ public class NamedKeyFactoryTest { var sk1 = new PrivateKey() { public String getAlgorithm() { return "SHA"; } public String getFormat() { return "RAW"; } - public byte[] getEncoded() { return RAND.nBytes(2); } + public byte[] getEncoded() { return RAW_SK; } }; var sk2 = new PrivateKey() { public String getAlgorithm() { return "sHA-256"; } public String getFormat() { return "RAW"; } - public byte[] getEncoded() { return RAND.nBytes(2); } + public byte[] getEncoded() { return RAW_SK; } }; var sk3 = new PrivateKey() { public String getAlgorithm() { return "SHA"; } public String getFormat() { return "RAW"; } - public byte[] getEncoded() { return RAND.nBytes(2); } + public byte[] getEncoded() { return RAW_SK; } public AlgorithmParameterSpec getParams() { return new NamedParameterSpec("sHA-256"); } }; @@ -201,6 +206,14 @@ public class NamedKeyFactoryTest { if (k instanceof AsymmetricKey ak && ak.getParams() instanceof NamedParameterSpec nps) { Asserts.assertEquals(pname, nps.getName()); } + if (k instanceof NamedPKCS8Key nsk) { + var raw = nsk.getRawBytes(); + Asserts.assertEqualsByteArray(Arrays.copyOf(RAW_SK, raw.length), raw); + } + if (k instanceof NamedX509Key npk) { + var raw = npk.getRawBytes(); + Asserts.assertEqualsByteArray(Arrays.copyOf(RAW_PK, raw.length), raw); + } } // Provider @@ -220,15 +233,24 @@ public class NamedKeyFactoryTest { public KF() { super("SHA", "SHA-256", "SHA-512"); } - } - public static class KF1 extends NamedKeyFactory { - public KF1() { - super("SHA", "SHA-256"); + + public KF(String name) { + super("SHA", name); + } + + @Override + protected byte[] implExpand(String pname, byte[] input) throws InvalidKeyException { + return null; } } - public static class KF2 extends NamedKeyFactory { + public static class KF1 extends KF { + public KF1() { + super("SHA-256"); + } + } + public static class KF2 extends KF { public KF2() { - super("SHA", "SHA-512"); + super("SHA-512"); } } public static class KPG extends NamedKeyPairGenerator { @@ -243,8 +265,8 @@ public class NamedKeyFactoryTest { @Override public byte[][] implGenerateKeyPair(String name, SecureRandom sr) { var out = new byte[2][]; - out[0] = RAND.nBytes(name.endsWith("256") ? 2 : 4); - out[1] = RAND.nBytes(name.endsWith("256") ? 2 : 4); + out[0] = name.endsWith("256") ? Arrays.copyOf(RAW_PK, 8) : RAW_PK; + out[1] = name.endsWith("256") ? Arrays.copyOf(RAW_SK, 8) : RAW_SK; return out; } } diff --git a/test/jdk/sun/security/provider/named/NamedKeys.java b/test/jdk/sun/security/provider/named/NamedKeys.java new file mode 100644 index 00000000000..e46cd981c70 --- /dev/null +++ b/test/jdk/sun/security/provider/named/NamedKeys.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2026, 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 8347938 + * @modules java.base/sun.security.pkcs + * java.base/sun.security.x509 + * @library /test/lib + * @summary check the Named***Key behavior + */ +import jdk.test.lib.Asserts; +import jdk.test.lib.security.SeededSecureRandom; +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.x509.NamedX509Key; + +import java.util.Arrays; + +public class NamedKeys { + public static void main(String[] args) throws Exception { + + // This test uses fictional key algorithms SHA and SHA-256, + // simply because they look like a family name and parameter + // set name and SHA-256 already have its OID defined. + + var r = SeededSecureRandom.one(); + var raw = r.nBytes(32); + + // Create a key using raw bytes + var sk = NamedPKCS8Key.internalCreate("SHA", "SHA-256", raw, null); + var enc = sk.getEncoded(); + + // The raw bytes array is re-used + Asserts.assertTrue(sk.getRawBytes() == sk.getRawBytes()); + // but the encoding is different + Asserts.assertTrue(sk.getEncoded() != sk.getEncoded()); + + // When source change + Arrays.fill(raw, (byte)0); + // Internal raw bytes also changes + Asserts.assertEqualsByteArray(sk.getRawBytes(), new byte[32]); + // No guarantee on getEncoded() output, could be cached + + // Create a key using encoding + var sk1 = new NamedPKCS8Key("SHA", enc, null); + var sk2 = new NamedPKCS8Key("SHA", enc, null); + var raw1 = sk1.getRawBytes(); + Asserts.assertTrue(raw1 != sk2.getRawBytes()); + Asserts.assertTrue(sk1.getEncoded() != sk2.getEncoded()); + + var encCopy = enc.clone(); // store a copy + Arrays.fill(enc, (byte)0); // clean the source and the key unchanged + Asserts.assertEqualsByteArray(encCopy, sk1.getEncoded()); + + // Same with public key + // Create a key using raw bytes + raw = r.nBytes(32); + var pk = new NamedX509Key("SHA", "SHA-256", raw); + enc = pk.getEncoded().clone(); + + // The raw bytes array is re-used + Asserts.assertTrue(pk.getRawBytes() == pk.getRawBytes()); + // but the encoding is different + Asserts.assertTrue(pk.getEncoded() != pk.getEncoded()); + + // When source change + Arrays.fill(raw, (byte)0); + // Internal raw bytes also changes + Asserts.assertEqualsByteArray(pk.getRawBytes(), new byte[32]); + // No guarantee on getEncoded() output, could be cached + + // Create a key using encoding + var pk1 = new NamedX509Key("SHA", enc); + var pk2 = new NamedX509Key("SHA", enc); + raw1 = pk1.getRawBytes(); + Asserts.assertTrue(raw1 != pk2.getRawBytes()); + Asserts.assertTrue(pk1.getEncoded() != pk2.getEncoded()); + + encCopy = enc.clone(); // store a copy + Arrays.fill(enc, (byte)0); // clean the source and the key unchanged + Asserts.assertEqualsByteArray(encCopy, pk1.getEncoded()); + } +} diff --git a/test/jdk/sun/security/provider/pqc/PrivateKeyEncodings.java b/test/jdk/sun/security/provider/pqc/PrivateKeyEncodings.java new file mode 100644 index 00000000000..25060d0b74e --- /dev/null +++ b/test/jdk/sun/security/provider/pqc/PrivateKeyEncodings.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2026, 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 8347938 + * @library /test/lib + * @summary ensure ML-KEM and ML-DSA encodings consistent with + * draft-ietf-lamps-kyber-certificates-11 and RFC 9881 + * @modules java.base/com.sun.crypto.provider + * java.base/sun.security.pkcs + * java.base/sun.security.provider + * @run main/othervm PrivateKeyEncodings + */ +import com.sun.crypto.provider.ML_KEM_Impls; +import jdk.test.lib.Asserts; +import jdk.test.lib.security.RepositoryFileReader; +import jdk.test.lib.security.FixedSecureRandom; +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.provider.ML_DSA_Impls; + +import javax.crypto.KEM; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.cert.CertificateFactory; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.NamedParameterSpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + +public class PrivateKeyEncodings { + + public static void main(String[] args) throws Exception { + // Example keys and certificates draft-ietf-lamps-kyber-certificates-11, Appendix B + // (https://datatracker.ietf.org/doc/html/draft-ietf-lamps-kyber-certificates-11#autoid-17) + // and RFC 9881, Appendix C.3 + // (https://datatracker.ietf.org/doc/html/rfc9881#name-example-certificates) + // + // These data can be retrieved from the following GitHub releases: + // https://github.com/lamps-wg/kyber-certificates/releases/tag/draft-ietf-lamps-kyber-certificates-11 + // https://github.com/lamps-wg/dilithium-certificates/releases/tag/draft-ietf-lamps-dilithium-certificates-13 + // + // Although the release tags include "draft", these values are the + // same as those in the final RFC 9881. + try (var kemReader = RepositoryFileReader.of(RepositoryFileReader.KYBER_CERTIFICATES.class, + "kyber-certificates-draft-ietf-lamps-kyber-certificates-11/"); + var dsaReader = RepositoryFileReader.of(RepositoryFileReader.DILITHIUM_CERTIFICATES.class, + "dilithium-certificates-draft-ietf-lamps-dilithium-certificates-13/")) { + good(kemReader, dsaReader); + badkem(kemReader); + baddsa(dsaReader); + } + } + + static void badkem(RepositoryFileReader f) throws Exception { + var kf = KeyFactory.getInstance("ML-KEM"); + + // The first ML-KEM-512-PrivateKey example includes the both CHOICE, + // i.e., both seed and expandedKey are included. The seed and expanded + // values can be checked for inconsistencies. + Asserts.assertThrows(InvalidKeySpecException.class, () -> + kf.generatePrivate(new PKCS8EncodedKeySpec( + readData(f, "example/bad-ML-KEM-512-1.priv")))); + + // The second ML-KEM-512-PrivateKey example includes only expandedKey. + // The expanded private key has a mutated s_0 and a valid public key hash, + // but a pairwise consistency check would find that the public key + // fails to match private. + var k2 = kf.generatePrivate(new PKCS8EncodedKeySpec( + readData(f, "example/bad-ML-KEM-512-2.priv"))); + var pk2 = ML_KEM_Impls.privKeyToPubKey((NamedPKCS8Key) k2); + var enc = KEM.getInstance("ML-KEM").newEncapsulator(pk2).encapsulate(); + var dk = KEM.getInstance("ML-KEM").newDecapsulator(k2).decapsulate(enc.encapsulation()); + Asserts.assertNotEqualsByteArray(enc.key().getEncoded(), dk.getEncoded()); + + // The third ML-KEM-512-PrivateKey example includes only expandedKey. + // The expanded private key has a mutated H(ek); both a public key + // digest check and a pairwise consistency check should fail. + var k3 = kf.generatePrivate(new PKCS8EncodedKeySpec( + readData(f, "example/bad-ML-KEM-512-3.priv"))); + Asserts.assertThrows(InvalidKeyException.class, () -> + KEM.getInstance("ML-KEM").newDecapsulator(k3)); + + // The fourth ML-KEM-512-PrivateKey example includes the both CHOICE, + // i.e., both seed and expandedKey are included. There is mismatch + // of the seed and expanded private key in only the z implicit rejection + // secret; here the private and public vectors match and the pairwise + // consistency check passes, but z is different. + Asserts.assertThrows(InvalidKeySpecException.class, () -> + kf.generatePrivate(new PKCS8EncodedKeySpec( + readData(f, "example/bad-ML-KEM-512-4.priv")))); + } + + static void baddsa(RepositoryFileReader f) throws Exception { + var kf = KeyFactory.getInstance("ML-DSA"); + + // The first ML-DSA-PrivateKey example includes the both CHOICE, i.e., + // both seed and expandedKey are included. The seed and expanded values + // can be checked for inconsistencies. + Asserts.assertThrows(InvalidKeySpecException.class, () -> + kf.generatePrivate(new PKCS8EncodedKeySpec( + readData(f, "examples/bad-ML-DSA-44-1.priv")))); + + // The second ML-DSA-PrivateKey example includes only expandedKey. + // The public key fails to match the tr hash value in the private key. + var k2 = kf.generatePrivate(new PKCS8EncodedKeySpec( + readData(f, "examples/bad-ML-DSA-44-2.priv"))); + Asserts.assertThrows(IllegalArgumentException.class, () -> + ML_DSA_Impls.privKeyToPubKey((NamedPKCS8Key) k2)); + + // The third ML-DSA-PrivateKey example also includes only expandedKey. + // The private s_1 and s_2 vectors imply a t vector whose private low + // bits do not match the t_0 vector portion of the private key + // (its high bits t_1 are the primary content of the public key). + var k3 = kf.generatePrivate(new PKCS8EncodedKeySpec( + readData(f, "examples/bad-ML-DSA-44-3.priv"))); + Asserts.assertThrows(IllegalArgumentException.class, () -> + ML_DSA_Impls.privKeyToPubKey((NamedPKCS8Key) k3)); + } + + static void good(RepositoryFileReader kemReader, RepositoryFileReader dsaReader) + throws Exception { + + var seed = new byte[64]; + for (var i = 0; i < seed.length; i++) { + seed[i] = (byte) i; + } + var cf = CertificateFactory.getInstance("X.509"); + var allPublicKeys = new HashMap(); + + for (var pname: List.of("ML-DSA-44", "ML-DSA-65", "ML-DSA-87", // DSA first, will sign KEM + "ML-KEM-512", "ML-KEM-768", "ML-KEM-1024")) { + + var isKem = pname.startsWith("ML-KEM"); + KeyPairGenerator g = KeyPairGenerator.getInstance(isKem ? "ML-KEM" : "ML-DSA"); + var prop = isKem ? "mlkem" : "mldsa"; + var f = isKem ? kemReader : dsaReader; + var example = isKem ? "example/" : "examples/"; + + g.initialize(new NamedParameterSpec(pname), new FixedSecureRandom(seed)); + var pk = g.generateKeyPair().getPublic(); + allPublicKeys.put(pname, pk); + Asserts.assertEqualsByteArray(readData(f, example + pname + ".pub"), pk.getEncoded()); + + var in = new ByteArrayInputStream(readData(f, example + pname + ".crt")); + var c = cf.generateCertificate(in); + var signer = switch (pname) { + case "ML-KEM-512" -> allPublicKeys.get("ML-DSA-44"); + case "ML-KEM-768" -> allPublicKeys.get("ML-DSA-65"); + case "ML-KEM-1024" -> allPublicKeys.get("ML-DSA-87"); + default -> c.getPublicKey(); + }; + c.verify(signer); + Asserts.assertEquals(c.getPublicKey(), pk); + + for (var type : List.of("seed", "expandedkey", "both")) { + System.err.println(pname + " " + type); + System.setProperty("jdk." + prop + ".pkcs8.encoding", type); + g.initialize(new NamedParameterSpec(pname), new FixedSecureRandom(seed)); + var sk = g.generateKeyPair().getPrivate(); + if (type.equals("expandedkey")) type = "expanded"; + Asserts.assertEqualsByteArray( + readData(f, example + pname + "-" + type + ".priv"), sk.getEncoded()); + checkInterop(pk, sk); + } + } + } + + // Ensures pk and sk interop with each other + static void checkInterop(PublicKey pk, PrivateKey sk) throws Exception { + if (pk.getAlgorithm().startsWith("ML-KEM")) { + var kem = KEM.getInstance("ML-KEM"); + var enc = kem.newEncapsulator(pk).encapsulate(); + var k = kem.newDecapsulator(sk).decapsulate(enc.encapsulation()); + Asserts.assertEqualsByteArray(k.getEncoded(), enc.key().getEncoded()); + } else { + var msg = "hello".getBytes(StandardCharsets.UTF_8); + var s = Signature.getInstance("ML-DSA"); + s.initSign(sk); + s.update(msg); + var sig = s.sign(); + s.initVerify(pk); + s.update(msg); + Asserts.assertTrue(s.verify(sig)); + } + } + + static byte[] readData(RepositoryFileReader f, String entry) throws Exception { + byte[] data = f.read(entry); + var pem = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(data))) + .lines() + .filter(s -> !s.contains("-----")) + .collect(Collectors.joining()); + return Base64.getMimeDecoder().decode(pem); + } +} diff --git a/test/jdk/sun/security/provider/pqc/SeedOrExpanded.java b/test/jdk/sun/security/provider/pqc/SeedOrExpanded.java new file mode 100644 index 00000000000..0a5b462b037 --- /dev/null +++ b/test/jdk/sun/security/provider/pqc/SeedOrExpanded.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2026, 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 8347938 + * @library /test/lib + * @modules java.base/com.sun.crypto.provider + * java.base/sun.security.pkcs + * java.base/sun.security.provider + * java.base/sun.security.util + * java.base/sun.security.x509 + * @summary check key reading compatibility + * @run main/othervm SeedOrExpanded + */ + +import com.sun.crypto.provider.ML_KEM_Impls; +import jdk.test.lib.Asserts; +import jdk.test.lib.security.DerUtils; +import jdk.test.lib.security.FixedSecureRandom; +import jdk.test.lib.security.SeededSecureRandom; +import sun.security.pkcs.NamedPKCS8Key; +import sun.security.provider.ML_DSA_Impls; +import sun.security.util.DerValue; + +import javax.crypto.KEM; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; + +public class SeedOrExpanded { + + static final SeededSecureRandom RAND = SeededSecureRandom.one(); + + public static void main(String[] args) throws Exception { + test("mlkem", "ML-KEM-768"); + test("mldsa", "ML-DSA-65"); + } + + static void test(String type, String alg) throws Exception { + + var seed = RAND.nBytes(alg.contains("ML-KEM") ? 64 : 32); + var g = KeyPairGenerator.getInstance(alg); + + // Generation + + g.initialize(-1, new FixedSecureRandom(seed)); + var kp = g.generateKeyPair(); + var pk = kp.getPublic(); + var kDefault = kp.getPrivate(); + + // Property value is case-insensitive + System.setProperty("jdk." + type + ".pkcs8.encoding", "SEED"); + g.initialize(-1, new FixedSecureRandom(seed)); + var kSeed = g.generateKeyPair().getPrivate(); + System.setProperty("jdk." + type + ".pkcs8.encoding", "expandedkey"); + g.initialize(-1, new FixedSecureRandom(seed)); + var kExpanded = g.generateKeyPair().getPrivate(); + System.setProperty("jdk." + type + ".pkcs8.encoding", "boTH"); + g.initialize(-1, new FixedSecureRandom(seed)); + var kBoth = g.generateKeyPair().getPrivate(); + + // Invalid property value + System.setProperty("jdk." + type + ".pkcs8.encoding", "bogus"); + g.initialize(-1, new FixedSecureRandom(seed)); + Asserts.assertThrows(IllegalArgumentException.class, + () -> g.generateKeyPair().getPrivate()); + + byte[] kExpandedEncoded = kExpanded.getEncoded(); + byte[] kSeedEncoded = kSeed.getEncoded(); + byte[] kBothEncoded = kBoth.getEncoded(); + + // Ensure tags match the CHOICE definition + Asserts.assertEquals((byte) 0x80, DerUtils.innerDerValue(kSeedEncoded, "2c").tag); + Asserts.assertEquals((byte) 0x04, DerUtils.innerDerValue(kExpandedEncoded, "2c").tag); + Asserts.assertEquals((byte) 0x30, DerUtils.innerDerValue(kBothEncoded, "2c").tag); + + byte[] seedData = DerUtils.innerDerValue(kSeedEncoded, "2c") + .withTag(DerValue.tag_OctetString).getOctetString(); + byte[] expandedData = DerUtils.innerDerValue(kExpandedEncoded, "2c").getOctetString(); + + Asserts.assertEqualsByteArray(seed, seedData); + Asserts.assertEqualsByteArray( + seedData, + DerUtils.innerDerValue(kBothEncoded, "2c0").getOctetString()); + Asserts.assertEqualsByteArray( + expandedData, + DerUtils.innerDerValue(kBothEncoded, "2c1").getOctetString()); + + // Ensure seedToExpanded correctly called + if (alg.contains("ML-KEM")) { + Asserts.assertEqualsByteArray(expandedData, + ML_KEM_Impls.seedToExpanded(alg, seedData)); + } else { + Asserts.assertEqualsByteArray(expandedData, + ML_DSA_Impls.seedToExpanded(alg, seedData)); + } + + test(alg, pk, kSeed); + test(alg, pk, kExpanded); + test(alg, pk, kBoth); + + var kf = KeyFactory.getInstance(alg); + + System.setProperty("jdk." + type + ".pkcs8.encoding", "seed"); + Asserts.assertEqualsByteArray( + test(alg, pk, kf.translateKey(kBoth)).getEncoded(), + kSeedEncoded); + Asserts.assertTrue(kf.translateKey(kSeed) == kSeed); + Asserts.assertThrows(InvalidKeyException.class, () -> kf.translateKey(kExpanded)); + + System.setProperty("jdk." + type + ".pkcs8.encoding", "expandedkey"); + Asserts.assertEqualsByteArray( + test(alg, pk, kf.translateKey(kBoth)).getEncoded(), + kExpandedEncoded); + Asserts.assertEqualsByteArray( + test(alg, pk, kf.translateKey(kSeed)).getEncoded(), + kExpandedEncoded); + Asserts.assertTrue(kf.translateKey(kExpanded) == kExpanded); + + System.setProperty("jdk." + type + ".pkcs8.encoding", "both"); + Asserts.assertTrue(kf.translateKey(kBoth) == kBoth); + Asserts.assertEqualsByteArray( + test(alg, pk, kf.translateKey(kSeed)).getEncoded(), + kBothEncoded); + Asserts.assertThrows(InvalidKeyException.class, () -> kf.translateKey(kExpanded)); + + // The following makes sure key is not mistakenly cleaned during + // translations. + var xk = new PrivateKey() { + public String getAlgorithm() { return alg; } + public String getFormat() { return "PKCS#8"; } + public byte[] getEncoded() { return kBothEncoded.clone(); } + }; + test(alg, pk, xk); + var xk2 = (PrivateKey) kf.translateKey(xk); + test(alg, pk, xk2); + test(alg, pk, xk); + } + + static PrivateKey test(String alg, PublicKey pk, Key k) throws Exception { + var sk = (PrivateKey) k; + if (alg.contains("ML-KEM")) { + var kem = KEM.getInstance("ML-KEM"); + var e = kem.newEncapsulator(pk, RAND); + var enc = e.encapsulate(); + var k1 = kem.newDecapsulator(sk).decapsulate(enc.encapsulation()); + Asserts.assertEqualsByteArray(k1.getEncoded(), enc.key().getEncoded()); + if (k instanceof NamedPKCS8Key npk) { + Asserts.assertEqualsByteArray( + ML_KEM_Impls.privKeyToPubKey(npk).getEncoded(), pk.getEncoded()); + } + } else { + var s = Signature.getInstance("ML-DSA"); + var rnd = RAND.nBytes(32); // randomness for signature generation + var msg = RAND.nBytes(20); + s.initSign(sk, new FixedSecureRandom(rnd)); + s.update(msg); + var sig1 = s.sign(); + s.initVerify(pk); + s.update(msg); + Asserts.assertTrue(s.verify(sig1)); + if (k instanceof NamedPKCS8Key npk) { + Asserts.assertEqualsByteArray( + ML_DSA_Impls.privKeyToPubKey(npk).getEncoded(), pk.getEncoded()); + } + } + return sk; + } +} diff --git a/test/lib/jdk/test/lib/process/Proc.java b/test/lib/jdk/test/lib/process/Proc.java index 2fe802fed6c..a989906b2ab 100644 --- a/test/lib/jdk/test/lib/process/Proc.java +++ b/test/lib/jdk/test/lib/process/Proc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -256,6 +256,15 @@ public class Proc { } } } + String patchPath = System.getProperty("test.patch.path"); + if (patchPath != null) { + try (var subs = Files.newDirectoryStream(Path.of(patchPath))) { + for (var sub : subs) { + var name = sub.getFileName(); + cmd.add("--patch-module=" + name + "=" + sub); + } + } + } var lcp = fullcp(); if (lcp != null) { diff --git a/test/lib/jdk/test/lib/security/RepositoryFileReader.java b/test/lib/jdk/test/lib/security/RepositoryFileReader.java index 4eefc7d82db..04bc3c88d2a 100644 --- a/test/lib/jdk/test/lib/security/RepositoryFileReader.java +++ b/test/lib/jdk/test/lib/security/RepositoryFileReader.java @@ -148,4 +148,13 @@ public sealed interface RepositoryFileReader extends AutoCloseable { unpack = false) public static class CMS_ML_DSA { } + + @Artifact( + organization = "jpg.tests.jdk.repos.lamps-wg", + name = "kyber-certificates", + revision = "29f3215", + extension = "zip", + unpack = false) + public static class KYBER_CERTIFICATES { + } } From 58d2edb9fc1bb68363e697b43be04c493ead81c5 Mon Sep 17 00:00:00 2001 From: Koushik Thirupattur Date: Tue, 3 Feb 2026 19:09:19 +0000 Subject: [PATCH 311/328] 8370688: java.util.jar.JarEntry.getCodeSigners() and getCertificates() should specify that they return a copy of the arrays Reviewed-by: jpai, mullan, liach --- .../share/classes/java/util/jar/JarEntry.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/java/util/jar/JarEntry.java b/src/java.base/share/classes/java/util/jar/JarEntry.java index ff0750a3342..6037ee243e5 100644 --- a/src/java.base/share/classes/java/util/jar/JarEntry.java +++ b/src/java.base/share/classes/java/util/jar/JarEntry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -114,8 +114,10 @@ public class JarEntry extends ZipEntry { * validate each signer's certificate chain, and determining whether * to trust the entry signed by the signers. * - * @return the {@code Certificate} objects for this entry, or - * {@code null} if none. + * @implSpec If non-null, this implementation returns a new array each time + * this method is invoked. + * + * @return the {@code Certificate} objects for this entry, or {@code null} if none. * */ public Certificate[] getCertificates() { @@ -139,8 +141,10 @@ public class JarEntry extends ZipEntry { * validate each signer's certificate chain, and determining whether * to trust the entry signed by the signers. * - * @return the {@code CodeSigner} objects for this entry, or - * {@code null} if none. + * @implSpec If non-null, this implementation returns a new array each time + * this method is invoked. + * + * @return the {@code CodeSigner} objects for this entry, or {@code null} if none. * * @since 1.5 */ From 5fea0741a6b7ff7e3a41844c86e422c0f0582333 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 3 Feb 2026 19:24:41 +0000 Subject: [PATCH 312/328] 8376297: ArrayIndexOutOfBoundsException Not Documented for SinglePixelPackedSampleModel.getSampleSize(int) Reviewed-by: aivanov, serb, azvegint, kizune --- .../java/awt/image/ComponentSampleModel.java | 8 +- .../image/MultiPixelPackedSampleModel.java | 8 +- .../image/SinglePixelPackedSampleModel.java | 9 +- .../jdk/java/awt/image/GetSampleSizeTest.java | 85 +++++++++++++++++++ 4 files changed, 104 insertions(+), 6 deletions(-) create mode 100644 test/jdk/java/awt/image/GetSampleSizeTest.java diff --git a/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java b/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java index d15a8d214aa..4460b0fc101 100644 --- a/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -503,7 +503,11 @@ public class ComponentSampleModel extends SampleModel } /** Returns the number of bits per sample for the specified band. - * @param band the specified band + *

    + * Since all bands of a {@code ComponentSampleModel} are the same + * size, this method ignores the {@code band} parameter and returns + * the size of the first (0th) band. + * @param band the specified band (ignored) * @return the number of bits per sample for the specified band. */ public final int getSampleSize(int band) { diff --git a/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java b/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java index a79ddf52cd9..d8f97562c6c 100644 --- a/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -235,7 +235,11 @@ public class MultiPixelPackedSampleModel extends SampleModel /** * Returns the number of bits per sample for the specified band. - * @param band the specified band + *

    + * Since {@code MultiPixelPackedSampleModel} has only one band, + * this method ignores the {@code band} parameter and returns + * the sample size of the single band. + * @param band the specified band (ignored) * @return the number of bits per sample for the specified band. */ public int getSampleSize(int band) { diff --git a/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java b/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java index d12c151a8fd..2ab226ea227 100644 --- a/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -250,7 +250,12 @@ public class SinglePixelPackedSampleModel extends SampleModel return bitSizes.clone(); } - /** Returns the number of bits per sample for the specified band. */ + /** Returns the number of bits per sample for the specified band. + * @param band the specified band + * @return the size of the samples of the specified band. + * @throws ArrayIndexOutOfBoundsException if the {@code band} index + * is less than zero or greater than or equal to {@code getNumBands()} + */ public int getSampleSize(int band) { return bitSizes[band]; } diff --git a/test/jdk/java/awt/image/GetSampleSizeTest.java b/test/jdk/java/awt/image/GetSampleSizeTest.java new file mode 100644 index 00000000000..dcf6d1e6ed5 --- /dev/null +++ b/test/jdk/java/awt/image/GetSampleSizeTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2026, 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.awt.image.ComponentSampleModel; +import java.awt.image.DataBuffer; +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.SinglePixelPackedSampleModel; + +/* + * @test + * @bug 8376297 + * @summary Test SampleModel.getSampleSize(int) + */ + +public class GetSampleSizeTest { + + public static void main(String[] args) { + + final int width = 10; + final int height = 10; + int[] bandOffsets = {0, 0}; + int[] bitMask = {0x00ff0000, 0x0000ff00, 0xff, 0x0}; + + { + ComponentSampleModel csm = + new ComponentSampleModel(DataBuffer.TYPE_BYTE, + width, height, 1, width, bandOffsets); + int numBands = csm.getNumBands(); + System.out.println("CSM numBands = " + numBands); + if (numBands != 2) { + throw new RuntimeException("Unexpected numBands"); + } + System.out.println("CSM sample size = " + csm.getSampleSize(numBands)); + } + + { + MultiPixelPackedSampleModel mppsm = + new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, width, height, 4); + int numBands = mppsm.getNumBands(); + System.out.println("MPPSM numBands = " + numBands); + if (numBands != 1) { + throw new RuntimeException("Unexpected numBands"); + } + System.out.println("MPPSM sample size = " + mppsm.getSampleSize(numBands)); + } + + { + SinglePixelPackedSampleModel sppsm = + new SinglePixelPackedSampleModel(DataBuffer.TYPE_BYTE, width, height, bitMask); + int numBands = sppsm.getNumBands(); + System.out.println("SPPSM numBands = " + numBands); + if (numBands != 4) { + throw new RuntimeException("Unexpected numBands"); + } + try { + System.out.println("SPPSM sample size = " + sppsm.getSampleSize(numBands)); + throw new RuntimeException("No expected AIOBE"); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println("Got expected AIOBE for SPPSM"); + } + } + + } +} + From f3c8502e38de714caab8edd895113528f1ea4f5e Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Wed, 4 Feb 2026 00:51:29 +0000 Subject: [PATCH 313/328] 8227493: Return a more useful error message from lookupAllHostAddr if getaddrinfo results in EAI_SYSTEM error Reviewed-by: dfuchs, djelinski, michaelm --- .../unix/native/libnet/Inet4AddressImpl.c | 6 ++- .../unix/native/libnet/Inet6AddressImpl.c | 6 ++- .../unix/native/libnet/net_util_md.c | 37 ++++++++++++++++--- .../unix/native/libnet/net_util_md.h | 5 ++- 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/src/java.base/unix/native/libnet/Inet4AddressImpl.c index 9bddbcaede7..e99dfd89411 100644 --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -112,6 +112,8 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, error == EAI_SYSTEM && errno == EINTR); if (error) { + // capture the errno from getaddrinfo + const int sys_errno = errno; #if defined(MACOSX) // If getaddrinfo fails try getifaddrs, see bug 8170910. // java_net_spi_InetAddressResolver_LookupPolicy_IPV4_FIRST and no ordering is ok @@ -122,7 +124,7 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, } #endif // report error - NET_ThrowUnknownHostExceptionWithGaiError(env, hostname, error); + NET_ThrowUnknownHostExceptionWithGaiError(env, hostname, error, sys_errno); goto cleanupAndReturn; } else { int i = 0; diff --git a/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/src/java.base/unix/native/libnet/Inet6AddressImpl.c index 8dce4f9cc6b..e0963c8dc3e 100644 --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -231,6 +231,8 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, error == EAI_SYSTEM && errno == EINTR); if (error) { + // capture the errno from getaddrinfo + const int sys_errno = errno; #if defined(MACOSX) // if getaddrinfo fails try getifaddrs ret = lookupIfLocalhost(env, hostname, JNI_TRUE, characteristics); @@ -239,7 +241,7 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, } #endif // report error - NET_ThrowUnknownHostExceptionWithGaiError(env, hostname, error); + NET_ThrowUnknownHostExceptionWithGaiError(env, hostname, error, sys_errno); goto cleanupAndReturn; } else { int i = 0, inetCount = 0, inet6Count = 0, inetIndex = 0, diff --git a/src/java.base/unix/native/libnet/net_util_md.c b/src/java.base/unix/native/libnet/net_util_md.c index 48cc1a7bb02..f7b690f1032 100644 --- a/src/java.base/unix/native/libnet/net_util_md.c +++ b/src/java.base/unix/native/libnet/net_util_md.c @@ -178,13 +178,21 @@ jint reuseport_supported(int ipv6_available) void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env, const char* hostname, - int gai_error) + int gai_error, + int sys_errno) { int size; char *buf; + const char *sys_errno_string = NULL; const char *error_string = gai_strerror(gai_error); - if (error_string == NULL) + if (error_string == NULL) { error_string = "unknown error"; + } + if (gai_error == EAI_SYSTEM) { + // EAI_SYSTEM implies that the actual error is stored in the system errno. + // Here we get the string representation of that errno. + sys_errno_string = strerror(sys_errno); + } int enhancedExceptions = getEnhancedExceptionsAllowed(env); if (enhancedExceptions == ENH_INIT_ERROR && (*env)->ExceptionCheck(env)) { return; @@ -195,16 +203,33 @@ void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env, } else { size = 0; } - size += strlen(error_string) + 3; - + if (sys_errno_string == NULL) { + // the 3 is for the additional 3 characters - colon, space and + // the NULL termination character, that we will include in the + // message of the Exception that we construct + size += strlen(error_string) + 3; + } else { + // the 5 is for the additional 5 characters - 2 colons, 2 spaces and + // the NULL termination character, that we will include in the + // message of the Exception that we construct + size += strlen(error_string) + strlen(sys_errno_string) + 5; + } buf = (char *) malloc(size); if (buf) { jstring s; int n; if (enhancedExceptions == ENH_ENABLED) { - n = snprintf(buf, size, "%s: %s", hostname, error_string); + if (sys_errno_string == NULL) { + n = snprintf(buf, size, "%s: %s", hostname, error_string); + } else { + n = snprintf(buf, size, "%s: %s: %s", hostname, error_string, sys_errno_string); + } } else { - n = snprintf(buf, size, " %s", error_string); + if (sys_errno_string == NULL) { + n = snprintf(buf, size, " %s", error_string); + } else { + n = snprintf(buf, size, " %s: %s", error_string, sys_errno_string); + } } if (n >= 0) { s = JNU_NewStringPlatform(env, buf); diff --git a/src/java.base/unix/native/libnet/net_util_md.h b/src/java.base/unix/native/libnet/net_util_md.h index dca6e97755a..639cf00515f 100644 --- a/src/java.base/unix/native/libnet/net_util_md.h +++ b/src/java.base/unix/native/libnet/net_util_md.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -76,7 +76,8 @@ typedef union { */ void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env, const char* hostname, - int gai_error); + int gai_error, + int sys_errno); void NET_ThrowByNameWithLastError(JNIEnv *env, const char *name, const char *defaultDetail); From 14a6e928ce9a10f6d85fae8db4ce303da20bde85 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Wed, 4 Feb 2026 02:04:04 +0000 Subject: [PATCH 314/328] 8376630: java/lang/ProcessBuilder/PipelineLeaksFD.java intermittent timed out Reviewed-by: rriggs --- .../java/lang/ProcessBuilder/PipelineLeaksFD.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/lang/ProcessBuilder/PipelineLeaksFD.java b/test/jdk/java/lang/ProcessBuilder/PipelineLeaksFD.java index 2b4cdfa9bdd..e7eaa57ec95 100644 --- a/test/jdk/java/lang/ProcessBuilder/PipelineLeaksFD.java +++ b/test/jdk/java/lang/ProcessBuilder/PipelineLeaksFD.java @@ -25,6 +25,7 @@ import org.junit.jupiter.api.condition.EnabledIf; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import static org.junit.jupiter.api.Assertions.*; +import jdk.test.lib.Utils; import java.io.BufferedReader; import java.io.IOException; @@ -32,6 +33,7 @@ import java.io.Writer; import java.lang.ProcessHandle; import java.nio.file.Files; import java.nio.file.Path; +import java.util.concurrent.TimeUnit; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; @@ -44,7 +46,8 @@ import java.util.stream.Collectors; * @bug 8289643 8291760 8291986 * @requires os.family == "mac" | (os.family == "linux" & !vm.musl) * @summary File descriptor leak detection with ProcessBuilder.startPipeline - * @run junit/othervm PipelineLeaksFD + * @library /test/lib + * @run junit/othervm/timeout=240 PipelineLeaksFD */ public class PipelineLeaksFD { @@ -236,8 +239,11 @@ public class PipelineLeaksFD { .redirectInput(lsofEmptyInput.toFile()) // empty input .redirectError(ProcessBuilder.Redirect.DISCARD) // ignored output .start()) { - int status = p.waitFor(); - assertEquals(0, status, "Process 'lsof' failed"); + boolean status = p.waitFor(Utils.adjustTimeout(120), TimeUnit.SECONDS); + if (!status) { + p.destroyForcibly(); + } + assertTrue(status, "Process 'lsof' failed"); return Files.readAllLines(lsofOutput); } catch (InterruptedException ie) { From 443cd77509bd4144ba7dfec26e3e7b2e62c799f9 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 4 Feb 2026 06:44:59 +0000 Subject: [PATCH 315/328] 8376758: Fix -Wzero-as-null-pointer-constant warnings in AIX code Reviewed-by: dholmes, jsjolen --- src/hotspot/os/aix/decoder_aix.hpp | 4 ++-- src/hotspot/os/aix/os_aix.cpp | 2 +- src/hotspot/os/aix/porting_aix.cpp | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/hotspot/os/aix/decoder_aix.hpp b/src/hotspot/os/aix/decoder_aix.hpp index 2ba3e1c5a3a..632355ccf4e 100644 --- a/src/hotspot/os/aix/decoder_aix.hpp +++ b/src/hotspot/os/aix/decoder_aix.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -38,7 +38,7 @@ class AIXDecoder: public AbstractDecoder { virtual bool demangle(const char* symbol, char* buf, int buflen) { return false; } // use AixSymbols::get_function_name to demangle virtual bool decode(address addr, char* buf, int buflen, int* offset, const char* modulepath, bool demangle) { - return AixSymbols::get_function_name(addr, buf, buflen, offset, 0, demangle); + return AixSymbols::get_function_name(addr, buf, buflen, offset, nullptr, demangle); } virtual bool decode(address addr, char *buf, int buflen, int* offset, const void *base) { ShouldNotReachHere(); diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index d7c1911a914..0a8efbece8d 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -703,7 +703,7 @@ static void *thread_native_entry(Thread *thread) { log_info(os, thread)("Thread finished (tid: %zu, kernel thread id: %zu).", os::current_thread_id(), (uintx) kernel_thread_id); - return 0; + return nullptr; } bool os::create_thread(Thread* thread, ThreadType thr_type, diff --git a/src/hotspot/os/aix/porting_aix.cpp b/src/hotspot/os/aix/porting_aix.cpp index 7311afc197b..b3f878fbfdd 100644 --- a/src/hotspot/os/aix/porting_aix.cpp +++ b/src/hotspot/os/aix/porting_aix.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2012, 2024 SAP SE. All rights reserved. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -78,7 +78,7 @@ class fixed_strings { public: - fixed_strings() : first(0) {} + fixed_strings() : first(nullptr) {} ~fixed_strings() { node* n = first; while (n) { @@ -113,7 +113,7 @@ bool AixSymbols::get_function_name ( // information (null if not available) bool demangle // [in] whether to demangle the name ) { - struct tbtable* tb = 0; + struct tbtable* tb = nullptr; unsigned int searchcount = 0; // initialize output parameters @@ -653,10 +653,10 @@ void AixNativeCallstack::print_callstack_for_context(outputStream* st, const uco // To print the first frame, use the current value of iar: // current entry indicated by iar (the current pc) - codeptr_t cur_iar = 0; - stackptr_t cur_sp = 0; - codeptr_t cur_rtoc = 0; - codeptr_t cur_lr = 0; + codeptr_t cur_iar = nullptr; + stackptr_t cur_sp = nullptr; + codeptr_t cur_rtoc = nullptr; + codeptr_t cur_lr = nullptr; const ucontext_t* uc = (const ucontext_t*) context; @@ -926,7 +926,7 @@ static struct handletableentry* p_handletable = nullptr; static const char* rtv_linkedin_libpath() { constexpr int bufsize = 4096; static char buffer[bufsize]; - static const char* libpath = 0; + static const char* libpath = nullptr; // we only try to retrieve the libpath once. After that try we // let libpath point to buffer, which then contains a valid libpath From 1069ccebcc32e02055985e2babfa2986a2e295ca Mon Sep 17 00:00:00 2001 From: Thomas Devoogdt Date: Wed, 4 Feb 2026 06:48:59 +0000 Subject: [PATCH 316/328] 8376684: Compile OpenJDK in headless mode without required X11 libraries Reviewed-by: erikj, aivanov --- doc/building.html | 7 +++---- doc/building.md | 6 ++---- make/autoconf/libraries.m4 | 8 ++++---- make/modules/java.desktop/lib/AwtLibraries.gmk | 16 ++++++++++++++-- .../unix/native/common/awt/utility/rect.h | 4 ++-- 5 files changed, 25 insertions(+), 16 deletions(-) diff --git a/doc/building.html b/doc/building.html index 8e5a7625371..534888ef667 100644 --- a/doc/building.html +++ b/doc/building.html @@ -1385,10 +1385,9 @@ dpkg-deb -x /tmp/libasound2-dev_1.0.25-4_armhf.deb .

  • can specify it by --with-alsa.

    X11

    -

    You will need X11 libraries suitable for your target system. -In most cases, using Debian's pre-built libraries work fine.

    -

    Note that X11 is needed even if you only want to build a headless -JDK.

    +

    When not building a headless JDK, you will need X11 libraries +suitable for your target system. In most cases, using Debian's +pre-built libraries work fine.

    • Go to Debian Package Search, search for the following packages for your diff --git a/doc/building.md b/doc/building.md index b626027f101..d653d36eb55 100644 --- a/doc/building.md +++ b/doc/building.md @@ -1178,10 +1178,8 @@ Note that alsa is needed even if you only want to build a headless JDK. #### X11 -You will need X11 libraries suitable for your *target* system. In most cases, -using Debian's pre-built libraries work fine. - -Note that X11 is needed even if you only want to build a headless JDK. +When not building a headless JDK, you will need X11 libraries suitable for your +*target* system. In most cases, using Debian's pre-built libraries work fine. * Go to [Debian Package Search](https://www.debian.org/distrib/packages), search for the following packages for your *target* system, and download them diff --git a/make/autoconf/libraries.m4 b/make/autoconf/libraries.m4 index 8dc3d55ed0c..5daacdc1ced 100644 --- a/make/autoconf/libraries.m4 +++ b/make/autoconf/libraries.m4 @@ -42,12 +42,12 @@ m4_include([lib-tests.m4]) AC_DEFUN_ONCE([LIB_DETERMINE_DEPENDENCIES], [ # Check if X11 is needed - if test "x$OPENJDK_TARGET_OS" = xwindows || test "x$OPENJDK_TARGET_OS" = xmacosx; then - # No X11 support on windows or macosx + if test "x$OPENJDK_TARGET_OS" = xwindows || + test "x$OPENJDK_TARGET_OS" = xmacosx || + test "x$ENABLE_HEADLESS_ONLY" = xtrue; then NEEDS_LIB_X11=false else - # All other instances need X11, even if building headless only, libawt still - # needs X11 headers. + # All other instances need X11 for libawt. NEEDS_LIB_X11=true fi diff --git a/make/modules/java.desktop/lib/AwtLibraries.gmk b/make/modules/java.desktop/lib/AwtLibraries.gmk index 463e09e12dc..8b6b50b9e62 100644 --- a/make/modules/java.desktop/lib/AwtLibraries.gmk +++ b/make/modules/java.desktop/lib/AwtLibraries.gmk @@ -88,6 +88,10 @@ LIBAWT_EXTRA_HEADER_DIRS := \ LIBAWT_CFLAGS := -D__MEDIALIB_OLD_NAMES -D__USE_J2D_NAMES -DMLIB_NO_LIBSUNMATH +ifeq ($(ENABLE_HEADLESS_ONLY), true) + LIBAWT_CFLAGS += -DHEADLESS +endif + ifeq ($(call isTargetOs, windows), true) LIBAWT_CFLAGS += -EHsc -DUNICODE -D_UNICODE -DMLIB_OS64BIT LIBAWT_RCFLAGS ?= -I$(TOPDIR)/src/java.base/windows/native/launcher/icons @@ -167,11 +171,18 @@ ifeq ($(call isTargetOs, windows macosx), false) $(TOPDIR)/src/$(MODULE)/$(OPENJDK_TARGET_OS_TYPE)/native/common/awt \ # + LIBAWT_HEADLESS_EXCLUDE_FILES := \ + GLXGraphicsConfig.c \ + GLXSurfaceData.c \ + X11PMBlitLoops.c \ + X11Renderer.c \ + X11SurfaceData.c \ + # + LIBAWT_HEADLESS_EXTRA_HEADER_DIRS := \ $(LIBAWT_DEFAULT_HEADER_DIRS) \ common/awt/debug \ common/font \ - common/java2d/opengl \ java.base:libjvm \ # @@ -191,7 +202,8 @@ ifeq ($(call isTargetOs, windows macosx), false) $(eval $(call SetupJdkLibrary, BUILD_LIBAWT_HEADLESS, \ NAME := awt_headless, \ EXTRA_SRC := $(LIBAWT_HEADLESS_EXTRA_SRC), \ - EXCLUDES := medialib, \ + EXCLUDES := medialib opengl, \ + EXCLUDE_FILES := $(LIBAWT_HEADLESS_EXCLUDE_FILES), \ ONLY_EXPORTED := $(LIBAWT_HEADLESS_ONLY_EXPORTED), \ OPTIMIZATION := LOW, \ CFLAGS := -DHEADLESS=true $(CUPS_CFLAGS) $(FONTCONFIG_CFLAGS) \ diff --git a/src/java.desktop/unix/native/common/awt/utility/rect.h b/src/java.desktop/unix/native/common/awt/utility/rect.h index ceea38f4349..91b5a17ec58 100644 --- a/src/java.desktop/unix/native/common/awt/utility/rect.h +++ b/src/java.desktop/unix/native/common/awt/utility/rect.h @@ -28,7 +28,7 @@ #ifndef _AWT_RECT_H #define _AWT_RECT_H -#ifndef MACOSX +#if !defined(HEADLESS) && !defined(MACOSX) #include typedef XRectangle RECT_T; #else @@ -39,7 +39,7 @@ typedef struct { int width; int height; } RECT_T; -#endif /* !MACOSX */ +#endif /* !HEADLESS && !MACOSX */ #define RECT_EQ_X(r1,r2) ((r1).x==(r2).x && (r1).width==(r2).width) From 7e8fad625a2cdc9a4e46eb31c485de074997c7c0 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Wed, 4 Feb 2026 07:30:46 +0000 Subject: [PATCH 317/328] 8376760: VerifyJimage.java#compare intermittent failed with fastdebug Reviewed-by: liach, alanb --- test/jdk/tools/jimage/VerifyJimage.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/test/jdk/tools/jimage/VerifyJimage.java b/test/jdk/tools/jimage/VerifyJimage.java index 08f567cbecb..723ad089fa9 100644 --- a/test/jdk/tools/jimage/VerifyJimage.java +++ b/test/jdk/tools/jimage/VerifyJimage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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 @@ -145,15 +145,9 @@ public abstract class VerifyJimage implements Runnable { pool.execute(new ModuleResourceComparator(rootDir, modName, jimage)); } } - pool.shutdown(); - if (!pool.awaitTermination(20, TimeUnit.SECONDS)) { - failed.add("Directory verification timed out"); - } + pool.close(); } catch (IOException ex) { throw new UncheckedIOException(ex); - } catch (InterruptedException e) { - failed.add("Directory verification was interrupted"); - Thread.currentThread().interrupt(); } } From d67f72e0d55ce4da5928716fc6ab87d87516443b Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Wed, 4 Feb 2026 07:54:57 +0000 Subject: [PATCH 318/328] 8377063: Add EchoPassword.java to manual group Reviewed-by: msheppar, rhalade --- test/jdk/TEST.groups | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index 27f6bb48a63..ccf745700d1 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -1,4 +1,4 @@ -# Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 2026, 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 @@ -664,7 +664,8 @@ jdk_core_manual_interactive = \ jdk_security_manual_interactive = \ sun/security/tools/keytool/i18n.java \ com/sun/security/auth/callback/TextCallbackHandler/Password.java \ - sun/security/krb5/config/native/TestDynamicStore.java + sun/security/krb5/config/native/TestDynamicStore.java \ + sun/security/tools/keytool/EchoPassword.java # Test sets for running inside container environment jdk_containers_extended = \ From b0829a54cd787d5e378573f69ec0b82b40602454 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Wed, 4 Feb 2026 08:24:42 +0000 Subject: [PATCH 319/328] 8372948: Store end positions directly in JCTree Reviewed-by: jlahoda, mcimadamore --- .../sun/tools/javac/api/JavacTaskImpl.java | 5 +- .../com/sun/tools/javac/api/JavacTrees.java | 4 +- .../com/sun/tools/javac/code/LintMapper.java | 23 +-- .../com/sun/tools/javac/comp/Attr.java | 5 +- .../com/sun/tools/javac/comp/Lower.java | 11 +- .../com/sun/tools/javac/jvm/CRTable.java | 10 +- .../classes/com/sun/tools/javac/jvm/Gen.java | 15 +- .../sun/tools/javac/main/JavaCompiler.java | 15 +- .../sun/tools/javac/parser/JavaTokenizer.java | 3 +- .../sun/tools/javac/parser/JavacParser.java | 127 +++--------- .../sun/tools/javac/parser/ParserFactory.java | 9 +- .../com/sun/tools/javac/tree/DCTree.java | 2 +- .../com/sun/tools/javac/tree/EndPosTable.java | 83 -------- .../com/sun/tools/javac/tree/JCTree.java | 11 +- .../com/sun/tools/javac/tree/TreeInfo.java | 60 +++--- .../tools/javac/util/DiagnosticSource.java | 13 -- .../sun/tools/javac/util/IntHashTable.java | 190 ------------------ .../sun/tools/javac/util/JCDiagnostic.java | 15 +- .../classes/com/sun/tools/javac/util/Log.java | 6 - .../jdk/javadoc/internal/tool/JavadocLog.java | 3 +- .../share/classes/jdk/jshell/ReplParser.java | 6 +- .../classes/jdk/jshell/ReplParserFactory.java | 9 +- .../share/classes/jdk/jshell/TaskFactory.java | 4 +- .../tools/javac/6304921/TestLog.java | 8 +- .../javac/diags/DiagnosticGetEndPosition.java | 13 +- .../javac/failover/CheckAttributedTree.java | 11 +- .../javac/parser/DeclarationEndPositions.java | 2 +- .../javac/parser/ReversedSourcePositions.java | 2 +- .../javac/parser/extend/TrialParser.java | 8 +- .../parser/extend/TrialParserFactory.java | 9 +- .../javac/tree/MissingSemicolonTest.java | 4 +- .../tools/javac/tree/TreePosTest.java | 11 +- 32 files changed, 132 insertions(+), 565 deletions(-) delete mode 100644 src/jdk.compiler/share/classes/com/sun/tools/javac/tree/EndPosTable.java delete mode 100644 src/jdk.compiler/share/classes/com/sun/tools/javac/util/IntHashTable.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java index 65ce640ef76..bc597876778 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java @@ -91,6 +91,8 @@ public class JavacTaskImpl extends BasicJavacTask { @Override @DefinedBy(Api.COMPILER) public Boolean call() { + if (used.get()) + throw new IllegalStateException(); return doCall().isOK(); } @@ -207,7 +209,6 @@ public class JavacTaskImpl extends BasicJavacTask { // init JavaCompiler and queues compiler = JavaCompiler.instance(context); compiler.keepComments = true; - compiler.genEndPos = true; notYetEntered = new HashMap<>(); if (forParse) { compiler.initProcessAnnotations(processors, args.getFileObjects(), args.getClassNames()); @@ -245,6 +246,8 @@ public class JavacTaskImpl extends BasicJavacTask { @Override @DefinedBy(Api.COMPILER_TREE) public Iterable parse() { + if (used.get()) + throw new IllegalStateException(); Pair, Throwable> result = invocationHelper(this::parseInternal); if (result.snd == null) { return result.fst; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java index 22ee2393a02..6bc5d358b6f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java @@ -114,7 +114,6 @@ import com.sun.tools.javac.tree.DCTree.DCParam; import com.sun.tools.javac.tree.DCTree.DCReference; import com.sun.tools.javac.tree.DocCommentTable; import com.sun.tools.javac.tree.DocTreeMaker; -import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCBlock; import com.sun.tools.javac.tree.JCTree.JCCatch; @@ -240,8 +239,7 @@ public class JavacTrees extends DocTrees { @Override @DefinedBy(Api.COMPILER_TREE) public long getEndPosition(CompilationUnitTree file, Tree tree) { - EndPosTable endPosTable = ((JCCompilationUnit) file).endPositions; - return TreeInfo.getEndPos((JCTree) tree, endPosTable); + return TreeInfo.getEndPos((JCTree) tree); } @Override @DefinedBy(Api.COMPILER_TREE) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java index 06caa70d478..4f33bb92b41 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java @@ -35,7 +35,6 @@ import java.util.function.Consumer; import javax.tools.JavaFileObject; -import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.tree.TreeInfo; @@ -134,9 +133,9 @@ public class LintMapper { * @param sourceFile source file * @param tree top-level declaration (class, package, or module) */ - public void calculateLints(JavaFileObject sourceFile, JCTree tree, EndPosTable endPositions) { + public void calculateLints(JavaFileObject sourceFile, JCTree tree) { Assert.check(rootLint != null); - fileInfoMap.get(sourceFile).afterAttr(tree, endPositions); + fileInfoMap.get(sourceFile).afterAttr(tree); } /** @@ -184,15 +183,15 @@ public class LintMapper { rootRange = new LintRange(rootLint); for (JCTree decl : tree.defs) { if (isTopLevelDecl(decl)) - unmappedDecls.add(new Span(decl, tree.endPositions)); + unmappedDecls.add(new Span(decl)); } } // After attribution: Discard the span from "unmappedDecls" and populate the declaration's subtree under "rootRange" - void afterAttr(JCTree tree, EndPosTable endPositions) { + void afterAttr(JCTree tree) { for (Iterator i = unmappedDecls.iterator(); i.hasNext(); ) { if (i.next().contains(tree.pos())) { - rootRange.populateSubtree(tree, endPositions); + rootRange.populateSubtree(tree); i.remove(); return; } @@ -225,8 +224,8 @@ public class LintMapper { static final Span MAXIMAL = new Span(Integer.MIN_VALUE, Integer.MAX_VALUE); - Span(JCTree tree, EndPosTable endPositions) { - this(TreeInfo.getStartPos(tree), TreeInfo.getEndPos(tree, endPositions)); + Span(JCTree tree) { + this(TreeInfo.getStartPos(tree), TreeInfo.getEndPos(tree)); } boolean contains(DiagnosticPosition pos) { @@ -256,8 +255,8 @@ public class LintMapper { } // Create a node representing the given declaration and its corresponding Lint configuration - LintRange(JCTree tree, EndPosTable endPositions, Lint lint) { - this(new Span(tree, endPositions), lint, new LinkedList<>()); + LintRange(JCTree tree, Lint lint) { + this(new Span(tree), lint, new LinkedList<>()); } // Find the most specific node in this tree (including me) that contains the given position, if any @@ -277,7 +276,7 @@ public class LintMapper { // Populate a sparse subtree corresponding to the given nested declaration. // Only when the Lint configuration differs from the parent is a node added. - void populateSubtree(JCTree tree, EndPosTable endPositions) { + void populateSubtree(JCTree tree) { new TreeScanner() { private LintRange currentNode = LintRange.this; @@ -320,7 +319,7 @@ public class LintMapper { // Add a new node here and proceed final LintRange previousNode = currentNode; - currentNode = new LintRange(tree, endPositions, newLint); + currentNode = new LintRange(tree, newLint); previousNode.children.add(currentNode); try { recursor.accept(tree); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 5109dfed22e..cdd88b22510 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -2762,8 +2762,7 @@ public class Attr extends JCTree.Visitor { clazzid1 = make.at(clazz.pos).Select(make.Type(encltype), ((JCIdent) clazzid).name); - EndPosTable endPosTable = this.env.toplevel.endPositions; - endPosTable.storeEnd(clazzid1, clazzid.getEndPosition(endPosTable)); + clazzid1.endpos = clazzid.getEndPosition(); if (clazz.hasTag(ANNOTATED_TYPE)) { JCAnnotatedType annoType = (JCAnnotatedType) clazz; List annos = annoType.annotations; @@ -5314,7 +5313,7 @@ public class Attr extends JCTree.Visitor { annotate.flush(); // Now that this tree is attributed, we can calculate the Lint configuration everywhere within it - lintMapper.calculateLints(env.toplevel.sourcefile, env.tree, env.toplevel.endPositions); + lintMapper.calculateLints(env.toplevel.sourcefile, env.tree); } public void attribPackage(DiagnosticPosition pos, PackageSymbol p) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java index 2db3435a382..69161fd682c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java @@ -48,7 +48,6 @@ import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.jvm.Target; -import com.sun.tools.javac.tree.EndPosTable; import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Flags.BLOCK; @@ -156,10 +155,6 @@ public class Lower extends TreeTranslator { */ Env attrEnv; - /** A hash table mapping syntax trees to their ending source positions. - */ - EndPosTable endPosTable; - /* ************************************************************************ * Global mappings *************************************************************************/ @@ -2059,8 +2054,8 @@ public class Lower extends TreeTranslator { } else { make_at(tree.pos()); T result = super.translate(tree); - if (endPosTable != null && result != tree) { - endPosTable.replaceTree(tree, result); + if (result != null && result != tree) { + result.endpos = tree.endpos; } return result; } @@ -4352,7 +4347,6 @@ public class Lower extends TreeTranslator { try { attrEnv = env; this.make = make; - endPosTable = env.toplevel.endPositions; currentClass = null; currentRestype = null; currentMethodDef = null; @@ -4382,7 +4376,6 @@ public class Lower extends TreeTranslator { // note that recursive invocations of this method fail hard attrEnv = null; this.make = null; - endPosTable = null; currentClass = null; currentRestype = null; currentMethodDef = null; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java index 2cd4142c748..3092d16469d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java @@ -32,7 +32,6 @@ import com.sun.tools.javac.tree.*; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.List; import com.sun.tools.javac.tree.JCTree.*; -import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.tree.JCTree.JCSwitchExpression; /** This class contains the CharacterRangeTable for some method @@ -57,10 +56,6 @@ implements CRTFlags { */ private Map positions = new HashMap<>(); - /** The object for ending positions stored in the parser. - */ - private EndPosTable endPosTable; - /** The tree of the method this table is intended for. * We should traverse this tree to get source ranges. */ @@ -68,9 +63,8 @@ implements CRTFlags { /** Constructor */ - public CRTable(JCTree.JCMethodDecl tree, EndPosTable endPosTable) { + public CRTable(JCTree.JCMethodDecl tree) { this.methodTree = tree; - this.endPosTable = endPosTable; } /** Create a new CRTEntry and add it to the entries. @@ -584,7 +578,7 @@ implements CRTFlags { */ public int endPos(JCTree tree) { if (tree == null) return Position.NOPOS; - return TreeInfo.getEndPos(tree, endPosTable); + return TreeInfo.getEndPos(tree); } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java index e40a2fbfcea..688ea1bd720 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -45,7 +45,6 @@ import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.jvm.Code.*; import com.sun.tools.javac.jvm.Items.*; import com.sun.tools.javac.resources.CompilerProperties.Errors; -import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.tree.JCTree.*; import static com.sun.tools.javac.code.Flags.*; @@ -162,11 +161,6 @@ public class Gen extends JCTree.Visitor { */ private int nerrs = 0; - /** An object containing mappings of syntax trees to their - * ending source positions. - */ - EndPosTable endPosTable; - boolean inCondSwitchExpression; Chain switchExpressionTrueChain; Chain switchExpressionFalseChain; @@ -455,7 +449,7 @@ public class Gen extends JCTree.Visitor { JCStatement init = make.at(vdef.pos()). Assignment(sym, vdef.init); initCode.append(init); - endPosTable.replaceTree(vdef, init); + init.endpos = vdef.endpos; initTAs.addAll(getAndRemoveNonFieldTAs(sym)); } else if (sym.getConstValue() == null) { // Initialize class (static) variables only if @@ -463,7 +457,7 @@ public class Gen extends JCTree.Visitor { JCStatement init = make.at(vdef.pos). Assignment(sym, vdef.init); clinitCode.append(init); - endPosTable.replaceTree(vdef, init); + init.endpos = vdef.endpos; clinitTAs.addAll(getAndRemoveNonFieldTAs(sym)); } else { checkStringConstant(vdef.init.pos(), sym.getConstValue()); @@ -1027,8 +1021,7 @@ public class Gen extends JCTree.Visitor { varDebugInfo, stackMap, debugCode, - genCrt ? new CRTable(tree, env.toplevel.endPositions) - : null, + genCrt ? new CRTable(tree) : null, syms, types, poolWriter); @@ -2478,7 +2471,6 @@ public class Gen extends JCTree.Visitor { attrEnv = env; ClassSymbol c = cdef.sym; this.toplevel = env.toplevel; - this.endPosTable = toplevel.endPositions; /* method normalizeDefs() can add references to external classes into the constant pool */ cdef.defs = normalizeDefs(cdef.defs, c); @@ -2508,7 +2500,6 @@ public class Gen extends JCTree.Visitor { attrEnv = null; this.env = null; toplevel = null; - endPosTable = null; nerrs = 0; qualifiedSymbolCache.clear(); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java index 2469dc9e031..94292d9a348 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -438,8 +438,6 @@ public class JavaCompiler { sourceOutput = options.isSet(PRINTSOURCE); // used to be -s lineDebugInfo = options.isUnset(G_CUSTOM) || options.isSet(G_CUSTOM, "lines"); - genEndPos = options.isSet(XJCOV) || - context.get(DiagnosticListener.class) != null; devVerbose = options.isSet("dev"); processPcks = options.isSet("process.packages"); werrorAny = options.isSet(WERROR) || options.isSet(WERROR_CUSTOM, Option.LINT_CUSTOM_ALL); @@ -504,10 +502,6 @@ public class JavaCompiler { */ public boolean lineDebugInfo; - /** Switch: should we store the ending positions? - */ - public boolean genEndPos; - /** Switch: should we debug ignored exceptions */ protected boolean devVerbose; @@ -655,9 +649,8 @@ public class JavaCompiler { TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, filename); taskListener.started(e); keepComments = true; - genEndPos = true; } - Parser parser = parserFactory.newParser(content, keepComments(), genEndPos, + Parser parser = parserFactory.newParser(content, keepComments(), lineDebugInfo, filename.isNameCompatible("module-info", Kind.SOURCE)); tree = parser.parseCompilationUnit(); if (verbose) { @@ -697,10 +690,7 @@ public class JavaCompiler { public JCTree.JCCompilationUnit parse(JavaFileObject filename) { JavaFileObject prev = log.useSource(filename); try { - JCTree.JCCompilationUnit t = parse(filename, readSource(filename)); - if (t.endPositions != null) - log.setEndPosTable(filename, t.endPositions); - return t; + return parse(filename, readSource(filename)); } finally { log.useSource(prev); } @@ -1162,7 +1152,6 @@ public class JavaCompiler { options.put("parameters", "parameters"); reader.saveParameterNames = true; keepComments = true; - genEndPos = true; if (!taskListener.isEmpty()) taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING)); deferredDiagnosticHandler = log.new DeferredDiagnosticHandler(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java index f40cb0fb6b7..babe372e7dc 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java @@ -33,7 +33,6 @@ import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle; import com.sun.tools.javac.resources.CompilerProperties.Errors; import com.sun.tools.javac.resources.CompilerProperties.LintWarnings; import com.sun.tools.javac.resources.CompilerProperties.Warnings; -import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.JCDiagnostic.*; @@ -1215,7 +1214,7 @@ public class JavaTokenizer extends UnicodeReader { this.cs = cs; this.pos = new SimpleDiagnosticPosition(pos) { @Override - public int getEndPosition(EndPosTable endPosTable) { + public int getEndPosition() { return endPos; } }; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index d658275d4dc..e78537c10f5 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -110,8 +110,7 @@ public class JavacParser implements Parser { /** The name table. */ private Names names; - /** End position mappings container */ - protected final AbstractEndPosTable endPosTable; + protected int errorEndPos = Position.NOPOS; /** A map associating "other nearby documentation comments" * with the preferred documentation comment for a declaration. */ @@ -167,9 +166,8 @@ public class JavacParser implements Parser { protected JavacParser(ParserFactory fac, Lexer S, boolean keepDocComments, - boolean keepLineMap, - boolean keepEndPositions) { - this(fac, S, keepDocComments, keepLineMap, keepEndPositions, false); + boolean keepLineMap) { + this(fac, S, keepDocComments, keepLineMap, false); } /** Construct a parser from a given scanner, tree factory and log. @@ -179,7 +177,6 @@ public class JavacParser implements Parser { Lexer S, boolean keepDocComments, boolean keepLineMap, - boolean keepEndPositions, boolean parseModuleInfo) { this.S = S; nextToken(); // prime the pump @@ -194,7 +191,6 @@ public class JavacParser implements Parser { this.docComments = newDocCommentTable(keepDocComments, fac); this.keepLineMap = keepLineMap; this.errorTree = F.Erroneous(); - this.endPosTable = newEndPosTable(keepEndPositions); this.allowYieldStatement = Feature.SWITCH_EXPRESSION.allowedInSource(source); this.allowRecords = Feature.RECORDS.allowedInSource(source); this.allowSealedTypes = Feature.SEALED_CLASSES.allowedInSource(source); @@ -218,19 +214,12 @@ public class JavacParser implements Parser { this.parseModuleInfo = false; this.docComments = parser.docComments; this.errorTree = F.Erroneous(); - this.endPosTable = newEndPosTable(false); this.allowYieldStatement = Feature.SWITCH_EXPRESSION.allowedInSource(source); this.allowRecords = Feature.RECORDS.allowedInSource(source); this.allowSealedTypes = Feature.SEALED_CLASSES.allowedInSource(source); updateUnexpectedTopLevelDefinitionStartError(false); } - protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) { - return keepEndPositions - ? new SimpleEndPosTable() - : new MinimalEndPosTable(); - } - protected DocCommentTable newDocCommentTable(boolean keepDocComments, ParserFactory fac) { return keepDocComments ? new LazyDocCommentTable(fac) : null; } @@ -667,7 +656,7 @@ public class JavacParser implements Parser { var src = log.currentSource(); return c.getStyle() == Comment.CommentStyle.JAVADOC_LINE && c.getPos().getStartPosition() == 0 && - src.getLineNumber(pos.getEndPosition(src.getEndPosTable())) == 1; + src.getLineNumber(pos.getEndPosition()) == 1; } /** @@ -681,23 +670,26 @@ public class JavacParser implements Parser { /* -------- source positions ------- */ protected void setErrorEndPos(int errPos) { - endPosTable.setErrorEndPos(errPos); + if (errPos > errorEndPos) { + errorEndPos = errPos; + } } /** * Store ending position for a tree, the value of which is the greater of - * last error position in {@link #endPosTable} and the given ending position. + * {@link #errorEndPos} and the given ending position. * @param tree tree node * @param endpos the ending position to associate with {@code tree} * @return {@code tree} */ protected T storeEnd(T tree, int endpos) { - return endPosTable.storeEnd(tree, endpos); + tree.endpos = Math.max(endpos, errorEndPos); + return tree; } /** * Store current token's ending position for a tree, the value of which - * will be the greater of last error position in {@link #endPosTable} + * will be the greater of {@link #errorEndPos} * and the ending position of the current token. * @param tree tree node */ @@ -707,7 +699,7 @@ public class JavacParser implements Parser { /** * Store current token's ending position for a tree, the value of which - * will be the greater of last error position in {@link #endPosTable} + * will be the greater of {@link #errorEndPos} * and the ending position of the previous token. * @param tree tree node */ @@ -733,7 +725,7 @@ public class JavacParser implements Parser { * @param tree The tree node */ public int getEndPos(JCTree tree) { - return endPosTable.getEndPos(tree); + return tree.endpos; } @@ -1269,7 +1261,7 @@ public class JavacParser implements Parser { JCAnnotation typeAnno = F.at(decl.pos) .TypeAnnotation(decl.annotationType, decl.args); - endPosTable.replaceTree(decl, typeAnno); + typeAnno.endpos = decl.endpos; return typeAnno; }); type = insertAnnotationsToMostInner(type, typeAnnos, false); @@ -1358,7 +1350,7 @@ public class JavacParser implements Parser { } else { JCExpression t = F.at(litBuf.first().getStartPosition()).Literal(TypeTag.CLASS, litBuf.stream().map(lit -> (String)lit.getValue()).collect(Collectors.joining())); - storeEnd(t, litBuf.last().getEndPosition(endPosTable)); + storeEnd(t, litBuf.last().getEndPosition()); opStack.prepend(t); return true; } @@ -1654,7 +1646,7 @@ public class JavacParser implements Parser { } // typeArgs saved for next loop iteration. t = toP(F.at(pos).Select(t, ident())); - if (token.pos <= endPosTable.errorEndPos && + if (token.pos <= errorEndPos && token.kind == MONKEYS_AT) { //error recovery, case like: //int i = expr. @@ -1878,7 +1870,7 @@ public class JavacParser implements Parser { tyannos = typeAnnotationsOpt(); } t = toP(F.at(pos1).Select(t, ident(true))); - if (token.pos <= endPosTable.errorEndPos && + if (token.pos <= errorEndPos && token.kind == MONKEYS_AT) { //error recovery, case like: //int i = expr. @@ -2533,7 +2525,7 @@ public class JavacParser implements Parser { int pos = token.pos; nextToken(); accept(CLASS); - if (token.pos == endPosTable.errorEndPos) { + if (token.pos == errorEndPos) { // error recovery Name name; if (LAX_IDENTIFIER.test(token.kind)) { @@ -2867,7 +2859,7 @@ public class JavacParser implements Parser { // error recovery if (token.pos == lastErrPos) return stats.toList(); - if (token.pos <= endPosTable.errorEndPos) { + if (token.pos <= errorEndPos) { skip(false, true, true, true); lastErrPos = token.pos; } @@ -4045,7 +4037,7 @@ public class JavacParser implements Parser { boolean firstTypeDecl = true; // have we seen a class, enum, or interface declaration yet? boolean isImplicitClass = false; OUTER: while (token.kind != EOF) { - if (token.pos <= endPosTable.errorEndPos) { + if (token.pos <= errorEndPos) { // error recovery skip(firstTypeDecl, false, false, false); if (token.kind == EOF) @@ -4156,7 +4148,6 @@ public class JavacParser implements Parser { toplevel.docComments = docComments; if (keepLineMap) toplevel.lineMap = S.getLineMap(); - toplevel.endPositions = this.endPosTable; return toplevel; } @@ -4576,7 +4567,7 @@ public class JavacParser implements Parser { hasStructuralErrors = true; } defs.append(enumeratorDeclaration(enumName)); - if (token.pos <= endPosTable.errorEndPos) { + if (token.pos <= errorEndPos) { // error recovery skip(false, true, true, false); } else { @@ -4599,7 +4590,7 @@ public class JavacParser implements Parser { wasError = false; defs.appendList(classOrInterfaceOrRecordBodyDeclaration(null, enumName, false, false)); - if (token.pos <= endPosTable.errorEndPos) { + if (token.pos <= errorEndPos) { // error recovery skip(false, true, true, false); } @@ -4696,7 +4687,7 @@ public class JavacParser implements Parser { */ List classInterfaceOrRecordBody(Name className, boolean isInterface, boolean isRecord) { accept(LBRACE); - if (token.pos <= endPosTable.errorEndPos) { + if (token.pos <= errorEndPos) { // error recovery skip(false, true, false, false); if (token.kind == LBRACE) @@ -4707,7 +4698,7 @@ public class JavacParser implements Parser { ListBuffer defs = new ListBuffer<>(); while (token.kind != RBRACE && token.kind != EOF) { defs.appendList(classOrInterfaceOrRecordBodyDeclaration(null, className, isInterface, isRecord)); - if (token.pos <= endPosTable.errorEndPos) { + if (token.pos <= errorEndPos) { // error recovery skip(false, true, true, false); } @@ -5067,7 +5058,7 @@ public class JavacParser implements Parser { boolean unclosedParameterList; if (!isRecord || name != names.init || token.kind == LPAREN) { params = formalParameters(); - unclosedParameterList = token.pos == endPosTable.errorEndPos; + unclosedParameterList = token.pos == errorEndPos; if (!isVoid) type = bracketsOpt(type); if (token.kind == THROWS) { nextToken(); @@ -5093,7 +5084,7 @@ public class JavacParser implements Parser { defaultValue = null; accept(SEMI, tk -> Errors.Expected2(LBRACE, SEMI)); } - if (token.pos <= endPosTable.errorEndPos) { + if (token.pos <= errorEndPos) { // error recovery // look if there is a probable missing opening brace, // and if yes, parse as a block @@ -5631,70 +5622,4 @@ public class JavacParser implements Parser { unexpectedTopLevelDefinitionStartError = Errors.Expected3(CLASS, INTERFACE, ENUM); } } - - /** - * A straightforward {@link EndPosTable} implementation. - */ - protected static class SimpleEndPosTable extends AbstractEndPosTable { - - private final IntHashTable endPosMap = new IntHashTable(); - - @Override - public T storeEnd(T tree, int endpos) { - endPosMap.put(tree, Math.max(endpos, errorEndPos)); - return tree; - } - - @Override - public int getEndPos(JCTree tree) { - int value = endPosMap.get(tree); - // As long as Position.NOPOS==-1, this just returns value. - return (value == -1) ? Position.NOPOS : value; - } - - @Override - public int replaceTree(JCTree oldTree, JCTree newTree) { - int pos = endPosMap.remove(oldTree); - if (pos != -1 && newTree != null) { - storeEnd(newTree, pos); - } - return pos; - } - } - - /** - * A minimal implementation that only stores what's required. - */ - protected static class MinimalEndPosTable extends SimpleEndPosTable { - - @Override - public T storeEnd(T tree, int endpos) { - switch (tree.getTag()) { - case MODULEDEF: - case PACKAGEDEF: - case CLASSDEF: - case METHODDEF: - case VARDEF: - break; - default: - return tree; - } - return super.storeEnd(tree, endpos); - } - } - - protected abstract static class AbstractEndPosTable implements EndPosTable { - - /** - * Store the last error position. - */ - public int errorEndPos = Position.NOPOS; - - @Override - public void setErrorEndPos(int errPos) { - if (errPos > errorEndPos) { - errorEndPos = errPos; - } - } - } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java index f9e187315ba..d06dd2cacda 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java @@ -28,7 +28,6 @@ package com.sun.tools.javac.parser; import java.util.Locale; import com.sun.tools.javac.api.JavacTrees; -import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.code.Preview; import com.sun.tools.javac.code.Source; import com.sun.tools.javac.tree.DocTreeMaker; @@ -89,13 +88,9 @@ public class ParserFactory { this.trees = JavacTrees.instance(context); } - public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap) { - return newParser(input, keepDocComments, keepEndPos, keepLineMap, false); - } - - public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap, boolean parseModuleInfo) { + public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepLineMap, boolean parseModuleInfo) { Lexer lexer = scannerFactory.newScanner(input, keepDocComments); - return new JavacParser(this, lexer, keepDocComments, keepLineMap, keepEndPos, parseModuleInfo); + return new JavacParser(this, lexer, keepDocComments, keepLineMap, parseModuleInfo); } public JavacTrees getTrees() { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java index a999786f119..023e5c74b3a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java @@ -305,7 +305,7 @@ public abstract class DCTree implements DocTree { } @Override - public int getEndPosition(EndPosTable endPosTable) { + public int getEndPosition() { return comment.getSourcePos(end); } }; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/EndPosTable.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/EndPosTable.java deleted file mode 100644 index 83fe402c0a7..00000000000 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/EndPosTable.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.javac.tree; - -import com.sun.tools.javac.util.Position; - -/** - * Specifies the methods to access a mappings of syntax trees to end positions. - * - *

      - * Implementations must store end positions for at least these node types: - *

        - *
      • {@link JCTree.JCModuleDecl} - *
      • {@link JCTree.JCPackageDecl} - *
      • {@link JCTree.JCClassDecl} - *
      • {@link JCTree.JCMethodDecl} - *
      • {@link JCTree.JCVariableDecl} - *
      - * - *

      This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own - * risk. This code and its internal interfaces are subject to change - * or deletion without notice.

      - */ -public interface EndPosTable { - - /** - * This method will return the end position of a given tree, otherwise a - * Positions.NOPOS will be returned. - * @param tree JCTree - * @return position of the source tree or Positions.NOPOS for non-existent mapping - */ - int getEndPos(JCTree tree); - - /** - * Store ending position for a tree, the value of which is the greater of - * last error position and the given ending position. - * @param tree The tree. - * @param endpos The ending position to associate with the tree. - * @return the {@code tree} - */ - T storeEnd(T tree, int endpos); - - /** - * Set the error position during the parsing phases, the value of which - * will be set only if it is greater than the last stored error position. - * @param errPos The error position - */ - void setErrorEndPos(int errPos); - - /** - * Give an old tree and a new tree, the old tree will be replaced with - * the new tree, the position of the new tree will be that of the old - * tree. - * @param oldtree a JCTree to be replaced - * @param newtree a JCTree to be replaced with, or null to just remove {@code oldtree} - * @return position of the old tree or Positions.NOPOS for non-existent mapping - */ - int replaceTree(JCTree oldtree, JCTree newtree); -} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java index 6501fd5d96c..e0a99a6f103 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java @@ -431,6 +431,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { */ public int pos; + /* The (encoded) end position in the source file. @see util.Position. + */ + public int endpos = Position.NOPOS; + /* The type of this node. */ public Type type; @@ -514,8 +518,8 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { } // for default DiagnosticPosition - public int getEndPosition(EndPosTable endPosTable) { - return noNoPos(TreeInfo.getEndPos(this, endPosTable)); + public int getEndPosition() { + return noNoPos(TreeInfo.getEndPos(this)); } private int noNoPos(int position) { @@ -552,9 +556,6 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { /** A table that stores all documentation comments indexed by the tree * nodes they refer to. defined only if option -s is set. */ public DocCommentTable docComments = null; - /* An object encapsulating ending positions of source ranges indexed by - * the tree nodes they belong to. Defined only if option -Xjcov is set. */ - public EndPosTable endPositions = null; protected JCCompilationUnit(List defs) { this.defs = defs; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java index 3f73bfd2296..aa616f3f580 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java @@ -31,7 +31,6 @@ import com.sun.source.tree.Tree; import com.sun.source.util.TreePath; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Symbol.RecordComponent; -import com.sun.tools.javac.comp.AttrContext; import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*; @@ -647,18 +646,13 @@ public class TreeInfo { /** The end position of given tree, given a table of end positions generated by the parser */ - public static int getEndPos(JCTree tree, EndPosTable endPosTable) { + public static int getEndPos(JCTree tree) { if (tree == null) return Position.NOPOS; - if (endPosTable == null) { - // fall back on limited info in the tree - return endPos(tree); - } - - int mapPos = endPosTable.getEndPos(tree); - if (mapPos != Position.NOPOS) - return mapPos; + int endpos = tree.endpos; + if (endpos != Position.NOPOS) + return endpos; switch(tree.getTag()) { case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG: @@ -678,57 +672,57 @@ public class TreeInfo { case COMPL: case PREINC: case PREDEC: - return getEndPos(((JCOperatorExpression) tree).getOperand(RIGHT), endPosTable); + return getEndPos(((JCOperatorExpression) tree).getOperand(RIGHT)); case CASE: - return getEndPos(((JCCase) tree).stats.last(), endPosTable); + return getEndPos(((JCCase) tree).stats.last()); case CATCH: - return getEndPos(((JCCatch) tree).body, endPosTable); + return getEndPos(((JCCatch) tree).body); case CONDEXPR: - return getEndPos(((JCConditional) tree).falsepart, endPosTable); + return getEndPos(((JCConditional) tree).falsepart); case FORLOOP: - return getEndPos(((JCForLoop) tree).body, endPosTable); + return getEndPos(((JCForLoop) tree).body); case FOREACHLOOP: - return getEndPos(((JCEnhancedForLoop) tree).body, endPosTable); + return getEndPos(((JCEnhancedForLoop) tree).body); case IF: { JCIf node = (JCIf)tree; if (node.elsepart == null) { - return getEndPos(node.thenpart, endPosTable); + return getEndPos(node.thenpart); } else { - return getEndPos(node.elsepart, endPosTable); + return getEndPos(node.elsepart); } } case LABELLED: - return getEndPos(((JCLabeledStatement) tree).body, endPosTable); + return getEndPos(((JCLabeledStatement) tree).body); case MODIFIERS: - return getEndPos(((JCModifiers) tree).annotations.last(), endPosTable); + return getEndPos(((JCModifiers) tree).annotations.last()); case SYNCHRONIZED: - return getEndPos(((JCSynchronized) tree).body, endPosTable); + return getEndPos(((JCSynchronized) tree).body); case TOPLEVEL: - return getEndPos(((JCCompilationUnit) tree).defs.last(), endPosTable); + return getEndPos(((JCCompilationUnit) tree).defs.last()); case TRY: { JCTry node = (JCTry)tree; if (node.finalizer != null) { - return getEndPos(node.finalizer, endPosTable); + return getEndPos(node.finalizer); } else if (!node.catchers.isEmpty()) { - return getEndPos(node.catchers.last(), endPosTable); + return getEndPos(node.catchers.last()); } else { - return getEndPos(node.body, endPosTable); + return getEndPos(node.body); } } case WILDCARD: - return getEndPos(((JCWildcard) tree).inner, endPosTable); + return getEndPos(((JCWildcard) tree).inner); case TYPECAST: - return getEndPos(((JCTypeCast) tree).expr, endPosTable); + return getEndPos(((JCTypeCast) tree).expr); case TYPETEST: - return getEndPos(((JCInstanceOf) tree).pattern, endPosTable); + return getEndPos(((JCInstanceOf) tree).pattern); case WHILELOOP: - return getEndPos(((JCWhileLoop) tree).body, endPosTable); + return getEndPos(((JCWhileLoop) tree).body); case ANNOTATED_TYPE: - return getEndPos(((JCAnnotatedType) tree).underlyingType, endPosTable); + return getEndPos(((JCAnnotatedType) tree).underlyingType); case ERRONEOUS: { JCErroneous node = (JCErroneous)tree; if (node.errs != null && node.errs.nonEmpty()) - return getEndPos(node.errs.last(), endPosTable); + return getEndPos(node.errs.last()); } } return Position.NOPOS; @@ -745,8 +739,8 @@ public class TreeInfo { public JCTree getTree() { return tree; } public int getStartPosition() { return TreeInfo.getStartPos(tree); } public int getPreferredPosition() { return endPos; } - public int getEndPosition(EndPosTable endPosTable) { - return TreeInfo.getEndPos(tree, endPosTable); + public int getEndPosition() { + return TreeInfo.getEndPos(tree); } }; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/DiagnosticSource.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/DiagnosticSource.java index baae3101811..3339900733f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/DiagnosticSource.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/DiagnosticSource.java @@ -31,7 +31,6 @@ import java.nio.CharBuffer; import javax.tools.JavaFileObject; import com.sun.tools.javac.file.JavacFileManager; -import com.sun.tools.javac.tree.EndPosTable; import static com.sun.tools.javac.util.LayoutCharacters.*; @@ -127,16 +126,6 @@ public class DiagnosticSource { } } - public EndPosTable getEndPosTable() { - return endPosTable; - } - - public void setEndPosTable(EndPosTable t) { - if (endPosTable != null && endPosTable != t) - throw new IllegalStateException("endPosTable already set"); - endPosTable = t; - } - /** Find the line in the buffer that contains the current position * @param pos Character offset into the buffer */ @@ -197,8 +186,6 @@ public class DiagnosticSource { /** The underlying file object. */ protected JavaFileObject fileObject; - protected EndPosTable endPosTable; - /** A soft reference to the content of the file object. */ protected SoftReference refBuf; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/IntHashTable.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/IntHashTable.java deleted file mode 100644 index 409dc703d60..00000000000 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/IntHashTable.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.javac.util; - -/** - * A hash table that maps Object to int. - * - * This is a custom hash table optimised for the Object {@literal ->} int - * maps. This is done to avoid unnecessary object allocation in the image set. - * - * @author Charles Turner - * @author Per Bothner - */ -public class IntHashTable { - private static final int DEFAULT_INITIAL_SIZE = 64; - protected Object[] objs; // the domain set - protected int[] ints; // the image set - protected int mask; // used to clip int's into the domain - protected int num_bindings; // the number of mappings (including DELETED) - private static final Object DELETED = new Object(); - - /** - * Construct an Object {@literal ->} int hash table. - * - * The default size of the hash table is 64 mappings. - */ - public IntHashTable() { - objs = new Object[DEFAULT_INITIAL_SIZE]; - ints = new int[DEFAULT_INITIAL_SIZE]; - mask = DEFAULT_INITIAL_SIZE - 1; - } - - /** - * Construct an Object {@literal ->} int hash table with a specified amount of mappings. - * @param capacity The number of default mappings in this hash table. - */ - public IntHashTable(int capacity) { - int log2Size = 4; - while (capacity > (1 << log2Size)) { - log2Size++; - } - capacity = 1 << log2Size; - objs = new Object[capacity]; - ints = new int[capacity]; - mask = capacity - 1; - } - - /** - * Compute the hash code of a given object. - * - * @param key The object whose hash code is to be computed. - * @return zero if the object is null, otherwise the identityHashCode - */ - protected int hash(Object key) { - return System.identityHashCode(key); - } - - /** - * Find either the index of a key's value, or the index of an available space. - * - * @param key The key to whose index you want to find. - * @return Either the index of the key's value, or an index pointing to - * unoccupied space. - */ - protected int lookup(Object key) { - Object node; - int hash = hash(key); - int hash1 = hash ^ (hash >>> 15); - int hash2 = (hash ^ (hash << 6)) | 1; //ensure coprimeness - int deleted = -1; - for (int i = hash1 & mask;; i = (i + hash2) & mask) { - node = objs[i]; - if (node == key) - return i; - if (node == null) - return deleted >= 0 ? deleted : i; - if (node == DELETED && deleted < 0) - deleted = i; - } - } - - /** - * Return the value to which the specified key is mapped. - * - * @param key The key to whose value you want to find. - * @return A non-negative integer if the value is found. - * Otherwise, it is -1. - */ - public int get(Object key) { - int index = lookup(key); - Object node = objs[index]; - return node == null || node == DELETED ? -1 : ints[index]; - } - - /** - * Associates the specified key with the specified value in this map. - * - * @param key key with which the specified value is to be associated. - * @param value value to be associated with the specified key. - * @return previous value associated with specified key, or -1 if there was - * no mapping for key. - */ - public int put(Object key, int value) { - int index = lookup(key); - Object old = objs[index]; - if (old == null || old == DELETED) { - objs[index] = key; - ints[index] = value; - if (old != DELETED) - num_bindings++; - if (3 * num_bindings >= 2 * objs.length) - rehash(); - return -1; - } else { // update existing mapping - int oldValue = ints[index]; - ints[index] = value; - return oldValue; - } - } - - /** - * Remove the mapping(key and value) of the specified key. - * - * @param key the key to whose value you want to remove. - * @return the removed value associated with the specified key, - * or -1 if there was no mapping for the specified key. - */ - public int remove(Object key) { - int index = lookup(key); - Object old = objs[index]; - if (old == null || old == DELETED) - return -1; - objs[index] = DELETED; - return ints[index]; - } - - /** - * Expand the hash table when it exceeds the load factor. - * - * Rehash the existing objects. - */ - protected void rehash() { - Object[] oldObjsTable = objs; - int[] oldIntsTable = ints; - int newCapacity = oldObjsTable.length << 1; - objs = new Object[newCapacity]; - ints = new int[newCapacity]; - mask = newCapacity - 1; - num_bindings = 0; // this is recomputed below - Object key; - for (int i = oldIntsTable.length; --i >= 0;) { - key = oldObjsTable[i]; - if (key != null && key != DELETED) - put(key, oldIntsTable[i]); - } - } - - /** - * Removes all mappings from this map. - */ - public void clear() { - for (int i = objs.length; --i >= 0;) { - objs[i] = null; - } - num_bindings = 0; - } -} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java index c9f529eae55..328183c0cb3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java @@ -38,7 +38,6 @@ import javax.tools.JavaFileObject; import com.sun.tools.javac.api.DiagnosticFormatter; import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.util.DefinedBy.Api; @@ -364,10 +363,8 @@ public class JCDiagnostic implements Diagnostic { /** Get the position within the file that most accurately defines the * location for the diagnostic. */ int getPreferredPosition(); - /** If there is a tree node, and if endPositions are available, get - * the end position of the tree node. Otherwise, just returns the - * same as getPreferredPosition(). */ - int getEndPosition(EndPosTable endPosTable); + /** If there is a tree node, get the end position of the tree node. */ + int getEndPosition(); /** Get the position that determines which Lint configuration applies. */ default int getLintPosition() { return getStartPosition(); @@ -389,8 +386,8 @@ public class JCDiagnostic implements Diagnostic { return orig.getPreferredPosition(); } @Override - public int getEndPosition(EndPosTable endPosTable) { - return orig.getEndPosition(endPosTable); + public int getEndPosition() { + return orig.getEndPosition(); } @Override public int getLintPosition() { @@ -421,7 +418,7 @@ public class JCDiagnostic implements Diagnostic { return pos; } - public int getEndPosition(EndPosTable endPosTable) { + public int getEndPosition() { return pos; } @@ -747,7 +744,7 @@ public class JCDiagnostic implements Diagnostic { } protected int getIntEndPosition() { - return (position == null ? Position.NOPOS : position.getEndPosition(source.getEndPosTable())); + return (position == null ? Position.NOPOS : position.getEndPosition()); } @DefinedBy(Api.COMPILER) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java index a4109a35ccb..b061d2283a0 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java @@ -55,7 +55,6 @@ import com.sun.tools.javac.comp.AttrContext; import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.main.Main; import com.sun.tools.javac.main.Option; -import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.tree.TreeInfo; @@ -594,11 +593,6 @@ public class Log extends AbstractLog { return diagListener != null; } - public void setEndPosTable(JavaFileObject name, EndPosTable endPosTable) { - Assert.checkNonNull(name); - getSource(name).setEndPosTable(endPosTable); - } - /** Return current sourcefile. */ public JavaFileObject currentSourceFile() { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocLog.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocLog.java index 84c32a4c732..b3bf1c14cb1 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocLog.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocLog.java @@ -55,7 +55,6 @@ import com.sun.source.doctree.TextTree; import com.sun.tools.javac.tree.DCTree.DCDocComment; import com.sun.tools.javac.tree.DCTree; -import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.util.Context.Factory; import com.sun.tools.javac.util.DiagnosticSource; import com.sun.source.tree.CompilationUnitTree; @@ -616,7 +615,7 @@ public class JavadocLog extends Log implements Reporter { } @Override - public int getEndPosition(EndPosTable endPosTable) { + public int getEndPosition() { return end; } }; diff --git a/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java b/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java index 0219fa0eaf8..11fe05fbb98 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java @@ -75,9 +75,8 @@ class ReplParser extends JavacParser { com.sun.tools.javac.parser.Lexer S, boolean keepDocComments, boolean keepLineMap, - boolean keepEndPositions, boolean forceExpression) { - super(fac, S, keepDocComments, keepLineMap, keepEndPositions); + super(fac, S, keepDocComments, keepLineMap); this.forceExpression = forceExpression; this.source = fac.source; } @@ -103,7 +102,7 @@ class ReplParser extends JavacParser { boolean firstTypeDecl = true; while (token.kind != EOF) { - if (token.pos > 0 && token.pos <= endPosTable.errorEndPos) { + if (token.pos > 0 && token.pos <= errorEndPos) { // error recovery skip(true, false, false, false); if (token.kind == EOF) { @@ -141,7 +140,6 @@ class ReplParser extends JavacParser { storeEnd(toplevel, S.prevToken().endPos); } toplevel.lineMap = S.getLineMap(); - toplevel.endPositions = this.endPosTable; return toplevel; } diff --git a/src/jdk.jshell/share/classes/jdk/jshell/ReplParserFactory.java b/src/jdk.jshell/share/classes/jdk/jshell/ReplParserFactory.java index 5c02561807b..3a3b25dade0 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/ReplParserFactory.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/ReplParserFactory.java @@ -60,13 +60,8 @@ class ReplParserFactory extends ParserFactory { } @Override - public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap) { + public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepLineMap, boolean parseModuleInfo) { com.sun.tools.javac.parser.Lexer lexer = scannerFactory.newScanner(input, keepDocComments); - return new ReplParser(this, lexer, keepDocComments, keepLineMap, keepEndPos, forceExpression); - } - - @Override - public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap, boolean parseModuleInfo) { - return newParser(input, keepDocComments, keepEndPos, keepLineMap); + return new ReplParser(this, lexer, keepDocComments, keepLineMap, forceExpression); } } diff --git a/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java b/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java index 13c07ea32c0..0de0e27ec07 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java @@ -819,9 +819,9 @@ class TaskFactory { } @Override - public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap, boolean parseModuleInfo) { + public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepLineMap, boolean parseModuleInfo) { com.sun.tools.javac.parser.Lexer lexer = scannerFactory.newScanner(input, keepDocComments); - return new JavacParser(this, lexer, keepDocComments, keepLineMap, keepEndPos, parseModuleInfo) { + return new JavacParser(this, lexer, keepDocComments, keepLineMap, parseModuleInfo) { @Override public JCExpression parseType(boolean allowVar, com.sun.tools.javac.util.List annotations) { int pos = token.pos; diff --git a/test/langtools/tools/javac/6304921/TestLog.java b/test/langtools/tools/javac/6304921/TestLog.java index 8f00a14b9e2..9d0219accf1 100644 --- a/test/langtools/tools/javac/6304921/TestLog.java +++ b/test/langtools/tools/javac/6304921/TestLog.java @@ -42,7 +42,6 @@ import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.parser.Parser; import com.sun.tools.javac.parser.ParserFactory; import com.sun.tools.javac.resources.CompilerProperties.Warnings; -import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.Context; @@ -96,9 +95,8 @@ public class TestLog CharSequence cs = fo.getCharContent(true); Parser parser = pfac.newParser(cs, false, genEndPos, false); JCTree.JCCompilationUnit tree = parser.parseCompilationUnit(); - log.setEndPosTable(fo, tree.endPositions); - TreeScanner ts = new LogTester(log, tree.endPositions); + TreeScanner ts = new LogTester(log); ts.scan(tree); check(log.nerrors, 4, "errors"); @@ -117,9 +115,8 @@ public class TestLog } private static class LogTester extends TreeScanner { - LogTester(Log log, EndPosTable endPosTable) { + LogTester(Log log) { this.log = log; - this.endPosTable = endPosTable; } public void visitIf(JCTree.JCIf tree) { @@ -138,7 +135,6 @@ public class TestLog } private Log log; - private EndPosTable endPosTable; } private static class StringJavaFileObject extends SimpleJavaFileObject { diff --git a/test/langtools/tools/javac/diags/DiagnosticGetEndPosition.java b/test/langtools/tools/javac/diags/DiagnosticGetEndPosition.java index 1835cd46167..160f358f32f 100644 --- a/test/langtools/tools/javac/diags/DiagnosticGetEndPosition.java +++ b/test/langtools/tools/javac/diags/DiagnosticGetEndPosition.java @@ -118,9 +118,16 @@ public class DiagnosticGetEndPosition { compiler.getTask( null, null, - d -> assertEquals("", //ideally would be "0", but the positions are not fully set yet - implCode.substring((int) d.getStartPosition(), - (int) d.getEndPosition())), + d -> { + // Use line and column instead of start and end positions + // to handle platform-dependent newlines, which could be + // different between the text block and the written file. + int line = (int) d.getLineNumber(); + int col = (int) d.getColumnNumber(); + assertEquals(1, d.getEndPosition() - d.getStartPosition()); + String substring = implCode.split("\\R")[line - 1].substring(col - 1, col); + assertEquals("0", substring); + }, List.of("-sourcepath", src.toString(), "-Xlint:divzero"), null, fm.getJavaFileObjects(src.resolve("test").resolve("Test.java")) diff --git a/test/langtools/tools/javac/failover/CheckAttributedTree.java b/test/langtools/tools/javac/failover/CheckAttributedTree.java index 9b28d2bebd4..050a302bc6e 100644 --- a/test/langtools/tools/javac/failover/CheckAttributedTree.java +++ b/test/langtools/tools/javac/failover/CheckAttributedTree.java @@ -92,7 +92,6 @@ import com.sun.source.util.TaskEvent.Kind; import com.sun.source.util.TaskListener; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCBreak; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; @@ -367,8 +366,7 @@ public class CheckAttributedTree { private class NPETester extends TreeScanner { void test(JCCompilationUnit cut, JCTree tree) { sourcefile = cut.sourcefile; - endPosTable = cut.endPositions; - encl = new Info(tree, endPosTable); + encl = new Info(tree); tree.accept(this); } @@ -379,7 +377,7 @@ public class CheckAttributedTree { return; } - Info self = new Info(tree, endPosTable); + Info self = new Info(tree); if (mandatoryType(tree)) { check(tree.type != null, "'null' field 'type' found in tree ", self); @@ -454,7 +452,6 @@ public class CheckAttributedTree { } JavaFileObject sourcefile; - EndPosTable endPosTable; Info encl; } } @@ -498,12 +495,12 @@ public class CheckAttributedTree { end = Integer.MAX_VALUE; } - Info(JCTree tree, EndPosTable endPosTable) { + Info(JCTree tree) { this.tree = tree; tag = tree.getTag(); start = TreeInfo.getStartPos(tree); pos = tree.pos; - end = TreeInfo.getEndPos(tree, endPosTable); + end = TreeInfo.getEndPos(tree); } @Override diff --git a/test/langtools/tools/javac/parser/DeclarationEndPositions.java b/test/langtools/tools/javac/parser/DeclarationEndPositions.java index 226b77769d1..c61a92e80cd 100644 --- a/test/langtools/tools/javac/parser/DeclarationEndPositions.java +++ b/test/langtools/tools/javac/parser/DeclarationEndPositions.java @@ -78,7 +78,7 @@ public class DeclarationEndPositions { throw new AssertionError(String.format( "wrong %s pos %d for \"%s\" in \"%s\"", "start", start, tree, input)); } - int end = TreeInfo.getEndPos(tree, unit.endPositions); + int end = TreeInfo.getEndPos(tree); if (markers.charAt(end - 1) != '>') { throw new AssertionError(String.format( "wrong %s pos %d for \"%s\" in \"%s\"", "end", end, tree, input)); diff --git a/test/langtools/tools/javac/parser/ReversedSourcePositions.java b/test/langtools/tools/javac/parser/ReversedSourcePositions.java index d092d23d8c1..6596430dca5 100644 --- a/test/langtools/tools/javac/parser/ReversedSourcePositions.java +++ b/test/langtools/tools/javac/parser/ReversedSourcePositions.java @@ -72,7 +72,7 @@ public class ReversedSourcePositions { public Void scan(Tree node, Void aVoid) { if (node instanceof JCTree tree) { int start = tree.getStartPosition(); - int end = tree.getEndPosition(unit.endPositions); + int end = tree.getEndPosition(); if (start >= end) { throw new AssertionError( String.format("[%d, %d] %s %s\n", start, end, tree.getKind(), tree)); diff --git a/test/langtools/tools/javac/parser/extend/TrialParser.java b/test/langtools/tools/javac/parser/extend/TrialParser.java index c9a858fbc47..ca4e3995bc3 100644 --- a/test/langtools/tools/javac/parser/extend/TrialParser.java +++ b/test/langtools/tools/javac/parser/extend/TrialParser.java @@ -66,9 +66,8 @@ class TrialParser extends JavacParser { public TrialParser(ParserFactory fac, com.sun.tools.javac.parser.Lexer S, boolean keepDocComments, - boolean keepLineMap, - boolean keepEndPositions) { - super(fac, S, keepDocComments, keepLineMap, keepEndPositions); + boolean keepLineMap) { + super(fac, S, keepDocComments, keepLineMap); } @Override @@ -102,7 +101,7 @@ class TrialParser extends JavacParser { boolean firstTypeDecl = true; while (token.kind != EOF) { - if (token.pos > 0 && token.pos <= endPosTable.errorEndPos) { + if (token.pos > 0 && token.pos <= errorEndPos) { // error recovery skip(true, false, false, false); if (token.kind == EOF) { @@ -139,7 +138,6 @@ class TrialParser extends JavacParser { storeEnd(toplevel, S.prevToken().endPos); } toplevel.lineMap = S.getLineMap(); - toplevel.endPositions = this.endPosTable; return toplevel; } diff --git a/test/langtools/tools/javac/parser/extend/TrialParserFactory.java b/test/langtools/tools/javac/parser/extend/TrialParserFactory.java index 6ac4c60d279..6f62175c82a 100644 --- a/test/langtools/tools/javac/parser/extend/TrialParserFactory.java +++ b/test/langtools/tools/javac/parser/extend/TrialParserFactory.java @@ -48,13 +48,8 @@ class TrialParserFactory extends ParserFactory { } @Override - public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap) { + public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepLineMap, boolean parseModuleInfo) { com.sun.tools.javac.parser.Lexer lexer = scannerFactory.newScanner(input, keepDocComments); - return new TrialParser(this, lexer, keepDocComments, keepLineMap, keepEndPos); - } - - @Override - public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap, boolean parseModuleInfo) { - return newParser(input, keepDocComments, keepEndPos, keepLineMap); + return new TrialParser(this, lexer, keepDocComments, keepLineMap); } } diff --git a/test/langtools/tools/javac/tree/MissingSemicolonTest.java b/test/langtools/tools/javac/tree/MissingSemicolonTest.java index 2c70c4841be..cedcf1e5f98 100644 --- a/test/langtools/tools/javac/tree/MissingSemicolonTest.java +++ b/test/langtools/tools/javac/tree/MissingSemicolonTest.java @@ -115,7 +115,7 @@ public class MissingSemicolonTest { public Void scan(Tree tree, Void p) { if (tree != null) { int start = ((JCTree) tree).getStartPosition(); - int end = ((JCTree) tree).getEndPosition(unit.endPositions); + int end = ((JCTree) tree).getEndPosition(); spans.add(new int[] {start, end}); } @@ -134,7 +134,7 @@ public class MissingSemicolonTest { public Void scan(Tree tree, Void p) { if (tree != null) { int start = ((JCTree) tree).getStartPosition(); - int end = ((JCTree) tree).getEndPosition(updated.endPositions); + int end = ((JCTree) tree).getEndPosition(); if (tree.getKind() != Kind.ERRONEOUS) { int[] expected = nextSpan.next(); diff --git a/test/langtools/tools/javac/tree/TreePosTest.java b/test/langtools/tools/javac/tree/TreePosTest.java index 9e6dcf61306..ecc0d477cdb 100644 --- a/test/langtools/tools/javac/tree/TreePosTest.java +++ b/test/langtools/tools/javac/tree/TreePosTest.java @@ -69,7 +69,6 @@ import com.sun.source.tree.CompilationUnitTree; import com.sun.tools.javac.api.JavacTaskPool; import com.sun.tools.javac.api.JavacTool; import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotatedType; import com.sun.tools.javac.tree.JCTree.JCCase; @@ -347,7 +346,6 @@ public class TreePosTest { private boolean compactSourceFile; void test(JCCompilationUnit tree) { sourcefile = tree.sourcefile; - endPosTable = tree.endPositions; encl = new Info(); List nonImports = tree.defs .stream() @@ -355,7 +353,7 @@ public class TreePosTest { .toList(); compactSourceFile = nonImports.size() == 1 && nonImports.get(0) instanceof JCClassDecl classDecl && - tree.endPositions.getEndPos(classDecl) == NOPOS; + classDecl.endpos == NOPOS; tree.accept(this); } @@ -364,7 +362,7 @@ public class TreePosTest { if (tree == null) return; - Info self = new Info(tree, endPosTable); + Info self = new Info(tree); if (check(encl, self)) { // Modifiers nodes are present throughout the tree even where // there is no corresponding source text. @@ -504,7 +502,6 @@ public class TreePosTest { } JavaFileObject sourcefile; - EndPosTable endPosTable; Info encl; } @@ -521,12 +518,12 @@ public class TreePosTest { end = Integer.MAX_VALUE; } - Info(JCTree tree, EndPosTable endPosTable) { + Info(JCTree tree) { this.tree = tree; tag = tree.getTag(); start = TreeInfo.getStartPos(tree); pos = tree.pos; - end = TreeInfo.getEndPos(tree, endPosTable); + end = TreeInfo.getEndPos(tree); } @Override From 3f3dcb708d2e8326c96c42566fa765a878e68bf6 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Wed, 4 Feb 2026 08:41:38 +0000 Subject: [PATCH 320/328] 8376810: Make Atomic default constructor non-explicit Reviewed-by: kbarrett, aboldtch, azafari, tschatzl --- src/hotspot/share/runtime/atomic.hpp | 14 ++-- test/hotspot/gtest/runtime/test_atomic.cpp | 87 +++++++++++++++++++++- 2 files changed, 95 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/runtime/atomic.hpp b/src/hotspot/share/runtime/atomic.hpp index f708e9c18ca..894e04eec57 100644 --- a/src/hotspot/share/runtime/atomic.hpp +++ b/src/hotspot/share/runtime/atomic.hpp @@ -58,9 +58,10 @@ // ValueType -> T // // special functions: -// explicit constructor(T) +// constexpr constructor() // See (2) below +// explicit constexpr constructor(T) // noncopyable -// destructor +// destructor // Trivial // // static member functions: // value_offset_in_bytes() -> int // constexpr @@ -343,7 +344,8 @@ class AtomicImpl::Atomic : public SupportsArithmetic { public: - explicit constexpr Atomic(T value = 0) : SupportsArithmetic(value) {} + constexpr Atomic() : Atomic(0) {} + explicit constexpr Atomic(T value) : SupportsArithmetic(value) {} NONCOPYABLE(Atomic); @@ -383,7 +385,8 @@ class AtomicImpl::Atomic : public CommonCore { public: - explicit constexpr Atomic(T value = 0) : CommonCore(value) {} + constexpr Atomic() : Atomic(0) {} + explicit constexpr Atomic(T value) : CommonCore(value) {} NONCOPYABLE(Atomic); @@ -399,7 +402,8 @@ class AtomicImpl::Atomic : public SupportsArithmetic { public: - explicit constexpr Atomic(T value = nullptr) : SupportsArithmetic(value) {} + constexpr Atomic() : Atomic(nullptr) {} + explicit constexpr Atomic(T value) : SupportsArithmetic(value) {} NONCOPYABLE(Atomic); diff --git a/test/hotspot/gtest/runtime/test_atomic.cpp b/test/hotspot/gtest/runtime/test_atomic.cpp index 753dde0ca57..80e67ef0bf9 100644 --- a/test/hotspot/gtest/runtime/test_atomic.cpp +++ b/test/hotspot/gtest/runtime/test_atomic.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,15 +22,100 @@ * */ +#include "cppstdlib/new.hpp" #include "cppstdlib/type_traits.hpp" #include "metaprogramming/primitiveConversions.hpp" #include "runtime/atomic.hpp" +#include "runtime/os.hpp" #include "unittest.hpp" // These tests of Atomic only verify functionality. They don't verify // atomicity. +template +struct AtomicInitializationTestSupport { + struct Holder { + Atomic _explicitly_initialized; + Atomic _default_initialized; + Atomic _value_initialized; + + Holder() + : _explicitly_initialized(T()), + /* _default_initialized */ + _value_initialized{} + {} + }; + + struct HolderNoConstructor { + Atomic _default_initialized; + }; + + void test() { + T t = T(); + + { + Holder h; + + EXPECT_EQ(t, h._explicitly_initialized.load_relaxed()); + EXPECT_EQ(t, h._default_initialized.load_relaxed()); + EXPECT_EQ(t, h._value_initialized.load_relaxed()); + } + + { + Holder h{}; + + EXPECT_EQ(t, h._explicitly_initialized.load_relaxed()); + EXPECT_EQ(t, h._default_initialized.load_relaxed()); + EXPECT_EQ(t, h._value_initialized.load_relaxed()); + } + + { + alignas(Holder) char mem[sizeof(Holder)]; + memset(mem, 0xFF, sizeof(Holder)); + Holder* h = new (mem) Holder(); + + EXPECT_EQ(t, h->_explicitly_initialized.load_relaxed()); + EXPECT_EQ(t, h->_default_initialized.load_relaxed()); + EXPECT_EQ(t, h->_value_initialized.load_relaxed()); + } + + // No-constructor variant + + { + HolderNoConstructor h; + + EXPECT_EQ(t, h._default_initialized.load_relaxed()); + } + + { + HolderNoConstructor h{}; + + EXPECT_EQ(t, h._default_initialized.load_relaxed()); + } + + { + alignas(HolderNoConstructor) char mem[sizeof(HolderNoConstructor)]; + memset(mem, 0xFF, sizeof(HolderNoConstructor)); + HolderNoConstructor* h = new (mem) HolderNoConstructor(); + + EXPECT_EQ(t, h->_default_initialized.load_relaxed()); + } + } +}; + +TEST_VM(AtomicInitializationTest, byte) { + AtomicInitializationTestSupport().test(); +} + +TEST_VM(AtomicInitializationTest, integer) { + AtomicInitializationTestSupport().test(); +} + +TEST_VM(AtomicInitializationTest, pointer) { + AtomicInitializationTestSupport().test(); +} + template struct AtomicIntegerArithmeticTestSupport { Atomic _test_value; From 651e01b44747574a4882e7cdd9f6d3b54d2280f9 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Wed, 4 Feb 2026 09:13:52 +0000 Subject: [PATCH 321/328] 8369393: NMT: poison the malloc header and footer under ASAN build Reviewed-by: jsjolen, phubner --- src/hotspot/share/nmt/mallocHeader.cpp | 2 +- src/hotspot/share/nmt/mallocHeader.hpp | 17 +++- src/hotspot/share/nmt/mallocHeader.inline.hpp | 39 +++++++--- src/hotspot/share/nmt/mallocTracker.cpp | 5 +- src/hotspot/share/nmt/mallocTracker.hpp | 9 --- src/hotspot/share/runtime/os.cpp | 65 +++++++--------- .../test_nmt_buffer_overflow_detection.cpp | 78 ++++++++++++++++++- .../gtest/nmt/test_nmt_cornercases.cpp | 7 +- .../NMTPrintMallocSiteOfCorruptedMemory.java | 2 + 9 files changed, 153 insertions(+), 71 deletions(-) diff --git a/src/hotspot/share/nmt/mallocHeader.cpp b/src/hotspot/share/nmt/mallocHeader.cpp index d88b5c790fb..e74e74fde48 100644 --- a/src/hotspot/share/nmt/mallocHeader.cpp +++ b/src/hotspot/share/nmt/mallocHeader.cpp @@ -75,4 +75,4 @@ void MallocHeader::print_block_on_error(outputStream* st, address bad_address, a // print one hex dump os::print_hex_dump(st, from1, to2, 1); } -} +} \ No newline at end of file diff --git a/src/hotspot/share/nmt/mallocHeader.hpp b/src/hotspot/share/nmt/mallocHeader.hpp index 45568243ef3..33e288dd8e4 100644 --- a/src/hotspot/share/nmt/mallocHeader.hpp +++ b/src/hotspot/share/nmt/mallocHeader.hpp @@ -27,10 +27,18 @@ #define SHARE_NMT_MALLOCHEADER_HPP #include "nmt/memTag.hpp" +#include "sanitizers/address.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/nativeCallStack.hpp" +// With ASAN, we omit NMT block integrity checks since ASAN does a better and faster +// job of alerting us to memory corruptions +#if INCLUDE_ASAN +#undef NMT_BLOCK_INTEGRITY_CHECKS +#else +#define NMT_BLOCK_INTEGRITY_CHECKS +#endif class outputStream; /* @@ -118,6 +126,7 @@ class MallocHeader { inline static OutTypeParam resolve_checked_impl(InTypeParam memblock); public: + static constexpr size_t footer_size = sizeof(uint16_t); // Contains all of the necessary data to to deaccount block with NMT. struct FreeInfo { const size_t size; @@ -126,8 +135,9 @@ public: }; inline MallocHeader(size_t size, MemTag mem_tag, uint32_t mst_marker); - - inline static size_t malloc_overhead() { return sizeof(MallocHeader) + sizeof(uint16_t); } + inline static size_t malloc_overhead() { return sizeof(MallocHeader) + footer_size; } + inline static MallocHeader* kill_block(void* memblock); + inline static void revive_block(void* memblock); inline size_t size() const { return _size; } inline MemTag mem_tag() const { return _mem_tag; } inline uint32_t mst_marker() const { return _mst_marker; } @@ -164,5 +174,4 @@ public: // This needs to be true on both 64-bit and 32-bit platforms STATIC_ASSERT(sizeof(MallocHeader) == (sizeof(uint64_t) * 2)); - -#endif // SHARE_NMT_MALLOCHEADER_HPP +#endif // SHARE_NMT_MALLOCHEADER_HPP \ No newline at end of file diff --git a/src/hotspot/share/nmt/mallocHeader.inline.hpp b/src/hotspot/share/nmt/mallocHeader.inline.hpp index 0ad0b3ddc81..09ab872c780 100644 --- a/src/hotspot/share/nmt/mallocHeader.inline.hpp +++ b/src/hotspot/share/nmt/mallocHeader.inline.hpp @@ -46,9 +46,6 @@ inline MallocHeader::MallocHeader(size_t size, MemTag mem_tag, uint32_t mst_mark } inline void MallocHeader::revive() { - assert(_canary == _header_canary_dead_mark, "must be dead"); - assert(get_footer() == _footer_canary_dead_mark, "must be dead"); - NOT_LP64(assert(_alt_canary == _header_alt_canary_dead_mark, "must be dead")); _canary = _header_canary_live_mark; NOT_LP64(_alt_canary = _header_alt_canary_live_mark); set_footer(_footer_canary_live_mark); @@ -96,16 +93,18 @@ inline bool MallocHeader::is_valid_malloced_pointer(const void* payload, char* m template inline OutTypeParam MallocHeader::resolve_checked_impl(InTypeParam memblock) { - char msg[256]; - address corruption = nullptr; - if (!is_valid_malloced_pointer(memblock, msg, sizeof(msg))) { - fatal("Not a valid malloc pointer: " PTR_FORMAT ": %s", p2i(memblock), msg); - } OutTypeParam header_pointer = (OutTypeParam)memblock - 1; - if (!header_pointer->check_block_integrity(msg, sizeof(msg), &corruption)) { - header_pointer->print_block_on_error(tty, corruption != nullptr ? corruption : (address)header_pointer, (address)header_pointer); - fatal("NMT has detected a memory corruption bug. Block at " PTR_FORMAT ": %s", p2i(memblock), msg); - } + #ifdef NMT_BLOCK_INTEGRITY_CHECKS + char msg[256]; + address corruption = nullptr; + if (!is_valid_malloced_pointer(memblock, msg, sizeof(msg))) { + fatal("Not a valid malloc pointer: " PTR_FORMAT ": %s", p2i(memblock), msg); + } + if (!header_pointer->check_block_integrity(msg, sizeof(msg), &corruption)) { + header_pointer->print_block_on_error(tty, corruption != nullptr ? corruption : (address)header_pointer, (address)header_pointer); + fatal("NMT has detected a memory corruption bug. Block at " PTR_FORMAT ": %s", p2i(memblock), msg); + } + #endif return header_pointer; } @@ -163,4 +162,20 @@ inline bool MallocHeader::check_block_integrity(char* msg, size_t msglen, addres return true; } +MallocHeader* MallocHeader::kill_block(void* memblock) { + MallocHeader* header = (MallocHeader*)memblock - 1; + ASAN_UNPOISON_MEMORY_REGION(header, sizeof(MallocHeader)); + ASAN_UNPOISON_MEMORY_REGION(header->footer_address(), footer_size); + resolve_checked(memblock); + header->mark_block_as_dead(); + return header; +} + +void MallocHeader::revive_block(void* memblock) { + MallocHeader* header = (MallocHeader*)memblock - 1; + header->revive(); + ASAN_POISON_MEMORY_REGION(header->footer_address(), footer_size); + ASAN_POISON_MEMORY_REGION(header, sizeof(MallocHeader)); +} + #endif // SHARE_NMT_MALLOCHEADER_INLINE_HPP diff --git a/src/hotspot/share/nmt/mallocTracker.cpp b/src/hotspot/share/nmt/mallocTracker.cpp index 2cf5034c0bf..532b6f41bd0 100644 --- a/src/hotspot/share/nmt/mallocTracker.cpp +++ b/src/hotspot/share/nmt/mallocTracker.cpp @@ -199,7 +199,7 @@ void* MallocTracker::record_malloc(void* malloc_base, size_t size, MemTag mem_ta assert(header2->mem_tag() == mem_tag, "Wrong memory tag"); } #endif - + MallocHeader::revive_block(memblock); return memblock; } @@ -207,7 +207,7 @@ void* MallocTracker::record_free_block(void* memblock) { assert(MemTracker::enabled(), "Sanity"); assert(memblock != nullptr, "precondition"); - MallocHeader* header = MallocHeader::resolve_checked(memblock); + MallocHeader* header = MallocHeader::kill_block(memblock); deaccount(header->free_info()); @@ -218,7 +218,6 @@ void* MallocTracker::record_free_block(void* memblock) { } header->mark_block_as_dead(); - return (void*)header; } diff --git a/src/hotspot/share/nmt/mallocTracker.hpp b/src/hotspot/share/nmt/mallocTracker.hpp index fc03faf7212..e96396ebbcb 100644 --- a/src/hotspot/share/nmt/mallocTracker.hpp +++ b/src/hotspot/share/nmt/mallocTracker.hpp @@ -311,15 +311,6 @@ class MallocTracker : AllStatic { // totally failproof. Only use this during debugging or when you can afford // signals popping up, e.g. when writing an hs_err file. static bool print_pointer_information(const void* p, outputStream* st); - - static inline MallocHeader* malloc_header(void *memblock) { - assert(memblock != nullptr, "null pointer"); - return (MallocHeader*)memblock -1; - } - static inline const MallocHeader* malloc_header(const void *memblock) { - assert(memblock != nullptr, "null pointer"); - return (const MallocHeader*)memblock -1; - } }; #endif // SHARE_NMT_MALLOCTRACKER_HPP diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 57971897400..3a5a5745095 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -702,57 +702,50 @@ void* os::realloc(void *memblock, size_t size, MemTag mem_tag, const NativeCallS if (new_outer_size < size) { return nullptr; } - - const size_t old_size = MallocTracker::malloc_header(memblock)->size(); - - // Observe MallocLimit - if ((size > old_size) && MemTracker::check_exceeds_limit(size - old_size, mem_tag)) { - return nullptr; - } + MallocHeader* header = MallocHeader::kill_block(memblock); + const size_t old_size = header->size(); // Perform integrity checks on and mark the old block as dead *before* calling the real realloc(3) since it // may invalidate the old block, including its header. - MallocHeader* header = MallocHeader::resolve_checked(memblock); assert(mem_tag == header->mem_tag(), "weird NMT type mismatch (new:\"%s\" != old:\"%s\")\n", NMTUtil::tag_to_name(mem_tag), NMTUtil::tag_to_name(header->mem_tag())); - const MallocHeader::FreeInfo free_info = header->free_info(); - - header->mark_block_as_dead(); - - // the real realloc - void* const new_outer_ptr = permit_forbidden_function::realloc(header, new_outer_size); - - if (new_outer_ptr == nullptr) { - // realloc(3) failed and the block still exists. - // We have however marked it as dead, revert this change. - header->revive(); - return nullptr; - } - // realloc(3) succeeded, variable header now points to invalid memory and we need to deaccount the old block. - MemTracker::deaccount(free_info); - - // After a successful realloc(3), we account the resized block with its new size - // to NMT. - void* const new_inner_ptr = MemTracker::record_malloc(new_outer_ptr, size, mem_tag, stack); + bool within_malloc_limit = !((size > old_size) && MemTracker::check_exceeds_limit(size - old_size, mem_tag)); + bool success = within_malloc_limit; + // Observe MallocLimit + if (success) { + // If realloc succeeds, the header is freed. Get FreeInfo before that. + MallocHeader::FreeInfo free_info = header->free_info(); + void* const new_outer_ptr = permit_forbidden_function::realloc(header, new_outer_size); + success = new_outer_ptr != nullptr; + if (success) { + // realloc(3) succeeded, variable header now points to invalid memory and we need to deaccount the old block. + MemTracker::deaccount(free_info); + // After a successful realloc(3), we account the resized block with its new size + // to NMT. + void* const new_inner_ptr = MemTracker::record_malloc(new_outer_ptr, size, mem_tag, stack); #ifdef ASSERT - assert(old_size == free_info.size, "Sanity"); - if (ZapCHeap && old_size < size) { - // We also zap the newly extended region. - ::memset((char*)new_inner_ptr + old_size, uninitBlockPad, size - old_size); - } + if (ZapCHeap && old_size < size) { + // We also zap the newly extended region. + ::memset((char*)new_inner_ptr + old_size, uninitBlockPad, size - old_size); + } #endif - rc = new_inner_ptr; - + rc = new_inner_ptr; + } + } + if (!success) { + // realloc(3) failed and the block still exists. + // We have however marked it as dead, revert this change. + MallocHeader::revive_block(memblock); + return nullptr; + } } else { - // NMT disabled. rc = permit_forbidden_function::realloc(memblock, size); if (rc == nullptr) { return nullptr; } - } DEBUG_ONLY(break_if_ptr_caught(rc);) diff --git a/test/hotspot/gtest/nmt/test_nmt_buffer_overflow_detection.cpp b/test/hotspot/gtest/nmt/test_nmt_buffer_overflow_detection.cpp index 5752d6df75d..c65808d3f4d 100644 --- a/test/hotspot/gtest/nmt/test_nmt_buffer_overflow_detection.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_buffer_overflow_detection.cpp @@ -32,8 +32,6 @@ #include "unittest.hpp" #include "testutils.hpp" -#if !INCLUDE_ASAN - // This prefix shows up on any c heap corruption NMT detects. If unsure which assert will // come, just use this one. #define COMMON_NMT_HEAP_CORRUPTION_MESSAGE_PREFIX "NMT has detected a memory corruption bug." @@ -52,6 +50,8 @@ /////// +#if !INCLUDE_ASAN + static void test_overwrite_front() { address p = (address) os::malloc(1, mtTest); *(p - 1) = 'a'; @@ -190,4 +190,78 @@ TEST_VM_FATAL_ERROR_MSG(NMT, memory_corruption_call_stack, ".*header canary.*") os::free(p); } +#else // ASAN is enabled + +#define DEFINE_ASAN_TEST(test_function) \ + DEFINE_TEST(test_function, ".*AddressSanitizer.*") + +static void test_write_header() { + const size_t SIZE = 10; + char* p = (char*)os::malloc(SIZE, mtTest); + // sizeof(MallocHeader) == 16, pick anywheree in [p - 16, p) + *(uint16_t*)((char*)p - 5) = 1; +} + +static void test_read_header() { + const size_t SIZE = 10; + char* p = (char*)os::malloc(SIZE, mtTest); + // sizeof(MallocHeader) == 16, pick anywheree in [p - 16, p) + uint16_t read_canary = *(uint16_t*)((char*)p - 5); +} + +static void test_write_footer() { + const size_t SIZE = 10; + char* p = (char*)os::malloc(SIZE, mtTest); + uint16_t* footer_ptr = (uint16_t*)(p + SIZE); + *footer_ptr = 1; +} + +static void test_read_footer() { + const size_t SIZE = 10; + char* p = (char*)os::malloc(SIZE, mtTest); + uint16_t* footer_ptr = (uint16_t*)(p + SIZE); + uint16_t read_footer = *footer_ptr; +} + +static void test_write_header_after_realloc() { + const size_t SIZE = 10; + char* p = (char*)os::malloc(SIZE, mtTest); + p = (char*)os::realloc(p, 2 * SIZE, mtTest); + // sizeof(MallocHeader) == 16, pick anywheree in [p - 16, p) + *(uint16_t*)((char*)p - 5) = 1; +} + +static void test_read_header_after_realloc() { + const size_t SIZE = 10; + char* p = (char*)os::malloc(SIZE, mtTest); + p = (char*)os::realloc(p, 2 * SIZE, mtTest); + // sizeof(MallocHeader) == 16, pick anywheree in [p - 16, p) + uint16_t read_canary = *(uint16_t*)((char*)p - 5); +} + +static void test_write_footer_after_realloc() { + const size_t SIZE = 10; + char* p = (char*)os::malloc(SIZE, mtTest); + p = (char*)os::realloc(p, 2 * SIZE, mtTest); + uint16_t* footer_ptr = (uint16_t*)(p + 2 * SIZE); + *footer_ptr = 1; +} + +static void test_read_footer_after_realloc() { + const size_t SIZE = 10; + char* p = (char*)os::malloc(SIZE, mtTest); + p = (char*)os::realloc(p, 2 * SIZE, mtTest); + uint16_t* footer_ptr = (uint16_t*)(p + 2 * SIZE); + uint16_t read_footer = *footer_ptr; +} + +DEFINE_ASAN_TEST(test_write_header); +DEFINE_ASAN_TEST(test_read_header); +DEFINE_ASAN_TEST(test_write_footer); +DEFINE_ASAN_TEST(test_read_footer); +DEFINE_ASAN_TEST(test_write_header_after_realloc); +DEFINE_ASAN_TEST(test_read_header_after_realloc); +DEFINE_ASAN_TEST(test_write_footer_after_realloc); +DEFINE_ASAN_TEST(test_read_footer_after_realloc); + #endif // !INCLUDE_ASAN diff --git a/test/hotspot/gtest/nmt/test_nmt_cornercases.cpp b/test/hotspot/gtest/nmt/test_nmt_cornercases.cpp index d1da65cb396..24ab9888521 100644 --- a/test/hotspot/gtest/nmt/test_nmt_cornercases.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_cornercases.cpp @@ -88,7 +88,6 @@ TEST_VM(NMT, realloc_failure_overflowing_size) { TEST_VM(NMT, realloc_failure_gigantic_size) { check_failing_realloc(SIZE_MAX - M); } -#endif // !INCLUDE_ASAN static void* do_realloc(void* p, size_t old_size, size_t new_size, uint8_t old_content, bool check_nmt_header) { @@ -154,8 +153,8 @@ TEST_VM(NMT, HeaderKeepsIntegrityAfterRevival) { size_t some_size = 16; void* p = os::malloc(some_size, mtTest); ASSERT_NOT_NULL(p) << "Failed to malloc()"; - MallocHeader* hdr = MallocTracker::malloc_header(p); - hdr->mark_block_as_dead(); - hdr->revive(); + MallocHeader* hdr = MallocHeader::kill_block(p); + MallocHeader::revive_block(p); check_expected_malloc_header(p, mtTest, some_size); } +#endif // !INCLUDE_ASAN \ No newline at end of file diff --git a/test/hotspot/jtreg/runtime/NMT/NMTPrintMallocSiteOfCorruptedMemory.java b/test/hotspot/jtreg/runtime/NMT/NMTPrintMallocSiteOfCorruptedMemory.java index 7f0f1be929b..f1d4964d6cf 100644 --- a/test/hotspot/jtreg/runtime/NMT/NMTPrintMallocSiteOfCorruptedMemory.java +++ b/test/hotspot/jtreg/runtime/NMT/NMTPrintMallocSiteOfCorruptedMemory.java @@ -24,6 +24,8 @@ /* * @test * @summary Check the allocation-site stack trace of a corrupted memory at free() time + * @comment Under ASAN build, memory corruption is reported by ASAN runtime and not JVM. + * @requires !vm.asan * @modules java.base/jdk.internal.misc * @library /test/lib * @build jdk.test.whitebox.WhiteBox From c5e973e03418d6528fce1aa4a68e0b07a82036ac Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Wed, 4 Feb 2026 09:14:24 +0000 Subject: [PATCH 322/328] 8374622: StressIncrementalInlining should also randomize the processing order Reviewed-by: thartmann, chagedorn, dfenacci --- src/hotspot/share/opto/compile.cpp | 31 +++++++++++++++++++++++------- src/hotspot/share/opto/compile.hpp | 8 ++++++++ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index c4c9445b61a..77b7636a150 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -2171,6 +2171,21 @@ void Compile::inline_incrementally_cleanup(PhaseIterGVN& igvn) { print_method(PHASE_INCREMENTAL_INLINE_CLEANUP, 3); } +template +static void shuffle_array(Compile& C, GrowableArray& array) { + if (array.length() < 2) { + return; + } + for (uint i = array.length() - 1; i >= 1; i--) { + uint j = C.random() % (i + 1); + swap(array.at(i), array.at(j)); + } +} + +void Compile::shuffle_late_inlines() { + shuffle_array(*C, _late_inlines); +} + // Perform incremental inlining until bound on number of live nodes is reached void Compile::inline_incrementally(PhaseIterGVN& igvn) { TracePhase tp(_t_incrInline); @@ -2178,6 +2193,10 @@ void Compile::inline_incrementally(PhaseIterGVN& igvn) { set_inlining_incrementally(true); uint low_live_nodes = 0; + if (StressIncrementalInlining) { + shuffle_late_inlines(); + } + while (_late_inlines.length() > 0) { if (live_nodes() > (uint)LiveNodeCountInliningCutoff) { if (low_live_nodes < (uint)LiveNodeCountInliningCutoff * 8 / 10) { @@ -2250,6 +2269,10 @@ void Compile::process_late_inline_calls_no_inline(PhaseIterGVN& igvn) { assert(_modified_nodes == nullptr, "not allowed"); assert(_late_inlines.length() > 0, "sanity"); + if (StressIncrementalInlining) { + shuffle_late_inlines(); + } + while (_late_inlines.length() > 0) { igvn_worklist()->ensure_empty(); // should be done with igvn @@ -5141,13 +5164,7 @@ void CloneMap::dump(node_idx_t key, outputStream* st) const { } void Compile::shuffle_macro_nodes() { - if (_macro_nodes.length() < 2) { - return; - } - for (uint i = _macro_nodes.length() - 1; i >= 1; i--) { - uint j = C->random() % (i + 1); - swap(_macro_nodes.at(i), _macro_nodes.at(j)); - } + shuffle_array(*C, _macro_nodes); } // Move Allocate nodes to the start of the list diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index d9a8ea15724..eb6be669f24 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -795,6 +795,7 @@ public: void remove_from_merge_stores_igvn(Node* n); void process_for_merge_stores_igvn(PhaseIterGVN& igvn); + void shuffle_late_inlines(); void shuffle_macro_nodes(); void sort_macro_nodes(); @@ -1059,6 +1060,13 @@ public: // Record this CallGenerator for inlining at the end of parsing. void add_late_inline(CallGenerator* cg) { _late_inlines.insert_before(_late_inlines_pos, cg); + if (StressIncrementalInlining) { + assert(_late_inlines_pos < _late_inlines.length(), "unthinkable!"); + if (_late_inlines.length() - _late_inlines_pos >= 2) { + int j = (C->random() % (_late_inlines.length() - _late_inlines_pos)) + _late_inlines_pos; + swap(_late_inlines.at(_late_inlines_pos), _late_inlines.at(j)); + } + } _late_inlines_pos++; } From 848171a6ccc6c3610b8de0c871d0082204369bee Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Wed, 4 Feb 2026 09:51:31 +0000 Subject: [PATCH 323/328] 8374782: Parallel: Remove specialized objArray iteration code Reviewed-by: tschatzl, ayang --- .../share/gc/parallel/psPromotionManager.cpp | 34 ++++++------------- .../share/gc/parallel/psPromotionManager.hpp | 3 +- .../gc/parallel/psPromotionManager.inline.hpp | 2 +- 3 files changed, 12 insertions(+), 27 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.cpp b/src/hotspot/share/gc/parallel/psPromotionManager.cpp index a41a9403082..d6208755374 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.cpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.cpp @@ -43,6 +43,7 @@ #include "memory/resourceArea.hpp" #include "oops/access.inline.hpp" #include "oops/compressedOops.inline.hpp" +#include "oops/oopsHierarchy.hpp" #include "utilities/checkedCast.hpp" PaddedEnd* PSPromotionManager::_manager_array = nullptr; @@ -248,30 +249,19 @@ void PSPromotionManager::flush_labs() { } } -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; - T* const chunk_end = base + end; - while (p < chunk_end) { - claim_or_forward_depth(p); - ++p; - } +void PSPromotionManager::process_array_chunk(objArrayOop obj, size_t start, size_t end) { + PSPushContentsClosure pcc(this); + obj->oop_iterate_elements_range(&pcc, + checked_cast(start), + checked_cast(end)); } void PSPromotionManager::process_array_chunk(PartialArrayState* state, bool stolen) { // Access before release by claim(). - oop new_obj = state->destination(); + objArrayOop to_array = objArrayOop(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(new_obj, start, end); - } else { - process_array_chunk_work(new_obj, start, end); - } + process_array_chunk(to_array, claim._start, claim._end); } void PSPromotionManager::push_objArray(oop old_obj, oop new_obj) { @@ -284,12 +274,8 @@ void PSPromotionManager::push_objArray(oop old_obj, oop new_obj) { 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(to_array, 0, end); - } else { - process_array_chunk_work(to_array, 0, end); - } + + process_array_chunk(to_array, 0, initial_chunk_size); } oop PSPromotionManager::oop_promotion_failed(oop obj, markWord obj_mark) { diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.hpp index 44df708eea4..2b0fc56c0bf 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.hpp @@ -97,9 +97,8 @@ class PSPromotionManager { inline static PSPromotionManager* manager_array(uint index); - template void process_array_chunk_work(oop obj, - int start, int end); void process_array_chunk(PartialArrayState* state, bool stolen); + void process_array_chunk(objArrayOop obj, size_t start, size_t end); void push_objArray(oop old_obj, oop new_obj); inline void promotion_trace_event(oop new_obj, Klass* klass, size_t obj_size, diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index f1fd49c7dfe..9e904e44b22 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -51,7 +51,7 @@ inline PSPromotionManager* PSPromotionManager::manager_array(uint index) { } template -inline void PSPromotionManager::claim_or_forward_depth(T* p) { +ALWAYSINLINE void PSPromotionManager::claim_or_forward_depth(T* p) { assert(ParallelScavengeHeap::heap()->is_in(p), "pointer outside heap"); T heap_oop = RawAccess<>::oop_load(p); if (PSScavenge::is_obj_in_young(heap_oop)) { From 13029e128ac7183af83234a031c62462aae14fad Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Wed, 4 Feb 2026 10:11:25 +0000 Subject: [PATCH 324/328] 8372942: AArch64: Set JVM flags for Neoverse V3AE core Reviewed-by: aph, fgao --- .../cpu/aarch64/vm_version_aarch64.cpp | 28 ++++++------------- .../cpu/aarch64/vm_version_aarch64.hpp | 27 ++++++++++++++++-- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 659c231464a..3fa85f8f47d 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -201,16 +201,14 @@ void VM_Version::initialize() { } } - // Cortex A53 - if (_cpu == CPU_ARM && model_is(0xd03)) { + if (_cpu == CPU_ARM && model_is(CPU_MODEL_ARM_CORTEX_A53)) { set_feature(CPU_A53MAC); if (FLAG_IS_DEFAULT(UseSIMDForArrayEquals)) { FLAG_SET_DEFAULT(UseSIMDForArrayEquals, false); } } - // Cortex A73 - if (_cpu == CPU_ARM && model_is(0xd09)) { + if (_cpu == CPU_ARM && model_is(CPU_MODEL_ARM_CORTEX_A73)) { if (FLAG_IS_DEFAULT(SoftwarePrefetchHintDistance)) { FLAG_SET_DEFAULT(SoftwarePrefetchHintDistance, -1); } @@ -220,16 +218,11 @@ void VM_Version::initialize() { } } - // Neoverse - // N1: 0xd0c - // N2: 0xd49 - // N3: 0xd8e - // V1: 0xd40 - // V2: 0xd4f - // V3: 0xd84 - if (_cpu == CPU_ARM && (model_is(0xd0c) || model_is(0xd49) || - model_is(0xd40) || model_is(0xd4f) || - model_is(0xd8e) || model_is(0xd84))) { + if (_cpu == CPU_ARM && + model_is_in({ CPU_MODEL_ARM_NEOVERSE_N1, CPU_MODEL_ARM_NEOVERSE_V1, + CPU_MODEL_ARM_NEOVERSE_N2, CPU_MODEL_ARM_NEOVERSE_V2, + CPU_MODEL_ARM_NEOVERSE_N3, CPU_MODEL_ARM_NEOVERSE_V3, + CPU_MODEL_ARM_NEOVERSE_V3AE })) { if (FLAG_IS_DEFAULT(UseSIMDForMemoryOps)) { FLAG_SET_DEFAULT(UseSIMDForMemoryOps, true); } @@ -261,12 +254,9 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseCRC32, false); } - // Neoverse - // V1: 0xd40 - // V2: 0xd4f - // V3: 0xd84 if (_cpu == CPU_ARM && - (model_is(0xd40) || model_is(0xd4f) || model_is(0xd84))) { + model_is_in({ CPU_MODEL_ARM_NEOVERSE_V1, CPU_MODEL_ARM_NEOVERSE_V2, + CPU_MODEL_ARM_NEOVERSE_V3, CPU_MODEL_ARM_NEOVERSE_V3AE })) { if (FLAG_IS_DEFAULT(UseCryptoPmullForCRC32)) { FLAG_SET_DEFAULT(UseCryptoPmullForCRC32, true); } diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp index 17087d243d3..38b112d9936 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp @@ -30,6 +30,8 @@ #include "runtime/abstract_vm_version.hpp" #include "utilities/sizes.hpp" +#include + class stringStream; #define BIT_MASK(flag) (1ULL<<(flag)) @@ -112,14 +114,26 @@ public: CPU_APPLE = 'a', }; -enum Ampere_CPU_Model { + enum Ampere_CPU_Model { CPU_MODEL_EMAG = 0x0, /* CPU implementer is CPU_AMCC */ CPU_MODEL_ALTRA = 0xd0c, /* CPU implementer is CPU_ARM, Neoverse N1 */ CPU_MODEL_ALTRAMAX = 0xd0c, /* CPU implementer is CPU_ARM, Neoverse N1 */ CPU_MODEL_AMPERE_1 = 0xac3, /* CPU implementer is CPU_AMPERE */ CPU_MODEL_AMPERE_1A = 0xac4, /* CPU implementer is CPU_AMPERE */ CPU_MODEL_AMPERE_1B = 0xac5 /* AMPERE_1B core Implements ARMv8.7 with CSSC, MTE, SM3/SM4 extensions */ -}; + }; + + enum ARM_CPU_Model { + CPU_MODEL_ARM_CORTEX_A53 = 0xd03, + CPU_MODEL_ARM_CORTEX_A73 = 0xd09, + CPU_MODEL_ARM_NEOVERSE_N1 = 0xd0c, + CPU_MODEL_ARM_NEOVERSE_V1 = 0xd40, + CPU_MODEL_ARM_NEOVERSE_N2 = 0xd49, + CPU_MODEL_ARM_NEOVERSE_V2 = 0xd4f, + CPU_MODEL_ARM_NEOVERSE_V3AE = 0xd83, + CPU_MODEL_ARM_NEOVERSE_V3 = 0xd84, + CPU_MODEL_ARM_NEOVERSE_N3 = 0xd8e, + }; #define CPU_FEATURE_FLAGS(decl) \ decl(FP, fp, 0) \ @@ -181,6 +195,15 @@ enum Ampere_CPU_Model { return _model == cpu_model || _model2 == cpu_model; } + static bool model_is_in(std::initializer_list cpu_models) { + for (const int& cpu_model : cpu_models) { + if (_model == cpu_model || _model2 == cpu_model) { + return true; + } + } + return false; + } + static bool is_zva_enabled() { return 0 <= _zva_length; } static int zva_length() { assert(is_zva_enabled(), "ZVA not available"); From d7523ec8d2255675547c0746d076efd7af5dd5af Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 4 Feb 2026 10:13:41 +0000 Subject: [PATCH 325/328] 8376031: HttpsURLConnection.getServerCertificates() throws "java.lang.IllegalStateException: connection not yet open" for the HEAD method Reviewed-by: jpai --- .../www/protocol/http/HttpURLConnection.java | 26 +- .../AbstractDelegateHttpsURLConnection.java | 113 +++++-- .../net/www/protocol/https/HttpsClient.java | 71 +--- .../GetServerCertificates.java | 302 ++++++++++++++++++ 4 files changed, 416 insertions(+), 96 deletions(-) create mode 100644 test/jdk/sun/net/www/protocol/https/HttpsURLConnection/GetServerCertificates.java diff --git a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index 89ad0cc48ed..3a915cf96df 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2026, 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 @@ -1677,11 +1677,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection { if (method.equals("HEAD") || cl == 0 || respCode == HTTP_NOT_MODIFIED || respCode == HTTP_NO_CONTENT) { - - http.finished(); - http = null; - inputStream = new EmptyInputStream(); - connected = false; + noResponseBody(); } if (respCode == 200 || respCode == 203 || respCode == 206 || @@ -1763,6 +1759,24 @@ public class HttpURLConnection extends java.net.HttpURLConnection { } } + /** + * This method is called when a response with no response + * body is received, and arrange for the http client to + * be returned to the pool (or released) immediately when + * possible. + * @apiNote Used by {@link sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection} + * to preserve the TLS information after receiving an empty body. + * @implSpec + * Subclasses that override this method should call the super class + * implementation. + */ + protected void noResponseBody() { + http.finished(); + http = null; + inputStream = new EmptyInputStream(); + connected = false; + } + /* * Creates a chained exception that has the same type as * original exception and with the same message. Right now, diff --git a/src/java.base/share/classes/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java index 7bf8280a7ad..1415658e34d 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java +++ b/src/java.base/share/classes/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -51,6 +51,7 @@ import sun.net.www.protocol.http.HttpCallerInfo; public abstract class AbstractDelegateHttpsURLConnection extends HttpURLConnection { + private SSLSession savedSession = null; protected AbstractDelegateHttpsURLConnection(URL url, sun.net.www.protocol.http.Handler handler) throws IOException { this(url, null, handler); @@ -92,6 +93,7 @@ public abstract class AbstractDelegateHttpsURLConnection extends public void setNewClient (URL url, boolean useCache) throws IOException { int readTimeout = getReadTimeout(); + savedSession = null; http = HttpsClient.New (getSSLSocketFactory(), url, getHostnameVerifier(), @@ -184,6 +186,7 @@ public abstract class AbstractDelegateHttpsURLConnection extends if (!http.isCachedConnection() && http.needsTunneling()) { doTunneling(); } + savedSession = null; ((HttpsClient)http).afterConnect(); } @@ -204,6 +207,19 @@ public abstract class AbstractDelegateHttpsURLConnection extends useCache, connectTimeout, this); } + @Override + protected void noResponseBody() { + savedSession = ((HttpsClient)http).getSSLSession(); + super.noResponseBody(); + } + + private SSLSession session() { + if (http instanceof HttpsClient https) { + return https.getSSLSession(); + } + return savedSession; + } + /** * Returns the cipher suite in use on this connection. */ @@ -211,11 +227,12 @@ public abstract class AbstractDelegateHttpsURLConnection extends if (cachedResponse != null) { return ((SecureCacheResponse)cachedResponse).getCipherSuite(); } - if (http == null) { + + var session = session(); + if (session == null) { throw new IllegalStateException("connection not yet open"); - } else { - return ((HttpsClient)http).getCipherSuite (); } + return session.getCipherSuite(); } /** @@ -231,11 +248,12 @@ public abstract class AbstractDelegateHttpsURLConnection extends return l.toArray(new java.security.cert.Certificate[0]); } } - if (http == null) { + + var session = session(); + if (session == null) { throw new IllegalStateException("connection not yet open"); - } else { - return (((HttpsClient)http).getLocalCertificates ()); } + return session.getLocalCertificates(); } /** @@ -256,11 +274,11 @@ public abstract class AbstractDelegateHttpsURLConnection extends } } - if (http == null) { + var session = session(); + if (session == null) { throw new IllegalStateException("connection not yet open"); - } else { - return (((HttpsClient)http).getServerCertificates ()); } + return session.getPeerCertificates(); } /** @@ -274,11 +292,11 @@ public abstract class AbstractDelegateHttpsURLConnection extends return ((SecureCacheResponse)cachedResponse).getPeerPrincipal(); } - if (http == null) { + var session = session(); + if (session == null) { throw new IllegalStateException("connection not yet open"); - } else { - return (((HttpsClient)http).getPeerPrincipal()); } + return getPeerPrincipal(session); } /** @@ -291,11 +309,11 @@ public abstract class AbstractDelegateHttpsURLConnection extends return ((SecureCacheResponse)cachedResponse).getLocalPrincipal(); } - if (http == null) { + var session = session(); + if (session == null) { throw new IllegalStateException("connection not yet open"); - } else { - return (((HttpsClient)http).getLocalPrincipal()); } + return getLocalPrincipal(session); } SSLSession getSSLSession() { @@ -307,11 +325,12 @@ public abstract class AbstractDelegateHttpsURLConnection extends } } - if (http == null) { + var session = session(); + if (session == null) { throw new IllegalStateException("connection not yet open"); } - return ((HttpsClient)http).getSSLSession(); + return session; } /* @@ -354,7 +373,7 @@ public abstract class AbstractDelegateHttpsURLConnection extends } HttpsClient https = (HttpsClient)http; try { - Certificate[] certs = https.getServerCertificates(); + Certificate[] certs = https.getSSLSession().getPeerCertificates(); if (certs[0] instanceof X509Certificate x509Cert) { return new HttpCallerInfo(url, proxy, port, x509Cert, authenticator); } @@ -372,7 +391,7 @@ public abstract class AbstractDelegateHttpsURLConnection extends } HttpsClient https = (HttpsClient)http; try { - Certificate[] certs = https.getServerCertificates(); + Certificate[] certs = https.getSSLSession().getPeerCertificates(); if (certs[0] instanceof X509Certificate x509Cert) { return new HttpCallerInfo(url, x509Cert, authenticator); } @@ -381,4 +400,58 @@ public abstract class AbstractDelegateHttpsURLConnection extends } return super.getHttpCallerInfo(url, authenticator); } + + @Override + public void disconnect() { + super.disconnect(); + savedSession = null; + } + + /** + * Returns the principal with which the server authenticated + * itself, or throw a SSLPeerUnverifiedException if the + * server did not authenticate. + * @param session The {@linkplain #getSSLSession() SSL session} + */ + private static Principal getPeerPrincipal(SSLSession session) + throws SSLPeerUnverifiedException + { + Principal principal; + try { + principal = session.getPeerPrincipal(); + } catch (AbstractMethodError e) { + // if the provider does not support it, fallback to peer certs. + // return the X500Principal of the end-entity cert. + java.security.cert.Certificate[] certs = + session.getPeerCertificates(); + principal = ((X509Certificate)certs[0]).getSubjectX500Principal(); + } + return principal; + } + + /** + * Returns the principal the client sent to the + * server, or null if the client did not authenticate. + * @param session The {@linkplain #getSSLSession() SSL session} + */ + private static Principal getLocalPrincipal(SSLSession session) + { + Principal principal; + try { + principal = session.getLocalPrincipal(); + } catch (AbstractMethodError e) { + principal = null; + // if the provider does not support it, fallback to local certs. + // return the X500Principal of the end-entity cert. + java.security.cert.Certificate[] certs = + session.getLocalCertificates(); + if (certs != null) { + principal = ((X509Certificate)certs[0]).getSubjectX500Principal(); + } + } + return principal; + } + + + } diff --git a/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java b/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java index 9f1d7b07021..f5804cd83bd 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java +++ b/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -599,75 +599,6 @@ final class HttpsClient extends HttpClient } } - /** - * Returns the cipher suite in use on this connection. - */ - String getCipherSuite() { - return session.getCipherSuite(); - } - - /** - * Returns the certificate chain the client sent to the - * server, or null if the client did not authenticate. - */ - public java.security.cert.Certificate [] getLocalCertificates() { - return session.getLocalCertificates(); - } - - /** - * Returns the certificate chain with which the server - * authenticated itself, or throw a SSLPeerUnverifiedException - * if the server did not authenticate. - */ - java.security.cert.Certificate [] getServerCertificates() - throws SSLPeerUnverifiedException - { - return session.getPeerCertificates(); - } - - /** - * Returns the principal with which the server authenticated - * itself, or throw a SSLPeerUnverifiedException if the - * server did not authenticate. - */ - Principal getPeerPrincipal() - throws SSLPeerUnverifiedException - { - Principal principal; - try { - principal = session.getPeerPrincipal(); - } catch (AbstractMethodError e) { - // if the provider does not support it, fallback to peer certs. - // return the X500Principal of the end-entity cert. - java.security.cert.Certificate[] certs = - session.getPeerCertificates(); - principal = ((X509Certificate)certs[0]).getSubjectX500Principal(); - } - return principal; - } - - /** - * Returns the principal the client sent to the - * server, or null if the client did not authenticate. - */ - Principal getLocalPrincipal() - { - Principal principal; - try { - principal = session.getLocalPrincipal(); - } catch (AbstractMethodError e) { - principal = null; - // if the provider does not support it, fallback to local certs. - // return the X500Principal of the end-entity cert. - java.security.cert.Certificate[] certs = - session.getLocalCertificates(); - if (certs != null) { - principal = ((X509Certificate)certs[0]).getSubjectX500Principal(); - } - } - return principal; - } - /** * Returns the {@code SSLSession} in use on this connection. */ diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/GetServerCertificates.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/GetServerCertificates.java new file mode 100644 index 00000000000..5de0d7aeb1a --- /dev/null +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/GetServerCertificates.java @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2026, 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 8376031 + * @modules jdk.httpserver + * @library /test/lib + * @summary Ensure HttpsURLConnection::getServerCertificates does not + * throw after calling getResponseCode() if the response doesn't have + * a body. + * @run main/othervm ${test.main.class} + * @run main/othervm -Djava.net.preferIPv6Addresses=true ${test.main.class} + */ + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; + +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 static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY; + + +public class GetServerCertificates { + + static final String URI_PATH = "/GetServerCertificates/"; + static final String BODY = "Go raibh maith agat"; + enum TESTS { + HEAD("head", 200, "HEAD"), + NOBODY("nobody", 200, "GET", "POST"), + S204("204", 204, "GET", "POST"), + S304("304", 304, "GET", "POST"), + S200("200", 200, "GET", "POST"); + final String test; + final int code; + final List methods; + private TESTS(String test, int code, String... methods) { + this.test = test; + this.code = code; + this.methods = List.of(methods); + } + boolean isFor(String path) { + return path != null && path.endsWith("/" + test); + } + + String test() { return test; } + int code() { return code; } + List methods() { return methods; } + static Optional fromPath(String path) { + return Stream.of(values()) + .filter(test -> test.isFor(path)) + .findFirst(); + } + } + + void test(String[] args) throws Exception { + SSLContext.setDefault(SimpleSSLContext.findSSLContext()); + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }); + HttpServer server = startHttpServer(); + try { + InetSocketAddress address = server.getAddress(); + URI uri = URIBuilder.newBuilder() + .scheme("https") + .host(address.getAddress()) + .port(address.getPort()) + .path(URI_PATH) + .build(); + for (var test : TESTS.values()) { + for (String method : test.methods()) { + doClient(method, uri, test); + } + } + + } finally { + server.stop(1000); + } + } + + void doClient(String method, URI baseUri, TESTS test) throws Exception { + assert baseUri.getRawQuery() == null; + assert baseUri.getRawFragment() == null; + assert test.methods().contains(method); + + String uriStr = baseUri.toString(); + if (!uriStr.endsWith("/")) uriStr = uriStr + "/"; + + URI uri = new URI(uriStr + test.test()); + assert uri.toString().endsWith("/" + test.test()); + int code = test.code(); + System.out.println("doClient(%s, %s, %s)" + .formatted(method, test.test(), test.code)); + + // first request - should create a TCP connection + HttpsURLConnection uc = (HttpsURLConnection) + uri.toURL().openConnection(Proxy.NO_PROXY); + if (!"GET".equals(method)) { + uc.setRequestMethod(method); + } + try { + uc.getServerCertificates(); + throw new AssertionError("Expected IllegalStateException not thrown"); + } catch (IllegalStateException ise) { + System.out.println("Got expected ISE: " + ise); + } + int resp = uc.getResponseCode(); + check(resp == code, "Unexpected response code. Expected %s, got %s" + .formatted(code, resp)); + + check(uc.getServerCertificates()); + if (test == TESTS.S200) { + byte[] bytes = uc.getInputStream().readAllBytes(); + String body = new String(bytes, StandardCharsets.UTF_8); + System.out.println("body: " + body); + check(BODY.equals(body), "Unexpected response body. Expected \"%s\", got \"%s\"" + .formatted(BODY, body)); + } + + // second request - should go on the same TCP connection. + // We don't have a reliable way to test that, and it could + // go on a new TCP connection if the previous connection + // was already closed. It is not an issue either way. + uc = (HttpsURLConnection) + uri.toURL().openConnection(Proxy.NO_PROXY); + if (!"GET".equals(method)) { + uc.setRequestMethod(method); + } + try { + uc.getServerCertificates(); + throw new AssertionError("Expected IllegalStateException not thrown"); + } catch (IllegalStateException ise) { + System.out.println("Got expected ISE: " + ise); + } + resp = uc.getResponseCode(); + check(resp == code, "Unexpected response code. Expected %s, got %s" + .formatted(code, resp)); + + check(uc.getServerCertificates()); + if (test == TESTS.S200) { + byte[] bytes = uc.getInputStream().readAllBytes(); + String body = new String(bytes, StandardCharsets.UTF_8); + System.out.println("body: " + body); + check(BODY.equals(body), "Unexpected response body. Expected \"%s\", got \"%s\"" + .formatted(BODY, body)); + } + + uc.disconnect(); + try { + uc.getServerCertificates(); + throw new AssertionError("Expected IllegalStateException not thrown"); + } catch (IllegalStateException ise) { + System.out.println("Got expected ISE: " + ise); + } + + // third request - forces the connection to close + // after use so that we don't find any connection in the pool + // for the next test case, assuming there was only + // one connection in the first place. + // Again there's no easy way to verify that the pool + // is empty (and it's not really necessary to bother) + uc = (HttpsURLConnection) + uri.toURL().openConnection(Proxy.NO_PROXY); + if (!"GET".equals(method)) { + uc.setRequestMethod(method); + } + uc.setRequestProperty("Connection", "close"); + try { + uc.getServerCertificates(); + throw new AssertionError("Expected IllegalStateException not thrown"); + } catch (IllegalStateException ise) { + System.out.println("Got expected ISE: " + ise); + } + resp = uc.getResponseCode(); + check(resp == code, "Unexpected response code. Expected %s, got %s" + .formatted(code, resp)); + check(uc.getServerCertificates()); + uc.disconnect(); + try { + uc.getServerCertificates(); + throw new AssertionError("Expected IllegalStateException not thrown"); + } catch (IllegalStateException ise) { + System.out.println("Got expected ISE: " + ise); + } + } + + // HTTP Server + HttpServer startHttpServer() throws IOException { + InetAddress localhost = InetAddress.getLoopbackAddress(); + HttpsServer httpServer = HttpsServer + .create(new InetSocketAddress(localhost, 0), 0); + var configurator = new HttpsConfigurator(SimpleSSLContext.findSSLContext()); + httpServer.setHttpsConfigurator(configurator); + httpServer.createContext(URI_PATH, new SimpleHandler()); + httpServer.start(); + return httpServer; + } + + static class SimpleHandler implements HttpHandler { + @Override + public void handle(HttpExchange t) throws IOException { + try { + String path = t.getRequestURI().getRawPath(); + var test = TESTS.fromPath(path); + if (!path.startsWith(URI_PATH) || !test.isPresent()) { + t.getRequestBody().close(); + t.getResponseHeaders().add("Connection", "close"); + t.sendResponseHeaders(421, RSPBODY_EMPTY); + t.close(); + return; + } + try (var is = t.getRequestBody()) { + is.readAllBytes(); + } + switch (test.get()) { + case S204, S304, NOBODY -> + t.sendResponseHeaders(test.get().code(), RSPBODY_EMPTY); + case S200 -> { + byte[] bytes = BODY.getBytes(StandardCharsets.UTF_8); + t.sendResponseHeaders(test.get().code(), bytes.length); + try (var os = t.getResponseBody()) { + os.write(bytes); + } + } + case HEAD -> { + assert t.getRequestMethod().equals("HEAD"); + byte[] bytes = BODY.getBytes(StandardCharsets.UTF_8); + t.sendResponseHeaders(test.get().code(), bytes.length); + } + } + t.close(); + } catch (Throwable error) { + error.printStackTrace(); + throw error; + } + } + } + + volatile int passed = 0, failed = 0; + boolean debug = false; + void pass() {passed++;} + void fail() {failed++;} + void fail(String msg) {System.err.println(msg); fail();} + void unexpected(Throwable t) {failed++; t.printStackTrace();} + void debug(String message) { if (debug) System.out.println(message); } + void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} + void check(java.security.cert.Certificate[] certs) { + // Use List.of to check that certs is not null and does not + // contain null. NullPointerException will be thrown here + // if that happens, which will make the test fail. + check(!List.of(certs).isEmpty(), "no certificates returned"); + } + public static void main(String[] args) throws Throwable { + Class k = new Object(){}.getClass().getEnclosingClass(); + try {k.getMethod("instanceMain",String[].class) + .invoke( k.newInstance(), (Object) args);} + catch (Throwable e) {throw e.getCause();}} + public void instanceMain(String[] args) throws Throwable { + try {test(args);} catch (Throwable t) {unexpected(t);} + System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} From 84e8787d1fdfe2d92f8b2c9b959651d8d63be91b Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 4 Feb 2026 11:03:56 +0000 Subject: [PATCH 326/328] 8367530: The exhaustiveness errors could be improved Reviewed-by: vromero, mcimadamore --- .../javac/comp/ExhaustivenessComputer.java | 729 ++++++++++++++++-- .../com/sun/tools/javac/comp/Flow.java | 67 +- .../tools/javac/resources/compiler.properties | 22 +- .../javac/diags/examples/BindingPattern.java | 33 + .../diags/examples/EnumConstantPattern.java | 37 + .../javac/diags/examples/NotExhaustive.java | 3 +- .../examples/NotExhaustiveStatement.java | 3 +- .../javac/diags/examples/RecordPattern.java | 37 + .../tools/javac/patterns/Exhaustiveness.java | 3 +- .../ExhaustivenessConvenientErrors.java | 593 ++++++++++++++ .../PrimitiveInstanceOfComboTest.java | 5 +- .../PrimitivePatternsSwitchConstants.java | 2 +- .../PrimitivePatternsSwitchErrors.java | 2 +- .../tools/javac/patterns/SwitchErrors.java | 2 +- .../platform/NonExportedPermittedTypes.java | 8 +- .../ExpressionSwitchNotExhaustive.java | 2 +- 16 files changed, 1449 insertions(+), 99 deletions(-) create mode 100644 test/langtools/tools/javac/diags/examples/BindingPattern.java create mode 100644 test/langtools/tools/javac/diags/examples/EnumConstantPattern.java create mode 100644 test/langtools/tools/javac/diags/examples/RecordPattern.java create mode 100644 test/langtools/tools/javac/patterns/ExhaustivenessConvenientErrors.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java index bbc330832f3..2a0bab1e330 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,11 +41,17 @@ import com.sun.tools.javac.code.Kinds.Kind; import com.sun.tools.javac.code.Type.TypeVar; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.SequencedSet; +import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.Stream; import static java.util.stream.Collectors.groupingBy; +import static com.sun.tools.javac.code.Flags.RECORD; /** A class to compute exhaustiveness of set of switch cases. * @@ -55,6 +61,14 @@ import static java.util.stream.Collectors.groupingBy; * deletion without notice. */ public class ExhaustivenessComputer { + private static final long DEFAULT_MAX_BASE_CHECKS = 4_000_000; + + //when baseChecks is set to a value different that this, the checks + //will be counter, and if too many will happen, the process will be stopped + //when baseChecks is set to this value, there's no counting, and the + //process will not continue as long as needed + private static final long NO_BASE_CHECKS_COUNTING = -1; + protected static final Context.Key exhaustivenessKey = new Context.Key<>(); private final Symtab syms; @@ -62,6 +76,8 @@ public class ExhaustivenessComputer { private final Check chk; private final Infer infer; private final Map, Boolean> isSubtypeCache = new HashMap<>(); + private final long maxBaseChecks; + private long baseChecks = NO_BASE_CHECKS_COUNTING; public static ExhaustivenessComputer instance(Context context) { ExhaustivenessComputer instance = context.get(exhaustivenessKey); @@ -77,9 +93,22 @@ public class ExhaustivenessComputer { types = Types.instance(context); chk = Check.instance(context); infer = Infer.instance(context); + Options options = Options.instance(context); + String baseChecks = options.get("exhaustivityMaxBaseChecks"); + long computedMaxBaseChecks = DEFAULT_MAX_BASE_CHECKS; + + if (baseChecks != null) { + try { + computedMaxBaseChecks = Long.parseLong(baseChecks); + } catch (NumberFormatException _) { + //ignore invalid values and use the default maximum number of checks + } + } + + maxBaseChecks = computedMaxBaseChecks; } - public boolean exhausts(JCExpression selector, List cases) { + public ExhaustivenessResult exhausts(JCExpression selector, List cases) { Set patternSet = new HashSet<>(); Map> enum2Constants = new HashMap<>(); Set booleanLiterals = new HashSet<>(Set.of(0, 1)); @@ -113,7 +142,7 @@ public class ExhaustivenessComputer { } if (types.unboxedTypeOrType(selector.type).hasTag(TypeTag.BOOLEAN) && booleanLiterals.isEmpty()) { - return true; + return ExhaustivenessResult.ofExhaustive(); } for (Entry> e : enum2Constants.entrySet()) { @@ -121,47 +150,77 @@ public class ExhaustivenessComputer { patternSet.add(new BindingPattern(e.getKey().type)); } } - Set patterns = patternSet; - Set> seenFallback = new HashSet<>(); - boolean useHashes = true; try { - boolean repeat = true; - while (repeat) { - Set updatedPatterns; - updatedPatterns = reduceBindingPatterns(selector.type, patterns); - updatedPatterns = reduceNestedPatterns(updatedPatterns, useHashes); - updatedPatterns = reduceRecordPatterns(updatedPatterns); - updatedPatterns = removeCoveredRecordPatterns(updatedPatterns); - repeat = !updatedPatterns.equals(patterns); - if (checkCovered(selector.type, patterns)) { - return true; - } - if (!repeat) { - //there may be situation like: - //class B permits S1, S2 - //patterns: R(S1, B), R(S2, S2) - //this might be joined to R(B, S2), as B could be rewritten to S2 - //but hashing in reduceNestedPatterns will not allow that - //disable the use of hashing, and use subtyping in - //reduceNestedPatterns to handle situations like this: - repeat = useHashes && seenFallback.add(updatedPatterns); - useHashes = false; - } else { - //if a reduction happened, make sure hashing in reduceNestedPatterns - //is enabled, as the hashing speeds up the process significantly: - useHashes = true; - } - patterns = updatedPatterns; + CoverageResult coveredResult = computeCoverage(selector.type, patternSet, PatternEquivalence.STRICT); + if (coveredResult.covered()) { + return ExhaustivenessResult.ofExhaustive(); } - return checkCovered(selector.type, patterns); + + Set details = + this.computeMissingPatternDescriptions(selector.type, coveredResult.incompletePatterns()) + .stream() + .flatMap(pd -> { + if (pd instanceof BindingPattern bp && enum2Constants.containsKey(bp.type.tsym)) { + Symbol enumType = bp.type.tsym; + return enum2Constants.get(enumType).stream().map(c -> new EnumConstantPattern(bp.type, c.name)); + } else { + return Stream.of(pd); + } + }) + .collect(Collectors.toSet()); + + return ExhaustivenessResult.ofDetails(details); } catch (CompletionFailure cf) { chk.completionError(selector.pos(), cf); - return true; //error recovery - } finally { - isSubtypeCache.clear(); + return ExhaustivenessResult.ofExhaustive(); //error recovery } } + /* Given the set of patterns, runs the reductions of it as long as possible. + * If the (reduced) set of patterns covers the given selector type, returns + * covered == true, and incompletePatterns == null. + * If the (reduced) set of patterns does not cover the given selector type, + * returns covered == false, and incompletePatterns == the reduced set of patterns. + */ + private CoverageResult computeCoverage(Type selectorType, Set patterns, PatternEquivalence patternEquivalence) { + Set updatedPatterns; + Set> seenPatterns = new HashSet<>(); + boolean useHashes = true; + boolean repeat = true; + do { + updatedPatterns = reduceBindingPatterns(selectorType, patterns); + updatedPatterns = reduceNestedPatterns(updatedPatterns, useHashes, patternEquivalence); + updatedPatterns = reduceRecordPatterns(updatedPatterns); + updatedPatterns = removeCoveredRecordPatterns(updatedPatterns); + repeat = !updatedPatterns.equals(patterns); + if (checkCovered(selectorType, patterns)) { + return new CoverageResult(true, null); + } + if (!repeat) { + //there may be situation like: + //class B permits S1, S2 + //patterns: R(S1, B), R(S2, S2) + //this might be joined to R(B, S2), as B could be rewritten to S2 + //but hashing in reduceNestedPatterns will not allow that + //disable the use of hashing, and use subtyping in + //reduceNestedPatterns to handle situations like this: + repeat = useHashes && seenPatterns.add(updatedPatterns); + useHashes = false; + } else { + //if a reduction happened, make sure hashing in reduceNestedPatterns + //is enabled, as the hashing speeds up the process significantly: + useHashes = true; + } + patterns = updatedPatterns; + } while (repeat); + if (checkCovered(selectorType, patterns)) { + return new CoverageResult(true, null); + } + return new CoverageResult(false, patterns); + } + + private record CoverageResult(boolean covered, Set incompletePatterns) {} + private boolean checkCovered(Type seltype, Iterable patterns) { for (Type seltypeComponent : components(seltype)) { for (PatternDescription pd : patterns) { @@ -215,6 +274,7 @@ public class ExhaustivenessComputer { if (clazz.isSealed() && clazz.isAbstract() && //if a binding pattern for clazz already exists, no need to analyze it again: !existingBindings.contains(clazz)) { + ListBuffer bindings = new ListBuffer<>(); //do not reduce to types unrelated to the selector type: Type clazzType = clazz.type; if (components(selectorType).stream() @@ -222,16 +282,7 @@ public class ExhaustivenessComputer { continue; } - Set permitted = allPermittedSubTypes(clazz, csym -> { - Type instantiated; - if (csym.type.allparams().isEmpty()) { - instantiated = csym.type; - } else { - instantiated = infer.instantiatePatternType(selectorType, csym); - } - - return instantiated != null && types.isCastable(selectorType, instantiated); - }); + Set permitted = allPermittedSubTypes(clazz, isApplicableSubtypePredicate(selectorType)); //the set of pending permitted subtypes needed to cover clazz: Set pendingPermitted = new HashSet<>(permitted); @@ -263,7 +314,7 @@ public class ExhaustivenessComputer { } if (pendingPermitted.isEmpty()) { - toAdd.add(new BindingPattern(clazz.type)); + toAdd.add(new BindingPattern(clazz.type, Set.of())); } } } @@ -304,6 +355,49 @@ public class ExhaustivenessComputer { return permitted; } + private Predicate isApplicableSubtypePredicate(Type targetType) { + return csym -> { + Type instantiated = instantiatePatternType(targetType, csym); + + return instantiated != null && types.isCastable(targetType, instantiated); + }; + } + + private Type instantiatePatternType(Type targetType, TypeSymbol csym) { + if (csym.type.allparams().isEmpty()) { + return csym.type; + } else { + return infer.instantiatePatternType(targetType, csym); + } + } + + private Set leafPermittedSubTypes(TypeSymbol root, Predicate accept) { + Set permitted = new HashSet<>(); + List permittedSubtypesClosure = baseClasses(root); + + while (permittedSubtypesClosure.nonEmpty()) { + ClassSymbol current = permittedSubtypesClosure.head; + + permittedSubtypesClosure = permittedSubtypesClosure.tail; + + current.complete(); + + if (current.isSealed() && current.isAbstract()) { + for (Type t : current.getPermittedSubclasses()) { + ClassSymbol csym = (ClassSymbol) t.tsym; + + if (accept.test(csym)) { + permittedSubtypesClosure = permittedSubtypesClosure.prepend(csym); + } + } + } else { + permitted.add(current); + } + } + + return permitted; + } + private List baseClasses(TypeSymbol root) { if (root instanceof ClassSymbol clazz) { return List.of(clazz); @@ -336,7 +430,8 @@ public class ExhaustivenessComputer { * as pattern hashes cannot be used to speed up the matching process */ private Set reduceNestedPatterns(Set patterns, - boolean useHashes) { + boolean useHashes, + PatternEquivalence patternEquivalence) { /* implementation note: * finding a sub-set of patterns that only differ in a single * column is time-consuming task, so this method speeds it up by: @@ -386,13 +481,13 @@ public class ExhaustivenessComputer { RecordPattern rpOther = candidatesArr[nextCandidate]; if (rpOne.recordType.tsym == rpOther.recordType.tsym && - nestedComponentsEquivalent(rpOne, rpOther, mismatchingCandidate, useHashes)) { + nestedComponentsEquivalent(rpOne, rpOther, mismatchingCandidate, useHashes, patternEquivalence)) { join.append(rpOther); } } var nestedPatterns = join.stream().map(rp -> rp.nested[mismatchingCandidateFin]).collect(Collectors.toSet()); - var updatedPatterns = reduceNestedPatterns(nestedPatterns, useHashes); + var updatedPatterns = reduceNestedPatterns(nestedPatterns, useHashes, patternEquivalence); updatedPatterns = reduceRecordPatterns(updatedPatterns); updatedPatterns = removeCoveredRecordPatterns(updatedPatterns); @@ -403,16 +498,11 @@ public class ExhaustivenessComputer { current.removeAll(join); } - for (PatternDescription nested : updatedPatterns) { - PatternDescription[] newNested = - Arrays.copyOf(rpOne.nested, rpOne.nested.length); - newNested[mismatchingCandidateFin] = nested; - RecordPattern nue = new RecordPattern(rpOne.recordType(), - rpOne.fullComponentTypes(), - newNested, - new HashSet<>(join)); - current.add(nue); - } + generatePatternsWithReplacedNestedPattern(rpOne, + mismatchingCandidateFin, + updatedPatterns, + Set.copyOf(join), + current::add); } } } @@ -434,11 +524,32 @@ public class ExhaustivenessComputer { * - it's type is a supertype of the existing pattern's type * - it was produced by a reduction from a record pattern that is equivalent to * the existing pattern + * - only if PatternEquivalence is LOOSE and the type is the same of the type + * of an existing record pattern (the binding pattern may stand in place of + * a record pattern). This is only used to compute the missing patterns that + * would make the original pattern set exhaustive. + * + * For example, having (with mismatchingCandidate == 0): + * existing: R(A _, Box(var _)) {} + * cadidate: R(B _, Box(var _)) {} + * these are always equivalent; as all nested patterns except of + * component 0 are exactly equivalent + * + * existing: R(A _, SubtypeOfBox _) {} + * cadidate: R(A _, Box _) {} + * this is only equivalent when useHashes == false; Box _ could be replaced + * with a more specific SubtypeOfBox _ + * + * existing: R(A _, Box(var _)) {} + * cadidate: R(A _, Box _) {} + * this is only equivalent when useHashes == false and patternEquivalence == LOOSE; + * Box _ is accepted in place of the more specific record pattern */ private boolean nestedComponentsEquivalent(RecordPattern existing, RecordPattern candidate, int mismatchingCandidate, - boolean useHashes) { + boolean useHashes, + PatternEquivalence patternEquivalence) { NEXT_NESTED: for (int i = 0; i < existing.nested.length; i++) { if (i != mismatchingCandidate) { @@ -457,22 +568,28 @@ public class ExhaustivenessComputer { return false; } } else if (existing.nested[i] instanceof RecordPattern nestedExisting) { - java.util.List pendingReplacedPatterns = - new ArrayList<>(nestedCandidate.sourcePatterns()); + if (patternEquivalence == PatternEquivalence.LOOSE) { + if (!isSubtypeErasure(nestedExisting.recordType(), nestedCandidate.type)) { + return false; + } + } else { + java.util.List pendingReplacedPatterns = + new ArrayList<>(nestedCandidate.sourcePatterns()); - while (!pendingReplacedPatterns.isEmpty()) { - PatternDescription currentReplaced = pendingReplacedPatterns.removeLast(); + while (!pendingReplacedPatterns.isEmpty()) { + PatternDescription currentReplaced = pendingReplacedPatterns.removeLast(); - if (nestedExisting.equals(currentReplaced)) { - //candidate.nested[i] is substitutable for existing.nested[i] - //continue with the next nested pattern: - continue NEXT_NESTED; + if (nestedExisting.equals(currentReplaced)) { + //candidate.nested[i] is substitutable for existing.nested[i] + //continue with the next nested pattern: + continue NEXT_NESTED; + } + + pendingReplacedPatterns.addAll(currentReplaced.sourcePatterns()); } - pendingReplacedPatterns.addAll(currentReplaced.sourcePatterns()); + return false; } - - return false; } else { return false; } @@ -563,6 +680,8 @@ public class ExhaustivenessComputer { } private boolean isBpCovered(Type componentType, PatternDescription newNested) { + reportCheck(); + if (newNested instanceof BindingPattern bp) { Type seltype = types.erasure(componentType); Type pattype = types.erasure(bp.type); @@ -574,9 +693,18 @@ public class ExhaustivenessComputer { return false; } - sealed interface PatternDescription { + protected void reportCheck() { + if (baseChecks != NO_BASE_CHECKS_COUNTING && + ++baseChecks > maxBaseChecks) { + throw new TooManyChecksException(null); + } + } + + public sealed interface PatternDescription { + public Type type(); public Set sourcePatterns(); } + public PatternDescription makePatternDescription(Type selectorType, JCPattern pattern) { if (pattern instanceof JCBindingPattern binding) { Type type = !selectorType.isPrimitive() && types.isSubtype(selectorType, binding.type) @@ -586,9 +714,7 @@ public class ExhaustivenessComputer { Type[] componentTypes; if (!record.type.isErroneous()) { - componentTypes = ((ClassSymbol) record.type.tsym).getRecordComponents() - .map(r -> types.memberType(record.type, r)) - .toArray(s -> new Type[s]); + componentTypes = instantiatedComponentTypes(record.type); } else { componentTypes = record.nested.map(t -> types.createErrorType(t.type)).toArray(s -> new Type[s]);; @@ -611,7 +737,7 @@ public class ExhaustivenessComputer { throw Assert.error(); } } - record BindingPattern(Type type, Set sourcePatterns) implements PatternDescription { + public record BindingPattern(Type type, Set sourcePatterns) implements PatternDescription { public BindingPattern(Type type) { this(type, Set.of()); @@ -631,7 +757,7 @@ public class ExhaustivenessComputer { return type.tsym + " _"; } } - record RecordPattern(Type recordType, int _hashCode, Type[] fullComponentTypes, PatternDescription[] nested, Set sourcePatterns) implements PatternDescription { + public record RecordPattern(Type recordType, int _hashCode, Type[] fullComponentTypes, PatternDescription[] nested, Set sourcePatterns) implements PatternDescription { public RecordPattern(Type recordType, Type[] fullComponentTypes, PatternDescription[] nested) { this(recordType, fullComponentTypes, nested, Set.of()); @@ -673,5 +799,450 @@ public class ExhaustivenessComputer { .map(pd -> pd.toString()) .collect(Collectors.joining(", ")) + ")"; } + + @Override + public Type type() { + return recordType; + } + } + + public record EnumConstantPattern(Type enumType, Name enumConstant) implements PatternDescription { + + @Override + public Type type() { + return enumType(); + } + + @Override + public Set sourcePatterns() { + return Set.of(); + } + public String toString() { + return enumType() + "." + enumConstant(); + } + } + + public record ExhaustivenessResult(boolean exhaustive, Set notExhaustiveDetails) { + public static ExhaustivenessResult ofExhaustive() { + return new ExhaustivenessResult(true, null); + } + public static ExhaustivenessResult ofDetails(Set notExhaustiveDetails) { + return new ExhaustivenessResult(false, notExhaustiveDetails != null ? notExhaustiveDetails : Set.of()); + } + } + + //computation of missing patterns: + protected Set computeMissingPatternDescriptions(Type selectorType, + Set incompletePatterns) { + if (maxBaseChecks == 0) { + return Set.of(); + } + try { + baseChecks = 0; + PatternDescription defaultPattern = new BindingPattern(selectorType); + return expandMissingPatternDescriptions(selectorType, + selectorType, + defaultPattern, + incompletePatterns, + Set.of(defaultPattern)); + } catch (TooManyChecksException ex) { + return ex.missingPatterns != null ? ex.missingPatterns : Set.of(); + } finally { + baseChecks = NO_BASE_CHECKS_COUNTING; + } + } + + private Set expandMissingPatternDescriptions(Type selectorType, + Type targetType, + PatternDescription toExpand, + Set basePatterns, + Set inMissingPatterns) { + try { + return doExpandMissingPatternDescriptions(selectorType, targetType, + toExpand, basePatterns, + inMissingPatterns); + } catch (TooManyChecksException ex) { + if (ex.missingPatterns == null) { + ex = new TooManyChecksException(inMissingPatterns); + } + throw ex; + } + } + + private Set doExpandMissingPatternDescriptions(Type selectorType, + Type targetType, + PatternDescription toExpand, + Set basePatterns, + Set inMissingPatterns) { + if (toExpand instanceof BindingPattern bp) { + if (bp.type.tsym.isSealed()) { + //try to replace binding patterns for sealed types with all their immediate permitted applicable types: + List permitted = ((ClassSymbol) bp.type.tsym).getPermittedSubclasses(); + Set applicableDirectPermittedPatterns = + permitted.stream() + .map(type -> type.tsym) + .filter(isApplicableSubtypePredicate(targetType)) + .map(csym -> new BindingPattern(types.erasure(csym.type))) + .collect(Collectors.toCollection(LinkedHashSet::new)); + + //remove the permitted subtypes that are not needed to achieve exhaustivity + boolean reduced = + removeUnnecessaryPatterns(selectorType, bp, basePatterns, inMissingPatterns, applicableDirectPermittedPatterns); + + if (!reduced && !hasMatchingRecordPattern(basePatterns, inMissingPatterns, toExpand)) { + //if all immediate permitted subtypes are needed + //give up, and simply use the current pattern: + return inMissingPatterns; + } + + Set currentMissingPatterns = + replace(inMissingPatterns, toExpand, applicableDirectPermittedPatterns); + + //try to recursively expand on each viable pattern: + for (PatternDescription viable : applicableDirectPermittedPatterns) { + currentMissingPatterns = expandMissingPatternDescriptions(selectorType, targetType, + viable, basePatterns, + currentMissingPatterns); + } + + return currentMissingPatterns; + } else if ((bp.type.tsym.flags_field & Flags.RECORD) != 0 && + //only expand record types into record patterns if there's a chance it may change the outcome + //i.e. there is a record pattern in at the spot in the original base patterns: + hasMatchingRecordPattern(basePatterns, inMissingPatterns, toExpand)) { + //if there is a binding pattern at a place where the original based patterns + //have a record pattern, try to expand the binding pattern into a record pattern + //create all possible combinations of record pattern components: + Type[] componentTypes = instantiatedComponentTypes(bp.type); + List> combinatorialNestedTypes = List.of(List.nil()); + + for (Type componentType : componentTypes) { + List applicableLeafPermittedSubtypes; + + if (componentType.tsym.isSealed()) { + applicableLeafPermittedSubtypes = + leafPermittedSubTypes(componentType.tsym, + isApplicableSubtypePredicate(componentType)) + .stream() + .map(csym -> instantiatePatternType(componentType, csym)) + .collect(List.collector()); + } else { + applicableLeafPermittedSubtypes = List.of(componentType); + } + + List> newCombinatorialNestedTypes = List.nil(); + + for (List existing : combinatorialNestedTypes) { + for (Type nue : applicableLeafPermittedSubtypes) { + newCombinatorialNestedTypes = newCombinatorialNestedTypes.prepend(existing.append(nue)); + } + } + + combinatorialNestedTypes = newCombinatorialNestedTypes; + } + + Set combinatorialPatterns = + combinatorialNestedTypes.stream() + .map(combination -> new RecordPattern(bp.type, + componentTypes, + combination.map(BindingPattern::new) + .toArray(PatternDescription[]::new))) + .collect(Collectors.toCollection(LinkedHashSet::new)); + + removeUnnecessaryPatterns(selectorType, bp, basePatterns, inMissingPatterns, combinatorialPatterns); + + CoverageResult coverageResult = computeCoverage(targetType, combinatorialPatterns, PatternEquivalence.LOOSE); + + if (!coverageResult.covered()) { + //use the partially merged/combined patterns: + combinatorialPatterns = coverageResult.incompletePatterns(); + } + + //combine sealed subtypes into the supertype, if all is covered. + //but preserve more specific record types in positions where there are record patterns in the original patterns + //this is particularly important for the case where the sealed supertype only has one permitted type, the record + //the base type could be used instead of the record otherwise, which would produce less specific missing pattern: + Set sortedCandidates = + partialSortPattern(combinatorialPatterns, basePatterns, replace(inMissingPatterns, toExpand, combinatorialPatterns)); + + removeUnnecessaryPatterns(selectorType, bp, basePatterns, inMissingPatterns, sortedCandidates); + + Set currentMissingPatterns = + replace(inMissingPatterns, toExpand, sortedCandidates); + + for (PatternDescription addedPattern : sortedCandidates) { + if (addedPattern instanceof RecordPattern addedRP) { + for (int c = 0; c < addedRP.nested.length; c++) { + currentMissingPatterns = expandMissingPatternDescriptions(selectorType, + addedRP.fullComponentTypes[c], + addedRP.nested[c], + basePatterns, + currentMissingPatterns); + } + } + } + + return currentMissingPatterns; + } + } + return inMissingPatterns; + } + + /* + * Inside any pattern in {@code in}, in any nesting depth, replace + * pattern {@code what} with patterns {@code to}. + */ + private Set replace(Iterable in, + PatternDescription what, + Collection to) { + Set result = new HashSet<>(); + + for (PatternDescription pd : in) { + Collection replaced = replace(pd, what, to); + if (replaced != null) { + result.addAll(replaced); + } else { + result.add(pd); + } + } + + return result; + } + //where: + //null: no change + private Collection replace(PatternDescription in, + PatternDescription what, + Collection to) { + if (in == what) { + return to; + } else if (in instanceof RecordPattern rp) { + for (int c = 0; c < rp.nested.length; c++) { + Collection replaced = replace(rp.nested[c], what, to); + if (replaced != null) { + Set withReplaced = new HashSet<>(); + + generatePatternsWithReplacedNestedPattern(rp, c, replaced, Set.of(), withReplaced::add); + + return replace(withReplaced, what, to); + } + } + return null; + } else { + return null; //binding patterns have no children + } + } + + /* Out of "candidates" remove patterns that are not necessary to achieve exhaustiveness. + * Note that iteration order of "candidates" is important - if the set contains + * two pattern, out of which either, but not both, is needed to achieve exhaustiveness, + * the first one in the iteration order will be removed. + */ + private boolean removeUnnecessaryPatterns(Type selectorType, + PatternDescription toExpand, + Set basePatterns, + Set inMissingPatterns, + Set candidates) { + boolean reduced = false; + + for (Iterator it = candidates.iterator(); it.hasNext(); ) { + PatternDescription current = it.next(); + Set reducedAdded = new HashSet<>(candidates); + + reducedAdded.remove(current); + + Set combinedPatterns = + Stream.concat(basePatterns.stream(), + replace(inMissingPatterns, toExpand, reducedAdded).stream()) + .collect(Collectors.toSet()); + + if (computeCoverage(selectorType, combinedPatterns, PatternEquivalence.LOOSE).covered()) { + it.remove(); + reduced = true; + } + } + + return reduced; + } + /* + * Sort patterns so that those that are preferred for removal are in front + * of those that are preferred to remain (when there's a choice). + */ + private SequencedSet partialSortPattern(Set candidates, + Set basePatterns, + Set missingPatterns) { + SequencedSet sortedCandidates = new LinkedHashSet<>(); + + while (!candidates.isEmpty()) { + PatternDescription mostSpecific = null; + for (PatternDescription current : candidates) { + if (mostSpecific == null || + shouldAppearBefore(current, mostSpecific, basePatterns, missingPatterns)) { + mostSpecific = current; + } + } + sortedCandidates.add(mostSpecific); + candidates.remove(mostSpecific); + } + return sortedCandidates; + } + //where: + //true iff pd1 should appear before pd2 + //false otherwise + private boolean shouldAppearBefore(PatternDescription pd1, + PatternDescription pd2, + Set basePatterns, + Set missingPatterns) { + if (pd1 instanceof RecordPattern rp1 && pd2 instanceof RecordPattern rp2) { + for (int c = 0; c < rp1.nested.length; c++) { + if (shouldAppearBefore((BindingPattern) rp1.nested[c], + (BindingPattern) rp2.nested[c], + basePatterns, + missingPatterns)) { + return true; + } + } + } else if (pd1 instanceof BindingPattern bp1 && pd2 instanceof BindingPattern bp2) { + Type t1 = bp1.type(); + Type t2 = bp2.type(); + boolean t1IsImportantRecord = + (t1.tsym.flags_field & RECORD) != 0 && + hasMatchingRecordPattern(basePatterns, missingPatterns, bp1); + boolean t2IsImportantRecord = + (t2.tsym.flags_field & RECORD) != 0 && + hasMatchingRecordPattern(basePatterns, missingPatterns, bp2); + if (t1IsImportantRecord && !t2IsImportantRecord) { + return false; + } + if (!t1IsImportantRecord && t2IsImportantRecord) { + return true; + } + if (!types.isSameType(t1, t2) && types.isSubtype(t1, t2)) { + return true; + } + } + + return false; + } + + /* + * Do the {@code basePatterns} have a record pattern at a place that corresponds to + * position of pattern {@code query} inside {@code missingPatterns}? + */ + private boolean hasMatchingRecordPattern(Set basePatterns, + Set missingPatterns, + PatternDescription query) { + PatternDescription root = findRootContaining(missingPatterns, query); + + if (root == null) { + return false; + } + return basePatternsHaveRecordPatternOnThisSpot(basePatterns, root, query); + } + //where: + private PatternDescription findRootContaining(Set rootPatterns, + PatternDescription added) { + for (PatternDescription pd : rootPatterns) { + if (isUnderRoot(pd, added)) { + return pd; + } + } + + return null; + } + + private boolean basePatternsHaveRecordPatternOnThisSpot(Set basePatterns, + PatternDescription rootPattern, + PatternDescription added) { + if (rootPattern == added) { + return basePatterns.stream().anyMatch(pd -> pd instanceof RecordPattern); + } + if (!(rootPattern instanceof RecordPattern rootPatternRecord)) { + return false; + } + int index = -1; + for (int c = 0; c < rootPatternRecord.nested.length; c++) { + if (isUnderRoot(rootPatternRecord.nested[c], added)) { + index = c; + break; + } + } + // 'index' must be one of rootPatternRecord.nested; if not, `isUnderRoot` is inconsistent. + Assert.check(index != (-1)); + + int indexFin = index; + Set filteredBasePatterns = + basePatterns.stream() + .filter(pd -> pd instanceof RecordPattern) + .map(rp -> (RecordPattern) rp) + .filter(rp -> types.isSameType(rp.recordType(), rootPatternRecord.recordType())) + .map(rp -> rp.nested[indexFin]) + .collect(Collectors.toSet()); + + return basePatternsHaveRecordPatternOnThisSpot(filteredBasePatterns, rootPatternRecord.nested[index], added); + } + + private boolean isUnderRoot(PatternDescription root, PatternDescription searchFor) { + if (root == searchFor) { + return true; + } else if (root instanceof RecordPattern rp) { + for (int c = 0; c < rp.nested.length; c++) { + if (isUnderRoot(rp.nested[c], searchFor)) { + return true; + } + } + } + return false; + } + + /* + * Using {@code basePattern} as a starting point, generate new {@code + * RecordPattern}s, such that all corresponding components but one, are the + * same. The component described by the {@code replaceComponent} index is + * replaced with all {@code PatternDescription}s taken from {@code + * updatedNestedPatterns} and the resulting {@code RecordPatterns}s are sent + * to {@code target}. + */ + private void generatePatternsWithReplacedNestedPattern(RecordPattern basePattern, + int replaceComponent, + Iterable updatedNestedPatterns, + Set sourcePatterns, + Consumer target) { + for (PatternDescription nested : updatedNestedPatterns) { + PatternDescription[] newNested = + Arrays.copyOf(basePattern.nested, basePattern.nested.length); + newNested[replaceComponent] = nested; + target.accept(new RecordPattern(basePattern.recordType(), + basePattern.fullComponentTypes(), + newNested, + sourcePatterns)); + } + } + + /* For a given record type, return the record's component types, with their + * types instatiated according to the exact record type. + */ + private Type[] instantiatedComponentTypes(Type recordType) { + Type[] componentTypes = ((ClassSymbol) recordType.tsym).getRecordComponents() + .map(r -> types.memberType(recordType, r)) + .toArray(s -> new Type[s]); + return componentTypes; + } + + /* The strictness of determining the equivalent of patterns, used in + * nestedComponentsEquivalent. + */ + private enum PatternEquivalence { + STRICT, + LOOSE; + } + + protected static class TooManyChecksException extends RuntimeException { + private static final long serialVersionUID = 0L; + private transient final Set missingPatterns; + + public TooManyChecksException(Set missingPatterns) { + super(null, null, false, false); + this.missingPatterns = missingPatterns; + } } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java index e74aed6a357..cbcb474a37f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, 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 @@ -50,9 +50,15 @@ import static com.sun.tools.javac.code.Flags.BLOCK; import static com.sun.tools.javac.code.Kinds.Kind.*; import static com.sun.tools.javac.code.TypeTag.BOOLEAN; import static com.sun.tools.javac.code.TypeTag.VOID; +import com.sun.tools.javac.comp.ExhaustivenessComputer.BindingPattern; +import com.sun.tools.javac.comp.ExhaustivenessComputer.EnumConstantPattern; +import com.sun.tools.javac.comp.ExhaustivenessComputer.ExhaustivenessResult; +import com.sun.tools.javac.comp.ExhaustivenessComputer.PatternDescription; +import com.sun.tools.javac.comp.ExhaustivenessComputer.RecordPattern; import com.sun.tools.javac.resources.CompilerProperties.Fragments; import static com.sun.tools.javac.tree.JCTree.Tag.*; import com.sun.tools.javac.util.JCDiagnostic.Fragment; +import java.util.Arrays; /** This pass implements dataflow analysis for Java programs though * different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that @@ -696,9 +702,18 @@ public class Flow { tree.isExhaustive = tree.hasUnconditionalPattern || TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases); if (exhaustiveSwitch) { - tree.isExhaustive |= exhaustiveness.exhausts(tree.selector, tree.cases); if (!tree.isExhaustive) { - log.error(tree, Errors.NotExhaustiveStatement); + ExhaustivenessResult exhaustivenessResult = exhaustiveness.exhausts(tree.selector, tree.cases); + + tree.isExhaustive = exhaustivenessResult.exhaustive(); + + if (!tree.isExhaustive) { + if (exhaustivenessResult.notExhaustiveDetails().isEmpty()) { + log.error(tree, Errors.NotExhaustiveStatement); + } else { + logNotExhaustiveError(tree.pos(), exhaustivenessResult, Errors.NotExhaustiveStatementDetails); + } + } } } if (!tree.hasUnconditionalPattern && !exhaustiveSwitch) { @@ -735,16 +750,54 @@ public class Flow { TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases)) { tree.isExhaustive = true; } else { - tree.isExhaustive = exhaustiveness.exhausts(tree.selector, tree.cases); + ExhaustivenessResult exhaustivenessResult = exhaustiveness.exhausts(tree.selector, tree.cases); + + tree.isExhaustive = exhaustivenessResult.exhaustive(); + + if (!tree.isExhaustive) { + if (exhaustivenessResult.notExhaustiveDetails().isEmpty()) { + log.error(tree, Errors.NotExhaustive); + } else { + logNotExhaustiveError(tree.pos(), exhaustivenessResult, Errors.NotExhaustiveDetails); + } + } } - if (!tree.isExhaustive) { - log.error(tree, Errors.NotExhaustive); - } alive = prevAlive; alive = alive.or(resolveYields(tree, prevPendingExits)); } + private void logNotExhaustiveError(DiagnosticPosition pos, + ExhaustivenessResult exhaustivenessResult, + Error errorKey) { + List details = + exhaustivenessResult.notExhaustiveDetails() + .stream() + .map(this::patternToDiagnostic) + .sorted((d1, d2) -> d1.toString() + .compareTo(d2.toString())) + .collect(List.collector()); + JCDiagnostic main = diags.error(null, log.currentSource(), pos, errorKey); + JCDiagnostic d = new JCDiagnostic.MultilineDiagnostic(main, details); + log.report(d); + } + + private JCDiagnostic patternToDiagnostic(PatternDescription desc) { + Type patternType = types.erasure(desc.type()); + return diags.fragment(switch (desc) { + case BindingPattern _ -> + Fragments.BindingPattern(patternType); + case RecordPattern rp -> + Fragments.RecordPattern(patternType, + Arrays.stream(rp.nested()) + .map(this::patternToDiagnostic) + .toList()); + case EnumConstantPattern ep -> + Fragments.EnumConstantPattern(patternType, + ep.enumConstant()); + }); + } + public void visitTry(JCTry tree) { ListBuffer prevPendingExits = pendingExits; pendingExits = new ListBuffer<>(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index 2ba9122c04a..bb81916becb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2026, 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 @@ -1476,6 +1476,26 @@ compiler.err.not.exhaustive=\ compiler.err.not.exhaustive.statement=\ the switch statement does not cover all possible input values +compiler.err.not.exhaustive.details=\ + the switch expression does not cover all possible input values\n\ + missing patterns: + +compiler.err.not.exhaustive.statement.details=\ + the switch statement does not cover all possible input values\n\ + missing patterns: + +# 0: type +compiler.misc.binding.pattern=\ + {0} _ + +# 0: type, 1: list of diagnostic +compiler.misc.record.pattern=\ + {0}({1}) + +# 0: type, 1: name +compiler.misc.enum.constant.pattern=\ + {0}.{1} + compiler.err.initializer.must.be.able.to.complete.normally=\ initializer must be able to complete normally diff --git a/test/langtools/tools/javac/diags/examples/BindingPattern.java b/test/langtools/tools/javac/diags/examples/BindingPattern.java new file mode 100644 index 00000000000..01913a47fd7 --- /dev/null +++ b/test/langtools/tools/javac/diags/examples/BindingPattern.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2026, 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. + */ + +// key: compiler.err.not.exhaustive.details +// key: compiler.misc.binding.pattern + +class BindingPattern { + int t(Object o) { + return switch (o) { + case String s -> 0; + }; + } +} diff --git a/test/langtools/tools/javac/diags/examples/EnumConstantPattern.java b/test/langtools/tools/javac/diags/examples/EnumConstantPattern.java new file mode 100644 index 00000000000..b2ab5b9028d --- /dev/null +++ b/test/langtools/tools/javac/diags/examples/EnumConstantPattern.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2026, 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. + */ + +// key: compiler.err.not.exhaustive.details +// key: compiler.misc.enum.constant.pattern + +class NotExhaustiveDetails { + int t(I i) { + return switch (i) { + case R r -> -1; + case E.A -> -1; + }; + } + sealed interface I {} + enum E implements I {A, B} + record R(E e) implements I {} +} diff --git a/test/langtools/tools/javac/diags/examples/NotExhaustive.java b/test/langtools/tools/javac/diags/examples/NotExhaustive.java index 8d36b013677..f048755ec79 100644 --- a/test/langtools/tools/javac/diags/examples/NotExhaustive.java +++ b/test/langtools/tools/javac/diags/examples/NotExhaustive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ */ // key: compiler.err.not.exhaustive +// options: -XDexhaustivityMaxBaseChecks=0 class NotExhaustive { int t(int i) { diff --git a/test/langtools/tools/javac/diags/examples/NotExhaustiveStatement.java b/test/langtools/tools/javac/diags/examples/NotExhaustiveStatement.java index 65a11abb0e6..49e4955cbdb 100644 --- a/test/langtools/tools/javac/diags/examples/NotExhaustiveStatement.java +++ b/test/langtools/tools/javac/diags/examples/NotExhaustiveStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ */ // key: compiler.err.not.exhaustive.statement +// options: -XDexhaustivityMaxBaseChecks=0 class NotExhaustive { void t(Object o) { diff --git a/test/langtools/tools/javac/diags/examples/RecordPattern.java b/test/langtools/tools/javac/diags/examples/RecordPattern.java new file mode 100644 index 00000000000..2bb43bfd800 --- /dev/null +++ b/test/langtools/tools/javac/diags/examples/RecordPattern.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2026, 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. + */ + +// key: compiler.err.not.exhaustive.statement.details +// key: compiler.misc.record.pattern + +class RecordPattern { + void t(R r) { + switch (r) { + case R(C1 _) -> {} + }; + } + sealed interface I {} + record C1() implements I {} + record C2() implements I {} + record R(I i) {} +} diff --git a/test/langtools/tools/javac/patterns/Exhaustiveness.java b/test/langtools/tools/javac/patterns/Exhaustiveness.java index 84e67855b3b..f1809e99e45 100644 --- a/test/langtools/tools/javac/patterns/Exhaustiveness.java +++ b/test/langtools/tools/javac/patterns/Exhaustiveness.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -2523,6 +2523,7 @@ public class Exhaustiveness extends TestRunner { "-Xlint:-preview", "--class-path", libClasses.toString(), "-XDshould-stop.at=FLOW", + "-XDexhaustivityMaxBaseChecks=0", stopAtFlow ? "-XDshould-stop.ifNoError=FLOW" : "-XDnoop") .outdir(classes) diff --git a/test/langtools/tools/javac/patterns/ExhaustivenessConvenientErrors.java b/test/langtools/tools/javac/patterns/ExhaustivenessConvenientErrors.java new file mode 100644 index 00000000000..6935fcfa006 --- /dev/null +++ b/test/langtools/tools/javac/patterns/ExhaustivenessConvenientErrors.java @@ -0,0 +1,593 @@ +/* + * Copyright (c) 2026, 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 8367530 + * @summary Check enhanced exhaustiveness errors + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavacTask + * @run main ExhaustivenessConvenientErrors +*/ + +import com.sun.tools.javac.api.ClientCodeWrapper.DiagnosticSourceUnwrapper; +import com.sun.tools.javac.util.JCDiagnostic; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.TestRunner; +import toolbox.ToolBox; + +public class ExhaustivenessConvenientErrors extends TestRunner { + + ToolBox tb; + + public static void main(String... args) throws Exception { + new ExhaustivenessConvenientErrors().runTests(); + } + + ExhaustivenessConvenientErrors() { + super(System.err); + tb = new ToolBox(); + } + + public void runTests() throws Exception { + runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + @Test + public void testExhaustiveSealedClasses(Path base) throws Exception { + doTest(base, + new String[]{""" + package lib; + public sealed interface S permits A, B {} + """, + """ + package lib; + public final class A implements S {} + """, + """ + package lib; + public final class B implements S {} + """}, + """ + package test; + import lib.*; + public class Test { + private int test(S obj) { + return switch (obj) { + case A a -> 0; + }; + } + } + """, + "lib.B _"); + } + + @Test + public void testExhaustiveSealedClassesTransitive(Path base) throws Exception { + doTest(base, + new String[]{""" + package lib; + public sealed interface S1 permits S2, A {} + """, + """ + package lib; + public sealed interface S2 extends S1 permits S3, B {} + """, + """ + package lib; + public sealed interface S3 extends S2 permits C, D {} + """, + """ + package lib; + public final class A implements S1 {} + """, + """ + package lib; + public final class B implements S2 {} + """, + """ + package lib; + public final class C implements S3 {} + """, + """ + package lib; + public final class D implements S3 {} + """}, + """ + package test; + import lib.*; + public class Test { + private int test(S1 obj) { + return switch (obj) { + case A a -> 0; + case B a -> 0; + case D a -> 0; + }; + } + } + """, + "lib.C _"); + } + + @Test + public void testTrivialRecord(Path base) throws Exception { + doTest(base, + new String[]{""" + package lib; + public sealed interface S permits A, B {} + """, + """ + package lib; + public final class A implements S {} + """, + """ + package lib; + public final class B implements S {} + """, + """ + package lib; + public record R(S s) {} + """}, + """ + package test; + import lib.*; + public class Test { + private int test(R r) { + return switch (r) { + case R(A a) -> 0; + }; + } + } + """, + "lib.R(lib.B _)"); + } + + @Test + public void testNonNestedRecord(Path base) throws Exception { + doTest(base, + new String[]{""" + package lib; + public sealed interface S permits A, B {} + """, + """ + package lib; + public final class A implements S {} + """, + """ + package lib; + public final class B implements S {} + """, + """ + package lib; + public record R(S s1, S s2) {} + """}, + """ + package test; + import lib.*; + public class Test { + private int test(R r) { + return switch (r) { + case R(A a, B b) -> 0; + case R(B b, A a) -> 0; + }; + } + } + """, + "lib.R(lib.A _,lib.A _)", + "lib.R(lib.B _,lib.B _)"); + } + + @Test + public void testComplex1(Path base) throws Exception { + doTest(base, + new String[0], + """ + package test; + import lib.*; + public class Test { + private int test(Root r) { + return switch (r) { + case Root(R1 _, _, _) -> 0; + }; + } + sealed interface Base {} + record R1() implements Base {} + record R2() implements Base {} + record R3(Base b1, Base b2) implements Base {} + record Root(Base b1, Base b2, Base b3) {} + } + """, + "test.Test.Root(test.Test.R2 _,test.Test.Base _,test.Test.Base _)", + "test.Test.Root(test.Test.R3 _,test.Test.Base _,test.Test.Base _)"); + } + + @Test + public void testComplex2(Path base) throws Exception { + doTest(base, + new String[0], + """ + package test; + import lib.*; + public class Test { + private int test(Root r) { + return switch (r) { + case Root(R1 _, _, _) -> 0; + case Root(R2 _, R1 _, _) -> 0; + case Root(R2 _, R2 _, R1 _) -> 0; + case Root(R2 _, R2(R1 _, R1 _), R2(R1 _, R1 _)) -> 0; + case Root(R2 _, R2(R1 _, R1 _), R2(R1 _, R2 _)) -> 0; + case Root(R2 _, R2(R1 _, R1 _), R2(R2 _, R1 _)) -> 0; + case Root(R2 _, R2(R1 _, R1 _), R2(R2 _, R2 _)) -> 0; + case Root(R2 _, R2(R1 _, R2 _), R2(R1 _, R1 _)) -> 0; + case Root(R2 _, R2(R1 _, R2 _), R2(R1 _, R2 _)) -> 0; + case Root(R2 _, R2(R1 _, R2 _), R2(R2 _, R1 _)) -> 0; + case Root(R2 _, R2(R1 _, R2 _), R2(R2 _, R2 _)) -> 0; + case Root(R2 _, R2(R2 _, R1 _), R2(R1 _, R1 _)) -> 0; + case Root(R2 _, R2(R2 _, R1 _), R2(R1 _, R2 _)) -> 0; + case Root(R2 _, R2(R2 _, R1 _), R2(R2 _, R1 _)) -> 0; + case Root(R2 _, R2(R2 _, R1 _), R2(R2 _, R2 _)) -> 0; + case Root(R2 _, R2(R2 _, R2 _), R2(R1 _, R1 _)) -> 0; + case Root(R2 _, R2(R2 _, R2 _), R2(R1 _, R2 _)) -> 0; + case Root(R2 _, R2(R2 _, R2 _), R2(R2 _, R1 _)) -> 0; +// case Root(R2 _, R2(R2 _, R2 _), R2(R2 _, R2 _)) -> 0; + }; + } + sealed interface Base {} + record R1() implements Base {} + record R2(Base b1, Base b2) implements Base {} + record Root(Base b1, Base b2, Base b3) {} + } + """, + "test.Test.Root(test.Test.R2 _,test.Test.R2(test.Test.R2 _,test.Test.R2 _),test.Test.R2(test.Test.R2 _,test.Test.R2 _))"); + } + + @Test + public void testComplex3(Path base) throws Exception { + doTest(base, + new String[0], + """ + package test; + public class Test { + private int test(Triple p) { + return switch (p) { + case Triple(B _, _, _) -> 0; + case Triple(_, A _, _) -> 0; + case Triple(_, _, A _) -> 0; + case Triple(A p, C(Nested _, NestedBaseA _), _) -> 0; + case Triple(A p, C(Nested _, NestedBaseB _), C(Nested _, NestedBaseA _)) -> 0; + case Triple(A p, C(Nested _, NestedBaseB _), C(Nested _, NestedBaseB _)) -> 0; + case Triple(A p, C(Nested _, NestedBaseB _), C(Nested _, NestedBaseC _)) -> 0; + case Triple(A p, C(Nested _, NestedBaseC _), C(Nested _, NestedBaseA _)) -> 0; + case Triple(A p, C(Nested _, NestedBaseC _), C(Nested _, NestedBaseB _)) -> 0; +// case Path(A p, C(Nested _, NestedBaseC _), C(Nested _, NestedBaseC _)) -> 0; + }; + } + record Triple(Base c1, Base c2, Base c3) {} + sealed interface Base permits A, B {} + record A(boolean key) implements Base { + } + sealed interface B extends Base {} + record C(Nested n, NestedBase b) implements B {} + record Nested() {} + sealed interface NestedBase {} + record NestedBaseA() implements NestedBase {} + record NestedBaseB() implements NestedBase {} + record NestedBaseC() implements NestedBase {} + } + """, + "test.Test.Triple(test.Test.A _,test.Test.C(test.Test.Nested _,test.Test.NestedBaseC _),test.Test.C(test.Test.Nested _,test.Test.NestedBaseC _))"); + } + + @Test + public void testComplex4(Path base) throws Exception { + doTest(base, + new String[0], + """ + package test; + import lib.*; + public class Test { + private int test(Root r) { + return switch (r) { + case Root(R1 _, _, _) -> 0; + case Root(R2 _, R1 _, _) -> 0; + case Root(R2 _, R2 _, R1 _) -> 0; + case Root(R2 _, R2(R1 _, R1 _), R2(R1 _, R1 _)) -> 0; + case Root(R2 _, R2(R1 _, R1 _), R2(R1 _, R2 _)) -> 0; + case Root(R2 _, R2(R1 _, R1 _), R2(R2 _, R1 _)) -> 0; + case Root(R2 _, R2(R1 _, R1 _), R2(R2 _, R2 _)) -> 0; + case Root(R2 _, R2(R1 _, R2 _), R2(R1 _, R1 _)) -> 0; + case Root(R2 _, R2(R1 _, R2 _), R2(R1 _, R2 _)) -> 0; +// case Root(R2 _, R2(R1 _, R2 _), R2(R2 _, R1 _)) -> 0; + case Root(R2 _, R2(R1 _, R2 _), R2(R2 _, R2 _)) -> 0; + case Root(R2 _, R2(R2 _, R1 _), R2(R1 _, R1 _)) -> 0; + case Root(R2 _, R2(R2 _, R1 _), R2(R1 _, R2 _)) -> 0; + case Root(R2 _, R2(R2 _, R1 _), R2(R2 _, R1 _)) -> 0; + case Root(R2 _, R2(R2 _, R1 _), R2(R2 _, R2 _)) -> 0; + case Root(R2 _, R2(R2 _, R2 _), R2(R1 _, R1 _)) -> 0; + case Root(R2 _, R2(R2 _, R2 _), R2(R1 _, R2 _)) -> 0; + case Root(R2 _, R2(R2 _, R2 _), R2(R2 _, R1 _)) -> 0; +// case Root(R2 _, R2(R2 _, R2 _), R2(R2 _, R2 _)) -> 0; + }; + } + sealed interface Base {} + record R1() implements Base {} + record R2(Base b1, Base b2) implements Base {} + record Root(Base b1, Base b2, Base b3) {} + } + """, + "test.Test.Root(test.Test.R2 _,test.Test.R2(test.Test.Base _,test.Test.R2 _),test.Test.R2(test.Test.R2 _,test.Test.Base _))"); + //ideally,the result would be as follow,but it is difficult to split Base on two distinct places: +// "test.Test.Root(test.Test.R2 _,test.Test.R2(test.Test.R1 _,test.Test.R2 _),test.Test.R2(test.Test.R2 _,test.Test.R1 _))", +// "test.Test.Root(test.Test.R2 _,test.Test.R2(test.Test.R2 _,test.Test.R2 _),test.Test.R2(test.Test.R2 _,test.Test.R2 _))"); + } + + @Test + public void testComplex5(Path base) throws Exception { + doTest(base, + new String[0], + """ + package test; + public class Test { + private int test(Triple p) { + return switch (p) { + case Triple(B _, _, _) -> 0; + case Triple(_, A _, _) -> 0; + case Triple(_, _, A _) -> 0; +// case Triple(A _, C(Nested _, NestedBaseA _), _) -> 0; + case Triple(A _, C(Nested _, NestedBaseB _), C(Nested _, NestedBaseA _)) -> 0; + case Triple(A _, C(Nested _, NestedBaseB _), C(Nested _, NestedBaseB _)) -> 0; + case Triple(A _, C(Nested _, NestedBaseB _), C(Nested _, NestedBaseC _)) -> 0; + case Triple(A _, C(Nested _, NestedBaseC _), C(Nested _, NestedBaseA _)) -> 0; + case Triple(A _, C(Nested _, NestedBaseC _), C(Nested _, NestedBaseB _)) -> 0; +// case Path(A _, C(Nested _, NestedBaseC _), C(Nested _, NestedBaseC _)) -> 0; + }; + } + record Triple(Base c1, Base c2, Base c3) {} + sealed interface Base permits A, B {} + record A(boolean key) implements Base { + } + sealed interface B extends Base {} + record C(Nested n, NestedBase b) implements B {} + record Nested() {} + sealed interface NestedBase {} + record NestedBaseA() implements NestedBase {} + record NestedBaseB() implements NestedBase {} + record NestedBaseC() implements NestedBase {} + } + """, + "test.Test.Triple(test.Test.A _,test.Test.C(test.Test.Nested _,test.Test.NestedBaseA _),test.Test.C _)", + //the following could be: + //test.Test.Triple(test.Test.A _,test.Test.C(test.Test.Nested _,test.Test.NestedBaseC _),test.Test.C(test.Test.Nested _,test.Test.NestedBaseC _)) + "test.Test.Triple(test.Test.A _,test.Test.C(test.Test.Nested _,test.Test.NestedBaseC _),test.Test.C _)"); + } + + @Test + public void testNoInfiniteRecursion(Path base) throws Exception { + doTest(base, + new String[0], + """ + package test; + public class Test { + private int test(R r) { + return switch (r) { + case R(_, _, R(_, _, _, _), String s) -> 0; + case R(_, _, R(_, _, _, String str), _) -> 0; + }; + } + } + public record R(R r1, R r2, R r3, Object o) {} + """, + "test.R(test.R _,test.R _,test.R(test.R _,test.R _,test.R _,java.lang.Object _),java.lang.Object _)"); + } + + @Test + public void testEnum(Path base) throws Exception { + doTest(base, + new String[0], + """ + package test; + public class Test { + private int test(I i) { + return switch (i) { + case E.A -> 0; + case C _ -> 1; + }; + } + sealed interface I {} + enum E implements I {A, B} + final class C implements I {} + } + public record R(R r1, R r2, R r3, Object o) {} + """, + "test.Test.E.B"); + doTest(base, + new String[0], + """ + package test; + public class Test { + private int test(I i) { + return switch (i) { + case C _ -> 1; + }; + } + sealed interface I {} + enum E implements I {A, B} + final class C implements I {} + } + public record R(R r1, R r2, R r3, Object o) {} + """, + "test.Test.E _"); + } + + @Test + public void testInstantiateComponentTypes(Path base) throws Exception { + doTest(base, + new String[0], + """ + package test; + public class Test { + private int test(Pair> p) { + return switch (p) { + case Pair(A(A(_)) -> 0; + case Pair(A(B(_)) -> 0; + case Pair(B(A(_)) -> 0; + }; + } + record Pair(T c) {} + sealed interface Base permits A, B {} + record A(T c) implements Base {} + record B(T c) implements Base {} + } + """, + "test.Test.Pair(test.Test.B(test.Test.B _))"); + } + + @Test + public void testNeedToExpandIfRecordExists(Path base) throws Exception { + doTest(base, + new String[0], + """ + package test; + class Test { + sealed interface A { } + record B() implements A { } + record C(A a) implements A { } + + void test(A a) { + switch (a) { + case C(B _) -> throw null; + } + } + } """, + "test.Test.B _", + "test.Test.C(test.Test.C _)"); + } + + @Test + public void testComplex6(Path base) throws Exception { + doTest(base, + new String[0], + """ + public class Test { + sealed interface Base {} + record NoOp() implements Base {} + record Const() implements Base {} + record Pair(Base n1, + Base b2) implements Base {} + + int t(Base b) { + return switch (b) { + case NoOp _ -> 0; + case Const _ -> 0; + case Pair(NoOp _, _) -> 0; + case Pair(Const _, _) -> 0; + case Pair(Pair _, NoOp _) -> 0; + case Pair(Pair _, Const _) -> 0; + case Pair(Pair _, Pair(NoOp _, _)) -> 0; + case Pair(Pair _, Pair(Const _, _)) -> 0; + case Pair(Pair _, Pair(Pair(NoOp _, _), _)) -> 0; + case Pair(Pair _, Pair(Pair(Const _, _), _)) -> 0; + case Pair(Pair(NoOp _, _), Pair(Pair(Pair _, _), _)) -> 0; + case Pair(Pair(Const _, _), Pair(Pair(Pair _, _), _)) -> 0; +// case Pair(Pair(Pair _, _), Pair(Pair(Pair _, _), _)) -> 0; + }; + } + } + """, + "Test.Pair(Test.Pair(Test.Pair _,Test.Base _),Test.Pair(Test.Pair(Test.Pair _,Test.Base _),Test.Base _))"); + } + + private void doTest(Path base, String[] libraryCode, String testCode, String... expectedMissingPatterns) throws IOException { + Path current = base.resolve("."); + Path libClasses = current.resolve("libClasses"); + + Files.createDirectories(libClasses); + + if (libraryCode.length != 0) { + Path libSrc = current.resolve("lib-src"); + + for (String code : libraryCode) { + tb.writeJavaFiles(libSrc, code); + } + + new JavacTask(tb) + .outdir(libClasses) + .files(tb.findJavaFiles(libSrc)) + .run(); + } + + Path src = current.resolve("src"); + tb.writeJavaFiles(src, testCode); + + Path classes = current.resolve("libClasses"); + + Files.createDirectories(libClasses); + Set missingPatterns = new HashSet<>(); + + new JavacTask(tb) + .options("-XDrawDiagnostics", + "--class-path", libClasses.toString(), + "-XDshould-stop.at=FLOW", + "-XDshould-stop.ifNoError=FLOW", + "-XDexhaustivityMaxBaseChecks=" + Long.MAX_VALUE) //never give up + .outdir(classes) + .files(tb.findJavaFiles(src)) + .diagnosticListener(d -> { + if ("compiler.err.not.exhaustive.details".equals(d.getCode()) || + "compiler.err.not.exhaustive.statement.details".equals(d.getCode())) { + if (d instanceof DiagnosticSourceUnwrapper uw) { + d = uw.d; + } + if (d instanceof JCDiagnostic.MultilineDiagnostic diag) { + diag.getSubdiagnostics() + .stream() + .map(fragment -> fragment.toString()) + .forEach(missingPatterns::add); + } + } + }) + .run(Task.Expect.FAIL) + .writeAll(); + + Set expectedPatterns = new HashSet<>(List.of(expectedMissingPatterns)); + + if (!expectedPatterns.equals(missingPatterns)) { + throw new AssertionError("Incorrect errors, expected: " + expectedPatterns + + ", actual: " + missingPatterns); + } + } + +} diff --git a/test/langtools/tools/javac/patterns/PrimitiveInstanceOfComboTest.java b/test/langtools/tools/javac/patterns/PrimitiveInstanceOfComboTest.java index 82064bd4baf..1830afeb187 100644 --- a/test/langtools/tools/javac/patterns/PrimitiveInstanceOfComboTest.java +++ b/test/langtools/tools/javac/patterns/PrimitiveInstanceOfComboTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,16 +103,19 @@ public class PrimitiveInstanceOfComboTest extends ComboInstance { diff --git a/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchConstants.java b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchConstants.java index 2890b315e62..249cdeb2464 100644 --- a/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchConstants.java +++ b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchConstants.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @summary Retain exhaustiveness properties of switches with a constant selector * @enablePreview - * @compile/fail/ref=PrimitivePatternsSwitchConstants.out -XDrawDiagnostics -XDshould-stop.at=FLOW PrimitivePatternsSwitchConstants.java + * @compile/fail/ref=PrimitivePatternsSwitchConstants.out -XDrawDiagnostics -XDshould-stop.at=FLOW -XDexhaustivityMaxBaseChecks=0 PrimitivePatternsSwitchConstants.java */ public class PrimitivePatternsSwitchConstants { void testConstExpressions() { diff --git a/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.java b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.java index dacd48f441c..3eab2fc83d0 100644 --- a/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.java +++ b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.java @@ -3,7 +3,7 @@ * @bug 8304487 8325653 8332463 * @summary Compiler Implementation for Primitive types in patterns, instanceof, and switch (Preview) * @enablePreview - * @compile/fail/ref=PrimitivePatternsSwitchErrors.out -XDrawDiagnostics -XDshould-stop.at=FLOW PrimitivePatternsSwitchErrors.java + * @compile/fail/ref=PrimitivePatternsSwitchErrors.out -XDrawDiagnostics -XDshould-stop.at=FLOW -XDexhaustivityMaxBaseChecks=0 PrimitivePatternsSwitchErrors.java */ public class PrimitivePatternsSwitchErrors { record R_int(int x) {} diff --git a/test/langtools/tools/javac/patterns/SwitchErrors.java b/test/langtools/tools/javac/patterns/SwitchErrors.java index 607052be583..ebff13e7fa5 100644 --- a/test/langtools/tools/javac/patterns/SwitchErrors.java +++ b/test/langtools/tools/javac/patterns/SwitchErrors.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 8262891 8269146 8269113 8348928 * @summary Verify errors related to pattern switches. - * @compile/fail/ref=SwitchErrors.out -XDrawDiagnostics -XDshould-stop.at=FLOW SwitchErrors.java + * @compile/fail/ref=SwitchErrors.out -XDrawDiagnostics -XDshould-stop.at=FLOW -XDexhaustivityMaxBaseChecks=0 SwitchErrors.java */ public class SwitchErrors { diff --git a/test/langtools/tools/javac/platform/NonExportedPermittedTypes.java b/test/langtools/tools/javac/platform/NonExportedPermittedTypes.java index bdafef7e39a..9a378ce346a 100644 --- a/test/langtools/tools/javac/platform/NonExportedPermittedTypes.java +++ b/test/langtools/tools/javac/platform/NonExportedPermittedTypes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,9 @@ * @bug 8318913 * @summary Verify no error is when compiling a class whose permitted types are not exported * @modules jdk.compiler - * @compile/fail/ref=NonExportedPermittedTypes.out -XDrawDiagnostics NonExportedPermittedTypes.java - * @compile/fail/ref=NonExportedPermittedTypes.out --release 21 -XDrawDiagnostics NonExportedPermittedTypes.java - * @compile/fail/ref=NonExportedPermittedTypes.out --release ${jdk.version} -XDrawDiagnostics NonExportedPermittedTypes.java + * @compile/fail/ref=NonExportedPermittedTypes.out -XDrawDiagnostics -XDexhaustivityMaxBaseChecks=0 NonExportedPermittedTypes.java + * @compile/fail/ref=NonExportedPermittedTypes.out --release 21 -XDrawDiagnostics -XDexhaustivityMaxBaseChecks=0 NonExportedPermittedTypes.java + * @compile/fail/ref=NonExportedPermittedTypes.out --release ${jdk.version} -XDrawDiagnostics -XDexhaustivityMaxBaseChecks=0 NonExportedPermittedTypes.java */ diff --git a/test/langtools/tools/javac/switchexpr/ExpressionSwitchNotExhaustive.java b/test/langtools/tools/javac/switchexpr/ExpressionSwitchNotExhaustive.java index 802e66570ef..05a73c0ba7a 100644 --- a/test/langtools/tools/javac/switchexpr/ExpressionSwitchNotExhaustive.java +++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchNotExhaustive.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 8206986 * @summary Verify behavior of not exhaustive switch expressions. - * @compile/fail/ref=ExpressionSwitchNotExhaustive.out -XDrawDiagnostics ExpressionSwitchNotExhaustive.java + * @compile/fail/ref=ExpressionSwitchNotExhaustive.out -XDrawDiagnostics -XDexhaustivityMaxBaseChecks=0 ExpressionSwitchNotExhaustive.java */ public class ExpressionSwitchNotExhaustive { From a181dd09bd7ba6b23bf34327aa2be61bb00768dd Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 4 Feb 2026 11:54:23 +0000 Subject: [PATCH 327/328] 8376761: ARM32: Constant base assert after JDK-8373266 Reviewed-by: stefank, ayang, tschatzl --- src/hotspot/os_cpu/linux_arm/javaThread_linux_arm.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/hotspot/os_cpu/linux_arm/javaThread_linux_arm.cpp b/src/hotspot/os_cpu/linux_arm/javaThread_linux_arm.cpp index d82b9d90417..2b96e978980 100644 --- a/src/hotspot/os_cpu/linux_arm/javaThread_linux_arm.cpp +++ b/src/hotspot/os_cpu/linux_arm/javaThread_linux_arm.cpp @@ -42,6 +42,16 @@ frame JavaThread::pd_last_frame() { void JavaThread::cache_global_variables() { BarrierSet* bs = BarrierSet::barrier_set(); +#if INCLUDE_G1GC + if (bs->is_a(BarrierSet::G1BarrierSet)) { + _card_table_base = nullptr; + } else +#endif +#if INCLUDE_SHENANDOAHGC + if (bs->is_a(BarrierSet::ShenandoahBarrierSet)) { + _card_table_base = nullptr; + } else +#endif if (bs->is_a(BarrierSet::CardTableBarrierSet)) { CardTableBarrierSet* ctbs = CardTableBarrierSet::barrier_set(); _card_table_base = (address)ctbs->card_table_base_const(); From 8ad91ac1109e76ee8485bf221adeac7e1751ef17 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 4 Feb 2026 12:58:38 +0000 Subject: [PATCH 328/328] 8377141: G1: Remove unused local declaration in G1BarrierSetC2 Reviewed-by: tschatzl, shade --- src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp index 61402301eb1..34d31702e80 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -351,7 +351,6 @@ Node* G1BarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) co Node* G1BarrierSetC2::atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access, Node* expected_val, Node* new_val, const Type* value_type) const { - GraphKit* kit = access.kit(); if (!access.is_oop()) { return BarrierSetC2::atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, value_type); } @@ -361,7 +360,6 @@ Node* G1BarrierSetC2::atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access Node* G1BarrierSetC2::atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val, Node* new_val, const Type* value_type) const { - GraphKit* kit = access.kit(); if (!access.is_oop()) { return BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type); } @@ -370,7 +368,6 @@ Node* G1BarrierSetC2::atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& acces } Node* G1BarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const { - GraphKit* kit = access.kit(); if (!access.is_oop()) { return BarrierSetC2::atomic_xchg_at_resolved(access, new_val, value_type); }